# -*- coding:utf-8 -*-

*******************************************************************************
    実装ログ
-------------------------------------------------------------------------------

2023-04-03

  * main (adjust-builtin-wrappers): IFS= が設定されてしまう @ bash-5.0 (reported by pt12lol) [#D2030]
    https://github.com/akinomyoga/ble.sh/issues/311

    POSIXLY_CORRECT=y の環境で IFS= ble/bash/read を実行していた為に IFS= が関
    数呼び出し後も残る様になってしまったのだった。

    ? 然し不思議なのは何故か bash-5.0 だけで振る舞いが再現するという事。
      bash-5.1 以降は関数呼び出しの変数代入は posix であっても環境に残らない様
      になっているのは良い。然し、bash-4.4 以前については bash-5.0 と同様に環境
      に tempenv が残る様に見える。何故この時にだけ問題がないのだろうか。或いは、
      何処か別のレベルで local IFS が設定されているという事か、或いは呼び出し元
      の local POSIXLY_CORRECT=y は影響を与えないという事なのだろうか。よく分か
      らないが取り敢えずは問題は封じた筈なので気にしない事にする。

    取り敢えず関数呼び出しの前に変数代入を置かない様にする。明らかに ble.sh の
    内部だけで使われる関数については気にしなくて良い。util.sh の一般のライブラ
    リ関数についてはちゃんと posix を避ける様にする事にする。

    ? これよりも前には問題にならなかったのかというのが疑問である→どうも試して
      みた所 read や builtin read では tempenv は posix モードであったとしても
      環境には残らない様である。つまり、本当にシェル関数特有の振る舞いだったと
      いう事である。

      builtin read から ble/bash/read に置き換えられたのが a5b10e8b である。こ
      れは #D1981 に関係している。

2023-04-02

  * bgproc: bash-4.2 での bgproc#start で {bgproc[0]} は存在しないというエラーメッセージ [#D2029]

    これは exec {fdvar}redirect で発生しているエラーだった。bash-4.1,4.2では
    {fdvar} の fdvar として配列要素には対応していない。

  * bgproc: シェルの終了時に即座に強制終了するオプションをつける? (motivated by bkerin) [#D2028]
    https://github.com/akinomyoga/ble.sh/discussions/309#discussioncomment-5498921

    然し実際にそれが良い事なのか分からない。というか現状の実装ではそうはなって
    いないのだったか? → child session はちゃんとすぐに終了する。然し端末が閉じ
    ない。これは stderr, stdout, stdin の何れかが未だ開いたままになっているのが
    原因と思われる。

    .kill ではちゃんと全部閉じている筈と思ったがよく考えたらスタートしたプロセ
    ス自体が stderr を保持しているのが原因の気がする。

    そのまま強制終了するというのもどうかという気がするが、それならばそれで良い。

    * done: 或いは終了チェックの interval をより短くする。これは
      ble/util/bgproc#stop/.wait で使っている 1000 という値を設定できる様にすれ
      ば良い。然し、これを変更したとして実際に終了にかかる時間がそんなに速くな
      るのだろうか。

      うーん。或いは conditional-sync の progressive-weight を使う? と思ったが
      conditional-sync は新しいサブシェルを待つ物なので単に或る条件を待つという
      事には使えない。conditional-sync を拡張して任意の条件を待つ事ができるよう
      にする可能性も考えたが、

      a うーん。或いはコマンドを開始するのではなくて既存のプロセスを待つという
        機能を持たせる? この時に conditional-sync に足りていないのは kill を二
        段階で行う機能である。SIGKILL を送る様にするオプションは実装しているが、
        kill で駄目だった時に段階的に SIGKILL を送るという機能は実装していない。
        そういう機能も追加して良いかもしれない。

        うーん。取り敢えず conditional-sync を2回呼び出して二回目で SIGKILL を
        指定すれば良いのだと気づいたので conditional-sync 自体に段階的に kill
        を実行する機能は実装しなくて良かった。

      b 或いはコマンドが空の時には指定された条件だけを待つという振る舞いにする。
        この場合にはコマンドの kill までは実行しない。

      然しもし原因が .kill の interval による物なのだとしても、
      stdout/stderr/stdin を封じている限りは生きているというのは .kill が原因な
      のではないのでは? 然し、プロセスが瞬間的に終了する事ができなかった場合に
      は .kill による自動 kill が起動する迄は bgproc が保持している stderr が開
      いたままである。然し、その場合には timeout になるまで相当待たなければなら
      ない (既定では 10sec である。或いは SIGKILL まで更に 10sec ある)。

      * ok: と思ったがもしかすると .kill 自体が fd を保持しているから bg
        process が終了しない可能性? と思ったがそれも変だ。.kill 自体は fd を閉
        じてから呼び出している筈 → 実際に確認した。

    ? ok: ところで set -m して起動した bgproc のなかで更にパイプやサブシェルな
      どを立ち上げた時に更に別の PGID になっているとその別の PGID までは kill
      しきれないのでは。なので set +m を中で実行しなければならないのでは。

      →と思ったが、実験してみた限りでは set -m が実際に効果を持つのはそれを呼
      び出したサブシェルだけの様である。なので更に入れ子で呼び出された物に関し
      ては敢えて set -m を実行しない限りはちゃんと元の pgid に属する様になって
      いる。

    即座に終了する方法について考えたがこれは単に kill-timeout を 0 に設定すれば
    良いのでは。結局向こうで起こっている事が何か分からないのでどうしようもない。

    * 2023-04-03 うーん。即座に終了しないのは subshell の stdout/stderr/stdin
      を閉じていても、ble/fd で保持している fd が残っているからでは。
      ble/fd#finalize を呼び出せば良いだろうか。或いは tty に関しては
      ble/fd#finalize での自動 close を抑制していただろうか。

      →確認してみると ble/fd#finalize には tty は登録されていない様だ。という
      か寧ろ msleep 等が使っている fd を削除してしまう様だから中で sleep が使え
      なくなってしまう。ble/fd#finalize は呼び出しても仕方がない。

      うーん。待避している fd を閉じても駄目の様である。どうも builtin exit 0
      を呼び出して終了しようとしているのだがその時に redirect をしている。その
      redirect によって保管している fd が未だ生きている様だ。つまり、本当に全て
      閉じようと思ったら redirect によって保管している物も全て閉じる必要がある。
      すべて閉じる為には fd を列挙しなければならない。

      a 一定の範囲の fd を全て閉じる? linux (もしくは bash) は現在の所は 255 付
        近に redirect にの fd を保管している様だが os によってはもっと巨大な値
        に保存しているかもしれない。なので可能性のある fd を全てスキャンすると
        いう訳にも行かない気がする。

      b 或いは /proc/$BASHPID/fd の中にある物を全て閉じる? 然しこれも使えるシス
        テムが限られている。

      また fd をスキャンして閉じるとしても msleep 等が使っている fd を閉じてし
      まうとサブシェルの動作に問題を起こしてしまう。これについては -t で判定し
      て端末だけを閉じる様にすれば良い気もする。

  * make: インストール時に元のコメントなどの情報への pointer をつける (suggested by bkerin) [#D2027]
    https://github.com/akinomyoga/ble.sh/discussions/309#discussioncomment-5498921

    make_command.sh install からでは元のソースがどれかは原理的には分からないが、
    取り敢えず現状では ble.sh 以外は全て対応するファイルが同名で存在しているの
    で、その仮定の下でファイル名を含める事にした。ble.sh についても ble.pp と
    src/*.sh を全て含める事にした。

    果たしてコメントを削除しないインストールが本当に必要なのかは謎だが一応機能
    としてはつけておく事にした。何れにしても元々ある日本語のコメントは個人用の
    物であって他の人に見せる為のものではない。

  * bgproc: bash-3 で idle.cancel がないと表示される [#D2026]

    実装を改めて確認してみたらそもそも bash-3 に対する考慮が全く入っていない。
    然し、将来的に bash-3 でも idle を使える様にする可能性を考えると単にバージョ
    ンで判定するのもよくない気がする。結局 function#try で調整する事にする。

2023-03-26

  * menu-complete (linewise): 長い行がある時に表示が崩れる (reported by bkerin) [#D2025]
    https://github.com/akinomyoga/ble.sh/issues/307

    これは実装を詳しく調べてみたら選択時の部分更新の時の幾何を記録する部分で、
    描画範囲を限定した時の記録が残っていないのが原因だった。そもそも linewise
    は試験的に最初に実装したもので余り真面目に実装されていない感じがする。その
    後で desc の実装でもっとちゃんと実装されてその時に限定された描画範囲につい
    てちゃんと対応が行われている。その desc に使われた仕組みを linewise からも
    使うだけで良かった。

    然しそれとは別に長い候補を入力した時に panel の高さが変わった時に menu の高
    さを制限した上で再描画を行う仕組みが欲しい。これについては簡単ではなさそう
    なので別の項目で議論する事にする。

2023-03-16

  * edit: bind -x で PS1 も一時的に復元する (requested by adoyle-h) [#D2024]
    https://github.com/akinomyoga/ble.sh/issues/304

    lincheney/fzf-tab-completion で退避中の一時 PS1 が表示されるというから何か
    と思ったら自分で PS1 を出力しているのだった。

  * 2023-03-06 menu-complete: 番号で選択する (requested by bkerin) [#D2023]
    https://github.com/akinomyoga/ble.sh/discussions/284

    これは実は実装はそんなに大変ではない気がする。

    LASTWIDGET のチェックは必要?  否、他のものは全て抜けるから関係ない? と思っ
    たが TAB や cursor key 等の移動コマンドの後も番号はリセットしたい。なのでや
    はり LASTWIDGET はチェックする。番号が溜まって一致する物がなくなったら一つ
    ずつ古い文字を削除して一致するものが出るまで削る。一つも一致しなかったら削
    る前にリセットして新しい文字自体をなかった事にする?

    試しに実装してみたが操作性に疑問が残る。先ず menu-complete の中に入らないと
    番号で選択できない。一方で、menu を表示しているだけの場合にも選択しようとす
    るのが自然の気がする。

    a menu-complete の外からでも M-0 等で選択できる様にするとしても
      menu-complete に入らずに select しても仕方がない。

      もう一つの問題点は menu が表示されていたらどの文脈であっても M-0 で menu
      に入ってしまうのかという事。auto-menu を実装していたりすると実質的に M-0
      は常に menu に入ってしまうという事になり操作できない。或いは、TAB を二回
      押した時に complete に入るのと同じ様に、LASTWIDGET が complete だった時に
      M-0 で menu-complete に入るというのは手の気がする。

      更にもう一つの問題点は menu の中に番号を表示していない時でも番号による選
      択を有効にするのかという事 → これは M-0 等のキーを使っている時点で、実際
      に番号が表示されているかどうかに関係なく menu-complete に入るという事で良
      い気がする。

    b 或いは、menu-complete の外で M-0 等で引数を入力し始めたらその場で
      menu-complete に入るという可能性も考えられる。

    * どの menu-style についても番号を表示する機能が欲しい。

      設定名を変更する?

        bleopt menu_item_prefix
        bleopt menu_item_prefix_linewise
        bleopt menu_item_prefix_align
        bleopt menu_item_prefix_desc

      と思ったが現在の設定名は他の設定と共に menu_STYLE_NAME の形で一貫している。
      これを壊すのも変な気がするので、既存のルールは保持する。全体の設定を一括
      で変更するオプションを用意したい気がするが、その名前は何にするか。単に
      menu_prefix で良いだろうか。

        bleopt menu_prefix
        bleopt menu_linewise_prefix
        bleopt menu_align_prefix
        bleopt menu_desc_prefix

      取り敢えず align と desc について候補番号に対応した。dense は対応していな
      い。が、完全性を期する為にはやはり dense も対応した方が良い気がする。→対
      応した。

    * done: wiki, blerc: menu_prefix, menu_{aling,dense,linewise,desc}_prefix

    * 返信

      for key in {0..9}; do ble-bind -m vi_imap -f "$key" 'append-arg enter-menu'; done
      for key in {0..9}; do ble-bind -m menu_complete -f "$key" 'menu/append-arg always'; done

2023-03-14

  * 2021-10-26 ble/builtin/read: WINCH を受信できていない気がする [#D2022]
    もしかすると subshell の中では受信できないという事なのかもしれない。

    2023-03-14 winsize を更新する関数を作ったのでこれにも対応する事にする。

    % と思ったが WINCH を受信できていない? 問題は WINCH を受信しても LINES
    % COLUMNS が更新されない事と思ったが、そもそも WINCH を受信できていないという
    % 事なのだった。
    % →即時 WINCH を受信できる訳では無いがユーザーが文字を入力した時にちゃんと
    % 受信できている。

    subshell の中で実行するとちゃんと内部で設定した trap が発火している様に見える。

    * fixed: ble/builtin/read/TRAPWINCH でも update-winsize を呼ぶ事にした。と
      思ったが 個別に色々処理するよりも単にここで ble/application/onwinch を呼
      び出してしまうのが自然である→その様に修正した。

    x fixed: "bash: ble/term/visible-bell:/clear: そのようなファイルやディレク
      トリはありません" というエラーが発生する。/clear は
      ble/term/visible-bell/.erase-previous-visible-bell から呼び出されるが、こ
      の関数は $_ble_base_run/$$.visible-bell.* に属している物を全て削除しよう
      とする。なので subshell で設定された物も削除しようとする。

      この時親 shell で一度も visible-bell を使っていないと visible-bell が初期
      化されていない状態になっていて問題が生じる。

      或いは subshell で発生した visible-bell は subshell だけで管理する事にし
      て subshell を抜ける時に始末する事にする? subshell というか read を抜ける
      時に処理すれば良い → read を終了する時に visible-bell/erase を呼び出して
      消去する事にした。C-c を押した時には結局中断して駄目なのでは? と思って試
      してみたが C-c の時にもちゃんとその場で visible-bell/erase が呼び出されて
      いる様なので、C-c もちゃんと ble.sh の上で処理されているという事なのだろ
      う。

    実際に read -ep でも WINCH もちゃんと発火している様に見える。LINES, COLUMNS
    も更新されている。それなのに textmap が更新されていない様な気がする → と思っ
    たが textmap を更新した後に出力して確認していたので更新されていない様に見え
    ただけだった。ちゃんと更新されていて新しい端末幅を反映した値になっている。
    ずれて見えたのは単に端末の折り返しによって行が増えている事による物だった。

    ? reject: redraw-here がちゃんと働いていない様な気がする? と思ったがそもそ
      も幅が縮まった時には、縦に内容がはみ出てしまってその分まで遡ろうとはしな
      いので、現在見えている振る舞いが元々意図した物である気がする。なので気に
      しない。

    * fixed: サイズの変更があった後に read を中断すると親のプロンプトが表示され
      てから [EOF] 等のマーカーが表示される。何故?

      うーん。read -ep ; read -ep をコマンドから実行すると一つ目の read と二つ
      目の read の間で既にプロンプトを表示しようとしている。SIGWINCH が走ってそ
      れで再描画が起こっている?

      ble-edit/attach/TRAPWINCH ではちゃんと _ble_term_state を確認しているのに
      何故かそれをすりぬけて表示が実行されている。_ble_term_state が一時的に
      internal になっている様に見える。

      と思ったら分かった気がする。ble/builtin/read/.impl の中で一旦
      ble/term/enter してその後で ble/term/leave している。この ble/term/leave
      するよりも前に WINCH が走って其処で internal 状態にあると勘違いしてプロン
      プトが表示されてしまうということの気がする。何故 subshell の中で実行しな
      いのかというと C-c やその他の事故で subshell が予期せず終了した時に状態の
      復元に失敗しない為だろうという気がする。

      →これは ble/application/onwinch を呼び出す時の条件を増やして対処する事に
      した。

2023-03-13

  * trap: winch の様々な問題 [#D2021]

    * fixed: bash-4.3..5.0 で ble-reload 後に WINCH が効かない

      一方で Cygwin の bash-4.4 で ble-reload した後に WINCH が正しく処理されな
      くなっている。chatoyancy 上では bash-5.2 も 4.4 もちゃんと動いている。

      builtin trap WINCH 自体が発火していない様だ。一方でウィンドウサイズを変更
      した後は謎の PS1 への代入ジョブ (終了ステータス 127) が表示される。而も、
      その PS1 に代入される値は現在の値とは関係ない。

      うーん。chatoyancy でも 4.4 で再現した。histdb を無効にした状態で reload
      すると動かなくなる。bash-5.2 では問題になっていない。5.1 でも OK。5.0,
      4.3 は駄目。bash-4.2 はちゃんと動いている。つまり 4.3,4.4,5.0 の問題。何
      故 reload だと駄目なのだろうか。

      詳しく調べてみると ble-detach してから ble-attach すると再び動く様になる。
      これは要するに rl winch hook のインストールが関係しているという事ではない
      か?  確認してみると実際に winch が再設定されている。既存の trap を確認し
      てみると、空になっている。つまり unload の時にクリアされているという事。

      unload-for-reload から呼び出している時には WINCH を削除しない事にした。動
      く様になった。因みに INT についても同様の処理はしなくて良いのか? と思った
      が取り敢えずは問題は起こっていない気がするので気にしないことにする。現在
      は WINCH だけ特別扱いする。

      x この実装だと元々存在していた user WINCH trap が消えてしまうのではないか。
        →実際に確かめてみたら消滅する。別の変数に記録しておく事にした。別の変
        数に記録しておいた物を拾う処理をする為に、今まで内部 trap を install 済
        みの時に単に return 0 していたのを trap_string, trap_command を空にして
        処理を続ける事にした。取り敢えず動いている。

    ? ok: bashrc で ble-attach しても WINCH はちゃんと有効なのか? bash-4.3 以外
      は大丈夫。

    * ok: bash-4.3 で WINCH が即時発火しない問題

      逆に bash-4.3 は最初から ble-attach しても prompt attach しても WINCH が
      全然発火していない。というか 4.3 は --norc で起動して WINCH に trap した
      としても WINCH が発火しない。次にユーザーが入力を試みた時に初めて発火して
      いる。逆に言えば 4.3 では入力を開始すれば何れにしても正しい幅で描画される。

      これは取り敢えず入力を開始さえすれば直るので取り敢えずは気にしない。

    * fixed: bash-5.2 でコマンド実行中にサイズ変更が発生した時に反映されない問題

      うーん。全てのコマンドを実行する度にサイズ再取得を実行する必要があるか?
      或いは idle で処理する必要があるかもしれない。

      できるだけ高速に判定する方法が欲しい。複数のコマンドで速度を比較する?

      stty size, resize, tput lines cols, bash -c

      試してみた所、tput が最も速く、その次が stty、更に resize が来て bash -c
      による方法が最も遅かった。一方で、stty size は ble/term/stty/enter で呼び
      出している stty とくっつけることができる。取り敢えず優先順位として stty,
      tput, resize, bash の順に試し、stty による実装が使える場合には
      ble/term/stty/enter の stty 呼び出しを修正する方法も考慮に入れる事にした。

      取り敢えず実装した。動いている。

  * edit: WINCH で拡大した時のサイズの変わり方が変だ [#D2020]

    調べてみると onwinch が入れ子で呼び出されている。SINGWINCH の処理が入れ子に
    なっている。bash 自体は入れ子にはしていないが、read-timeout が WINCH 発火を
    遅延していて、read-timeout の中から主導で呼び出した WINCH の中で、更に trap
    WINCH が発火している様だ。

    一方で、ble/application/onwinch の実装を見ると入れ子で呼び出した時の対策は
    ちゃんとしてある様に見える。

    うーん。ble/application/onwinch の中では何れにしても一切の更新処理は実行し
    たくない。ble/application/onwinch を抜ける時に改めて処理を行いたい。

    ? 今の実装だと _ble_decode_hook_Processing=body|prologue の時に winch を受
      け取ると後の ble/application/render の際に無駄に二回描画される気がする。
      どうせ onwinch の中で ble/application/render が発生するのだから、直接
      ble/application/render を呼び出せば良いのではないか。

    取り敢えず onwinch 全体を WINCH の抑制対象として onwinch の末尾でも WINCH
    の発火が途中であった時に onwinch を呼び出す様にした。ble/application/render
    の前に onwinch があった時には ble/application/render をせずに最初から
    onwinch をする様にした。実装した。動いている。前よりも素早い動作になった。

  * execmark: wrong usage (2), command_not_found (127) 等の文字列 [#D2019]
    https://qiita.com/Linda_pp/items/1104d2d9a263b60e104b に面白い記述がある

    /usr/include/sysexits.h に幾らか値が定義されている様だ。EX_USAGE..EX_CONFIG
    が 64..78 に定義されている。

2023-03-12

  * global: ret が leak する様になっている [#D2018]

    だいぶ遡ってもずっと leak している。何故だろうか。取り敢えず最新版で修正した。

    * ble/util/bgproc#keepalive がリークしていた
    * ble/complete/sabbrev/expand もリークしていた

    →ずっと遡っても発生している ret の上書きはどうも ble.sh --norc で発生して
    いる? 調べてみると任意のキー入力の後で低確率で発生している様に見える。或い
    は auto-complete が関係しているのだろうか。

    * 結局 emacs keymap の __after_widget__ に問題があった。
    * 更に類似の呼び出しで PS0 についても ret の leak があった。両方とも直した。

  * bgproc: histdb から切り離して再利用可能にする (motivated by bkerin) [#D2017]
    https://lists.gnu.org/archive/html/help-bash/2023-03/msg00068.html
    https://github.com/akinomyoga/ble.sh/issues/302#issuecomment-1462977627

    * done: ble/opts#has バグ修正。影響は cmdspec_opts の plus-options だけの様だ。
      全然判定できていなかった。常にほぼ false になっていたと思われる。

    * done: ble/util/bgproc 既に開いている prefix を指定した場合は以前のものは
      削除する。

    * done: 複数のプロセスが走っている場合に対応できる様にプロセスグループを作
      らせる事にする。set -m を実行すれば良い。

      * done: 実は負の引数を kill -0 に渡すことでプロセスグループの何れかのプロ
        セスが残っているかどうかを判定することができると分かった → これを利用
        して改めて kill 部分の処理を作り直した。

      * done: どうやらコマンド置換の中でやるとプロセスグループが作られない様だ。
        なので bgpid=$(set -m; bgproc & echo "$!") ではなくて ble/util/assign
        bgpid '(set -m; ...)' とする必要がある。

        一方で、そもそもコマンド置換にしていた理由はあったのだったか。もし別の
        理由があったのであればそれについても () で壊れないか確認する必要がある。
        調べてみるとコマンド置換を使っていたのは最初からで (#D1925) 特に考察は
        していない様に見える。取り敢えず普通のプロセス置換にしても大丈夫。

        修正した。

    * done: EXIT (もしくは internal_EXIT) に自動で登録する?

      →と思ったが単なる close ではなくて EXIT の時に特別の処理をしたい時に
      EXIT もしくは internal_EXIT を設定していると、期せずして先に bgproc#close
      されてしまって後処理ができなくなってしまう。

      a うーん。後処理を行いたい場合の為に internal_EXIT に登録しない設定を作る?

        特に指定しない場合に自動で終了処理を追加するとしても、internal_EXIT で
        呼び出して良いのだろうか。他の EXIT 処理が bgproc を利用したいという場
        合に問題が起こる可能性がある。という事を考えると、EXIT の方に登録するべ
        き? 然し EXIT の方に登録したとしても呼び出しの順序によって変なことが起
        こる可能性がある。

      b reject: bgproc/onclose:prefix の中で EXIT 処理を実装してもらう

        別の方法として bgproc#close の中で終了処理としての close なのか一時的な
        close なのかを判定して各自処理を切り替える方針で実装してもらう? しかし
        これだと bgproc が生きていても死んでいても実行するべき処理の場合に困る。
        単に bgproc#close からの呼び出しを期待していると bgproc が走っていない
        場合にその処理が呼び出されなくなってしまう。それに分かりにくい。

      取り敢えず owner-close-on-exit と no-close-on-exit を opts として指定可能
      にすることにした。

    * fixed: unload の時にも同様に呼び出すべきなのではないか? というか寧ろ今ま
      で EXIT でやっていたのは unload でやるべきだったのではないか。

      →histdb と bgproc の両方を EXIT ではなく unload を使う様に変更した。

    * done: close-callback は関数に置き換えるべきなのでは? 結局 bgproc#close を
      呼び出す必要があるのであれば、opts の中に直接コマンドを記述するよりはちゃ
      んとした関数を定義して関数名を close-callback に指定することになるが、そ
      うであるのならば最初から関数名を ble/util/bgproc/close:_ble_histdb 等に固
      定してそれを直接呼び出す様にした方がわかりやすい。

      また callback の中で ble/util/bgproc#close を呼び出すのも一見して無限ルー
      プになるのでインターフェイスとして分かりにくい。それよりは単に close 直前
      の終端処理として呼び出す様にするのが良い気がする。それでも
      ble/util/bgproc#close を入れ子で呼び出した時の対策は今のまま残しておく事
      にする。

    * done: request を送る機能 & 死んでいたら再始動する機能

      timeout でデータを削除してしまうと restart 時に問題なのでは? なので
      timeout 時には [4] だけ消す事にする? timeout で終了した場合と期せず終了し
      てしまった場合は区別するべき。

      適当にいい加減な bgproc を作って動作確認した。取り敢えず簡単な使い道の範
      囲ではちゃんと動いている様である。

      また help-bash で提供されていた例に関しても cotnrib/config/github302 に実
      装してみて動作確認した。動いている気がする。

    面倒なので取り敢えずこれで push する事にする。何れにしても histdb は未だ実
    験中でドキュメントにも記していないし、また例として実装した perlre-server も
    help-bash / GitHub #302 の為の例に過ぎないので寧ろテストしてもらうぐらいで
    良い。

2023-03-10

  * complete: complete_source_sabbrev_ignore が動いていない [#D2016]

    * done: そもそも全然動作していなかった。修正した。

    * fixed: opts の方も動作をチェックする。no-empty-completion は '\' から始め
      ても候補が生成されない様だ。うーん。COMPV ではなく COMPS に対して適用する
      べきである。

    * done: wiki, blerc: complete_source_sabbrev_{opts,ignore}

2023-03-09

  * readonly blacklist のチェックを m scan に含める (motivated by mozirilla213) [#D2015]
    https://github.com/akinomyoga/ble.sh/issues/289#issuecomment-1457920928

    * done: m scan

    * done: readonly でファイル名・行番号を表示する。

    * done: 警告の表示の回数上限はパス毎に決める? (dict が使えない場合を除く)

      →一回表示した(パス,行,変数)の組み合わせに関しては二度と表示しない様にす
      る。トップレベルの呼び出しの時には回数上限を使う。

    * done: 回数上限はコマンドラインの実行ごとにリセットする?

    2023-03-10 ちゃんと動いていない。FUNCNAME を最後の要素までチェックする事にした。

  * complete: option:source を他のコマンド名として呼び出せる様にする (requested by mozirilla213) [#D2014]

    complete: progcomp_alias と同様の処理をその他の補完生成の時にも行う
    https://github.com/akinomyoga/ble.sh/discussions/287

    と思って source:options の実装を確認したが既にちゃんと alias を考慮した処理
    になっている。

    より詳しい設定について尋ねたら返信が戻ってきた。要するに、他のコマンドのオ
    プションを別のコマンドの補完に表示したいという事らしい。これに関しては自前
    で新しい補完を定義する必要がある。

    * done: それと現在の source:option の生成はコマンド名を決め打ちにしているの
      で、それを関数に切り出して調整可能にしたい。取り敢えず source:option を真
      ん中で分割した。

    取り敢えず試しに簡単に実装してみて振る舞いを調べる。動いている気がする。

2023-03-08

  * contrib: sabbrev 補完候補を生成しない設定 (motivated by mozirilla213) [#D2013]
    https://github.com/akinomyoga/ble.sh/discussions/288#discussioncomment-5159335

    これを contrib に入れて改良する。例えば simple-word eval する。argument か
    ら呼び出された時にだけ不活性にする。ADVICE_FUNCNAME で本来の FUNCNAME を記
    録する (もしくは function#advice 側で advice 関連の FUNCNAME を削除した物を
    取得して返す関数を作る?)。

    ble.sh 側でも sabbrev は empty completion しない設定や、literal sabbrev 候
    補の生成を抑える設定などを考えても良い気がする。etc.

    bleopt complete_sabbrev_opts=no-empty-completion:literal

    うーん。実装仕掛けたがこれは literal を実装してからにするべきの気がする。取
    り敢えず inline, linewise sabbrev を実装した (#D2012)。

    改めて考えてみたが取り敢えず literal sabbrev の類いは wordwise ではないので
    source:argument では生成しなくて良いという気がする。後になって欲しくなった
    らその時に考える。

  * 2021-05-19 sabbrev: 単語でなくても任意の文脈で発動する sabbrev が欲しい [#D2012]

    \ 等で前置すれば特に問題ないのではないか? 然し、その為には全ての場合につい
    て一致するかどうか確認する必要がある。

    2023-03-08 どうも実際に \ に色々割り当てて使おうとしている人がいる様だ。こ
    の用途だと実際に単語でしか発動しないというのは困るのではないだろうか。
    https://github.com/akinomyoga/ble.sh/discussions/288#discussioncomment-5226973

    例えば ble-sabbrev --literal 的なオプションにするのはどうだろうか。通常の
    sabbrev が見つからない場合に --literal sabbrev を試みる。literal sabbrev に
    関しては -m は対応しなくて良い (もしかしたら最終的に実装する可能性もあるが
    今ではない)。

    ? resolved: 取り敢えず literal という名前で実装したが本当にそれで良いのか。

      % literal というと -m の反対という気もするし、そもそも sabbrev 自体が
      % literal である。元々伝えたかったのは文法情報等を無視した sabbrev という
      % 事だった。例えば context-free sabbrev expansions 等の方が自然の気がする。
      % 然し、context-free を表現するオプション名として適切な物が思い浮かばない。
      %
      % a 何も考えなければ頭文字の -c だが、実際は context 依存の逆という事なの
      %   で変な気がする。
      %
      %   或いは漢字変換的な使い方を想定して conversion の頭文字と取る事もでき
      %   る?  然し漢字変換というとどういう名前だろうか。IME と考えて -i とする
      %   か。然しそれだと i は input の i なので一般的すぎて微妙? 否、input 専
      %   用と思えばやはり良い? 然しオプション名が例えば input-no-insert だとよ
      %   く分からない。やはり実際の呼称と紐づいたオプション文字にしたいと考え
      %   ると呼称自体から丁寧に決めたい。
      %
      % b context に依存しないという意味でやはり literal 的な要素があって、そう
      %   思うと -l でも良い様な気もしてくる。
      %
      % c -c の逆という事で -C 等を使うという可能性もある? がやはり分かりにくい
      %   気がする。
      %
      % d -f はどうだろうか。ble-bind -f (bindable Function) という既存の例があっ
      %   てその印象があるが、それを抜きにすれば悪くない気はする。然し、やはり
      %   自然かというと疑問が残る。
      %
      % e 英小文字にしたい。という事を考えると片っ端から可能な物を列挙して考え
      %   てみても良いのかもしれない。zsh alias で既に使われているオプションは
      %   避けたい。
      %
      %   zsh alias で使われているのは gmrsL である。grs はそれぞれ alias の種
      %   類を指定する為のオプションで、-g はグローバル alias (ble-sabbrev に対
      %   応)、-s は suffix alias (拡張子展開)、-r は通常 alias である。-m
      %   PATTERN はまとめて複数の alias を glob で指定するのに使う。-L は現在
      %   の alias の定義を出力するのに使われる。
      %
      %   ble-sabbrev では -P を出力に使いたい気がする。
      %
      %   * -a は grep の -a の様に文字列 (ascii) をそのまま解釈するという意味
      %     に使えるかもしれない。
      %
      %     或いは anywhere という意味にも取れる。これが良い気がする (anywhere
      %     という意味に取れば every where -e もありかもしれないが -e はより色々
      %     な意味に取れそう)。でも anywhere というのも微妙なのは、anywhere と
      %     言いつつカーソルの直前で起こる必要があるという事。何処からスタート
      %     しても良いという意味での anywhere であるが、それを表現するのに丁度
      %     良い別の表現はあるだろうか。
      %
      %   * -b は backward?
      %   * -i は inplace という漢字がするけれど違う気もする。
      %   * -djkwyz ???
      %   x -e は grep の様に次に通常のパターンが来るという意味の引数に使えるか
      %     もしれないが、それはいま目的としている物とは違う気がする。
      %   x -gs は既に zsh で別用途に使われているので混乱の元
      %   x -n は特別な効果を全て削除しているという雰囲気が出るかもしれない? で
      %     もやはり変な気がする
      %   x -o はオプションを指定しそうな気がする。
      %   x -p は出力という漢字がする。
      %   x -q は quoted という感じがするが現在の目的からすると混乱の元
      %   x -t は tail という意味に取れる気もするがそもそも sabbrev は常に末尾
      %     にカーソルがある時に発火している。これは context-free sabbrev 特有
      %     の特徴ではない。類似の考えで -h (here) 的なものも駄目。
      %   x -u は変更のある項目の選択に使いそう? でも ble-sabbrev に既存設定や
      %     既定値などない為、登録されている全ての物が変更ありになるのでこのオ
      %     プションをその意味で使っても意味がない。
      %   x -v も literal 的なものを想起する。C-v 関係だろう。然し、これも現在
      %     の用途に合っているかというと微妙な気がする。
      %   x -x は何か実行しそう。
      %
      % 長い呼称を先に決めてからそれの短縮オプション文字を決めるのが良さそう。
      %
      % literal-no-insert, conversion-no-insert, contextfree-no-insert,
      % inplace-no-insert, inword-no-insert 等。うーん。inword が良い気がしてき
      % た。類似の物として inword subword, substr, substring, suffix, 等。
      % inword だと空白も含む略語展開に合わないし、丁度単語に一致している時も変
      % な気がする。代わりに inline というのも良いのかもしれない、と思ったが
      % sabbrev 自体既にある意味で inline なので混乱の元かもしれない。唯の置換
      % と思えば substitute だとか replace だとかもありなのだろうか。然し、これ
      % も sabbrev 一般の性質を表して言えるのに過ぎない。

      うーん。コマンド行全体に作用する sabbrev も定義したくなって来た。それも定
      義すれば全体として consistent になる気がする。

      →結局 -l (--linewise) 及び -i (--inline) を両方定義する事にした。これが
      インターフェイス的にも分かりやすい。

    * done: 取り敢えず実装仕掛けた literal は inline に変更する。と思ったが、-il
      をまとめて linewise と呼ぶ事にする。

    * done: wordwise vs literal は最長一致に変更する。呼び出し元で一々指定しな
      くて良い様にする。同時にどの種類の展開が起こったのかを取得できる仕組みを
      作る。文字で返すのが良い? もしくは終了ステータス?

    * done: 現在の実装では inline も単語で切ってから判定しているが
      _ble_edit_str 全体に対して適用するべきの気がする。

    * done: 呼び出し元に展開の種類を返す機能。

    * done: ble-sabbrev の -mil は全体に作用する様にインターフェイスを変更する。

    * done: ble-sabbrev に long option を用意する事にする。

    * done: wiki: ble-sabbrev -il

    * done: wiki: edit_magic_opts
    * done: blerc: edit_magic_opts

    * done: -w で通常の sabbrev の種類を選択できる様にする。通常の sabbrev を選
      択するのに毎回 --type=wordwise としなければならないのは不便である。

    ? resolved: linewise は本当に linewise と呼んで良いのか? コマンドライン全体
      に一致するのだから bufferwise とか whole とか all とか exact とかにするべ
      きなのでは。或いは実際に linewise に一致する様に変更した方が便利? その時
      にはインデントも許す様にする。extglob を一時的に有効にしないと面倒だろう
      か。

      [[ $1 == "$key" || $1 == *$'\n'*(["$sp"])"$key" ]]

      或いは $'\n' で切断して trim しても良いかもしれないと思ったがそうすると今
      度は key に改行や空白が含まれていた場合に都合が悪い。それに trim は regex
      を使っているので別に extglob よりも早いとも限らない。

      extglob は実装の問題から遅くなる可能性があるがそれは気にしない事にする?
      と思ったが現在の codebase では extglob はほぼ使っていない。というか確認し
      てみたらユーザーの提供したパターンなどを評価するときを除いて全く使用して
      いない。なので、ここでも使わない実装を目指したい様な気もする。

      というか最初に末尾が $key に一致するか確かめてその上で残っている文字列に
      対して regex で確認を行えば良いだけなのでは? その様に実装する事にする。

  * 2023-03-02 complete (source:argument): sabbrev 候補が気になるのは最初に表示されるから? (motivated by mozirilla213) [#D2011]
    https://github.com/akinomyoga/ble.sh/discussions/288

    後ろに回した方が良い気がする。修正した。

    コマンド補間についても同様ではないか? と思ったが変数名よりは sabbrev の方が
    先に来て欲しい。コマンド名と sabbrev だとどちらが先にくる事を期待するのかは
    微妙である。コマンドは基本的に大量にある。一方で、sabbrev は有限個である。
    具体的にコマンド名を入力してコマンド名が絞れてきた頃には sabbrev も絞られて
    いると期待される。なので、コマンド名に関しては表示しなくて良い気がしてきた。

    然しそう考えると引数の場合も本当に sabbrev を後回しにするべきなのか分からな
    い。と思ったが、引数補間の場合にはオプションの数は少ない可能性がある。一方
    で予め定義しておいた sabbrev が大量に存在している時には、sabbrev 候補で全部
    が埋め尽くされて実際に知りたいオプションのリストを見る事ができなくなる。な
    のでやはり引数補間の場合には sabbrev 候補は後ろに回すべきである。

  * [棄却] prompt: $PWD in airline が更新されない? [#D2010]
    https://github.com/akinomyoga/ble.sh/discussions/294#discussioncomment-5227252

    bind -x の中でディレクトリを移動してもそれが反映されたりされなかったりする
    という事。うーん。\w を使っていればちゃんと反映されるのではないか。

    直接 $PWD があれば自動的に抽出される筈だし \w や \W があっても抽出されるの
    では? と思ったが、勝手に変更をリアルタイムで追跡するのは変だという事になっ
    た様な気もする。例えばコマンド終了直後の値を表示しておきたいのにすぐに変わっ
    てしまっては困るのである。

    然しそうだとしても別の理由でプロンプトの再評価が起こった時に結局表示が更新
    されてしまうのだから、そういう揮発性の情報を表示する時には元より ble.sh で
    はちゃんと別の変数に記録しておく必要があるのではないか。

    →実際試してみると \w にしておけばちゃんと反映される。$PWD だと反映されない。
    section 毎のキャッシュがちゃんと働いているからであろう。

    これに関しては更新したければ適切に設計する必要がある。

    * ok: wiki に説明を書く? と思ったら既にちゃんと add-hash が記述されていた。

    実際に簡単なものを作って実演してみる(以下)。動いている。これは後で返信する。
    これに関しては現状で修正する事はない気がする。

      function ble/prompt/backslash:mypwd {
        ble/prompt/unit/add-hash '$PWD'
        ble/prompt/print "$PWD"
      }
      bleopt vim_airline_section_c='\q{mypwd}'
      bind -x '"\C-t": cd - &>/dev/null'

  * complete: limit line length for auto-complete [#D2009]

    "a @b" の時に @ に { を入力すると固まる

    どうも a5b10e8 で問題が発生する様になっている。うーん
    ble/application/render で固まっている。となるとやはり文法が関係しているので
    はないか。という気がする。調べて行くと textmap#update で時間がかかっている。
    どうも巨大な文字列が自動補完で挿入されてそれの解析で時間がかかっている様だ。
    長さ 50170 になっている。

    x fixed: 自動補完で limit が効いていないのは何故か? line_limit_length は
      10000 の筈である。それの5倍の長さになっている。

      →挿入の時点では replace-limited を使っている。然し、何故かそれをすり抜け
      ている。うーん。line_limit_type が editor で、editor の場合には
      replace-limited の時点では何も行わない。__line_limit__ という名前の特別な
      キーが送信されてくる仕組みになっている。

      誰が __line_limit__ を送っているのかというと ble/content/check-limit とい
      う関数である。そしてこの関数はどうやら ble-decode/EPILOGUE から呼び出され
      ている。丁度最後の render を呼び出す直前である。期待としては表示を試みる
      前に editor が起動されるという事だが、auto_complete の中にいるので
      __line_limit__ が単に無視されてそのまま描画ルーチンに入っているということ
      の様だ。

      うーん。そもそも auto-complete に入るのが間違いの気がするので
      auto-complete/enter の時点で reject する様に修正した。

    x この巨大な補完候補は何処から生成されているのか? histdb? → どうやら
      histdb の様である。とても長い単語が登録されているのだろう。histdb の側で
      余りに長い物は除外するべきだろう。登録する時点で保持する? それとも補完す
      る時点で保持する?

      取り敢えず今はテストの為にこの長い単語を保持しておく事にする。

    x ok: 幾ら文字列が長かったとしても 50k 程度でフリーズするのは変な気がする。
      何故?

      →調べてみたら textmap#update で 20s かかって update-syntax (parse) で
      39s かかっている。更に何処かで 20s ぐらいかかって最終的に表示される。
      textmap#update は全ての文字の表示位置を計算しているので遅い。parse は勿論
      時間がかかる。その他も何か一つずつ処理しているか何かなのだろう。つまり、
      何処かが特別に時間がかかっているのではなくて、全体的に処理に時間がかかっ
      ているということの様だ。

      うーん。これは結局単に時間がかかっているというだけの事。

    * histdb: もし巨大な単語が紛れ込んでいたとしても検索の時点で文字数に制限を
      かける事はできないか→取り敢えず検索の時点で文字数に制限をかける事にした。
      動いている。

  * edit: ~name による "named directory" 展開機能? [#D2008]
    https://github.com/akinomyoga/ble.sh/discussions/299

    sabbrev の新しい展開の種類として実装する可能性? チルダ展開と同じ文脈で活性
    化して、それが直前の単語に含まれていた場合に展開する。コマンド実行前に展開
    する機能は混乱の元なので実行したくない気もするが…。

    * 然し ~xxx の状態で展開されていないと補完が効かない気がする。補完する時に
      内部で ~xxx も考慮に入れて候補を生成するのは大変だ。なので補完を試みる前
      に展開するべきの気がする。/ を入力する瞬間か或いは補完を実行する直前か。
      うーん。というか magic-insert という widget を作る方が良い気がして来た。
      それで / も magic-insert にしてしまう。

    * 同時にコマンド実行の瞬間に全体をスキャンして展開する仕組みを作っても良い
      気がする。

    % 取り敢えず magic-insert は実装する。実装した。
    %
    % さて、ここでの疑問は既定で / magic-insert を設定しておくべきかどうかという
    % 事。というか / で履歴展開が実行されると困るのでは。なので、一部の展開だけ行
    % うべきの気がする。というか alias 展開も実行したくない。
    %
    % やっぱり現在の振る舞いは space だからこそ動くのである。magic-insert はやめ
    % る事にする。

    色々考えると / に対しては sabbrev だけ行う関数を定義するべきの気がする。
    magic-slash を実装してみた。

    x done: 然し、tilde 展開を装っている場合に普通と違うのは変数代入形式の引数
      の右辺で : 区切りの位置の最初から sabbrev expansion を試みる必要があると
      いう事。

      と思ったがこれは通常の sabbrev expansion でも対応するべきの気がする。うー
      ん。対応した。

    ここでの疑問はこの magic-slash を既定の binding として登録するべきかどうか
    という事である。或いは ~ で始まる物だけを magic-slash で変換の対象とする?
    或いは / に感応する sabbrev の category を新しく作る? うーん。~ で始まる物
    だけを特別扱いするのが良い気がする。

    * done: wiki

    * done: slash-strip: magic-slash で挿入を行う場合は元から sabbrev の定義に
      含まれる末尾の / は削除する。

    * done: slash-strip: -m の方も対応する必要がある? と思ったが実際にやってみ
      ると menu-complete が始まった後に / が挿入されて変な事になる。これはちゃ
      んと magic-space でやっているのと同様に処理する必要がある。一意確定の時に
      は slash-strip を自前で処理する。

  * syntax: echo alpha[0]+=~ がチルダ展開として認識されていない [#D2007]
    これは単純なミスだった。修正した。

  * sabbrev: 変数代入右辺での展開の対応 [#D2006]

    変数代入の右辺では右辺に対して sabbrev 展開を行う。: で区切ったフィールドも
    認識する。

    * ok: 然しこれに対応するには複数の sabbrev 展開位置について考慮に入れる必要
      がある気がする。例えば locale-key の context に rhs も対応すれば良い気が
      するが、そうすると今度は通常の sabbrev で = も含めて展開しようとしている
      物が動かなくなる。と思ったが、現在の設定だと = を含む sabbrev はそもそも
      定義できないのでは?なので rhs は含めてしまって良い気がする。

    * done: 変数代入右辺の特定

      実際に変数代入の右辺での sabbrev に対応するとしてどの様にして変数代入の右
      辺を特定するのか。一旦その様な関数を書いたかもしれないと思ったがどのよう
      に探せば良いか分からない。使っていそうな所を探すのが良い気がする。

      arr=([0]=xxx) 及び var=xxx の場合には rhs でちゃんと抽出できている。問題
      は argument の時にどの様にしているのかという事。

      a var=xxx の時にどの様に抽出しているのかを確認すれば良いのではないか?

      b 或いは complete 側で source:argument の fallback をどの様に処理している
        か。うーん。これは単に正規表現で一致させているだけの気がする。

      c と思ったら ble/syntax:bash/find-rhs という名前のそのままな関数があった。
        この関数を使って見る事にする。

      取り敢えず対応した。更に : による区切りにも対応したい気がするがそれは後回
      しにする。と思ったがやはり後になると面倒なのでここで対応する事にする。

    * done: rhs や argument (変数代入) の時に : 区切りで一番近いフィールドに対
      して sabbrev 展開を実行する?

      ":" を含む sabbrev があっても良いが、特に a=...:... の形式をしている時に
      は効かない様にしてしまっても良い気がする。

      a 取り敢えず simple-word で区切る事にした。

      b もっとちゃんとやろうと思ったら文法情報を参照する事もできるかもしれない。

        特に、rhs の文脈では必ず : で stat を設置しているのだから rhs 内部を舐
        めて stat に記録された ctx をチェックすれば良いのでは?

        local i
        for ((i=asrc[1];i<comp_index;i++)); do
          [[ ${_ble_edit_str:i:1} == : && ${_ble_syntax_stat[i]-} ]] || continue
          local ctx=${_ble_syntax_stat[i]%%' '*}
          [[ ${_ble_syntax_bash_command_IsAssign[ctx]-} ]] &&
            ((asrc[1]=i+1))
        done

        と思ったがこれだと $() 等の内部にある : も拾ってしまう。なので本当にちゃ
        んとやろうと思ったら nest 情報も参照しなければならず大変である。今は実
        装しない事にする。

    * done: _a-zA-Z0-9 に統一する。検索しやすい為。

  * complete: adb completion で "no devices/emulators found" というエラーメッセージ (reported by mozirilla213) [#D2005]
    https://github.com/akinomyoga/ble.sh/issues/292

    これは結局通常の bash での TAB 補完でも同様のエラーメッセージが発生するとい
    う事だった。何が問題なのかは分からないが、ちゃんと設定されていない状態で補
    完を試みようとするとエラーメッセージが表示されるという事なのだろうか。設定
    されていても設定されていなくても補完の途中でエラーメッセージは出すべきでは
    ない気がするが、取り敢えずエラーメッセージは封殺する事にする。

    * upstream に報告しようと思ったが何処に報告すれば良いのかよく分からない。
      platform/system/core に昔 adb.bash が含まれていた? ような含まれていなかっ
      た様だ。野良 repository に adb.bash が追加されていて、それが広まったとい
      う可能性もある。或いは、大本の repository では管理していないが配布アーカ
      イブには含まれていた?

      sdk/bash_completion/adb.bash 的な物もあるようだが。これは大昔だ。
      https://android.googlesource.com/platform/sdk/+/3056c8e/bash_completion/adb.bash

      ここにもあるがこれは報告者の使っている物とは微妙に異なる様だ。
      https://github.com/mbrubeck/android-completion

      結局よく分からない。Google が何処か人目に触れないところで最新版を管理して
      いて配布しているという事なのだろうか。

  * decode: M-S-o in konsole? (reported by mozirilla213) [#D2004]
    https://github.com/akinomyoga/ble.sh/issues/298

    これは取り敢えず分かった。 ESC O が他のキーの prefix になっている為に次の文
    字を待っている。失敗した時には decode_error_cseq_discard=1 になっているので
    全体が捨てられる。という事が起こっている。

    x 保留: テストで ESC [ を何回か押していたら無限ループになって死んでしまった。

      何が起こっているのだろうか。ESC { を複数回押したのがよくなかったのかもし
      れない。 M-{ は補完をブレース展開で全て挿入する機能になっていて、空のコマ
      ンドラインで実行すると全てのコマンド名をブレース展開で挿入する事になる。
      とても長いコマンドラインになって処理に時間がかかっていたのではないか。

    * reject: charseq 毎に timeout を設定できるようにする機能についても考えたが、
      必要性がない気がする。そもそも keyseq に timeout を指定できる様にしたのは
      ユーザーがそれで動作を変える (keychord などの様に) ことができるためであっ
      た。然し、charseq にそのような使い方があるとは思えない。また、考えてみる
      と timeout が必要なケースも実はかなり限られている。実は ESC <char> の時だ
      けの個別対応で良い。

    * ok: ESC [ 1 等についても手で入力した場合と続きがある場合で区別が付かない
      のではないか。と思ったが、手で一瞬で ESC [ 1 まで入力することはできないし、
      ESC [ で止まった時点で M-[ に確定する気がする。逆に ESC [ 1 まで一気に受
      信したとしたらこれはより長い CSI シーケンスの一部であると判断するのが自然
      である。なので、 ESC [ 1 等に対して timeout を考える必要はない。

    取り敢えず timeout を設定する事にした。現在の位置で一致するが続きがあっても
    良い曖昧なシーケンスの場合、または ESC を受け取った状態の時には 5ms 待って
    続きが来なければ現在のシーケンスで確定という事にする。取り敢えずは動いている。

    ? yes: vim はちゃんとこの場合に対応しているのだろうか。と思って確認してみた
      らちゃんと動いている。やはりユーザーから文句があったのだろうか。

2023-03-06

  * edit (rps1): PS1 に prompt_rps1 の色が残る (reported by linwaytin) [#D2003]
    https://github.com/akinomyoga/ble.sh/issues/293#issuecomment-1452786142
    https://github.com/akinomyoga/ble.sh/issues/293#issuecomment-1453507285
    Ref #D1972

    今迄問題が生じていなかったのは ble/textarea#render/.show-rprompt の直後にプ
    ロンプト原点以外の場所にカーソルを配置していたので、sgr に色が設定されてい
    たとしても何れにしても goto.draw の際に色がクリアされていたから。

    それが e128801c1 によってプロンプト原点に強制的に戻る様にしたので PS1 の開
    始位置に移動する時の sgr0 が出力されなくなって色が残る事となった。元々移動
    する時に sgr0 を出力したのはそうしないと変な所の色に影響が出てしまう端末を
    避ける目的があったので、元々 show-rprompt で先頭に戻る CR の直前の時点で
    _ble_term_sgr0 を出力するべきである。その様に修正した。

  * contrib/prompt-git: git gc したら branch 名など取得できなくなった [#D2002]

    調べてみるとどうも .git/info/refs の中にまとめて記録される様になった様だ。
    対応した。

2023-03-05

  * コマンドラインに文字列を挿入する関数 (zsh print -z) (requested by mozirilla213) [#D2001]
    https://github.com/akinomyoga/ble.sh/discussions/291

    * done: TMOUT= は ble/bash/read の中で指定してしまうのが良い気がする。
      ble/bash/read を使う時に必ず TMOUT= の設定を試みなければならないというの
      は面倒な契約であるし忘れてしまう可能性が高い。

    * Bash プロセス間通信の整備

      これは何らかのプロセス間通信を実装する必要がある気がする。前々から考えて
      いた枠組みをこれを機に実装してしまうのが良い気がする。さて、何らかのメッ
      セージが来た時にどの瞬間に読み込むのかという問題がある。

      a joblist をチェックするタイミング? 今回の場合に丁度良い気がする。

        joblist.flush は現在は ble-edit/exec:gexec/.end から呼び出している。コ
        マンドを実行していない時の joblist の表示は何処で呼び出している?
        →ble/util/joblist.bflush を .insert-newline の中から呼び出していた。

      b history_share をチェックしている箇所? これはコマンド実行直前、
        discard-line、履歴移動直前等で行っている。今回の場合には余り適していな
        い様に思われるし、一般の枠組みとしても適したタイミングを与える様には思
        われない。

      c 何かキー入力をする度に? 然しこれは何か画面更新をしたい場合等には余り適
        していない気がする。

      d PRECMD と同じタイミングで呼び出すという手もある気がする。と思ったが、
        precmd が呼び出されるのは既に leave-command-layout した後なので不用意に
        何かを出力できない気がする。

        一方で joblist.bflush のタイミングだとしても問題になる様な気がする。

        寧ろ precmd でなにか出力したい時には enter-command-layout /
        leave-command-layout を自分で呼び出して出力する事にすれば問題ない気がす
        る。既に enter-command-layout には呼び出し階層のカウントも実装している
        ので呼び出している箇所が既に command-layout なのかどうかなどについて考
        えなくて良い。更に ble/util/buffer の flush 等についても意識しなくて良
        い。

      % 最終的に複数の処理タイミングの種類を考える必要があるかもしれないが、取
      % り敢えずは a という事にする。後で処理タイミングを追加できる様に最初の実
      % 装から処理タイミングを指定するフィールドを作っておく。暫定的な名前は何
      % にするか。postexec だと複数 exec の時に正しくないし、exec_end にしたと
      % してもまた空のコマンドを実行した直後にも発火することを考えると正しくな
      % い。

      うーん d の方が良い気がしてきた。これにすれば最初の実装における既定の処理
      タイミングに対応する名前も precmd で良くてすっきりする。また、単に
      blehook internal_PRECMD に ble/message.check を指定しておけば良い。

      ユーザーの作成したイベントについても処理できる様にしたい。broadcast の関
      数も作りたい。message という関数も用意する。

      取り敢えず一通り実装した。試験的な handler print で動作確認もした。
      subshell からデータを送信できる事も確認した。

    * コマンドラインへの文字列挿入を実装する。

      コマンド名は何が良いか。ble-print はない。ble insert-string string ぐらい
      にする→結局 append-line にした。文字列を挿入するとしても既に入力されてい
      る行に続けて挿入するのも変である。独立な新しい行を追加するのが自然である。
      すると insert-string よりは insert-line の方が自然である。line は widget
      の名前でもよく使われている。また、現在のカーソル位置などにいきなり挿入す
      るのも変な気がする。コマンドラインの末尾に挿入するのが自然である。という
      ことを考えると append-line が自然の気がする。

      取り敢えず実装した簡単だった。

    ? ok: 特に大量の文字列を挿入する時に何が起こるか? line_limit_length のチェッ
      クはどの時点で入るのだったか → ble-edit/content/replace-limited によって
      挿入している限りはちゃんとチェックが入る様だ。

    o C-o とちゃんと一貫した動作になるか→OK ちゃんと動いている。
    o 複数の append-line があってもちゃんと動くか → 動いている。

    ----

    その他の修正

    * main (read): ble/bash/read で bash-5.2 で -r を付け忘れていた。

    * main (ble): "- " が名前に含まれている ble.sh 関数 "ble-*" も "ble *" の形
      で呼び出せるようにする。

    * util: ble/string#quote-word を set -ue 等で呼び出しても大丈夫な様にする。

    * util: "builtin : >| file" は単に ">| file" で良い。

    * global: builtin read する時の TMOUT= は ble/bash/read の中で指定する

    ----

    2023-03-06 直接 eval するのはやはり変な事が起こりそうで嫌なので is-simple
    の判定だけ行ってから eval する事にした。

    ----

    wiki に ble-append-line の説明を追加した。

    * done: wiki: ble append-line

  * 2022-07-06 highlight: "function aaa bbb ccc" と素早く入力すると変なエラー着色の残り方をする [#D2000]

    % function aaa bbb ccc として C-l すると描画の着色がおかしい。C-l としなく
    % ても高速に入力するとこういう事が起こる様だ。

    素早く入力した時などに発生し C-l で再描画しても残っている。

    調べてみるとどうやらエラー着色が layer に残留してしまうのが原因の様である。

    _ble_syntax_attr/tree/nest/stat?
    06 a    000 'f' |  stat=(CMDX w=- n=- t=-:-)
     | a    001 'u' |
     | a    002 'n' |
     | a    003 'c' |
     | a    004 't' |
     | a e  005 'i' |
     | a    006 'o' |
     | a    007 'n' +  word=CMDI:0-8/(wattr=d)
     3 a    008 ' '
    22 a    009 'f'

    しかもこのエラーは単語着色のエラーではなくて文法的に閉じていない時に実施
    されるエラー着色である。何故この様な中途半端な事が起こるのかよく分からな
    い。うーん。起こる条件が分からない。滅多に起こらない。

    これはなかなか再現しないので別項目にして後で考える事にする。
    →どうも syntax.sh が遅延ロードされた時に発生する様である。

    2023-03-05 SIGWINCH 対策を行った時に改めてこれについて考えた

    | * reject: 文法情報が初期化時に壊れるのは SIGWINCH などによって再描画が解
    |   析の最中に発生するからではないか。その場合には SIGWINCH の処理を延期す
    |   るべきである。というか、それは ble/application/render の時点で入れ子で
    |   render が発生しない様に調整するべきである。→と思って実装を確認したら既
    |   にその様な実装になっていた。
    |
    |   →というか初期化時に壊れるのは SIGWINCH とは関係ない。ウィンドウサイズ
    |   を変更していなくても、文字列を素早く入力するだけで文法情報が破壊される
    |   ので。やはり初期化時に function というのを素早く入力した時に壊れがちで
    |   ある。特に入力し始めた時に未だ syntax がロードされておらず白黒の状態の
    |   まま入力した後に発生する気がする。
    |
    | * reject: ble/syntax/parse の呼び出しを確認してみたが別に入れ子で呼び出さ
    |   れる等の問題が起こっている訳でもない。
    |
    | ble/highlight/layer:syntax/update-error-table の実装が関係している気がす
    | る。特にコメントアウトされている syntax3_table をクリアする行を入れる様に
    | してみると問題は発生しない。うーん。_ble_highlight_layer_syntax3_list に
    | 登録されているエラーを削除する事になっているが、この配列に登録されている
    | データが壊れるか或いは失われるかずれているか、という事なのだろうか。
    |
    | どうも _ble_highlight_layer_syntax3_table の compaction が起こっている様
    | な気がする。というか layer table は shift の対象だと考えると sparse になっ
    | ているのが問題なのでは? うーん。shift の履歴を見ていて気づいた。どうも
    | (DMIN,DMAX0,DMAX) の呼び出しが欠けてしまっている? なので本来挿入されるべ
    | き要素が挿入されずに sparse になって変な事が起こっている。では何故
    | (DMIN,DAMX0,DMAX) が欠けてしまうのだろうか。
    |
    | →つまり遅延して読み込まれているので、読み込まれた後の (DMIN,DMAX0,DMAX)
    | しか受け取れていないという事。

    [原因] core-syntax は遅延して読み込まれる。読み込まれる迄は syntax_buff や
    その他の layer 固有の buffer は更新されない。そして読み込まれた時に空の配列
    として初期化している。

    一方で、これらのテーブルに対して layer/update/shift が呼び出される時、配列
    は前回の更新時の文字列の長さと同じだけの要素を持つ dense な配列であることを
    想定している。ここで実際に要素の足りない配列に対して layer/update/shift が
    呼び出されると意図しない compaction 等が発生してエラーの設置位置がずれてし
    まう。

    [修正] 初期化時に要素の数が足りていない時にはちゃんと補う必要があるという事。
    initialize-vars の時点でちゃんと要素を必要な数だけ入れておけば良い。

    うーん。然し、どの長さを持っている事が期待されているのかは非自明である。

    a initialize-vars の時点での要素数は直前の ble/highlight/layer/update の呼
      び出し時における _ble_edit_str の文字数である。もし現在の _ble_edit_str
      及び DMIN,DMAX,DMAX0 から遡って取得しようと思ったら DMIN,DMAX0,DMAX が記
      録されている場所を知らなければならない。遡っていくと
      ble/textarea#update-text-buffer で _ble_edit_dirty_draw_{beg,end,end0} を
      拾っている。うーん。これを取得するのは複雑だし、edit.sh からの呼び出しを
      仮定する事になる。モジュール外の呼び出し元の情報を参照しなければならない
      のでカプセル化に失敗している。

    b 或いは別の buffer の要素数をそのまま真似するのが良い様な気がする。という
      か plain_buff は必ず存在する事になっているのでその要素数をそのまま真似れ
      ば良いのではないか。

    実際に plain buff の長さを確認してみたらちゃんと期待通りの要素数を持ってい
    る。この要素数を真似て新しい配列を初期化する事にした。動いている。問題は解
    決した様に見える。

  * term (mlterm), vim-airline: prompt_status_line がちゃんとレイアウトできていない [#D1999]

    * mlterm detection

      0;96;0   v3.1.0 (2012-03-24) https://github.com/arakiken/mlterm/commit/6ca37d7f99337194d8c893cc48285c0614762535
      1;96;0   v3.1.2 (2012-05-20) https://github.com/arakiken/mlterm/commit/6293d0af9cf1e78fd6c35620824b62ff6c87370b
      1;277;0  v3.4.2 (2014-12-27) https://github.com/arakiken/mlterm/commit/c4fb36291ec67daf73c48c5b60d1af88ad0487e6
      1;279;0  v3.7.2 (2016-08-06) https://github.com/arakiken/mlterm/commit/24a2a4886b70f747fba4ea7c07d6e50a6a49039d
      24;279;0 v3.7.2 (2016-08-11) https://github.com/arakiken/mlterm/commit/d094f0f4a31224e1b8d2fa15c6ab37bd1c4c4713

    mlterm: どうも status_line の内容がちゃんと表示できていない。カーソルの位置
    計算については今の所問題は生じていない様だが。実際に出力されているシーケン
    スと、それを出力した時に mlterm がどの様に振る舞うかについて確認しておく必
    要がある気がする。

    どうやらシーケンスを生成した時点で何故か一番右のフィールドを折り返してしまっ
    ている様だ。何故?

    最後の全体の trace によって (1\E[80D\E[1B,36) という具合に生成されている。
    二つの問題がある。

    x fixed: sep の幅を 1 と仮定しているので mlterm ではstatus_line に収まり切
      らない内容が設定されている。sep の幅もちゃんと考えて判定を行うべき。

    x fixed: confine が指定されているのにも関わらず何故か折り返されている。これ
      に関しては ros, cols を確認してみた所、何故か 80x24 になっていた。
      status_line の場合には高さ 1 に制限していた筈。或いはその制限を解除する等
      しただろうか?

      →うーん。確認してみたが prompt_rows=24 に明示的に設定されている。どの段
      階で設定されているか確認する事にする。

      ble/prompt/unit:_ble_prompt_term_status/update では prompt_rows=1 を設定
      している。と思ったら _ble_prompt_term_status は別の物であって
      _ble_prompt_status が問題の関数だった。確認してみた所 prompt_cols=1
      prompt_cols=$cols としていてこれは明らかに prompt_rows=1 の間違いである。
      これを修正したら折り返しが被さってしまう問題はなくなった。

    x reject: 初期化時 (char_width_mode 未確定時) に status_line が二重になってしまう問題

      更にもう一つの問題は char_width_mode が response によって変化して再描画が
      発生した時に、以前出力した status bar が残ってしまって二重になってしまう
      問題。

      a WINCH の時には全体をクリアしていたので折り返しがあっても問題がなかった。
        char_width_mode の変更に際しても同様に間にある内容を消去する様にしても
        良いのではないか。うーん。winch の時に何が画面を消去しているのかと思っ
        たが、これは恐らく ble/canvas/panel/invalidate height ではないか。
        char_width_mode=auto 完了時にも呼び出すか?

        x 然し、これを呼び出してしまうと char_width_mode 確定時に結局配置に変更
          がなかったとしても必ず再描画を実行しなければならなくなる。再描画の必
          要が分かった時にだけ消去するという事はできない物だろうか。

      b 或いは bottom-dock の一番上の panel を描画する時点で全消去する? と思っ
        たが行数が分からないので bottom-dock の別の panel を消去しない様にする
        ことができない。

      c 或いは端末からの応答がある迄は描画を開始しない

        x 折角色々の処理を遅延させてプロンプトを先に表示する事によって応答を早
          くしているのに、端末の応答を待つようにしてしまっては意味がない。また
          端末が応答しなかった場合にプロンプトが表示されない事になってしまう。
          短い timeout を設定するとその timeout の間だけ確実にフリーズする事に
          なるので避けたい。また制御も面倒である。

      d もしくは二回完全描画を行い二回目は全消去を実行する。

        これはちらつきが気になるし、殆どの場合には必要にならない二回の描画を毎
        回実行する事になるので避けたい。特定の条件を満たした時にだけ二回完全描
        画にするとしても、完全性を期すのであれば厳密な Unicode version 一致も必
        要になるので問題である。

        とは言っても結局プロンプトは二回表示しているのでは? と思ったがそれは
        git 情報を表示しているから? うーん。基本の設定では、プロンプトは最初に
        一回だけ表示すれば十分という事になっている筈。

      e 或いは vim-airline を char_width_mode 未確定の時には表示しない様にする?

        然し結局応答しない端末が合った時に vim-airline がいつまで経っても表示さ
        れないという問題が発生する。

      f 或いは最初の char_width_mode は安全側に倒して char_width_mode=east にし
        ておく? 然し最近の端末は全て west なので、east を規定値にすると毎回必ず
        再表示が起こってやはり不都合なのではないか。

        ja_JP の時にだけ最初を char_width_mode=east にする? と思ったがそれでも
        mlterm を別の言語で使っている人もいるだろうし、完全な解決にはならない。

        しかし再描画が起こって、プロンプトの配置が微妙に変わるだけであれば大し
        た問題ではないのでは? と思ったがカーソル位置が変わったり、或いは rps1
        の表示位置が変わったり等の事が起こるのはやはり微妙な気もする。うーん。

        x これもやはり応答がない west な端末の場合に問題が持続してしまう。

          最初の描画の瞬間だけ幅を変更する様にしたらどうか。そうしたとしても、
          やはり応答がない端末の場合に変な不整合が起こるかもしれない。次の再描
          画の時に再配置するとしても、char_width_mode とは独立に表示幅などを勝
          手に弄ると文字幅キャッシュ等で不整合が起こって変な事になる。なので
          char_width_mode と _ble_unicode_c2w_ambiguous を独立に一時的に変更し
          て処理することは非現実的である。

      やはり mlterm の場合には最初から bleopt char_width_mode=east を設定してお
      く様にしてもらうしかないのだろうか。逆に言えば最初から
      char_width_mode=east を設定してもらうだけで済むのであればそちらの方が良い
      気がする。

      これには対応しない事にする。

    2023-03-06 うーん。~/b.txt にデバグ用のデータを出力していた。行を削除する。
    make_command.sh make scan でチェックしていたと思ったが確認した所 a.txt しか
    チェックしていなかった。危ない。[a-z].txt を全てチェックする様にした。

  * syntax: ${arr[@]@k} に対応できていない [#D1998]

    対応した。

2023-03-04

  * 2022-10-13 nix completion で止まる問題 (reported by aiotter, Aleksana) [#D1997]
    https://github.com/akinomyoga/ble.sh/issues/58#issuecomment-1272222143

    これは説明を書く。何処かにこういうののまとめを書く方が良いのではない
    かという気がする。

    Sorry for the late reply. I have been busy recent days (and am stil
    busy actually...). This is actually one of the compatibility
    problems that are hard to solve.  ble.sh extends the usage of the
    programmable completions for auto-complete

    やはり問題を解決してから対処する事にする。

    2022-12-03 報告を受けた筈なのに何処かに行ってしまったとおもったら #58 の下
    にあった。

    2022-12-04 cevhyruz への私信での解説を何処かに移植して説明するのが良い気が
    する。

    https://github.com/akinomyoga/ble.sh/issues/246#issuecomment-1294893636
    ここでも少し言及している。

    2023-03-03 また issue が上がったので見てみる事にする。

    以前の nix-bash-completion のファイルを持ってきて試してみたが動かない。補完
    しようとすると行が消えてしまう。調べてみると同じ現象が以下で報告されていて、
    しかし最早このリポジトリは管理されていなくて古いということの様に思える。

    https://github.com/hedning/nix-bash-completions/pull/22

    という事は最新版は何処か別の場所にあるという事になるが何処にあるのだろうか。
    というか普通に nix を入れたら入るという事なのだろうか。だとしても何処にある
    のか謎である。よく読むと ncfavier が代わりにメンテナンスするとかしないとか。

    https://github.com/NixOS/nixpkgs/pull/207224

    然し ncfavier の github 上のリポジトリに bash-completion っぽいのはない。別
    の場所で管理しているという事なのだろうか。

    適当にファイルを漁ってみると以下の場所に nix completion が置いてある。これ
    を確認してみる事にする。

    /nix/var/nix/profiles/default/share/bash-completion/completions/nix

  * syntax: coproc 変数名が alias に一致する時、着色を変更する [#D1996]

    うーん。実はもっと詳しく調べてエラー着色にするべきなのではないか? →多少
    alias の中身もチェックする事にした。alias の中身が複数の単語に展開される場
    合にはエラー着色になる様にした。

    展開前の時点でキーワードに一致している場合にはどうするのか。内部での解釈と
    は独立に構文解析が行われる事になるので、内部でキーワードに展開されたからキー
    ワード着色にするなどの工夫をした所で外側の構文解析が壊れてしまう。

    →alias が展開されてキーワードになる場合には、当初はその場で簡単な物だけ処
    理する様にしてみたが、結局通常のコマンド処理に fallback する様にした。元々
    変数名に一致しない場合にはその様に処理していたので問題ない。

2023-03-03

  * menu-complete: enter_menu であっても一意確定なら補完完了する機能 [#D1995]
    https://github.com/akinomyoga/ble.sh/discussions/297#discussioncomment-5159146

    実装した。menu を既に表示してしまっている時に単に menu に入る処理をしている
    所では、既存のメニューを選択してから即座に menu の確定処理を行う。menu を未
    だ表示していない時には menu の処理は一切せずにその場で挿入を実行する。menu
    を既に表示していて二回連続 TAB を押した時についてはまた別の処理が必要になる。

    うーん。単純に opts を継承する事にした。調べてみると menu/enter が処理して
    いる opts は backward と今回追加した insert_unique だけなので別の物が指定さ
    れていたとしても突然問題になる様には思われない。なので、単に opts を
    menu/enter に渡してしまう事にする。この様にすれば個別に insert_unique を実
    装しなくて済む。

    うーん。widget/menu-complete は enter_menu:insert_unique を既定にしてしまっ
    て良いのではないか → 変更した。

  * vi: operator:filter で end が文字列の最後の時には追加の改行は入れない [#D1994]

    x fixed: うーん。v 等で中途半端な場所にある時に beg は行頭に移動するけれど
      も end は行末に移動しない状態でフィルターが適用されて変な事になる。vim の
      振る舞いを見ると何れにしても行全体に適用される様である。

      実装を確認してみると ble/keymap:vi/expand-range-for-linewise-operator を
      呼び出しているので、行志向に拡張するのは意図的に行っている。然し、それが
      ちゃんと拡張されていないということの気がする。

      →これは思いっきりバグだ。local end と宣言してしまっていたので折角実行し
      た変更が関数の呼び出し元に伝わっていなかった。修正した。

    どういう条件で改行を挿入するのかは非自明である。取り敢えず変換前の文字列に
    改行が含まれていれば改行を挿入する? うーん。空文字列だった時にはそうではな
    い気がするし、更に改行が含まれていなかったとしても続きに文字列があればやは
    り改行が必要な気がする。

    1 end の次に改行以外の文字がある時は改行を入れる必要がある。

    2 end の次に改行がある場合でも改行を入れる必要があるのでは。これは二重改行
      の時に起こる。然し、非空行の行末に end があった場合 (本来この様な事は起こ
      らない筈だが) には改行は入れたくない。

      従って非行頭行末の時には改行は省略する? 然し本来この様な状況にはならない
      と思っているし、いざなったとしても改行は入れるか入れないかは微妙な気がす
      るので、この様な複雑な判定はせずに、この場合でも常に改行を入れるという形
      で良い気がする。

    つまり end が文字列末尾にあるのでなければ常に改行を挿入するという事で良い気
    がする。

  * zoxide: zi を bind -x から呼び出すと Enter が効かないらしい (reported by linwaytin) [#D1993]
    https://github.com/akinomyoga/ble.sh/issues/293#issuecomment-1451208995

    何故か自分の手元では再現しないが取り敢えず stty icanon を実行すれば直る様で
    ある。bind -x の度に stty を二回実行するのはコストが高いのでデフォルトで実
    行するのは微妙だが、zi を実行した時にだけという事であればそんなに問題にはな
    らないだろう。という事で関連する関数を上書きする事にする。

  * histdb: bash-3.2 で idle を使おうとして失敗している [#D1992]

    bash-3.2 では自動的に kill する機能はなくす?

2023-03-02

  * edit: ジョブ情報が出力されるとステータスバーが消える (reported by mozirilla213) [#D1991]
    https://github.com/akinomyoga/blesh-contrib/issues/11
    Ref #D1800

    うーん。これは coproc でなくても sleep 1 & で発生する。joblist の出力部分を
    ちゃんと command layout で囲んで置かなければならないという事? 或いは
    display-shell-version 等と同じ様にして出力する必要?

    ble/widget/print を呼び出せば良い様な気もする。

    うーん。出力は joblist.bflush で行われていて buffer に問題の文字列が混入す
    るという事になっている様だ。呼び出し元を見るとble/util/joblist.bflush
    ble/widget/.insert-newline となっている。つまり、layout 変更の途中の様な気
    がするのでこの状態で command layout への切り替えなどすると変な事になる気が
    する。後でよく考える必要がある。

    一方で joblist.check や ble/util/joblist では直接出力はしていない様なので
    joblist.bflush と joblist.flush だけ抑えて置けば大丈夫の気がする。実はこれ
    らは三箇所でしか呼び出されていないので対応はそんなに難しくない気がする。

    うーん。調べてみたが joblist.bflush を呼び出す所まではちゃんとできている気
    がする。それよりも一旦 collapse した状態を抜けていないのが原因の気がする。
    実際 joblist.bflush の呼び出しをなくしても問題が発生する。

    どうもこれは #D1800 で問題にしていたのと同じ問題の様に見える。うーん。どう
    も keep-info が指定されている時には enter/leave-command-layout がバランスす
    るという仮定の様な気がする。keep-info が指定されていない時は #D1800 を気に
    してコメントが書かれているが、keep-info のついている .insert-newline に関し
    ては #D1800 のコメントはついていない。

    単に keep-info の時に leave-command-layout を呼び出す様にしたら解決した。

  * [棄却] external: coproc c { sleep 1; echo; } とすると文法エラーになる [#D1990]

    "bash --norc" だと問題はない。何故? "bash --norc" で .blerc を読み込んでも
    問題はない。 mshex をロードしていると blerc をロードしていなくても問題にな
    る。何らかの shopt が関係しているという事だろうか。

    shopt を完全に合わせてみたがそれでも問題は再現しない。mshex について bisect
    するしかないのだろうか。

    うーん。分かった。alias c が展開されている。つまり、coproc の次はコマンドで
    も良いし変数名でも良いので取り敢えず alias 展開が実行されてしまうという事。
    そして一文字エイリアスはよく使われてかつ一文字変数も良く使われるので衝突す
    るという事。

2023-03-01

  * syntax: 5.3: 配列要素代入の右辺でブレース展開は無効 [#D1989]
    https://git.savannah.gnu.org/cgit/bash.git/commit/?h=devel&id=349e21043e362914551277728159f8e55350bad7

    これの修正は簡単だった。

  * vi_imap: M-S-o に対する fallback が ESC o になっている [#D1988]

    これは redispatch の時に S-o が O になっていないのが原因。そもそもの問題と
    して S-o も ble-bind を用意しておくべきなのかそれとも常に S に解決するべき
    なのかという疑問がある。うーん。然しキーボード上で両者を区別する事に意味は
    ない様な気がするのでこれで良い気がする。

    ? CapsLock が入っている場合にはどうするべきなのか。この場合には実際のキー入
      力として [Shift]+[O key] を送っている気がするが、操作としては "o" を送っ
      ているつもりなのではないか…。うーん。CapsLock の状態を取得するのは難しい。
      それも送信する様にするプロトコルもある様だが、そういうプロトコルばかりで
      はないので CapsLock の情報に依存せずに処理できる方法が望ましい。

      うーん。結局 CapsLock は信用できないし CapsLock が入っているからと言って
      操作体系を変更するのも変な気がするので、そのまま S-o を信じて S-o は常に
      O に変換するということで良い気がする。

    * 実は類似の箇所が他にもあるのではないか。検索してみると以下の様なものが見つかった。

      $ grc 'KEYS(\[[^][]+\])?&~_ble_decode_Meta'
      ./keymap/vi.sh:120:    ble/decode/widget/redispatch-by-keys "$esc" "$((KEYS[0]&~_ble_decode_Meta))" "${KEYS[@]:1}"
      ./keymap/vi.sh:141:    ble/decode/widget/redispatch-by-keys "$esc" "$((KEYS[0]&~_ble_decode_Meta))" "${KEYS[@]:1}"
      $ grc '&=?~_ble_decode_Meta'
      (同じ物しか当たらなかったので省略)

    * reject: 既に似たような処理を何処かで実装している様な気がする。例えばレジ
      スターの文字を取得する箇所など。確認する。_ble_decode_Shft で検索すれば見
      つかる筈…と思ったが見つからない。 k2c という名前の関数だった気がする。→
      ble/keymap:vi/k2c だった。然しこの関数は C-? を byte に戻す役割であって
      S-o を O にするなどの処理を実装した物ではなかった。

      なので今回はまた別に実装する必要がある。と思ったが既に上記の検索で当たっ
      ていた 141 行目が decompose-meta という関数で汎用に用意した物だった。120
      だけ特別に実装したものだった。なので基本的にこの二箇所を修正するだけで良
      い。

    修正した。と思ったが動作していない。

    % うーん。実際に流れてきているキーを確認してみたら既に M-S-o は
    % M-O に翻訳されていた。なのでわざわざこの場所で再構成する必要はな
    % いのであった。という事はちゃんと処理されていない原因は別の場所に
    % あるという事になる。

    →よく見たら M-O になっていて欲しいのに M-S-o でも M-O でもなく単
    に M-o になっていた。受信しているのは 27;2;111 でありこれは S-o で
    あるのにも関わらずちゃんと復元できないという事。

    ===== keys =====
    M-o ESC o C-u b l e auto_complete_enter
    / d e b u g C-e C-_ e auto_complete_ente
    r n d C-m C-m

    うーん。最初に受信した時点で S が消えている。どの時点で消滅したの
    か確認する必要がある。

    分かった。これは意図的に通常文字に対して S だけが付加されている時にそれを削
    除している。何故なら xterm & vte で <Meta-Shift-o> というキー入力に対して
    M-S-O というシーケンスを送ってくる為。M-S-o というシーケンスが来た場合には
    CapsLock が有効になった状態で Meta+Shift+O → M-S-o となったという解釈なの
    である。一方で contra は CapsLock 等関係なく実際のキーの組み合わせに一対一
    対応する様に処理している。

    * 今回はどの様に修正するか。取り敢えず contra での取り扱いについてはそれ専
      用に実装する事にした。一方で他の端末での振る舞いについても考える。konsole
      はそもそも modifyOtherKeys に対応していない。単に ESC O を最初から送信し
      て来ている。

      xterm は CSI 27;4;79 ~ で M も S も同時に指定した状態で来ている。これだと
      M-S-o になってしまう。然し本当は M-O になって欲しい。どの様に処理するべき
      だろうか。

      受信時点で調整しようかと思ったがやはり両方許容しておいて良い様な気がして
      きた。もし ESC 大文字 で送られてきたら M-O 等の形式にするのは自然だが、
      CSI 27;4;79 ~ 等の形式で来た時にどの様に取り扱うかは微妙。

      実際に確認してみると既存の binding は M-S-y と M-Y の両方の形式を同時に設
      定する様になっている。取り敢えずは現状のままにしておく事にする。

    * konsole の端末判定

      https://qiita.com/kefir_/items/0bda5e55f43392420d66 '0;115;0'
      https://github.com/KDE/konsole/blob/0bd20ac6542de5ea16d06f5af255389a3afa8f67/src/Vt102Emulation.cpp#L2051 '1;115;0'

      以下 (2022-02-24) によると v22.03.80 (2022-03-18) より 1 に変わった様だ。
      https://github.com/KDE/konsole/commit/0cc64dcf7b90075bd17e46653df3069208d6a590
      以下 (2001-09-16) によると v3.0.0 から 0;115;0 だった様だ。
      https://github.com/KDE/konsole/commit/2d93fed82aa27e89c9d7301d09d2e24e4fa4416d

      2023-03-02 初期化時に _ble_term_TERM が未初期化の状態で modify-key が呼び
      出されると負の配列添字になってエラーになる。

  * vim mode ! で複数行の結果を返すと描画位置がずれて変な事になる [#D1987]

    どうやら行数が増えると駄目な様だ。単に複数行を replace-range で挿入する
    widget を作成しても問題は再現しない。終了時の _ble_canvas_y の問題だろうか。
    うーん。.replace-range を実行している時の _ble_canvas_y の位置は正しい。ちゃ
    んと復帰した位置になっている。またこの時点で buffer.flush を実行しても問題
    の振る舞いに変化はなかったので buffering の問題ではない気がする。

    * todo: 行末の場合には末尾の改行は省略する。然しこの処置は現在のバ
      グを隠してしまうので現在のバグを修正してからにする。

    どうやら determine-scroll をした瞬間にずれている? 中身を見ると panel_height
    を拡張して更にその分だけカーソル位置も移動したことになっているが、実際には
    移動していないということが問題になっている気がする。

    何か分かった気がする。 DRAW_BUFF の中身をスクロールの直後で flush したら問
    題が発生しなくなった。これが意味する所は、後ろの方の出力で DRAW_BUFF ではな
    くて直接 util/buffer に出力している箇所があるという事。特に各行の文字数を調
    整する部分が怪しい。

  * global: コード中の /dev/tty は予め持っておいた fd に置き換えるべきなのでは [#D1986]
    修正した。

  * util: readonly を上書きする? (requested by mozirilla213) [#D1985]
    https://github.com/akinomyoga/ble.sh/issues/289

    其処まで積極的にユーザー環境を上書きして良いのか不明である。

    - alias doesn't affect existing functions.

    - command line can be easily detected, but this is still incomplete
      detection because even if the user does not directly write declare -r,
      the functions called by the user could contain declare -gr, etc.

    The scope that the readonly is called and the scope of the variable
    specified to readonly are unrelated to each other.  One needs to test each
    variable name whether it is in the global scope or not.

    * propagating tempenv にも気をつけなければならない。

      $ f1() { ble/variable#is-global fdsafdsa; }
      $ fdsafdsa=a f1

      このテストだと global ではないと判定されてそれは is-global の判定としては
      期待する動作である。然しこれに対して export/readonly を実行すると外側に
      propagate してしまう。global に propagate しないという事までちゃんと判定
      する方法はあるのだろうか。そもそも tempenv をそうと判定する方法があるのか
      という事も疑問である。

      まあこの場合は仕方がないと思って諦めるべきだろうか。

      これの判定は完全ではない。

    * done: global readonly に対しても whitelist は作っても良いのかもしれない。
      全て [A-Z0-9_] であり 2 文字以上で Bash の特殊変数に一致していなくて
      ble.sh が使っていない変数名?

      ble.sh 内部で使っている大文字変数も実は改名するべきの気もする。特に vi.sh
      の中で使っている変数が気になる…がこれは禁止リストに入れてしまっても良い
      気がする。

      小文字でも _ble で始まらない _[a-zA-Z]* の様な変数名も許容して良いのでは
      ないか。然し、ble.sh の内部で使っている変数もあるのでそれらは ble.sh の側
      で改名する等して避ける事にする。

    * done: is-global の実装で readonly が使われている。

    * done: adjust builtins: readonly はユーザーによる上書きを許容する。

    * done: エラーメッセージは一回しか実行しない→もう何回か表示して良い気がす
      る。10回迄表示する事にした。

    * ユーザーが既に readonly を上書きしている場合にはどうするのか。
      function#push,pop で処理する事にすれば良いだろうか。と思ったがその様にす
      るのであれば他の builtin も同様にする必要があるのではないかという事になっ
      てくる。もしこれについて考えるのであれば全ての builtin について同時に適用
      するべき。

    2023-03-02 文法エラーが発生している。bash-4.0 以降では "!" 単体はエラーにな
    らないのだろうか。何れにしても修正した。

  * exec: BLE_PIPESTATUS 公開する (motivated by mozirilla213) [#D1984]
    https://github.com/akinomyoga/ble.sh/issues/290

    * done: wiki misc

    * ok: 然し、実際に BLE_PIPESTATUS をどの様に PIPESTATUS と使い分けるのかと
      いうとよく分からない。現在のコマンドが ble.sh 内での一番最初のコマンドか
      どうかの情報がないので両方にアクセスできる時にどちらを選ぶべきか分からな
      い。

      一応 exec が終わったら BLE_PIPESTATUS を削除すれば良い気もするが、でもそ
      もそも exec が終わったら ble.sh の内部なので誰も BLE_PIPESTATUS を参照し
      ないので削除してもしなくても関係ない気がする。

      然し気にし出したら限がない気がするので考えない事にする。

    * ok: 唯一削除したほうが良いかもしれないのは ble-detach する時だが、そうだ
      としても ble-detach する時のステータスを復元する必要はないのか。というか、
      ble-detach した時の $_ $? などはちゃんと保持されているのか (そもそも保持
      する必要があるのかも怪しいが。何故なら ble-detach コマンドを結局呼び出す
      のでその $? や $_ が適用されるのでは。より複雑な構成で非自明な場合を考え
      る事も可能だが其処まで考えても意味がない気がする)。同様に PIPESTATUS に関
      しても敢えて ble-detach の PIPESTATUS を保持する事が有用である様には思え
      ない。なので考えなくて良い事にする。

    * done: 序でなので POSTEXEC 及び ERREXEC にも BASH_COMMAND を引数に指定する
      様に変更する事にした。

    * done: README Limitations

  * decode: compat zoxide bind -x (reported by linwaytin) [#D1983]
    https://github.com/akinomyoga/ble.sh/issues/293

    leave-for-widget を毎回呼ぶ事にしてしまっても良いのでは。

    ? ここで fzf-key-bindings の advice を残すかどうかが問題になる。もしこれら
      の関数を completion にも流用しようとしている人がいてこれらを直接呼び出し
      たとすると問題になる。しかし、fzf-completion を弄って (もしくは自分で新し
      く設定を作って) いる人がいたら何れにしても fzf-completion はちゃんと動か
      ない。なので、現状で中途半端に fzf-key-bindings の中の関数だけ patch して
      も余り意味は無いのではないか。

      やはり単純に削除してしまって良い気がする。

    * ok: もう一つの懸念事項は bind -x の全てに対して毎回呼び出すと重くなるので
      はないかという事。うーん。ble.sh の上で更に ble.sh 的な事をしようという様
      な事がない限りは多少エスケープシーケンスが端末に沢山送られても別に大した
      処理量にはならない気がする。

      但し、visible-bell/erase に関してはファイル等をチェックする等するはずなの
      で多少のコストはあるかもしれない。然し、ble/util/assign 等もっと沢山の非
      自明な事をしているのだから bind -x の時にファイルを確認するぐらいであれば
      無視できる筈である。

  * 2023-02-21 histdb: 終了時に sqlite3 のエラーが発生して失敗する事がある [#D1982]

    Runtime error near line 779: database is locked (5)

    調べてみるとどうやら timeout を指定していたとしても BEGIN TRANSACTION は即
    座に失敗するらしい。IMMEDIATE を指定する必要がある。

    https://blog.ver001.com/sqlite-databaseislocked/

    これは単に IMMEDIATE を指定したがそれ以降エラーは出ていない。これ
    で直っていると良いが、エラーがそもそも出る確率が少ない様だから確認
    が難しい。次にまた問題が出た時に考える。

    2023-03-01 やはりまたエラーが出た。改めて確認してみるとどうやら exec でバッ
    クグラウンドで起動した時に timeout が指定できていない。起動時にちゃん
    と.timeout を指定する事にした。何度か起動と収量を繰り返したが新しいものの方
    では問題は生じない様に見える。と思ったが古い方でも起こる確率はやはり小さい
    様なので何とも言えない。

    もう一つ気づいた事は histdb の remarks に ANSI 色シーケンスが混入しているこ
    と→これは単に .blerc で明示的に colored を指定していたのが悪い。修正した。
    更にこれを元にして作成した histdb の既定の remarks にも同様の間違いがあった。
    これも修正した。

    % 2023-03-03 うーん。やっぱり駄目。何らかの拍子に失敗する。timeout をもっと
    % 長く取るか或いは諦めてエラーを強制的に suppress するか。どうも終了する時
    % に発生する様なのでエラーメッセージに関してはそれ程気にしなくても良いのか
    % もしれない。一方で、終了する瞬間にメッセージが表示されることを思うと実は
    % .timeout が短い事による問題ではなくて、やはり .timeout で待たない様な設定
    % になっているという事だろうか。と思って気づいたが contrib の dev ブランチ
    % に前回の修正があって、それが有効になっていなかった。

    取り敢えず平和に動いている様な気がするので #D1992 と一緒に修正を適用する事
    にする。

  * 2023-02-21 どうも bash-5.2 で WINCH が効かなくなっている [#D1981]

    最初は効いているが、同時に複数の WINCH を受け取る等の事が一旦起こるとそれ以
    降は WINCH が効かなくなってしまう。bash-5.1 では問題は起こらない。より簡単
    な設定で再現しようとしたが再現しない。bash 自体の内部で何が起こっているのか
    確認するべきの気がする。

    * 更に devel で試してみると無限ループになってしまう。何故? 自前で適当に
      setup しても無限ループにはならない。この devel の無限ループでは別に
      ble/builtin/trap/.handler が沢山呼び出されている訳でもない様だ。bash の側
      で無限ループになっている。

      devel 407d9af (20221119) は大丈夫。3687888 (20230220) も大丈夫。という事
      は DPF で勝手に書き換えているのが問題という事? 或いは debug version が駄
      目という事なのだろうか。どうやら ./configure --with-bash-malloc=no でコン
      パイルすると駄目? と思ったが ./configure でも駄目の様だ。どうも maint の
      時にだけ発生する問題の様である。うーん。これの優先度は低い。

    * うーん。一応 WINCH は受信はできている様だ。然し COLUMNS LINES が更新され
      ていないという状態。subshell を呼び出したとしても更新されない。但し内部で
      改めて builtin trap 等を実行して WINCH を呼び出すと WINCH 自体が動かなく
      なる。

    これは結局 histdb の timeout の処理の為に動かしている msleep が良くない様だ。
    つまり、ble/util/msleep (中身は read -t) が待っている間に WINCH が来るとそ
    の WINCH は消えてなくなるという事。実は 5.1 では read -t の途中で WINCH が
    来ても read -t が終わった後にちゃんと WINCH が発火してくれる。これは
    sigmask 等を弄ったら動く様にならないだろうか。

    改めて bash-5.2 --norc で起動して read -t 5 をしてみたら実はその場 (read -t
    の timeout を待たずに) で発火する。何れにしても 5.1 とは振る舞いが微妙に違
    うが、これは ble.sh の時に全く発火しないのとは振る舞いが違う。或いは、read
    -t の読み取り元の fd の種類によって振る舞いが違うのだろうか。

    * ble.sh の中にいると WINCH が不活性になってしまう問題。起動した瞬間に
      builtin trap WINCH を実行している場合には問題は生じない。つまり、WINCH の
      処理中に更に新しい WINCH が来るなどの事があると不活性になってしまうという
      事だろうか。

      またこれは bash のバグなのかという事もある。bash のバグとしての修正と、そ
      れから既に出ている bash-5.2 に対する workaround の両方を実装する必要があ
      る。取り敢えず bash 側で何が起こっているのかについては確認する必要がある。

    * WINCH が不活性の時は bash の中で何が起こっているのか。

      % 先ず _rl_signal_handler は通常の動作している状態であっても ble.sh の中で
      % は呼び出されていない。つまり、自分が設定した WINCH だけが有効になっている
      % 状態で、readline signal handler がない状態だろう。これは不活性になってい
      % る時でもちゃんと WINCH が活性している時でも問題になっている。
      %
      % trap でどう設定されるのかを見て呼び出し経路を探る事にする。set_signal を
      % 呼び出している。中では trap_handler という関数をシステムに登録している。
      %
      % 実際に trap_handler が呼び出されているかどうかを確認してみると
      % trap_handler までは不活性の状態でも呼び出されている様だ。trap_handler は
      % set_trap_state を呼び出して抜ける。更に pending_traps[SIGWINCH]++ が実行
      % される。この配列をチェックして実際の trap string を実行している箇所を探せ
      % ば良い。
      %
      % →どうやら set_trap_state までは呼び出されるけれどもその後
      % run_pending_traps が実行されない状態になっているということの気がする。
      %
      % どうも running_trap が有効になったままになってしまい無限ループ状態になっ
      % ている。つまり running_trap の復元に失敗している。running_trap はどの様に
      % 復元する事になっているのだったか。
      %
      % どうも parse_and_execute で実行している最中に実行が途切れて戻ってこないの
      % が問題の様である。然し何故だろうか。実行しているコマンドの内容による? 特
      % 定のコマンドの後に変な事が起こるのか、それとも最後まで実行した挙げ句に変
      % な事になるのか。
      %
      % 調べてみると blehook internal_WINCH の実行途中に制御が消滅する様である。
      % どんどん調べていくと結局やはり ret=$(msleep 50; bash -c ... ) として端末
      % サイズを取得しようとしている所で失敗している。これを assign に置き換えて
      % も失敗する。assign は mapfile で失敗する。つまり、read -t の最中に起こっ
      % たシグナルの中で何らかの読み取り動作を実行しようとすると失敗するという事。
      % 実際に sigmask で sigwinch が即時発火しない様に修正したら問題は生じなくな
      % る。

      まとめると、read -t (msleep) で待っている間に SIGWINCH を受信するとその場
      で WINCH handler が呼び出され、更にその中で a=$() や mapfile 等の読み取り
      を使おうとするとエラーが発生して、run_pending_trap 自体の実行が中途半端に
      キャンセルされてしまう。これにより run_pending_trap が設定している
      runnning_trap がクリアされずに残ってしまい、入れ子の trap 実行と判定され
      て run_pending_trap が全く実行されなくなってしまう。

      read -t の実行時に sigmask を指定して SIGWINCH をブロックしておけば変な事
      は起こらない。なので 5.3 以降では気にしなくて良い。

      以下 ble/application/onwinch の COLUMNS, LINES 取得部分で行った実験コード

      | # bash-5.2 では read -t の最中の WINCH がその場で発火して、(1) 内部で
      | # ble/util/msleep を実行しようとすると外側の timeout 設定が削除されてロッ
      | # クする (2) WINCH が受信できない変な状態になる。
      |
      | # local ret
      | # ble/util/msleep 50
      | # ble/util/assign-words ret 'ble/bin/stty size'
      | # LINES=${ret[0]}
      | # COLUMNS=${ret[1]}
      |
      | # (ble/util/msleep 50)
      | # local cmd='(:); echo "COLUMNS=$COLUMNS LINES=$LINES"' ret
      | # ble/util/assign ret '"$BASH" -O checkwinsize -c "$cmd"'
      | # builtin eval -- "$ret"
      |
      | echo "$FUNCNAME @3" >/dev/tty
      | # 5.2 コマンド置換 $() を使うと停止する。
      | #builtin eval -- "$(sleep 0.05; "$BASH" -O checkwinsize -c '(:); echo "COLUMNS=$COLUMNS LINES=$LINES"' 2>/dev/null)"
      | #local ret=$(ble/util/msleep 50; "$BASH" -O checkwinsize -c '(:); echo "COLUMNS=$COLUMNS LINES=$LINES"' 2>/dev/null)
      | #local ret=$(sleep 0.05; "$BASH" -O checkwinsize -c '(:); echo "COLUMNS=$COLUMNS LINES=$LINES"' 2>/dev/null)
      | #local ret=$(echo echo yes)
      | #(echo yes)
      | (ble/util/msleep 50)
      | echo "$FUNCNAME @3.1" >/dev/tty
      | (echo >/dev/null; bash -c ':')
      | echo "$FUNCNAME @3.2" >/dev/tty
      | (bash -c ':')
      | echo "$FUNCNAME @3.3" >/dev/tty
      | local _ble_local_tmpfile;
      | echo "$FUNCNAME @3.31" >/dev/tty
      | ble/util/assign/.mktmp;
      | echo "$FUNCNAME @3.32" >/dev/tty
      | builtin eval -- "(echo echo yes)" >| "$_ble_local_tmpfile";
      | echo "$FUNCNAME @3.33" >/dev/tty
      | local _ble_local_ret=$? _ble_local_arr=;
      | echo "$FUNCNAME @3.34" >/dev/tty
      | mapfile -t _ble_local_arr < "$_ble_local_tmpfile";
      | echo "$FUNCNAME @3.35" >/dev/tty
      | ble/util/assign/.rmtmp;
      | echo "$FUNCNAME @3.36" >/dev/tty
      | #ble/util/assign ret '(echo echo yes)'
      | echo "$FUNCNAME @3.4" >/dev/tty
      | local script='(:); echo "COLUMNS=$COLUMNS LINES=$LINES"'
      | ble/util/assign ret '"$BASH" -O checkwinsize -c "$script" 2>/dev/null'
      | #ble/util/assign ret '(ble/util/msleep 50; "$BASH" -O checkwinsize -c "$script" 2>/dev/null)'
      | #builtin eval -- "$ret"
      | echo "$FUNCNAME @4 ($ret)" >/dev/tty

    5.2 における対策としては ble/util/assign を全く使わないという処置は大変なの
    で、(read -t 実行中) または ble/decode/.hook 実行中は SIGWINCH をその場で処
    理するのはやめて後回しにする? 然し、これは SIGWINCH に限った問題ではない気
    がするので、trap/.handler 全般に read -t を実行中の場合にはそれが終わるまで
    trap を pending するという機能が必要の気がする。

    ? bash: 然しそもそもの疑問は何故 SIGWINCH が即時発火するのかという事。
      run_pending_trap が read -t の最中に呼び出されるという事があるのだろうか?
      trap_handler は単にシグナルを受信して pending_traps 配列に記録するだけの
      筈なので、何処か別の場所から run_pending_trap を呼び出す必要がある。そう
      しないとその場で発火はしないのではないか。

    * 再現スクリプト? 少し試してみたが全然再現しない。そもそも別の修正で発生し
      なくなるからこれについて簡単なスクリプトで再現する必要は実はない。

    * done: 実は builtin read は全て置き換える必要があるのではないか? 序に
      _ble_bash_tmout_wa の配列も関数の側で指定する事にする。

      builtin read -t 0 や builtin read --help 等は一瞬で終わると思われるし、ま
      た内部で実際の読み取りを試行する訳でもなさそうなので入れ子にしても問題は
      ないと期待してそのままにする。また detach 状態で呼び出す builtin read に
      関してもそのままで良い。

      と思ったが動かない。と思ったら分かった。bash version 判定に使っている
      _ble_bash が定義されるよりも前の段階で ble/bash/read を _ble_bash に基づ
      いて切り替えようとしていた。実際に ble/bash/read が使われるのはもっと後な
      ので、もっと後ろに移動する事にした。直った。

2023-02-27

  * idle: prompt-defer による自動更新が発生していない気がする [#D1980]

    以前は background で処理が完了し次第プロンプトが更新される様にしてその様に
    実際に動いていた気がする。しかし現在はキー入力が来るまで更新されない様だ。

    →実は idle sleep の最中には表示更新が発生しないという可能性? 或る一定以上
    の時間 sleep するのであれば更新するべきである。

    * reject: sleep の interval を決定する際に使っている時間が idle.do を開始し
      てからの時間になっているがそれで良いのだろうか。最後の task からの時間の
      方が良いのではないか。

      と思ったが、screen saver 的な使い方や定期的に時刻を更新する使い方を考える
      と、task が走る度にリセットされると本来の意図と異なる事になる。なので、や
      はり idle.do の開始時刻からの時間を使って決定するという事で良い。

    * 取り敢えず待機時間の最初に DO_EVENTS を実行して、それ経由で
      ble/application/render を呼び出す様にして見ようと思ったが、これだと毎秒プ
      ロンプトの再描画を試行してしまって重いのではないか?

      以前に時計を表示する実験をした時にはどのようにしていたか。.blerc にある時
      刻表示を確認してみたら時刻を info に表示しているので info だけの更新をそ
      の場で呼び出していた。そもそもこれは実際に更新が起こる時に呼び出しを行っ
      ているので、再描画を呼び出すのは当たり前である。一方で今回の場合には恐ら
      く更新がないのに全体再描画を試行する事になっていて問題である。

      DO_EVENTS の中で render を呼び出す条件を指定するべきなのではないか。プロ
      ンプト更新の可能性がある場合にそれを伝える仕組みが必要? 現在は一応その枠
      組として prompt hash を使っているが、それでも複数のプロンプトを管理してい
      ると全てのプロンプト hash を eval しなければならず、それはコスト的に高い
      様な気がする。

    ? また、DO_EVENTS 経由で描画を実行するのも変な気がする。IS_IDLE と同じ箇所
      で上書きするのであれば良いかと思っていがが確認してみたところ IS_IDLE は
      decode.sh で上書きしている。ble/application/render を入れるとしたら寧ろ
      canvas.sh か edit.sh の様な気がするので、別の箇所で定義しなければならない。
      それは避けたいので、ここはそれ専用の hook を用意する方が自然なのではない
      か。

    * reject: ble/textarea#render-defer.idle という枠組みが edit.sh で既に実装
      されている事に気づいた。つまり元から遅延して再描画する仕組みが整っていた?
      と思ったがこれはどうやらユーザー入力に対して反応しているのに過ぎない様だ。
      更に使っている箇所を確認するとこれは prompt-defer ではなくて単語着色に時
      間がかかっている時に先にユーザー入力を処理する、という時に使っている。
      wait-for-user-input で中断するかどうかを確認しているのはこれが理由という
      事だろう。なのでこれは今回のものとは関係ないし、今回使えるものでもない気
      がする。

    プロンプト更新の必要性がある可能性があるという事を示す枠組みを入れる? 現在
    の invalidate 関係の仕組みがどうなっているのかについて確認する必要がある。

    a 先ず以下の panel::invalidate によって 設定される変数に関しては、そのパネ
      ル全体について実際に再描画のシーケンスを出力する必要がある事を示している。
      つまり、「内容が更新されている可能性がある&もしチェックして必要があれば変
      わった部分だけ更新する」というものに使われるものではない。

      _ble_prompt_status_dirty=1
      _ble_edit_info_invalidated=1
      _ble_textarea_invalidated=1

    b 次に _ble_prompt_update_dirty は単に現在既にプロンプトが表示されているか
      どうかの判定に使っている様な気がする。

      % と思ったが処理の流れが何か変な気がする。dirty だったら dirty=dirty という
      % 値を設定する。その次の呼び出しで dirty だったら dirty=done に設定し直して
      % 改めて再描画するという構造になっている。これは何だかおかしい気がする。必
      % ず2回呼び出されるという事?
      %
      % 実際にこの部分を追加した commit は e199beee であり #D1750 である。この議
      % 論では wezterm integration が勝手に PROMPT_COMMAND から何か文字列を出力す
      % るという問題に対する workaround を追加している。どうも textarea 以外の枠
      % 組みから ble/prompt/update が呼び出された時に、その時点で dirty という事
      % になって、それをその後で処理したい時に done を指定している気がする。
      %
      % うーん。実はプロンプト毎にも _ble_prompt_ps1_dirty 等の様なものを管理して
      % いるのでプロンプト自体が毎回重複して出力されるという訳では無い様だ。然し、
      % そうだとしても ble/prompt/update が必ず2回 dirty を返すという事になってし
      % まって、だとしたらそれはおかしいのではないか?
      %
      % と思って実際に試してみたが一回しか prompt dirty になっていない。何故だろ
      % うか。分かった。そもそもプロンプト内容に変更がなければ dirty にならないの
      % である。なので確かめる時には cd の直後の振る舞いを調べるべきである。
      %
      % うーん。実際に cd 直後のプロンプトの初回更新時に見てみると既に最初の呼び
      % 出しの時点でちゃんと _ble_prompt_update_dirty=done になっている。何故?

      分かった。現在の実装では ble/application/render の時点で既に
      ble/prompt/update を呼び出す事になっているのである。なので、
      textarea#render からの ble/prompt/update の呼び出しは単に先に呼び出した時
      の計算結果を参照しているのに過ぎない。:check-dirty: というのは実際に
      prompt update 操作を試行せずに結果だけ読み取るという取り扱いなのであって、
      同時に実際にその結果を使って描画を行うから dity state をクリアするという
      役割があるという事なのである。

      そしてそもそも :check-dirty: なしでの呼び出しは ble/application/render か
      ら必ず毎回行われるので、:check-dirty: 以降のコードも
      ble/application/render を呼び出す場合には毎回実行される。なので、
      _ble_prompt_update_dirty の値は実際には ble/prompt/update 処理の省略に使
      われている訳では無いという事なのである。

    c ble/prompt/clear ... これが最も怪しい。と思ったが、この関数を呼び出すと結
      局内部で textarea#invalidate を呼び出しているので全体の強制再描画を引き起
      こしてしまう。これはではない気がする。

      或いは新しい関数を追加してプロンプト情報の更新だけ試みる? hash だけクリア
      すれば良いのでは? と思ったが、今は ble/application/render 自体の呼び出し
      を省略できないかという事を考えているのであって、hash をクリアして更に
      ble/application/render を呼び出すというのでは半分だけである。

      というか b の項目は実は余り関係なかったという事が判明した今改めて
      _ble_prompt_hash の取り扱いを見てみると、別に _ble_prompt_hash を更新して
      いようが更新していまいが ble/prompt/update の各プロンプトの hash 値確認は
      全部行っているので、 _ble_prompt_hash をクリアしようがしまいが
      ble/application/render を呼び出す限りは同じ事の気がする。

    今欲しい物は何かについて改めて考える。idle.do の中で何か更新が必要になって
    いないか確認し、もし必要になっていたら強制的に再描画を実施するという事を考
    えている。

    d 或いは application/render を実際に毎回呼び出してしまっても良いのではない
      か?  タスクが走る度に実行するとは言っても、実際に本当にタスクを走らせてい
      るのであれば、呼び出してしまっても問題がない気がする。

      →これで実装してみたら実際に思うように即時に反映される様になったが、今度
      は逆に ble/application/render が各キー入力の後に重複して呼び出されるよう
      になった。うーん。そもそも ble/application/render を先に呼び出している筈
      なので、改めて呼び出す必要はない筈なのである。

    今気づいたのだが、実はそもそも auto-complete すら動いていなかった。sleep し
    ている時には定期的に抜けて処理を実行する必要があるのであった。

    do_events で ble/application/render を呼び出す様にしたがそれでも重複して
    ble/application/render が呼び出されている様だ。更に、重複して呼び出されてい
    るのにも関わらずプロンプトが期待通りに更新されていない。二つの問題があるの
    で分けて考える。

    * idle do_events がキー入力毎に複数回呼び出されるのは何故か。

      % 背景処理がそんなに実行されるのだろうか。どういう処理が実行されているの
      % か出力して観察してみる事にする。
      %
      % →idle.do の中から呼び出しているのは一回である。これは期待通りである。一
      %   方で、bind/.tail からの呼び出しが二回ある。これは期待していない。
      %
      % 一方で histdb をロードしていない時には各キーストロークに対して2回実行して
      % いる。これは期待通りである。idle を実行する前と idle を実行した後。
      %
      % うーん。これは auto-complete を無効にしても同様である。なので、
      % auto-complete を抜ける時に内部的に生成しているキーが原因ではない。という
      % かそもそも内部的に生成するキーに関しては bind/.tail は呼び出されない気が
      % する。

      分かった。これは (1) ユーザー入力があって idle.do から抜ける時 (2) ユーザー
      入力の処理の後に抜ける時 (3) 更に auto-complete 等を処理した後に sleep を
      開始した時 の三回処理が実行されているという事である。

      実際には単に sleep しているだけで最終的に何も実行する前にユーザー入力があっ
      た時には抜ける時の render は必要ない。do_events に対する処理は実は
      idle.do の内部で呼び出すべきなのかもしれない。そもそも idle.do が中で実際
      に処理が行われたかどうかに応じて修了スターテスを決めるというのも変な気が
      する。と思ったが「最後にタスクを処理してから do_events を実行したかどうか」
      を終了ステータスにするのはもっと変だ。

      うーん。do_events は after_task, onaftertask, on_after_task 等に変更する。
      blehook idle_on_after_task, blehook idle_after_task うーん。
      idle_after_task という名前にする事にする。

      実装した。idle 後の再描画も idle_after_task 経由で実行する事にした。取り
      敢えず期待通りに動いている。

    * プロンプトが prompt-defer で更新されないと思っていたが、上の問題を解決し
      たら何故かこちらの問題も発生しなくなっていた。関係していたのだろうか。或
      いは、表示されてはいたけれどもデバグ用の情報出力によって紛れて更新されて
      いないと勘違いしていた可能性もある。

      何度かやってみたが問題は全く発生しなくなっていた。前はほぼ確実に問題が生
      じていたのを考えると実際に解決したのだと思って良い気がする。

  * menu (linewise): 行番号を表示すると表示レイアウトが壊れる (reported by bkerin) [#D1979]
    https://github.com/akinomyoga/ble.sh/discussions/284
    https://github.com/akinomyoga/ble.sh/issues/286

    これは簡単なミスだった。単に x を更新した後に x を参照していた。すぐ直った。

  * completion: fzf-completion がまた動かなくなっている (reported by christianknauer) [#D1978]
    https://github.com/akinomyoga/ble.sh/issues/285

    コードを調べてみると ble/syntax-raw を指定していても noquote を指定していな
    いとちゃんと quote しないという分岐に入らない様だ。一方で、contrib で
    2022-11-12 に noquote を外している。議論としては #D1889 である。

    https://github.com/akinomyoga/blesh-contrib/commit/e102241466dfda8cf3e7efb6891e223102e0b2a9
    https://github.com/akinomyoga/ble.sh/issues/250

    ? これは fzf 経由で生成された候補は quote された状態で生成されるけれども、
      fzf が更に呼び出している bash_completion の側では quote されていないとい
      う事なのだろうか。

      具体的にどの様に候補が生成されているの確認する事にする。うーん。
      fzf-completion の内部で見ている時点で既に cd sp**[TAB] の時と cd sp[TAB]
      の時で quote されるされないが分かれてしまっている。これは ble.sh なしの普
      通の bash の時には問題にならなかったのか。何故か。改めて確認する。

      うーん。plain bash だとちゃんと動いている。COMPREPLY の内容を確認してみて
      も cd sp[TAB] と cd sp**[TAB] で異なる結果を返している。それにも関わらず
      どちらも同じく正しい quoting を最終的に実行できているのは何故か。compopt
      の呼び出しが粉割れている可能性? compopt によって生成された comp_opts の内
      容も確認する事にする。

      うーん。"space dir" という名前で生成されている時には compopt -o filenames
      が指定されていて、"space\ dir" という形で生成されている時には filenames
      が指定されていない。filenames に関してはちゃんと実装しているのか不明であ
      る。以前に filenames の時の振る舞いについて確認した気がするが、それはどう
      だったか。

    元の補完の枠組みの範囲内で noquote は指定していないのだから、ble.sh の内部
    で勝手に noquote を指定した物として見做してその上で filenames が指定されて
    いる時されていない時で振る舞いを変える等の実装にすると混乱の元である。特に、
    本当にユーザーが noquote も指定した時にどう振る舞うのかだとかと整合性が取れ
    なくなる。なので、#D1889 以前の様に noquote を改めて指定してその上で条件判
    定で振る舞いを調整するというのは良い解決方法ではないと思われる。

    ble/syntax-raw が指定されていてかつ filenames が指定されていない時の振る舞
    いを変更するのが良い気がする。

    * ok: command noquote の時の awk batch の処理が通常の処理と違っている様な気
      がする。通常の処理の時には noquote を参照しているが、awk batch では参照し
      ていない。通常実装の方の変更に伴って awk 実装も更新しなければらないところ
      を忘れていたのではないか。これについては後で確認する必要がある。

      % 調べてみるとこの部分は d6242a79 (2021-12) に導入されている。そもそもそ
      % れより前には command に対する分岐は存在していなかった。同時に awk batch
      % の方にもコードが追加されているが、その時点で異なる条件になっていた様だ。
      % これはどういう事だろうか。別の場所で処理されているという事だろうか。
      %
      % 改めて noquote が処理されている箇所を確認して他で処理されていなければ処
      % 理が一致する様に変更する。実際に調べてみたが処理している気配はない。一
      % 方で command の場合には DATA に対して判定を行っている。
      %
      % うーん。そもそも yield.batch の段階では DATA は生成されていない。全体共
      % 通の DATA が渡されているだけの気がする。一方で、action:command に対して
      % はそもそも DATA が指定されていない? 或いは動的に生成されている可能性も
      % ある。
      %
      % という事は DATA を参照して noquote かどうかを判定しているのは完全に無駄
      % な機能? 或いは DATA ではなくて comp_opts の勘違いだろうか。元の意図が完
      % 全に分からなくなった。そもそもコマンド名は progcomp で生成していない限
      % りは自前で生成しているのだから勝手に noquote が付加される事も考えにくい。
      % 将来的に付ける事を考えての処理だったかもしれない。
      %
      % 1 そもそも action=command を生成しているのは soruce:command しか存在し
      %   ない。progcomp でコマンド名を生成するとしても action=command にはなら
      %   ない。
      %
      % 2 source:command の中では noquote という文字列に対しての取り扱いは存在
      %   していないように見える。

      と思ったら alias の生成に対して :noquote: を指定していた。そして alias の
      設定には yield.batch を用いていない。これはコメントで補足が必要である。補
      足した。

    動作確認する。

    x fixed: うーん。quote しない様にしようとしたら単純に元の文字列がそのまま挿
      入される様になってしまった。何故だろう。調べるとちゃんと候補は生成されて
      いる。

      どうやら .apply-partial-comps によって元に復元されてしまっている様だ。うー
      ん。comp_opts が syntax-raw の場合にはその処置を行わない様にする? 然し
      comp_opts の情報は既に失われている様な気もする。

      取り敢えず単一確定の時に progcomp の時は cand_pack DATA に comp_opts が記
      録されているのでそれを参照して判定する事にした。そもそもこの様な特別な処
      理が必要になるのは bash の既存インターフェイスである progcomp から借用し
      ようとしている時の不整合によって起こるのだから、それ以外の場合には問題に
      ならない筈である。よって progcomp の時にだけ処理すれば良くて、一般化した
      枠組みにする必要はない。

    x ok: 今度は普通に補完しようとした時に動作していない。filenames が付加され
      ていれば quote に進む筈であるのに。と思ったらこれは単にテストコードの埋込
      時に失敗していただけだった。テストコードを除去したらちゃんと動く様になっ
      た。

    本当にこれで完全なのか等よく分からないが取り敢えず ble/syntax-raw は現在は
    fzf しか使っていないし、fzf で動かないのであれば他の枠組みが ble/syntax-raw
    を使ったとしてもやはり動かない場合があるという事だろう。なので取り敢えず
    fzf に合わせるというので良い気がする。本来は syntax-raw が指定された時には
    完全に readline と同じ振る舞いになる事が求められているのかもしれない (つま
    り quote する条件もちゃんと調べる?) が取り敢えずは現状のままで良い。

    * done: compopt に他の quote を制御するオプションがないかだけは最後に確認しておく。

      →特に他には関係のありそうな物はなさそうだ。filenames の項目には trailing
      spaces を suppress すると書かれている。これは後で問題になった時に処理する
      事にする。

2023-02-21

  * prompt: PS1='\g{fg=#FF0000,bold}\$ ' としても色が反映されない [#D1977]

    これは単純なバグだった。

  * 5.3: case insensitive history search (bash 72c4a0f4) [#D1976]

    rlvar search-ignore-case を on にすると readline での検索機能が ignore-case
    になる機能が bash devel に実装されている。

    実装してみた。

    x fixed: 動いていない→ nocasematch を使うべきなのに nocaseglob を使ってい
      る場所があった。修正した。

    x fixed: 一文字目は大文字小文字が違っても一致しても、続けて文字を入力して行
      くとより前の物を探しに行ってしまう。これは文字追加の時の検査で失敗してい
      るという事だろうか → 確認したら単に ignore-case を渡すのを忘れていた。直
      した。動いている。

    x nsearch で一致範囲を着色する機能があるが、大文字小文字が違って見つかった
      項目については一致範囲の着色ができていない。カーソル位置も末端になってし
      まっている。

2023-02-20

  * cygwin: sudo すると PS1 の \u が bash に化けてしまう。何故? [#D1975]

    PS1='\u' だと発生しない。 PS1='\u\$ ' だと発生する。Cygwin では '\$' を特別
    視してこれが含まれている時には自前処理している。

    何と \s で展開していた。これは a9551e54 (2022-03-12 #D1801) で導入されている。

  * 2022-06-09 macOS の nawk の振る舞いが変だという事 (reported in killermoehre) [#D1974]
    https://github.com/akinomyoga/ble.sh/issues/190

    % workaround を追加できるのかどうかも定かではないが、取り敢えずおかしな振る舞
    % いをするという事までは確かめていた。これについては改めて調べる事にする。特
    % に binding の状態について確認する。
    %
    % 調べてみるとどうも "上下左右 home/end" などの unbind を正しく実行できていな
    % い様である。
    %
    % a bind/unbind 用のスクリプトに問題がある可能性? → と思ったが別にこれらのファ
    %   イルはその場で awk によって生成されるのではなくて、昔作ったキャッシュによっ
    %   て生成された物を再利用しているだけに見える。なので今回は関係ないのではな
    %   いか。
    %
    %   逆に言うと報告されている問題は壊れた nawk によってキャッシュが生成される
    %   事により被害が拡大している可能性もある。
    %
    % b TERM による bash の上書きを検出できていない可能性? これが怪しい気がする。
    %   これの検出を行っている部分のコードを確認する。うーん。先ず勝手に上書きさ
    %   れたという事が検出されたという訳でもない。或いは検出できないという事が問
    %   題になっているのだろうか。然し、検出には awk は使っていないので awk の
    %   version で振る舞いが変わるのも変である。
    %
    %   正常に動作する awk の場合にも TERM/is-dirty で引っかかっている様子はない。
    %   やはりこれは本当に TERM が書き換わった時にだけ起こる問題なのではないか。
    %
    % c 改めて unbind のコードの部分で何が起こっているのかについて確認する。
    %
    %   うーん。unbind 用のコードは
    %   ble/decode/bind/.generate-source-to-unbind-default で生成している。なので
    %   別にキャッシュをしていた訳ではない。よく考えてみたら、ユーザーがその場で
    %   binding を変えているかもしれないので、毎回その場で unbind のコードを生成
    %   しなければならないのだった。
    %
    %   →何と generate-source-to-unbind-default が何も出力していないのだった。うー
    %   ん。エラーメッセージは、標準エラー出力を使って記録している .save の方に記
    %   録されていると思われる → と思ったが標準エラー出力ですら空であった。awk
    %   が途中で終了してしまっているのだろうか。
    %
    %   うーん。然しこの箇所の awk は LC_ALL=C で動かしている様なので unicode サ
    %   ポート関係で失敗する訳もないと思われる。一方で報告を受けたエラーはどうも
    %   unicode サポート関係の様である。
    %
    % 実際に awk に読み取らせている内容をファイルにダンプして、自分で awk に入れ
    % てみてどの様な問題が起こっているのか確認する。と思ったら何も表示されない。
    % END まで到達していない。更に確かめていくとそもそもこの自前でコンパイルした
    % awk は何を入力しても全く動作していないという事が判明した。つまり、この awk
    % は全く動作していない。逆に何故これで今まで微妙にでも動いている様に見えたの
    % かが謎である。改めてちゃんと動く apple awk を作る事が必要である。
    %
    % [結論] Linux 上でコンパイルした apple nawk は実はちゃんとコンパイルできてい
    % なくてそもそも全く動作していなかった。

    Apple nawk を改めて確認するべきかもしれない。

    2023-02-19 改めて apple の awk を見てみたがまた最近更新されている。然し、こ
    れに関連する部分が修正された様な形跡はない。恐らくずっとエラーを出力し続け
    るつもりなのだろう。よく考えてみたら nawk は元々 unicode にサポートしていな
    かったので、macOS awk を強制的に LC_ALL= LC_CTYPE=C で動かしても問題はない
    のではないか。

    * github actions

      うーん。これに関しては取り敢えず GitHub Actions の macos-latest を使って
      実験してみる? 取り敢えずダミーのリポジトリを作って見てその上で振る舞いを
      実験してみる。

      awk --version の出力は "awk version 20200816" であり当てにならない。報告
      されている awk も同じ年月日を出力している様だが、blame を見ると問題のエラー
      メッセージがソースコードに埋め込まれたのは awk-32 (2021-02-08 もしくは 16
      Feb) である。strings で "towc: multibyte conversion failure on:" という文
      字列を抽出して見る? →実際にこれを試してみた所、ちゃんと文字列が含まれて
      いるという事が分かった。

      うーん。LC_ALL=en_US.UTF-8 で特に問題もなく動作している気がする。というか
      最初から en_US.UTF-8 が設定されている。色々変えたがよく分からない。因みに
      macos-11 ではそもそも multibyte conversion failure のエラーメッセージが
      /usr/bin/awk に含まれていないので、これは影響がないのだろうと思われる。

      github actions の上で awk-32 をコンパイルする様にしてみたが、それでもエラー
      メッセージは再現しない。或いは特定の環境だけで起こる問題? 或いは特定の文
      字列に対してだけ発生する問題?

    何時迄も保留にしていても仕方がないので取り敢えず対策を入れておく。単に
    LC_CTYPE=C を指定する。

2023-02-19

  * edit: EXIT trap の中のサブシェルの中で exit が動作しない [#D1973]

    builtin exit 自体の処理判定が駄目という事。実際に確認してみるとexit 経由で
    これらの close の処理が呼び出されているので入れ子の exit を実行している事に
    なっている。入れ子の exit に対する特別の処理を行っている?

    →うーん。これは EXIT の中で exit してしまう駄目な設定を回避する為に使って
    いる。然し、subshell の中での exit は別に main のシェルを終了させるのに使っ
    ている物ではないから気にしなくても良い。なので、単に
    _ble_builtin_trap_processing を確認するだけでなくて BASHPID を記録してそれ
    から確認する必要がある。もしくは BASH_SUBSHELL の値を確認する。

    a _ble_builtin_trap_processing に BASH_SUBSHELL も一緒に記録する

      _ble_builtin_trap_processing を現在のどの様に使っているか確認する。現在は
      _ble_builtin_trap_processing には基本的には sig の番号を入れているが、特
      別に exit:* という値を設定している。値を使っている箇所は実は exit:* かど
      うかの判定を行っている所しかない様だ (+ 値が "exit:xxx" の時 trap
      postproc に ble/builtin/exit xxx を設定している)。つまり、sig の値を使っ
      ている箇所は存在しない?

    取り敢えず _ble_builtin_trap_processing に BASH_SUBSHELL を入れる事にした。

    * exit の判定条件はどの様にするのが良いか

      現在の判定には subshell で実行しているかどうか、attach しているかどうか、
      trap を処理中かどうかという三要素を使っている。

      attach していない時に関しては、trap 処理中でなければそのまま exit してい
      る。trap 処理中の時には DEBUG を用いて上まで bubble する様にしている。先
      ず、何故 trap 処理中には bubble を行うのかという事。いきなり終了では駄目
      なのだろうか。うーん。でもやはり trap 処理中であれば trap handling の途中
      で勝手に終了されては困るという事だろう。

      だとすると trap を処理しているサブシェルよりも更に下のサブシェルにいる時
      には普通に builtin exit して良いという事になる。

      つまり以下で良い様な気がする。

      if (trap processing) {
        if (trap processing subshell != current subshell)
          builtin exit
      } else {
        if (subshell || unbound)
          builtin exit
      }

      % 実は
      %
      % if (trap processing subshell != current subshell)
      %   builtin exit
      % else if (unbound)
      %   builtin exit
      %
      % で良いのではないか? subshell の中にいて trap の外にいる場合には何れにして
      % も trap processing subshell ＝ nil ≠ current subshell なので、最初の分岐
      % に入る。と思ったが、unbound の時には !(trap processing) の時にだけ
      % builtin exit したい。!(trap processing) かつ unbound の時は最初の分岐に入
      % るが、(trap processing) かつシェルレベルが同じの時には、やはり強制的に
      % exit する訳には行かない。

      改めて整理する。builtin exit せずに特別な処理を実行する必要があるのは、
      (1) trap processing を top レベルで処理する為 (2) 実際に抜けようとする時
      に job 等のチェックをする為。の二種類がある。(1) の処理に関しては同じサブ
      シェルの trap でなければ必要ない。(2) の処理に関してはトップレベルのシェ
      ルでかつ attach しているという事。従来の判定は単に ¬(1)∧¬(2) を書き下
      しただけの話である。という事で (1) の条件を更新すれば良いだけ。

    実装した。動作確認する。ちゃんとその場で終了している。OK

    histdb/sqlite3.kill の方は実は exit ではなくて単に return を呼び出しておけ
    ば良いのでその様に修正しておく。

2023-02-18

  * 2022-10-02 prompt: 実行直前の rps1 の更新時にカーソル位置がずれる [#D1972]

    * [reject] dirty 状態の更新時にカーソル位置がずれる?

      →これは勘違いだった。或いは別の問題? と思って repository 切り替え直後に
      色々入力してみる等したが、rps1 に固定文字列がある場合だとやはり何も問題は
      発生しない。なので素早く入力した時にずれが生じる問題も rps1 の更新に伴う
      物だったのだろうと思われる。

    gnome-terminal と mintty でも起こっている。screen や contra では起
    こっていない。

    * bleopt prompt_rps1='\q{blerc/rps1}' では発生するが bleopt
      prompt_rps1='\q{contrib/git-info}' では発生しない。bleopt
      prompt_rps1='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\q{contrib/git-info}' として
      幅を合わせてみても再現しない。分かった。時刻が含まれているとずれる。そし
      て rps1='$RANDOM' でも再現する。

    つまり実行直前の rps1 の更新時にずれが生じているという事。固定文字列を表示
    している限りは実行直前に rps1 が再描画されないのでずれが生じないという事。
    また、通常の初期描画時にずれが発生しないのは途中に \r 等があってそれによっ
    てやはりずれが生じないからなのだと思われる。

    rps1 は丁度最後の列のぎりぎりまで文字列を描画する。その時のカーソル位置のず
    れの問題によるものだろう。或いは最後のぎりぎりまで描画した後にシーケンスが
    続く場合にずれが生じるという事。実際に以下のコマンドで振る舞いに違いが見ら
    れる。

    $ printf '%*s\e[5Dworld\n' "$COLUMNS" hello

    というかそもそも rps1 は relative で trace しているのだから右端に到達した時
    にカーソル位置がどうなるのかについては分からないのではないか? 何故右端ぎり
    ぎりに出力する様になっているのだったか。実際に確かめると
    confine:relative:right:measure-gbox で解析している。

    ? つまり、relative なので、例えば複数行のrps1 の時にも mintty や vte では表
      示がずれてしまうという事になる。と思って試してみたが複数行の rps1 の表示
      自体は普通である。$RANDOM 等を含むとやはり実行直前の更新時に問題のずれが
      発生してしまうが。

      別に screen や contra の中で逆にずれるという事が起こっている訳でもない。

      うーん。どうやってぎりぎりの位置で rps1 内部の移動の時に正しくカーソル位
      置を移動できているのか。一旦は rps1 の esc 生成結果を確認する事にする。

      \e[205Chello\e[5D\e[205D\e[1B\e[205Cworld\e[5D\e[205D\e[1B\e[206C6785

      うーん。何だかすごい移動の仕方をしている。vte や mintty 等の一部の端末に
      対して特別なシーケンスを出力しているのかとも考えたが、screen の中で実行し
      ても同様に物凄いカーソル移動を行っている。

      \e[234Chello\e[5D\e[234D\e[1B\e[234Cworld\e[5D\e[234D\e[1B\e[234C11235

      うーん。何故この様な実装になっているのか。justify で right にしている時に
      は必ずこの様に振る舞うのだったか。

      実際に canvas/trace の中でどの様に処理が進んでいるかを確認してみると、
      end-line で生成している内容の時点でこのカーソル移動が発生しているという事
      が分かった。更に詳しく見てみると、justify_fields として [改行] と [右寄せ
      内容] が含まれている。つまり、改行の操作自体もフィールドとして登録されて
      いて、それが一旦カーソルを行頭に移動する役割を果たしているという事。

      ? これは恐らく改行ではなく CUD で下に移動した時等の動作も保持する為? 然し
        CUD だと実際に端末によって座標計算がずれてしまう気がする。というか
        justify する前の解析ではカーソル位置が末端に行っているかどうかも分から
        ないのだから CUD を出力したら確実に CUD がそのまま調整無しで出力される
        事になり、右寄せの場合には確実にずれが生じる事になる。

        結局 CUD 等だと動かない気がするが、これはそもそも rps1 の中で行末でその
        様な事を試みる事自体が問題の気がするから気にしなくて良い気がする。

    何故複数行 rps1 で問題が起きないのかについては複数行 rps1 に含まれる \n が
    実際にカーソルを行頭に運んでいるからなのだと分かった。然し、そうだとして現
    在の問題である rps1 の末端でのカーソル位置が不定になってしまう問題に対する
    対策には関係がない。

    現在の問題に対してどの部分で対策を実装するべきなのかという問題がある。

    a trace の時点でカーソルを丁度良い位置に移動してカーソル位置が不定にならな
      い様にする?

      x 然し、trace は指定した文字列を出力した後のカーソル位置 x y を計算して返
        すという事になっている。

        これで例えば x=0 等として調整された後の物を出力すると、使う側で続いて続
        きの文字列を末尾から続けて出力したい場合等に問題が起こる。
        ble/canvas/trace を通して複数の文字列を調整してから出力したとしてもその
        振る舞いが変わってしまうのは困る。

        x=0 まで移動するのは大袈裟だとして x=cols-2 の位置にカーソルを置くこと
        にすれば派手にずれるという事はなくなるが、この様にしたとしても連続して
        出力する文字列の一文字目が前の文字列の最後の文字を上書きする事になって
        しまうので元のふるまいと厳密に同じにはならない。

    b 或いは rps1 の出力の側で調整を行う。

      trace 生成結果 (_ble_prompt_rps1_data) の時点で調整を行うか、出力の際に調
      整を行うか。最初は生成結果を弄る方が良いと思ったが、出力部分の調整の方が
      すっきりする。生成結果の座標などを弄ると、他の箇所で特定の想定の下に座標
      位置を参照している箇所があった時に壊れてしまう。少し確認した所その様な場
      所はないような気もしたが、ちゃんと確認している訳でもないし、出力部分の調
      整で既に十分にすっきりしているのでこちらの方向は考えないことにする。

    c うーん。或いは、そもそも \r を prompt_rps1 の末端に加えてから trace を呼
      び出すと何が起こるのだろうか。

      もし \r が justify_fields に含まれてしまうのであれば、右寄せが効かなくなっ
      てしまう。或いは効いたとしても相対移動になってしまうので行頭までは戻って
      くれない。

      →うーん。やっぱり現在のフィールドの中で先頭に戻るだけで全体の行の先頭に
      戻る訳ではない様だ。

    →b の方針で実装する事にした。特に出力部分で CR を出力して横位置をクリアし
    てしまう事にする。

    ? ble/textarea#render/.show-rprompt で

      local rps1x=$((_ble_prompt_rps1_data[3]+COLUMNS-_ble_prompt_rps1_gbox[2]))

      として出力後のカーソル位置を計算しているのは何故だろうか。

      % 単に _ble_prompt_rps1_gbox[2] では駄目なのだろうか。うーん。そもそも
      % _ble_prompt_rps1_data[3] と _ble_prompt_rps1_gbox[2] は本来は同じ結果に
      % なって欲しい。\r 等が rps1 に含まれている時にずれてしまう。ずれたとして
      % この様な方法で計算するのは何故だろうか。
      %
      % うーん。先ず、 COLUMNS と gbox[2] は一緒になる様にしている筈。ずれると
      % したら gbox[2] が COLUMNS よりも左に来てしまうという事である。例えば 3
      % 文字左までしか実際の文字列を出力しなかったとする。この時に rps1x は
      % data[3] が報告する x 位置よりも 3 文字だけ右側にずらした位置を実際の出
      % 力後の位置として報告する様にしている。よく分からない。
      %
      % 変更履歴を探る事にする。
      %
      % cf8d9493
      % -  local rps1x=$((_ble_edit_rprompt[1]+COLUMNS-_ble_edit_rprompt_bbox[2]))
      % +  local rps1x=$((_ble_prompt_rps1_data[3]+COLUMNS-_ble_prompt_rps1_gbox[2]))
      % 4fa139ad (canvas/trace の右寄せ対応 #D1502)
      % -  local rps1x=${_ble_edit_rprompt[1]}
      % +  local rps1x=$((_ble_edit_rprompt[1]+COLUMNS-_ble_edit_rprompt_bbox[2]))
      %
      % 先ず gbox は元々は bbox だった様だ。gbox にしたのは右寄せを実際に出力さ
      % れる文字内容に位置で行う様に変更した時に一緒に変更したのだろう。実際に
      % このよく分からない調整が付け加えられたのは canvas/trace 側で右寄せが実
      % 装された時の様である。#D1502 の議論を確認したがこの補正について特に言及
      % している気がしない。
      %
      % うーん。端末幅が最後に解析してから変わった時に備えての事だろうか。それ
      % が一番疑わしい気がする。実際に rps1 の解析を行った後に COLUMNS が増えた
      % り減ったりする場合を考えると、うーん。 rprompt[1] が (0,0) から仮描画し
      % た時の終了位置で、COLUMNS-_ble_edit_rprompt_bbox[2] が描画開始位置とい
      % う事だろうか。なのだとすると現在の実装でこの計算が問題を起こしていない
      % のは奇跡の様な気もする。(と思ったが単に rprompt[1] と bbox[2] の両方に
      % 同じだけ offset が加わったのだと考えれば余り影響はない)。
      %
      % そう考えてみたら、そもそも端末幅が変わる様な事を考えなくても、ちゃん
      % とこの様にして開始位置の分だけずらす処理をしなければちゃんと計算でき
      % ない。

      つまり、元々は rprompt[1] + (COLUMNS - bbox[2]) であった。この時
      rprompt[1] 及び bbox[2] の計測は x=0 を起点として行った物がそのまま入っ
      ていたので、rprompt[1] を直接使う訳には行かなかった。rprompt 表示開始位
      置 (COLUMNS - bbox[2]) の分だけ右にずらす為に、これを加算していたのだっ
      た。

      現在は _ble_prompt_rps1_data[3] に直接実際の描画終了位置が入っているの
      で、わざわざ変な補正を実施する必要はないのであった。

      ところで #D1502 当時の考え方だと rps1 は右からの相対病がなので端末の幅
      が変わっても、適切な位置から描画を開始して相対移動で描画することで、表
      示が崩れたりせずに右端にプロンプトを配置できることを意図した様だ。然し、
      現在の実装では端末幅が変わる毎に再計算を行う様になったし、そもそも描画
      の際にも 0,0 から描画を始めている。なのでその様な配慮の元で描画終了位置
      を調整するなどの事は今となっては難しい。

2023-02-16

  * histdb: bg process timeout [#D1971]

    * 終了を指示した後にもしプロセスが残り続けた時にどうするかの問題について

      a .pid ファイルを残したままにすると正常に終了してその後に別のプロセスが同
        じ pid を持った時に誤爆する可能性がある。

      b .pid ファイルをクリアするとプロセスが残ってしまった時に残り続ける。

      c background で一定時間待ってから生存確認をして生きていたら強制終了する事
        にすると、bgpid 変数が混ざってしまって変な事になる? と思ったが bg だと
        subshell になるので関係ない? どうせ暫く idle にした時に呼び出されるのだ
        から、subshell background ぐらい作れば良い気がする。或る一定時間プロセ
        スが消えなかったら強制終了する。

      d 或いは foreground で暫く待つ? と思ったがビジー状態等の時には結構長くデー
        タベース更新に時間がかかるという事もあるかもしれない。なので余りに長く
        待つのは非現実的である。

      ここは c の方針で良い気がする。実装した。

    2023-02-19 うーん。プロセスが残る様になってしまっている。また、tty が閉じら
    れるのに時間がかかる様になっている。これも何れかのプロセスが fd を掴んだま
    ま残っているのが原因である。

    どうも sqlite3.kill のプロセスがやはり残留してしまっている。

    % * ble/bin/msleep が固まって動かなくなるのが原因のようだ。msleep の実装は
    %   run/$$.util.msleep.pipe に対する fd を用いた物だが、もしかするとこの
    %   pipe ファイルが削除されると動かないのかもしれない。或いは、この fd を開
    %   いているプロセスが2つ以上ないとだめという事なのかもしれない。一応最初の
    %   msleep は動作しているので、サブシェルでは msleep は使えないとかそういう
    %   問題ではない筈である。
    % →これを ble/bin/sleep に変えても元の問題は直らなかったし、逆に本体の問題
    %   を解決したら別に msleep でもちゃんと動いた。

    然し、msleep を ble/bin/sleep に置き換えてもやはり暫くプロセスが生きている
    様である。exit を builtin exit に変更したらちゃんと動く様になった。

    これは ble/builtin/exit の問題なので別項目で議論する (#D1973)。そもそも実は
    ここでは exit よりも return を使うべきなので、ここは単に return に変更する
    事にする。動作している。

2023-02-14

  * make: no-argument return がまたある。make scan でチェックするべき [#D1970]

    $ grc 'return[[:space:]]*($|[;|&])'

  * histdb: git info 等追加情報を user の指定で記録できる様にする [#D1969]
    → "bleopt histdb_remarks" として実装した。

    2023-02-18 そもそも rps1 での dirty 更新が発生していない。因みに
    prompt_status_line に関しては dirty 更新は働いている様だ。然し、これは独立
    した問題の気がする。

    うーん。mintty の中だけでなく、普通に新しいセッションでは全て動いていない。
    何故? うーん。histdb_remarks の対応 commit で以降で動かなくなっている。→同
    期処理等を破壊したかと思ったが単に dirty_mark の生成コードでバグを埋め込ん
    でいただけだった。

  * histdb: PS1=(\$ ' で ( を挿入した時にエラーメッセージ [#D1968]

    これは master 81e376a (もう存在していない。対応するのは 8d5cab8 が近い) で
    は発生していない。

    これは最初は syntax のバグかと思ったがどうやら histdb-word で発生している。

    うーん。response で現在のコマンド内容と全く関係ない物が生成されている? とい
    うかそもそも空の文字列で候補生成されているのではないか。然し、そうだとして
    も index が 8 になっているのはよく分からない。

    _ble_edit_str='PS1=(\$ '\''' len=9
    _ble_edit_ind="5"
    ret="8:'.timeout 1001'" # response

    うーん。分かった request の時点で全ての単語に対して補完を試みようとしている。
    何故かというと現在のカーソル位置がコマンドラインの末端にあるという事を仮定
    している。

    カーソルが行の途中にある場合には個別に実装する必要があるのではないか。と思っ
    たが、カーソルが単語の途中にある時にはその単語について補間する必要はない。
    飽くまで単語の末尾にいる時にだけ補完を実行すれば良い。行の途中にいてかつ単
    語の末尾にいるという状況では、まだ閉じていない単語の末尾にいるという事はあ
    りえない。という事は、現在位置にある単語について調べれば十分である。

    うーん。現在の単語の開始位置を調べる方法が非自明だったが (wbegin を stat に
    設置せずに一気に読み取ってしまう単語が存在する) 取り敢えず実装した。

  * blerc.template: update unicode versions [#D1967]

2023-02-13

  * 2021-10-26 edit: winch の際の遡って再描画する条件をより広げる [#D1966]
    https://github.com/akinomyoga/ble.sh/issues/142#issuecomment-955181640
    https://github.com/akinomyoga/ble.sh/issues/276
    ref #D1679

    取り敢えず端末の reflow について仮定はする事にする。つまり、行末にまで達し
    ていなければ、端末幅を広げた時のその行の次の行が一緒に動くという事はない。
    一方で、行末で折返しが起こっていなかったとしても一番最後の列まで文字が存在
    している時には、端末によっては行継続として取り扱う可能性があるので、安全側
    を取って幅が変化している可能性について考える。

    * ok: 直前のコマンドが行末まで文字を埋めている時

      | というか直前のコマンドの出力結果が端末末端まで存在している時には結局問題
      | になるのではないか? 然し、その様な場合は少ないと考えられる (全画面 TUI な
      | コマンドの場合にはそれも怒るかもしれないがその場合には altscreen 上に描画
      | すると期待したい)。
      |
      | また、折返しをちゃんと記録する端末で更に xenl の場合には、(a) 行末ぎりぎ
      | りで終わった場合には、 [EOF] マーカーが挿入されるし (b) もし行末で改行を
      | した場合には行が切り離されるので端末幅を広げた時に行がくっつくという事も
      | ない。折返しを記録せずに単に最後の列に文字があるかどうかだけで再配置をす
      | る端末については関知しないとして良い気がする。

      その様な場合は少ないし、xenl な端末で折り返しをちゃんと記録していれば、
      ble.sh では EOF マーカーがあるので問題にならない筈。

    * そもそもこの判定は edit よりは canvas の側で管理するべき事の気もする。

      各パネルについて再配置で予期しない結果になる可能性について判定する。

    2023-02-13 改めて考える。各パネルの内容を見に行く事にする。実装していない時
    は安全側に倒して行数が変わっている可能性を考慮に入れる。

    うーん。各パネルは safe/unsafe で判断するのではなくて、最低でも終端点が何処
    以降になるのかという事を返す様にすれば良いのではないか?

    というか現在のカーソル位置から文字数を割り出して最低でも上から何行目以下に
    あるという事までは計算できるのではないか?

    * canvas_winch_action に関する端末依存性は色々考えられる:

      * 全角文字や emoji, 結合文字などの折り返しはどうなるのか。折り返した事に
        よって結合していなかった物が改めてくっついて幅が減るなどの減少はあるだ
        ろうか。

      * 全角文字が入り切らなくて行末に空白を空けて折り返しがあった時に reflow
        でまた行がくっついた時に空けて置いた空白は潰れるのかそれとも残ったまま
        になるのか。

        →複数回 winch が来たらその回数の分だけ減少している可能性がある。然し、
        処理中に届いた WINCH は消滅してしまうのでこれを正確に測るのは困難である。
        最悪の場合は伸びた文字数だけ幅が消滅する事があるのではないか? うーん。
        最悪でも拡張前の行数よりも沢山の空白が潰れるという事はありえない。

      * reflow するかどうかの marker は ECH, EL, DCH によって破壊されるのか其処
        に残り続けるのか。

      * 行末まで文字が行った時点で reflow mark がつくのか、更に文字が追加されて
        次の行に行った時点で reflow mark がつくのか。

      * カーソルの位置は reflow と一緒にどの様に動くのか。

      * DECSC/DECRC で一時移動していた時に、一旦記録していた位置も一緒に reflow
        するのか、それとも戻ってきたら絶対位置に戻ってくるのか。

      * 連続的に複数の再配置が起こる端末と一気に最終サイズに於いて再配置が起こ
        る端末の振る舞いの違い等も考えられる。

    * done: wiki redraw-safe
    * done: blerc: redraw-safe
    * done: ChangeLog

  * README: ビルド過程に対する説明 [#D1965]

    勘違いする人が沢山いるし勝手に馬鹿にしている人がいるので README の make の
    部分に色々書いておく。

    * make/README にも各ファイルの説明を書いている。

  * README: Guix package の位置が変わっている [#D1964]

2023-02-12

  * prompt: \g{} は ble/color/setface/.spec2g を使う? [#D1963]
    https://github.com/akinomyoga/ble.sh/issues/278

    そうしたらカスタム face を指定できて、ユーザーが自分で定義する事に直接の意
    義が出てくる。

    * done: wiki: 他にも faces はあるという事を書く (motivated by bkerin)

    2023-02-13 .spec2g は動的な face の為に算術式を返すので、color.sh の枠組み
    の外側で算術式評価する様になっていると、後に face 継承などを実装した時に評
    価文脈が違って変な事になる可能性がある。評価文脈をちゃんと把握する為に、算
    術式評価した結果を返す関数を color.sh の側で用意してそれを呼び出す様にする
    べきである。.spec2g は .spec2gexpr に改名し、それとは別に spec2g という関数
    を用意してそれを呼び出させる事にした。

  * syntax: 5.2 以降では (()) [[]] の直後は } 等が来ても良い [#D1962]
    これの修正は簡単。

  * color: ble palette の並び方をより分りやすく (suggested by stackoverflow/caoanan) [#D1961]
    https://superuser.com/a/1512656/980046 コメント by caoanan

    色の排列を考え直す余地はある。現在は横幅 64 使っている。高さが 32 なのは実
    は端末の 80x24 には入り切らない。

  * syntax: 履歴展開 & "$!", heredoc [#D1960]

    bash-4.1 以下で echo "$!" を実行しようとしても履歴展開周りで変な事が起こっ
    てコマンドを実行する事ができない。更に bash-3.0 では

    bash-3.0: ble/history:bash/resolve-multiline: そのようなファイルやディレクトリはありません

    と表示される。

    また暫くして実行してみた所違う失敗の仕方をする。どうも本当に履歴展開が起こっ
    ている様だ。--norc で実行しても履歴展開が起こって変な事になってしまっている。
    つまり、これは ble.sh 自体の問題ではないという事。

    a ble.sh の側で履歴展開があるかどうかの判定を行って、履歴展開文字が存在しな
      い時には履歴展開をそもそも試みないという可能性?

      然しそれだと普通の履歴展開と "$!" が混在している場合には結局履歴展開を実
      行することになるので、問題を回避できていない。それに元々の bash の振る舞
      いとして履歴展開が起こる筈なのにそれを無理やり回避するのは間違っている気
      がする。

    b 或いは履歴展開の文法解釈を弄る。というかその様に対応するべきである。そう
      すれば混乱もないだろう。

    →b の方針で修正する事にする。

    * fixed: というか調べてみるとどうやら 4.2 でも "echo!" 等で展開は実施される
      様である。これについては対応した。

    * fixed: 4.1 以下での $!... の展開

      然し今回問題になっているのは 4.1 以下では $! の ! であっても履歴展開を誘
      導してしまうという事である。これを文法的に正しく処理するのは難しい。とい
      うか、$! に続いて何か文字列があると必ず展開されてしまうという事になる。こ
      の振る舞いは困る。もう少し色々試してみる事にする。

      $ echo $!a

      も履歴展開されてしまう。${!} は展開されない。つまり $! に丁度一致する時に、
      $! に引き続き履歴展開がある場合には履歴展開とするという事。

      これに対応する為には check-dollar の中で $! に一致した時に 4.1 以下で特別
      に check-history-expansion を呼び出す必要がある。所で histchar も考えると
      単に '$!' だけ確認すれば良い訳では無い。

      因みに check-dollar が有効な文脈は全て履歴展開も有効の様なので、
      check-dollar の中で履歴展開を試みるかどうかについて追加の条件で判定を行う
      必要はない。

      →実装した。取り敢えず実際の bash の振る舞いと同じになる様に履歴展開の着
      色がされる様になった。

    * fixed: 履歴展開 in heredoc

      履歴展開の着色がされていない。また、\\ \$ 等の着色もされていない。但し、
      \a 等の元よりエスケープする必要のなかった物についてはエスケープとしては処
      理されない。\" もエスケープとしては処理されない。\<LF> はエスケープとして
      認識される。\! は unquote されないが履歴展開を抑制する効果はある。

      * heredoc 内での \\ \$ \` \<LF> エスケープの着色に対応した
      * heredoc 内での履歴展開の着色に対応した

    * fixed: 3.0 での ble/history:bash/resolve-multiline のエラーメッセージは依
      然として表示される。

      どうやら bash-3.0 では resolve-multiline は有効になっていないのに、その外
      側で resolve-multiline を呼び出している箇所が2箇所ある。それぞれに対応す
      る (mutiline サポートなしの) 実装を提供する事にした。とは言っても
      multiline サポートなしなので両方ともほぼ自明な操作である。

    * fixed: histreedit は二回連続だと accept するべきなのでは? 4.1 で展開に失
      敗する時何度でも失敗する。と思ったが、寧ろ 3.0 で二回連続で実行した時に実
      際に実行された方が問題であった。plain Bash だと histreedit だと何回実行し
      ようとしても実行できない。

      代わりにエラーメッセージが表示される。というか何故エラーメッセージが表示
      されていない? in ble.sh → 分かった。ble/widget/.internal-print-command
      が $command を被覆している所為でちゃんとエラーメッセージの起こる履歴展開
      を評価できていなかった。

  * [棄却] histdb: コマンドも histdb-word と同様に数えて良いのではないか? [#D1959]

    これは quote 等を除去した状態で数えるのが良い? それとも quote も含めて記録
    する? コマンドの種類も記録するべき? 然し、実の所、わざわざ記録しなくても、
    後でコマンド履歴を見れば何を呼び出したかは基本的に分かる。

    これは #D1958 と同様の理由で今は数えない。実際に必要になったらその時に実装
    すれば良いが、実際に必要になるのか分からない。

  * [棄却] histdb: histdb-word で一つのコマンドに同じ単語が複数あった時に数える? [#D1958]

    然し目的が使用頻度を記録して後の補完での優先順位に役立てるのだとしたら、一
    つのコマンドの中で複数同じ単語が登場するのは自明の可能性が高く、使用頻度と
    して計上するのは違う気がする。もし実際に単語の使用頻度を興味として知りたい
    のであれば、command_history の command を抽出して自前で処理するべきなのであ
    る。histdb で記録するのは高速にそういった処理をするのが大変だから補完候補生
    成の為のキャッシュとして用いているという側面がある。

  * histdb: auto-complete-history で ' を含むコマンドがあると SQL でエラーメッセージが出る [#D1957]

    これは単に q=\' qq=\'\' の初期化していない状態でエスケープを実行していたか
    らだった。修正した。

  * histdb: bash-3.0 で fork したプロセスが消滅してしまう。謎 [#D1956]

    普通に自分で実行すると生きている様な気がする。

    どうも bash-3.0 では function fname { ... } <&"$fd1" >&"$fd2" 等の様にして
    リダイレクトするとちゃんとリダイレクトされていない様だ。何故か /dev/null に
    繋ってしまう。中でリダイレクトする様にしたら直った。

  * [棄却] histdb-word: edit insert-last-argument 等についても [#D1955]

    実は histdb-word を使った方が良いのでは。と思ったが

    x 現在の histdb-word の実装だと単語の順序等が失われるし (同じコマンドの中に
      含まれている単語は同じ時刻になるのでは)

    x また重複する単語があった時に古いものが抜けてしまう (その方が望ましいとい
      う考え方もあるかもしれないが、やはり思い出しながら探す時に通り過ぎた後で
      もちゃんと現れた方が親切な様な気もする)。

    また現在の insert-last-argument の実装を確認すると履歴展開を使って単語を抽
    出しているので、結局別に現在の実装で問題があるという訳でもない。寧ろ、現在
    の実装は (subshell fork するものの) 他のプロセスとの交信がない分だけ安定し
    ているのではないかという気がする。

2023-02-10

  * histdb: 4.2 で算術式のエラー(配列負の添字) のエラーが生じている [#D1954]

    実は printf %(%s)T に対応しているとは言っても、bash-4.2 では -1 を指定しな
    いとちゃんと現在時刻になってくれない様だ。これが為に BLE_SESSION_ID の為の
    時刻決定で失敗していた。

    * 2023-02-12 bash-4.2 の last_time が 0 になっている。これも同じ事が原因だっ
      た。ble/histdb/.get-time の関数の中でも %(%s)T を用いて時刻を取得しようと
      していたが、明示的に -1 を指定する必要がある。

  * histdb: 3.2以下で session が登録されていない [#D1953]
    これは単にデバグ用に置き換えていた関数名 assign2 が残っていたのが原因だった。

  * histdb: sqlite のエラーメッセージは端末に表示するようにする [#D1952]

    本来は全く表示されない事を期待しているので、もし表示されるのだとしたらバグ
    である。なので表示する。

2023-02-06

  * 2022-01-23 [対応済み] コマンドのログ機能を作成する [#D1951]

    特定のファイルに情報を書き込む。

    同時に複数の書き込みがあった場合に混ざり合う危険性がある。滅多に起こらない
    と思いたいがちゃんと防止策は作っておく必要がある。例えばシェル毎に履歴を記
    録して終了する時に合成するという手が考えられる。合成自体が衝突する自体を防
    ぐために mkdir/rmdir を使うのが一つの手である。

    コマンドにはコマンド実行前とコマンド実行後の二つに分けて結果を書き込みたい
    という欲求がある。という事を考えると、

    $ printf '%x/%s/%s.e%s\n' $(printf '%(%s)T' -1) "$HOSTNAME" $$ "$LINENO"

    * バックグラウンドのジョブの状態はどの様に記録するのか。うーん。ジョブに関
      しては一応 ble.sh の中で追跡はしている。それに従って終端を幾らか荒い尺度
      で検出する事はできる。しかし正確な時間は分からない。

      プロンプトを表示した時刻も記録しておくと良い様に思われる。しかしそうなる
      と大量の記録が残ってしまう事になるのではないか。うーん。プロンプトを表示
      した時刻に関しては別に全てを記録する必要はない。前回のプロンプトの表示時
      刻だけ覚えておいて、ジョブ変化を検出した時にその情報を備考として乗せるだ
      けで良いのである。

    * 記録する情報は以下の通り。

      cmd, pwd, 終了ステータス(PIPESTATUS), 各種時刻情報, files(自動補完用), 構
      文解析情報(後で単語を抽出する為。というか単語の範囲だけで良い).

      これを使って処理するのはもしかしたら外部プログラムに頼らなければならない
      かもしれない。

    或いはデータベース等も保存先として考えても良いのかもしれない。但し、その場
    合には sqlite3 等に対する依存性が発生する。一方で、sqlite3 には最低限の排他
    制御が含まれている様ではある。

  * 2022-06-28 [対応済み] コマンド名の曖昧補完ができない。./adf[tab] [#D1950]

    これは . で始まるコマンド名を列挙してそれで補完を実行しようとしている為であ
    る。/ が含まれる場合には glob で一致させてその上で実行属性でフィルタする必
    要がある気がする。

    引数の場合にはできている。うーん。/ が含まれる場合は別に生成するべきなので
    はないか。

  * 2022-07-20 [解決済み] konsole drag&drop [#D1949]
    https://github.com/akinomyoga/ble.sh/issues/211
    https://invent.kde.org/utilities/konsole/-/merge_requests/714

    konsole に PR を出したが返事がない。この2日の間に別の PR はマージされている。
    暫く待っても何も反応がなかったら Bugzilla の方にも提出する事にする。もしく
    はメーリングリストに直接問い合わせる。

  * [棄却] histdb: 現在の有効なファイル名をコマンドに紐づけて記録する可能性について [#D1948]

    * コマンドが前提としているファイルの存在を確認して history を skip する。

    ファイル名着色などの情報を参照したい。そうすればファイル名と偶々一致してい
    る単語を誤って登録してしまうという事もなくなる。chroma を充実させる動機にも
    なる。

    複数のファイル名が考えられるので別テーブルに記録する事も考えたが、それだと
    データベースサイズが大きくなる気がする。或いは、別テーブルにファイル名だけ
    記録しておいて但し id リストを command_history の entry の中に保存するとい
    う事にすれば良いのかもしれない。

    余り形式を複雑にしても仕方がないしデータベース上でファイル名を操作するとも
    思えない。後で特定のファイル名を指定しているコマンドを探るとしても、ファイ
    ルの相対パスを解決しなければ使えない。

    然し改めて考えたら、既にファイルが存在しているかどうかに関わらず実行するコ
    マンドもあるのだからファイル名と一致するかどうかで候補として生成するかどう
    かを変えるのは余り良いアイディアではない様な気もする。どうなのだろう。

    * 更に改めて考えてみると本当に fish がここまでの情報を記録しているのかも不
      明である。oil の zulip ではその様な事を言っている人がいたが、実は単に
      fish は cwd だけを見て判定している可能性もある。実際検索しても其処まで積
      極的に履歴を記録している訳でもない様だ。2016に初めて cwd を一緒に記録し始
      めた程度である。

    →今 fish の振る舞いを試してみたが、コマンド実行時に存在したファイルを消し
    ても、同じディレクトリで同じファイルが autosuggestion の候補として表示され
    る。つまり、(少なくともデフォルトの設定では) fish は別にコマンドライン中に
    含まれるファイル名について記録して存在を照合しているという訳ではない様だ。

    逆に cd 等の既知のコマンドについてそれが成功するかどうかをその場で判定して
    いるというだけの事なのかもしれない。

    うーん。これについては棄却する事にする。代わりにコマンドが成功するかどうか
    を高速に判定できればそのコマンドをスキップするという機能を項目として残す。

  * histdb: 様々の sql query エラーの修正 [#D1947]

    * main: bash-3.2 で BLE_SESSION_ID の時刻決定が誤っている。

      bash-3.2 でちゃんと words を登録できていない気がする何故? 或いは、もっと
      前から駄目だった? と思ったらどうやら時刻が誤っている様だ。そし
      て_ble_base_session の時刻を見ると何故か 1000000 分の1の少数にされている。
      うーん。結局これは ble/base/initialize-session の初期化が問題だった。

    更に bash-3.2 で session が登録されていない。うーん。調べてみた所様々なエラー
    が出ていた。bash-3.2 に限らず bash-4.0+ でも sqlite がエラーメッセージを出
    しているのを捨てていた。直した。

  * 2022-01-08 term: prompt_status_line でずれが生じる端末がやはり存在している。何故だろうか [#D1946]
    Ref https://github.com/borisfaure/terminology/pull/115

    2022-02-02 windows terminal でもずれる。改めて確認してみる。実は status を
    表示していなくても端末の一番下の行で改行をしようとしても改行されないのであ
    る。という事はここで使っているシーケンスの内 windows terminal で動作しない
    物が存在しているという事。

    increase-height.draw が動作していないのではないだろうか。

    うーん。もしかして DL をした時に新しく追加した行が削除されて逆スクロールし
    ている? 更に IL も動作が変だという事が判明した。

    →Cygwin に報告したらすぐに修正してくれた。これで待っていればちゃんとした振
    る舞いになる。それまでは仕方がないので我慢する。

    * 2022-03-04 terminology でずれる原因は分かった。これは terminology のバグで
      ある。以下で変な振る舞いをするという事が分かる。

      $ printf 'O\e7\e[%d;%dHA\e8K\n' $LINES $COLUMNS

      https://github.com/borisfaure/terminology 報告しようと思ったが何だか良く
      分からない。http://issues.terminolo.gy/ から
      https://phab.enlightenment.org/project/view/8/ に跳んだが issue を作る方
      法が分からないので取り敢えずログインする事にしてみた。そしたら元からある
      チケットですら見ることができなくなってしまった。

      面倒になったのでこれは PR にして出す事にした。
      https://github.com/borisfaure/terminology/pull/115

      * terminology version 判定

        WA を追加しようと思ったが terminology を判定する方法は実は無い。xterm の
        ふりをしているので区別が付かない。もし terminology の区別がつくのだとした
        ら、terminology では最後の行を使わない様に修正するのが良い。

        DA2 応答は 1.4.0 以降は 61;337;0 である。それより前は 41;285;0 だった様だ。
        https://github.com/borisfaure/terminology/commit/96bbfd054b271f7ad7f31e699b13c12cb8fbb2e2 1.4.0 "61;337;0"
        https://github.com/borisfaure/terminology/commit/e4d7cb93f2ad3c09d50362cee557815e10997687 1.4.0 "41;337;0" (not-released)
        https://github.com/borisfaure/terminology/commit/59ad20f6f8e364b02e1c65ec28f480649eea714a 0.4.0 (DA2 には変更なし)
        https://github.com/borisfaure/terminology/commit/526cc2aeacc0ae54825cbc3a3e2ab64f612f83c9 0.3.0 "41;285;0"
        https://github.com/borisfaure/terminology/commit/db902446540f5e014694da0ec6fb495cfab15e62 0.2.0 "0;271;0"
        https://github.com/borisfaure/terminology/commit/500e7be8b2b876462ed567ef6c90527f37482adb 0.2.0 "1;271;0" (not-released)
        https://github.com/borisfaure/terminology/commit/8b822a61d7721fce16e145b57dc67ca6ae8b752d 0.1.0 "\e[?1;0c" DA2 じゃない (initial commit)

        まとめると、

        terminology-0.1.0 ... DA2 応答は返さない
        terminology-0.2.0 ... 0;271;0
        terminology-0.3.0 ... 41;285;0
        terminology-1.4.0 ... 61;337;0

      一応 temrinology はこれで100%ではないが検出できる。然し、考えてみれば検出
      できたとしてもどうやって workaround を加えれば良いのか不明である。うーん。
      \e8 する前に一旦 \r で行頭に戻るというのが一つの対策かもしれない。
      →この対策でちゃんと動く様になった。

    * [自然解消] 2022-03-08 上記と同様の現象が bash-3.2 では未だ健在である。何故だろうか。

      terminal ID がうまく動いていないという事だろうか。→terminal ID はちゃん
      とうまく行っている。terminology 1.4 という事になっている。

      また別の問題という事だろうか → patched terminology では発生していない。
      つまり同じバグ。

      _ble_term_rc がちゃんと置き換わっていない可能性? → そうでもない。ちゃん
      と \r が挿入されている。

      直接 '\e8' を記述している箇所がある可能性? →うーん。そういう箇所もない。
      DECSTBM のテストに用いている \e[r によって wrapnext が不自然な状態になっ
      ている可能性? → テストの方にも \r を入れてみたが振る舞いは変わらない。

      また問題が発生するのは最初の1回だけの様でもある。つまり、未だ端末の種類を
      特定するよりも前の時点で実行した rc により wrapnext が壊れている可能性。

      2023-02-06 うーん。今実行したら再現しない。恐らく terminology の側が修正
      されたので問題が出なくなったのだろう。なのだとすれば、わざわざ古い
      terminology を持ち出してテストするのも大変だし、気にしない事にする。

    * fixed: 2022-03-04 terminology で最初のコマンドを実行する迄 C-h 及び BS が
      全く効かない。何故だろうか。そもそも C-h を受信できているのかも不明である。
      一回コマンドを実行すれば問題なくなる。

      builtin bind -X を見た感じが問題ない。然し、何故か bind -X の実行結果に

      "\C-h": "ble-decode/.hook 8; builtin eval -- \"$_ble_decode_bind_hook\""

      というのが混入する状態になっている。

      ? 何故 terminology だけで発生するのだろうか。うーん。不思議だ。調べるとど
        の端末でも bind uvw は何か変な状態になって登録されている状態になってい
        る。然し、\C-h も同様に設定されているのは terminology だけである。

        然し、そもそも何故 uvw が直接 bind されてそれが bind external に登録さ
        れてしまっているのか。これは何らかのミスなのではないか。

        そもそもこれらの bind が設定されている箇所を特定すれば何処でこれが起こっ
        ているのか判明する筈。

        うーん。bind -x を実行している箇所を見たが別に .hook 8 を特別に指定して
        いる箇所もないし、decode.bind.50108.UTF-8.bind も特に変な事はない。

      * うーん。bind -X で違いが出るという事は bind.save に問題があるのかもしれ
        ないと考えたが、どうやらそうでもない様だ。別に bind.save の内容は変化し
        ていない。

      * bash の version によるバグかもしれないと思って調べてみたが bash-3.2 か
        ら 5.1 まで全て問題は再現する。plain Bash + ble.sh --norc でも再現する。
        noattach でスタートして ble-attach を使って attach した時にも再現する。

      * うーん。分かった。terminology は erase を ^? から ^H に差し替えて端末を
        初期化している。これによって UVW? の workaround が効かなくなっていたと
        いう事。うーん。つまり、原理的にあらゆる文字がこの影響を受ける可能性が
        あるという事では。

      --- stty1.txt^I2022-03-08 20:10:24.782885825 +0900
      +++ stty2.txt^I2022-03-08 20:10:44.466968954 +0900
      @@ -1,5 +1,5 @@
       speed 38400 baud; rows 24; columns 80; line = 0;
      -intr = ^C; quit = ^\; erase = ^H; kill = ^U; eof = ^D; eol = <undef>;
      +intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
       eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
       werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
       -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts

      * 愈 bind-tty-special-chars を off にする必要があるという事だろうか。

        但し bash-3.0 には bind-tty-special-chars は存在していない様である。

      結局これは ble/decode/bind/adjust-uvw で ^H についても同時に上書きする事
      にした。これで動いている。adjust-uvw は実際の所、初回呼び出し時だけしか処
      理を行わないのでここで多少沢山のコマンドを走らせても困らない。

    2023-02-06 一年以上も放置されているのでまた改めて確認する。うーん。どうも少
    し弄ったら直った様なのでこれで良い事にする。

  * util/idle: background で何が動いているのか分からないので immediate-show で表示する? [#D1945]

    オプションで切り替えられる様にする。うるさいので既定では off。

    immediate-show で表示していると menu-complete 等他の物が使えなくなるので、
    scheme == default の時にだけ ble/util/idle で現在実行中のタスクを表示する。

    * info: Emacs の *Messages* の様に後で記録を見返す事ができると良い気がする。
      後でログにする事も考えて時刻も含めておく (但しどの様にログにするのかは謎。
      info に新しく schene を追加して log という事にして、更に何処かのファイル
      にキャッシュとして保存するなど? 何れにしても全然必要性を感じないので今の
      所は気にしない事にする)。

  * histdb: backup機能 [#D1944]

    sqlite3 データベースが破壊される事が実際起こるのか分からないが、消えるとショッ
    クなのでバックアップは時々したい。".backup ファイル名" でバックアップを作れ
    る様だが、バックアップのファイル名は自分で決める必要がある。またバックアッ
    プの頻度も考えたい。取り敢えず終了時に前回のバックアップから時間が経ってい
    たらバックアップするという形にするのが良い気がする。前回のバックアップ時刻
    はデータベース内部に直接記録してしまって良いのでは。

    壊れたファイルで上書きしても駄目なので sqlite3 が壊れていないかのチェックも
    行う。チェックに失敗したら警告を発する。データサイズが大きくなってくると
    "PRAGMA integrity_check;" は時間がかかるらしい。代わりに "PRAGMA
    quick_check;" という物があるらしい。

    https://sqlite.org/forum/forumpost/9d9e63a8d4
    https://serverfault.com/questions/8048/how-can-i-verify-that-a-sqlite-db3-file-is-valid-consistent

    .backup を実行するのと直接コピーするので何が違うのかと思ったが、直接コピー
    すると中途半端な transaction のデータもコピーしたり、或いは書き換えながらコ
    ピーされたりして壊れるという事。
    hourly, daily, weekly, monthly ぐらい backup しておけば十分の気がする。

    と思ったが integrity_check を行うのであれば hourly で十分の気がする。或いは
    そんなに頻繁に壊れる物でもないと考えれば daily でも良いのかもしれない。

  * histdb: sqlite3 のプロセスだけ残ってしまったのをどう始末するか [#D1943]

    * sqlite3 のコマンドライン引数に親 pid を含める可能性

      考えたが、無駄な文字列を指定できる様な雰囲気はない。と思ったが -cmd を使
      えばコメントを指定できるのではないか。然し、その様にしたとしても ps をし
      た時に見える様になるだけで、スクリプトから対応する親プロセスを抜き出して
      殺すのに使える訳でもない。というか、そもそも sqlite3 のプロセスを列挙する
      時点で簡単ではない。なので、これは単に ps をした時に分かりやすいというだ
      けの事である。

      或いはプロセスツリーで見やすくする為に直接親プロセスから起動して disown
      する? と思ったが、やはり無駄なメッセージが表示されてしまう。そもそも、$!
      を勝手に書き換えてしまう事になるのでやはり避けたい。

    a 別の方法はプロセスを書き込んでおいて他の ble.sh session がそのファイルを
      削除する時に中に書かれているプロセス ID に対して kill を送信するという事。
      然し、これも pid 記録ファイルの削除のタイミング等によって変な事にならない
      かの懸念が残る。

    b うーん。或いは。。sqlite3 のプロセス id で run/histdb.$bgpid.ppid という
      ファイルを作って置いて、もし run/histdb.$bgpid.ppid に含まれている親プロ
      セスが既に存在していなかったらその sqlite3 プロセスは kill する。

    c 或いは本当は $$.histdb.pid というファイル名にして中に記録する方が良い様な
      気もするが、それだと ble.sh 本体の方の管理によって削除されてしまうので駄
      目。或いは、ble.sh 本体の方で *.pid というファイル名だったら中に書かれて
      いるプロセスを削除するというルールにしておくという可能性もある。

      うーん。その方が今後類似の事をしたいと思った時に consistent に処理できる
      様な気がする。

    d reject: 別の可能性としては、一つの sqlite3 プロセスを全体で共有するという
      可能性?  その様にすれば常に一つのインスタンスだけを持っていれば良いし、一
      旦起動したら起動しっぱなしで良い気がするので、わざわざ kill しなくても良
      い。と思ったが、そうすると今度は stream の同期の問題が出てくる。複数の
      query が混ざり合ってしまうともう駄目になってしまう。そもそも同期の問題を
      解決する為に sqlite3 を使っているのだから、やはり sqlite3 をセッションご
      とに持つのは避けられない。

    この b の方法が良い気がする。と思ったが c の方法にする。

  * histdb: _ble_histdb_exec_ignore の管理をちゃんとする [#D1942]

    現在の実装だと複数の exec lines がある時に最後のコマンドの ignore が最初の
    コマンドの ignore として使われる事になってしまっている。

    a 毎回判定する事にする? →それだと途中で設定が変更された時に変な事になる。

    b 同じ command_id で既に項目が登録されている時にだけ更新する? →無駄にコマ
      ンドを発行する事になる気がする。然し、update を使えば該当する項目がない時
      には無視されるだけなので、単に request を一回送信するだけである。

      これを考えたら単に _ble_histdb_exec_ignore の現在のチェックを削除するだけ
      で良い。そもそもよく考えたら session 情報の更新は histdb_ignore に該当し
      たとしても行っておくべきだし、何れにしても request は送るのではないか。

    c exec line に追加情報を埋め込める様にする? 然し histdb だけの為に専用のフィー
      ルドを用意するのは拡張性がよくない (使いたい項目ごとに拡張を行う必要があ
      る) し、別の配列に項目を保存するとしてもインデックスの管理などをどうする
      のかが分からない。

      と思ったが command_id を使って記録すれば良いだけなのでは? そして使ったら
      unset する。

    結局 c の方針で実装する事にした。結局 ignore されたコマンドに関しては
    session 時刻及び cwd も更新されないがそれで良い事にする。

2023-02-05

  * histdb: 同じディレクトリの一番最近の履歴を抽出する [#D1941]

    有効なファイル名を記録するのよりも先にこちらを実装するべきである。

    histdb-history

    * ディレクトリが移動した後も追跡できれば追跡する。

      ディレクトリの inode を記録するという手もある? 然しファイルシステムが異な
      る場合もあるので何とも言えない。別のファイルシステムのディレクトリを掴ん
      でしまったら仕方ないので諦める。そもそもディレクトリが移動して元の場所に
      ないのであれば別の物を拾っても仕方がない。それを言い出したら一旦ディレク
      トリを削除した後に別のディレクトリを移動して持ってきた場合なども考えなけ
      ればならなくなる。

      と思ったが inode を持っていてもそのディレクトリのパスを取得する方法がない。
      ファイルシステム依存で特別のコマンドを走らせれば inode に対応するファイル
      名を列挙する事はできるが、一般にはファイルシステムを浚うしかないので単な
      る補完の為には現実的に実行できない。
      https://stackoverflow.com/questions/14822611/is-there-any-way-that-i-can-search-for-a-file-or-a-filename-using-a-given-inode

      可能性があるとしたら移動先のディレクトリでコマンドを実行した事があるとし
      たら、inode が一致する物をデータベース内で探して列挙する事はできる。

      * うーん。どうやら stat は posix ではないらしい。つまり、inode を取れるか
        どうかは分からない。ls -i もあるが、これも明らかに posix ではない。

        しかも stat ですら BSD と Linux でオプションの指定方法が異なる。Linux
        では stat -c %i file だが BSD では stat -f %i file である。因みに ls
        -di file は寧ろ BSD と Linux で同じである。

        確認してみた所 ble/file#mtime で既に stat を使っていて -c と -f の判定
        も行っていた。取り敢えずこの判定を流用する事にする。

      % うーん。track_directory というテーブルを作る事にする。作った。一応登録
      % はできている→結局これは使わない事になったので削除した。

    一文字コマンド等の自明なコマンドを対象としない。これは histdb_ignore で指定
    すれば良さそうな気もするが、実行時間などが気になる場合もあるかもしれないし、
    完全なログを後で欲しいという場合もあるかもしれないので、ignore は別に指定で
    きる様にするべきかもしれない。つまり、ログに残すかどうかの ignore と補完で
    現れるかどうかの ignore は本来は別の物であるのに関わらず元の bash では一緒
    くたになっていた (寧ろ元の bash ではログを残すという意味合いは弱くて後でコ
    マンドを再利用するというのが目的だったのだから、元の bash で設定ができない
    のは理解できる)。

    * source:histdb-history で source:history を置き換える?

      うーん。それだと .bash_history にあって histdb にない物が表示されなくなる。
      また、HISTIGNORE で除去していた物も設定される様になるので不都合があるかも
      しれない。strip が HISTCONTROL にある時には strip を実行するべきだろうか?
      等色々難しい。そもそも検索時には先頭の空白は無視しても良い気がする…が
      sqlite はその様な場合の glob には対応していない。

    これの実装は意外と簡単だった。単語補完が難しかったのは実の所、単語の抽出及
    び不完全単語のん特定などの処理が難しかったのだという事。

    * done: track_directory 登録廃止

      一方で、track_directory による inode の検索はそんなに簡単ではない。うーん。
      現在ディレクトリで検索して見つからなければ inode で検索して云々としたい所
      だが…。うーん。track_directory なるテーブルを作ったのは余り意味がなかっ
      た様な気もしてきた。現在いるディレクトリの inode を使って検索すれば良いだ
      けなのでは? 元々 track_directory で何をしたかったのかというと、"現在ディ
      レクトリ名 → inode の集合" だろうか。然しそれは変である。"inode" は一つ
      しか無い筈で、それは現在ディレクトリの inode を参照すれば良い。

    結局 command_history に新しく inode カラムを追加してそれを元にして検索する
    事にした。

  * 2023-01-26 histdb: 形式を変更する時は形式自動アップグレードを実装する [#D1940]

    misc/version に基づき行う。ダウングレードが必要ならば代わりにファイル名にバー
    ジョン番号を含めて (例: history@chatoyancy.v1.sqlite3) ファイルを開き直す。

    正に同じ事 (column がなければ column を追加する) をしようとしている人がいた。
    然し、sql query 一発で実行する方法はない様である。
    https://stackoverflow.com/questions/56762261/sqlite-how-to-use-select-count-in-case-statement

    仕方がないので version を取得してそれを元に upgrade が必要であれば実行する
    という事にした。結局これは実装する。実装した。取り敢えず動いている。

  * contrib: fzf, bash-preexec などは integration dir に移動する [#D1939]

    install 時に symlink を貼る。

    古いインストール先を上書きする場合を考えたら symlink でなかったら削除するべ
    きでは。→実際にやってみたら timestamp で比較してちゃんと rule が発火するの
    で ln -sf で上書きしてしまえばOK。

  * histdb: 今までに入力した単語を記録する機能。単語自動補完 (histdb-word) [#D1938]

    当初は対応する session_id, exec_id と紐づけて管理する事を考えていたが、其処
    までする必要性はあるだろうか。そもそも何故単語を記録するのかというと、補完
    で使う為である。そう思ったら、最終使用日時及び使用回数だけ記録すれば良い気
    がする。

    既存の値から増やすという事を sqlite でするにはどうすればいいのか。と思って
    調べてみたら update で既存の値を使った計算式を指定できる様だ。
    https://stackoverflow.com/questions/744289/how-to-increase-value-by-a-certain-number

    既に登録されていればそれを更新し、そうでなければ新しく挿入する方法は? と思っ
    て調べたら色々あるようだ。
    https://stackoverflow.com/questions/3634984/insert-if-not-exists-else-update
    https://stackoverflow.com/questions/418898/sqlite-upsert-not-insert-or-replace

    SQLite-3.24.0 [2018-06-04] で追加された UPSERT という機能が求める機能の気が
    する。然し、これは比較的最近の機能なので使えるとは限らない。更に独自拡張な
    ので別の sql db では使えない。色々読むと今回の場合は文字列以外は完全に置き
    換えるので単に insert or replace で十分の気がする。

    2023-02-03 まず最初に newline を実行する前の時点で項目を登録する様にする必
    要がある。新しく blehook exec_register を作って、其処から histdb のコマンド
    登録を実行する事にした。

    * fixed: LINENO の設定と実際の値が変な事になっている気がする。

    * fixed: PS1 \# についても更新のタイミングと初期値がおかしい。

    * fixed: また、\# は初期値は bash では 1 の様である。然し、現在の実装だと 0
      になっている気がする。

    * fixed: history_index の値も変である。1 少ない。更に履歴を遡って編集して実
      行した場合も変である。histdb_ignore で無視された項目は前の項目よりも次の
      項目と同じ履歴番号になるべきである。

    取り敢えず実装した。

    * fixed: HOSTNAME に / が含まれている時にファイルが作れないのでは。/ は %
      に置換する事にした。

    更に記録した単語を元にして auto-complete で単語を提示する?

    * done: 外部から auto-complete source を追加する枠組みは整えた。

    * 現在位置を含む単語を列挙する。これは wbegin を辿っていけば良い筈だが…。
      既に類似の事をしている箇所はあるか?
      ble/syntax/completion-context/.check-prefix で現在位置が属している単語を
      決めている。うーん閉じていない非単語 node の先頭を見つけるのは難しそうだ。
      tprev を辿って行って -1 になった所で更に遡って node を見つける? 否、stat
      に格納されている nlen を見れば良い気がする。

      然し、よく考えてみればそもそも単語の途中にカーソルがいる時に自動補完で単
      語として補完するのは変な気がする。特に suffix が続きと一致している時に、
      それを skip するのかしないのか。等。(但し skip についてはちゃんと処理して
      いるのではないか? ble/complete/insert が処理する)

      最後の時点で単語を閉じているのではなかったか? と思ったが syntax_debug を
      設定してみてみても単語は閉じていない様だ。単に最後に閉じていない単語のエ
      ラーを列挙しているだけ。逆に言えば閉じていない文脈を同様に拾ってその文脈
      での単語の開始点を調べれば良いのである。
      ble/highlight/layer:syntax/update-error-table の実装を参照すれば良い。

      うーん。同様にやってみたが一番上の文脈の情報しか取れない。何故? というか、
      同様の処理を実は parse の最後でもやっている様な気がする。何が違うのだろう
      か。また、nest-pop を実行する時に tree に登録している様に見えるが、何故そ
      れが参照できないのだろうか。

      一方で syntax_debug ではちゃんと木構造を再構築できているので何処かには情
      報がある筈である。と思ったが tree-enumerate の場合には最初に木構造を閉じ
      るための処理を追加で行っていた気がする。→
      ble/syntax/tree-enumerate/.initialize を見たら当にその様な処理を行ってい
      た。

    * 単純単語の場合にそれがファイル名かどうかを記録する? そうすると最悪単語の
      登録数は2倍になる。勿論 simple-word でない物は展開できないので、これは二
      倍にはならない。しかし其処までするのも変な気がする。

    2023-02-06 words の登録順序が気になる。ちゃんと順序が保たれる様に変更した。

  * 5.3: ble/builtin/trap -P [#D1937]

    trap に -p と -P の両方が指定されていた場合はどちらが勝つのか? と思ったら両
    方指定する事はできませんというエラーになった。ble/builtin/trap でもその様に
    実装する。

    うーん。builtin trap -P を使ってより効率の良い実装に切り替えようと思ったが、
    実際には ble.sh の中では « trap '' xxx » の形になっている事を想定した処理に
    なっていた。読み取る時も結局 eval "ble/builtin/$(trap -p INT)" 的な形にして
    ble/builtin/trap に委譲して処理している (つまり、eval を使って引数を評価し
    ている)。なので今迄通り trap -p を使い続けるので良い気がする。敢えて複雑に
    処理を切り替える必要もない。

  * 2022-03-19 [対応済み] compat bash-5.2 で \q{...} が動かなくなっている [#D1936]

    どうもこれは bleopt の設定時に \ が重複しているのが原因の様だ。表示時の問題
    ではなくて本当に値が変わってしまっているという事を確認した。

    どうもこれは ${var[@]/%/"=$value"} の振る舞いに関する物の様だ。というかこれ
    は既に別に patch を用意した物の気がする。というか既にこの問題を発見してそれ
    で修正したという事の気がする。やはり早く patch を提出する事にする。

    →これはもう修正を提案して修正されている。現在の 5.2 では何も問題は生じてい
    ない。

  * 2021-06-12 [対応済み] bash: 開発版 version に関して [#D1935]

    実は bash-dev 版は 5.1.xxx の儘推移している。本当は 5.2.xxx-alpha の様な形
    にするべきなのではないかという気がする。よく分からない。提案しようかとも思っ
    たが実際の所は 5.1.x-maint になっている事から、本来は devel branch は既に出
    た version のメンテナンスモードという意味合いだったのかも知れない。然し、こ
    の様になっていると次の version かどうかを判定するのに BASH_VERSINFO を利用
    する事ができない。今迄は新しい version になる事によって何か機能が減るなどし
    て動かなくなるという事はなかったので余り気にならなかったが、"テスト" という
    観点から本来は早くに bash-5.2 に増やすべきなのではないかという気がする。

    差し当たっての ble.sh の側では release status も見て version を上げる様にす
    るのが良いだろうか。と思ったが…。自分はテストの為に release を release に
    しているし、逆に maint で動かしているユーザーがいたとしても遅くて使い物にな
    らない。自分の relstatus に関してはまた別の値を指定するという手もあるのかも
    しれない。と思ったが、それをするぐらいであれば実は configure.ac に於いて
    version を 5.2 に書き換えてしまえば良いのである。

    2023-02-05 これは一回提案したが自分が決めるんだと言って reject された。仕方
    がないんで自分の側で処理する事にする。

  * 2021-05-03 [対応済み] 5.2 新機能: READLINE_ARGUMENT [#D1934]

    調べてみると引数が存在している時にのみ定義される様である。また今気づいた事
    だが -x 属性が入っている。

2023-02-02

  * leakvar: いい加減に pending な leakvar fix を入れる [#D1933]

    最近の profile.d 変数たちも除外リストに追加する。

    * done: key という変数が mshex によって leak している → これは修正した。

    j という変数が確率的に leak している。

  * ble/syntax/highlight/vartype: ローカル変数を拾っている [#D1932]

    declare -p ret (配列), echo ${lookahead} (空変数) などグローバルに存在しな
    い変数の属性を拾ってしまっている。

    これに対応するには ble/util/print-global-definitions の様にトップレベルの変
    数にアクセスする必要があるが subshell 内部で行わないと行けないので問題があ
    る。ローカル変数に当たってしまってグローバルを直接見れない時にのみ特別の処
    理をするとしても、その判定に ble/variable#is-global 等を呼び出すだけで fork
    コストがかかるので既定でこれに対応するのは余り気が進まない。

    ? ok: 所で、 ble/util/print-global-definitions の中で呼び出している
      ble/variable#is-global は先に declare -g -r してしまっているので、常に真
      を返すのではないか。つまり、ローカルかどうかの判定には使えない → と思っ
      たが見えている一番上が local readonly であれば global readonly があっても
      関係なく新しく local 変数を内側の関数で定義できる様だ。なのでちゃんと判定
      する事ができる。

    例えば bleopt syntax_ensure_global_variable 等の設定が指定された時にだけ
    global 変数の状態を見に行く等?

    試しに実装してみたが動かない。readonly にする方式だと ret という変数自体を
    新しく定義する事ができなくなるので駄目。結局実装してしまった。うーん。多少
    遅くなるかもしれないが気にしない事にする。

    2023-02-03 $_ でエラーメッセージが表示される。$$ に対しても readonly からエ
    ラーメッセージが表示される。どうも ble/variable#is-global は特別変数に対
    して使ったことがなかった様だ。単に stderr を潰す事にした。

2023-02-01

  * main: ble-reload が動かなくなっている [#D1931]

    "--rcfile=$HOME/.blerc" を指定して再 source しようとして $HOME/.blerc が存
    在しない事によって失敗している

  * complete: ../ で始まるパスの曖昧補完が効いていない [#D1930]

    ../out/data/c2w.wcwidth-compare.musl-vs-12.1.txt[TAB] の曖昧補完が効いていない

    どうやら .. を .*.* 等に変換すると .. に一致しなくなってしまう様だ。
    ble/complete/source:file/.construct-ambiguous-pathname-pattern を修正したら
    すぐ直った。

  * canvas: char_width_mode=musl の判定をより正確にする [#D1929]
    https://github.com/akinomyoga/ble.sh/issues/269#issuecomment-1407360550

    konsole の中で起動すると文字幅スキームが 15.0-musl であると勘違いしている。
    何故? 或いは konsole が内部的に musl を使っている可能性? と思ったが、
    Unicode 15.0 等もちゃんと認識している。もし本当に musl の実装であれば最新の
    Unicode には対応できていない筈。

    Refs: #D1880 #D1668

    これは fedora でも発生している問題。

    * konsole で U+D7B0 の幅が 1 ではなく 2 を返すのが問題の様である。

    他の端末の振る舞いを調べる。

    * kitty はちゃんと 1 になっていて 15.0-west と判定されている。U+D7B0:U+3099
      に対して 1:0 である。

    * xterm は 0 を返していて 14.0-west と判定されている。U+D7B0:U+3099 に対し
      て 0:0 である。

    * terminology は 15.0-west で大丈夫と思ったが、何故か 3099 に対して 2 を返
      している。Unicode 15.0 に従っていない気がするが大丈夫なのか?

    * lxterminal は U+D7B0:U+3099 に対して 0:0 を返していて 15.0-west になって
      いる。

    うーん。これらの振る舞いを見るとどの端末も何処か異なる振る舞いをしている。

    * というかそもそも ble.sh が使っている musl のテーブル自体も古いという事が
      判明した。何処かの野良 github repository から持ってきたが滅茶苦茶古い。こ
      れも一緒に更新したい。もしかすると新しい musl では 0 にならないという可能
      性もある。確認してみると以下の時点で修正が入っている。

      2017-12-18 /src/ctype/{wide,nospacing}.h
      2019-10-25 /src/ctype/{wide,nospacing}.h
      2020-01-01 /src/ctype/wcwidth.c
      2021-12-27 /src/ctype/nospacing.h

      % 取り敢えず最新版に更新する事にする。うーん。どうやら D7B0 は以前は幅2だっ
      % たが現在は幅 0 の様である。使えない。改めて
      %
      % $ (source make/canvas.c2w.list-ucsver-detection-codes.sh)
      %
      % を使ってテーブルを生成してみる。
      %
      %                | -----Unicode EAW+GeneralCategory                   |musl
      % ws[0]  U+09FBC | -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
      % ws[1]  U+09FC4 | -1 -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
      % ws[2]  U+031B8 | -1 -1 -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
      % ws[3]  U+0D7B0 | -1 -1  2  2  2  1  1  1  1  1  1  1  1  1  1  1  1 | 0 (Note: これは結合文字なので xterm/konsole/vte 等で 0 で上書きしている)
      % ws[4]  U+03099 |  2  2  2  2  2  2  2  0  0  0  0  0  0  0  0  0  0 | 0
      % ws[5]  U+09FCD | -1 -1  2  2  2  2  2 -2  2  2  2  2  2  2  2  2  2 | 2
      % ws[6]  U+1F93B | -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  1  1  1 | 2
      % ws[7]  U+0312E | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  2  2 | 2
      % ws[8]  U+0312F | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  2 | 2
      % ws[9]  U+16FE2 | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2 | 2
      % ws[10] U+032FF | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2 | 2
      % ws[11] U+031BB | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2 | 1
      % ws[12] U+09FFD | -1 -1  2  2  2  2  2 -2 -2 -2 -2 -2 -2 -2 -2  2  2 | 2
      % ws[13] U+1B132 | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2 | 1
      %
      % うーん。これを見る限りは musl と Unicode 12.1 の違いはない。プログラムで
      % 具体的に Unicode 12.1 との違いを確認する事にする。
      %
      % $ ./canvas.c2w.wcwidth.exe compare_musl2023
      % $ awk '$4 == 0' ../out/data/c2w.wcwidth-compare.musl-vs-12.1.txt
      % 00ad       wcwidth=1 width(eaw=3,gencat=Cf)=0 0
      % 1160..11ff wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      % d7b0..d7c6 wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      % d7cb..d7fb wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      % e007f       wcwidth=1 width(eaw=1,gencat=Cf)=0 0
      % e01ef       wcwidth=1 width(eaw=3,gencat=Mn)=0 0
      %
      % 最初の四行は他の wcwidth 実装と同じ。なので本質的には最後の2行で区別でき
      % る可能性がある。U+E007F はタグをキャンセルするという制御文字。U+E01EF は
      % variation selector である。U+E01EF は端末側で特別に処理していると予想され
      % るので使うとしたら U+E007f である。

      やはりこれを見ると実は musl の最新版は殆ど Unicode と一致している。なので、
      敢えて区別する必要もないのではないかと思われる。やはり古い musl を区別す
      るのを目的として、musl のテーブルは今まで通り古い musl の物にして、但し、
      最近の Unicode を誤って新しい musl と判定しない様に判定の調整を行う。

      と言っても konsole が変な振る舞いをしているだけなので気にしなくて良いかも
      しれない。

    * konsole の wcwidth がどの様に振る舞うのかについてちゃんと調べて判定できれば判定する

      更に調べてみると konsole は konsole_wcwidth という関数を持っているらしい。
      https://api.kde.org/legacy/4.12-api/applications-apidocs/konsole/html/konsole__wcwidth_8h_source.html
      と思ったが現在の konsole には konsole_wcwidth という関数は存在しない。テス
      トコードのコメント内にはあるので、恐らく昔は実際にそういう関数が存在した。
      改めて konsole_wcwidth を検索してみると11年前のコードなどが当たる。kde-4.12
      で検索してみると 2013年12月の記事が出てくる。なので、純粋に古いのだろう。見
      つけた。現在のコードは以下にある。

      https://github.com/KDE/konsole/blob/master/src/characters/CharacterWidth.src.cpp テンプレート
      https://github.com/KDE/konsole/blob/master/src/characters/CharacterWidth.cpp 生成結果

      そして幅のテーブルを生成しているコードは以下にある。

      https://github.com/KDE/konsole/blob/master/tools/uni2characterwidth/uni2characterwidth.cpp

      うーん。konsole の幅スキームまでテーブルを埋め込んで対応するのは大変だ。
      しかも version が変わる度に変更される。

      分かった。どうやら以下のファイルによって U+D7B0 の幅が上書きされている? 然
      し、結果として 2 になっている理由は謎。

      https://github.com/KDE/konsole/blob/master/tools/uni2characterwidth/overrides.txt
      https://github.com/KDE/konsole/commit/cfff2326f98e1077c519bbb8d18c80262d1e2d1b 導入コミット

      うーん。konsole_wcwidth の文字幅を Unicode の文字幅と比べると以下の差分が
      ある。wcwidth の段階では U+D7B0 は幅0の様である。つまり、konsole は
      grapheme clusters に対応していてそれでハングルだと判定して文字幅2にしてい
      るという事だろうか。U+D7B0 は Unicode 6.1 の判定に使われている。代わりに
      別の文字にしたらこういう変な事が起こらないで済むだろうか?

      $ ./canvas.c2w.wcwidth.exe compare_konsole2023
      $ awk '$4==0' ../out/data/c2w.wcwidth-compare.konsole2023-vs-15.0.txt
      00ad       wcwidth=1 width(eaw=3,gencat=Cf)=0 0
      1160..11ff wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      d7b0..d7c6 wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      d7cb..d7fb wcwidth=0 width(eaw=1,gencat=Lo)=1 0
      1f1e6..1f1ff wcwidth=2 width(eaw=1,gencat=So)=1 0

      調べてみると Unicode 6.1 で新しく変更された幅は全てハングル関係である。然
      し、これらは恐らく全て konsole のハングルの実装によって幅2になってしまう
      と予想される。一方でこれらの文字は musl でも全て 2 になっている。つまり、
      どの文字を Unicode 6.1 に選んだとしても musl の判定には使えないという事に
      なる。

    * unicode version も参照して musl を判定する事にする。

      うーん。本当に musl2014 の場合には unicode version 判定の時点で特定の ver
      になるはずなので、それも一緒に確認する事で musl を判定するのが正しい気が
      する。

      musl は判定用文字幅は以下のようになっている。

      $ ./canvas.c2w.wcwidth.exe vector_musl2014
      ws[0]=1 # U+25BD
      ws[1]=1 # U+25B6
      ws[2]=2 # U+9FBC
      ws[3]=2 # U+9FC4
      ws[4]=2 # U+31B8
      ws[5]=2 # U+D7B0
      ws[6]=0 # U+3099
      ws[7]=2 # U+9FCD
      ws[8]=1 # U+1F93B
      ws[9]=1 # U+312E
      ws[10]=1 # U+312F
      ws[11]=1 # U+16FE2
      ws[12]=1 # U+32FF
      ws[13]=1 # U+31BB
      ws[14]=2 # U+9FFD
      ws[15]=1 # U+1B132

      これに基づくと char_width_version=10.0 になる。なので 10.0 の時にだけ
      musl と判定する事にした。

2023-01-31

  * decode: bash-4.4 以下で補完が全く起動されない [#D1928]

    cygwin で completion を起動しようとすると固まる。何故?
    最近の変更が原因かもしれない。確認する必要がある。

    そもそも complete が全く呼び出されていない。色々試してみたがそもそもキー入
    力がちゃんと通っていない気がする。

    auto-complete 候補が出ていても出ていなくても関係ない。

    どうも 138c476 の前後で振る舞いが変わっている。+o posix を追加すると問題が
    再現する。どうもそもそも $_ble_bash_options_adjusted が有効になっていない状
    態で .hook が呼び出されている。然し、それもなぜだか分からない。

    Linux でも bash-4.4 以下で再現する。

    うーん。分かって来た。set +o posix すると complete が bash の complete に変
    わってしまう。ここで readline のコマンドラインは空なのでコマンド名補完が行
    われる。no_empty_cmd_completion off にしているので、そのまま全てのコマンド
    の補完を処理しようとして固まる。

    set +o posix は実際に変化がある時にのみ実行するべきである。

2023-01-30

  * main: 空の LANG に対して警告を表示する (movivated by Ultra980) [#D1927]
    https://github.com/akinomyoga/ble.sh/issues/269

    文字幅計算がずれる。空の LANG なのに starship&terminal が UTF-8 を想定して
    いる。

  * main: openSUSE inputrc.keys は強制的に排除する? (motivated by Ultra980) [#D1926]
    https://github.com/akinomyoga/ble.sh/issues/268

    これが何度も問題を起こしている。

    a 最早強制的に off にしても良いのではないか。

    b 或いは自前で ~/.inputrc だけ読み取る事にする。

      元々 --noinputrc は最早 inputrc とは関係なく bind の出力を plain Bash と
      diff を取ってユーザー設定を復元している。という事を考えたらどの方式でユー
      ザー設定を復元するかをオプションで選べる様にしても良いのではないか。

      --inputrc={none,user,all,diff}

    c 或いは、デフォルトとの bind diff を取った後で比較するのではなくて、仮に
      ble-bind で全部登録した後の状態で diff を取って残った物だけ採用する? と思っ
      たがこれだと問題は解決しない。

    と思ったら既に opensuse では振る舞いを変える様になっていた。今までは
    https://github.com/openSUSE/aaa_base/pull/84 の修正が入っているかどうかで問
    題があるか判定していた気がするが、もう inputrc.keys が存在する時点で問題が
    あると判定する事にする。

    2023-02-02 実際に openSUSE で試してみたらエラーメッセージが色々表示されてし
    まう。改めて確認したところ --inputrc=auto に対する処理で openSUSE での既定
    の方法が誤っていた。修正した。

2023-01-26

  * 2021-05-17 histdb: 履歴が余りに消滅するので ble.sh の側で独立した履歴の仕組みを作りたい [#D1925]

    * 然し何処に履歴ファイルを置くのかという問題がある。

      a 今日日、~/.ble_history 的なファイルを置くのは憚られる。

      b .cache には消えても良い物を置くべきだから置くなという話もあれば、

      c .config はユーザー設定に纏わる物で dotfiles に入れている人もいるから勝手
        に書き込まないで欲しいという話もある。

      d 結局、.local/share/blesh/xxxx に置く事になるのだろうか。まあ、
        .local/share/blesh/data 辺りに置いて置けば良いだろう。然しその為には更に
        新しいディレクトリを生成する必要がある。現在は _ble_base, cache, run の三
        種類のディレクトリがある。

      →これは XDG_STATE_HOME (~/.local/state) 以下に保存する事にする。

    履歴はどの様に記録するのが良いか。日付は unix time で記録するのが人間に分か
    る様に記録するのか。カレントディレクトリも記録したいし、存在する相対パスも
    記録したい。所で存在する相対パスはどの様にして抽出するのが良いのだろうか。
    単語着色の時に検知した物を何処かに記録しておく必要がある。

    2023-01-25 同期等面倒だし、sqlite3 形式で記録する可能性について考える。既に
    atuin 等、他の類似のフレームワークも sqlite を使っている。

    * sqlite3 / SQL の使い方

      基本的な使い方は以下のページが分かりやすかった。ページが分割されていてペー
      ジを移動しにくいが。

      https://www.javadrive.jp/sqlite/

      * sqlite3: 直前に挿入した項目の番号は last_insert_rowid() で取得できる。

      * sqlite3: シェル側で処理できる様に複数の値を出力する方法は?
        NUL-terminatedで出力できるのが望ましい。

        以下のページによると NUL separated でデータを読み取る事はできないらしい?
        https://www.reddit.com/r/sqlite/comments/a9xort/help_please_cli_line_null_separated/

        以下のページはデータ自体に NUL が含まれている時にどうするかだがこれも微妙に難しいらしい。
        https://sqlite-users.sqlite.narkive.com/mMwpNBzZ/getting-text-data-w-embedded-nulls-from-shell

        sqlite3 --help |& grep output を実行すると色々使えそうなオプションはある。

        * 然し、-newline '\000' 等とすると実際に '\000' という文字列が
          separatorとして使われてしまう。或いは -newline __ble_sep__ 等としてそ
          れを別のプログラムで置換すれば良い気もするが、大量のデータの場合に全
          てが一行に繋がった状態で読み込まれてそれを分割する事になり、効率が気
          になる。

        * -newline '' も試してみたが、これだと単にデータが separator なしでくっつ
           いてしまう。

        * -ascii は RS か何かを分割文字として使ってくれるが、それでも RS 自体がデー
           タに含まれる場合に困る。

        * -quote は sqlite3 の文字リテラル方式で quote してくれる物である。今の
           所、これを用いて処理するのが現実的の気がする。-html, -json, -csv,
           etc でも独自の方法で曖昧でない様に quote してくれると思われる
           が、-quote の方式に比べると規則が複雑になる。

          awk で行を読み込んだら 1) 先頭の ' を削除する 2) '' を先頭から順に '
          に置換して行って、一番最後に単独 ' が残っていれば OK. そうでなければ
          LFを追加して次の行を読み込んで同様に '' を置換していく。最後に単独 '
          が残っているのをどの様に判定するのかはよく分からない。或いは置換する
          前に ' の数を数えて偶数か奇数かで判定する可能性。或いは、最初に末尾の
          ' の数を数えて奇数か偶数かを判定する可能性。こちらの方が現実的の様な
          気がする。つまり、match(/'+$/, $0) で一致しておいて、RLENGTH が偶数か
          奇数かで判定する。以下の様に書けば NUL-separated に変換する事ができる
          気がする。

          awk '
            {
              if (line == "" && sub(/^'/, "") == 0) {
                # NULL や数値など
                printf("%s%c", $0, 0);
                next;
              }

              if (match(/'+$/, $0) && RLENGTH % 2 == 1) {
                sub(/'$/, "");
                line = line $0;
                gub(/''/, "'", line);
                printf("%s%c", line, 0);
                line = "";
              } else {
                line = line $0 "\n";
              }
            }
          '

    * 履歴項目として何を記録するか。

      - done: session_id, exec_id, cmd, cwd, start_time, end_time, 各種時刻情報,
        $?, $!, $_, PIPESTATUS

      - done: user, hostname 等の情報は session_id の方で登録するべきの気がする。

      - 記録するべきか微妙な物: BASHOPTS/$- (before/after), ret (after), $@
        (before/after), 背景ジョブ情報

    * 関連プロジェクトの情報も集める。これは review として note.txt の上部に残
      しておく事にする。

    * hook point

      素朴には PREEXEC 及び POSTEXEC にて項目を登録 & update すれば良い。一方で、
      単語情報やファイル名情報も一緒に記録するのだとしたら、文法情報が消滅する
      前に登録しておく必要がある。

      a ADDHISTORY を通して記録するのが良いだろうか。その為には
        ble/widget/default/accept-line に於いて ble/history/add の位置を移動す
        る必要がある。今は histexpand の結果を表示してから ble/history/add をし
        ている。然し、histexpand の結果を表示するよりも前に newline を実行しな
        ければならず、その時点で文法情報などは失われている。なので、newline を
        実行する前に ble/history/add を呼び出す様に変更した方が良いだろうか。

        然し、ble/history/add で更に何かを出力する可能性があるのであれば、やは
        りそれより前に newline を実行しておく必要があるので使えない。現在の所は
        ble/history/add で直接何かを出力するという事はない様である。一方で、
        ADDHISTORY を呼び出したら失敗があるという事。

      そもそもよく考えてみたら ADDHISTORY は文法情報等とは関係ない気がする。然
      し、一方で history の一環として登録するという意味においてやはり history
      とは切り離せない。 history.sh を拡張する形で実装するのだとしたらやはり
      ADDHISTORYを通して介入するのは自然である。

      そうは言っても新しい history の枠組みは既存の history とは全く異なる物で
      あって、現在の entry point だけでは不十分である。寧ろ様々な箇所で介入が必
      要な気がする。という事を考えると、やはり ADDHISTORY とは別に hook を作成
      するべきなのだろうか。

      →改めて考えてみたが単に ble/history/add を newline の前に移動しても問題
      ない気がしてきた。ADDHISTORY から何かメッセージを標準出力に出す可能性につ
      いては、特に有効な使い道も思い浮かばない (とは言いつつ、現状では未だ
      ADDHISTORY のタイミングで呼び出しておく必要のある情報など記録していないの
      で気にしなくて良い気がする)。

      2024-05-20 (Ref #D2204) やはり問題がある。先に ble/history/add を実行する
      と履歴の個数が変化するので、PS1 の中に履歴の個数に対する参照がある可能性
      により、PS1 が強制的に再計算される。PS1 の中に明示的に履歴の個数がなくて
      も、 _ble_prompt_hash 経由で強制的に再計算される事になっているので、(直前
      のコマンドが履歴に登録されなかった場合を除き) ほぼ毎回 PS1 を2回評価して
      いることになっていた。これは修正するべき。

    * 速度について

      もう一つの懸念点は、この設計だと最低でも ADDHISTORY, PREEXEC, POSTEXEC の
      三回の sqlite3 呼び出しが必要になる。

      或いは ADDHISTORY の時点で sqlite3 に渡す sql 文を部分的に生成して置いて
      その時点では sqlite3 は呼び出さない。sql 文を exec の枠組みの中で保持して
      おいて、更に PREEXEC で sql 文を追加した後に呼び出すという形の方が良いか
      もしれない。

      因みにどういった種類の情報を記録するのかについては現在の文法言語 (現在は
      基本的に "bash" しかないが) に依存している。文法言語ごとに指定できる様に
      するのが良い気がする。table 名として syntax_bash_filename だとか
      syntax_bash_word 等が良い気がする。

      長いコマンドの実行中に bash (もしくはコンピュータ全体) がクラッシュする場
      合等を考えたら PREEXEC と POSTEXEC は両方とも sqlite3 を呼び出しておくべ
      きだろう。

      →実際に実装してみた所、PREEXEC, POSTEXEC だけでも結構遅くなる。時間を計
      測してみるとそれぞれの呼び出しで 0.070 程度の時間がかかっている。合計で
      0.140 である。0.140 ならば短い様な気がしたが実際に sleep 0.140 を実行して
      みると確かに遅い。

      という事を考えると coproc (bash-4.0) もしくは procsubst を用いて bg で
      sqlite3 を実行する必要があるのではないか。以下で coproc で sqlite3 を実行
      する事について書かれている。一応技術的には可能の様である。
      https://hackerpublicradio.org/eps/hpr3413/full_shownotes.html

      もしこれを実装するのだとしたら ADDHISTORY, PREEXEC, POSTEXEC の全てで実行
      するというのは別に大変という訳でもない。

      →取り敢えず名前付きパイプを用いて実装してみた。どうやら期待どおりに動い
      ている様な気がする。stdbuf を使わなくてもその場で応答してくれている。速度
      は挿入時に 0.060s ぐらいかかっているが使っている感じだと余り意識しなくて
      済む。この 0.060 かかっているのは恐らく rowid の読み取りの為。

      うーん。既に非同期にしてしまったので rowid を読み取らなくても直接
      (session_id, exec_id) で指定して挿入してしまって良いのではないか→その様
      にしたら待ち時間は全くなくなった。rowid は再配置等が途中で起こった時に変
      な事になる可能性があるので、今回の様にちゃんと一意のIDで指定できる様にす
      るのは大切な事である。

    * done: BLE_SESSION_ID などを公開する。これらは contrib/histdb 側ではなくて
      ble.sh の方で設定するべきではないか。

      コマンド番号については BLE_COMMAND_ID で公開する。BLE_COMMAND_ID は
      _ble_edit_CMD を公開する形にし、また reload で減少しない様に対処する。

    * done: start_time -> issue_time in TABLE command_history

    * done: exec_id と command_id は役割が重複していないか?

      _ble_edit_CMD は gexec prologue で increment されている。一方で exec_id
      も同様に PREEXEC で increment されている。

    * done: また、万が一 command_id が重複した時に何が起こるのかについて考えて
      おく必要がある。うーん。以前のコマンドの情報が上書きされて消えてしまうと
      いう事の気がする。消えない様に調整などは可能だろうか。

      a 例えば session 名を変更する等? 然し、その必要があったという事を外側に伝
        える必要がある。或いは、上書きされてしまっても仕方がないと諦める事にす
        るか。或いは、既に存在する場合には元々あった方を無難な session に変更す
        る等?

      b 或いは command_id を何か中途半端な値に書き換える。順番が分からなくなる
        と思ったが何れにしても時刻は記録しているので必要があれば時刻を用いて並
        び替えるしかない。例えば既存の項目に対して command_id を使われていない
        最小の負の値に書き換えるなど。

      取り敢えず b の方法を実装してみた。実際にそれを起こすのは大変の気がする。
      手で直接 db を弄れば行ける → 実際に重複が起こる様にして試してみたところ
      ちゃんと期待通りに動いている。

    * done: 将来の history の形式の変更に備えて history_format_version を埋め込
      む。misc table でも作って置けば良い。TABLE misc(key, value) に version と
      いう項目を入れて整数値で version を指定する事にした。

      将来的に形式を変更する暁には version を増やして、また初期化時に version
      が小さい場合にはアップグレードし、version が大きい場合には明示的に
      version をファイル名に入れてファイルを開き直す。これはその時になってから
      また考えれば良い。

    * done: sqlite3 を nfs の上で使うと何が起こるのか?

      やはり駄目な事になってしまう様である。NFS の設定によってはちゃんと動くけ
      れども、恐らくパフォーマンス上の問題から、普通は安全側に倒した設定にはなっ
      ていないと考えるべきである。

      https://techblog.raccoon.ne.jp/archives/1635140633.html

      となるとホスト毎に history を保持するべきの気がする。流石にホスト名に関し
      ては重複している場合は考えなくて良いだろう。

      NFSv4 は AFS (Andrew file system) の影響を受けてよりファイルロックに関し
      て良い振る舞いをするらしいがよく分からない。

      →ホスト名を履歴ファイル名に含める事にした。

    ? done: HISTIGNORE に一致するコマンドは履歴に登録するべきなのだろうか?

      a 登録するべきでない気がする。やはり既存の bash_history の拡張という考え
        方だとしたら HISTIGNORE 等の取り扱いにちゃんと従っていて欲しい。そう考
        えると preexec ではなく ADDHISTORY で全て追加するべきだろうか。然し、
        ADDHISTORY に介入するとしても、別の ADDHISTORY hook によって追加がキャ
        ンセルされたという場合も考えられる。また、加工した物を history -s で追
        加している場合等も考えると単純にはキャンセルされたかどうか判定できない。

      b reject: うーん。ADDHISTORY によるキャンセルは考慮せず、ADDHISTORY に到
        達したら問答無用で追加するという事で良い様な気がする。また、現在は
        start_time と exec_time_beg を別々に管理しているので start_time は
        ADDHISTORY の段階で設定してしまって問題ないのである。一方で、issue のタ
        イミングと exec のタイミングがちゃんと交互になっていない場合にどうする
        のかについては注意が必要。

      c これについては bleopt histdb_ignore で独立な設定として管理して貰うのが
        良い気がしてきた。HISTCONTROL の影響も受けない (例えば ignoredups 等に
        よって最近のコマンドと同じコマンドだったら履歴には追加しないという振る
        舞いも、様々な情報を記録する場合には余り望ましい物ではない)。

      うーん。変更の方針としては ble/history/add の時点で histdb の更新も行う。
      但し、複数の履歴が絡んでいる事が考えられるので gexec に登録すると分かって
      いる時にだけこれを実行する。その時点で _ble_edit_CMD の更新も行う。実行は
      ADDHISTORY 経由ではなくて必ず呼び出す事にして、独自に bleopt
      histdb_ignore 等の処理を行う。exec の枠組みに対しては exec_id を渡す事に
      する。

    * done: sqlite3 のプロセスが死んだ時にどうするのか?

      毎回 kill で生存確認するのが良い気がする。何れにしても sqlite3 がクラッシュ
      すればその親の subshell の bash はすぐに終了するはずなので $! で取ったプ
      ロセス ID で生存確認すれば良い。或いは、exec を実行してしまえば $! が直接
      sqlite3 になる筈。

    * done: last_wd を session に記録する。後でフィルタするのに役立つ。通常は最
      初は home で始まって、最後のディレクトリが実際の作業ディレクトリだから。
      last_time も記録する。

    * reject: coproc による実装

      * うーん。coproc は同時に複数起動できないという説が出回っている。
        https://lists.gnu.org/archive/html/help-bash/2023-01/msg00181.html

        それならば何故変数名を指定できるのか

        →うーん。どうもジョブ管理 or exit status の追跡という意味で同時に複数
        管理できないというだけであって、同時に複数起動する事自体ができない訳で
        はない様な気がする。しかし、そもそも coproc で起動したプロセスをどの様
        に管理するのか、どの範囲まで成業できるのかというのが不明である。そもそ
        も、現在裏で走っている coproc を閉じる方法はあるのだろうか。

        うーん。どうも fd を開放してしまえば coproc が生きている等のエラーは表
        示されない様である。勿論、ちゃんと fd を (親プロセス内で) dup して他の
        fd として保持しておく必要があるが、その為には coproc は親プロセスで実行
        する必要があって、そうすると bash の foreground dead job の振る舞いによっ
        て sqlite の項目が表示されてしまう事になる。或いは
        __ble_suppress_joblist__ さえ含めておけば問題なく行けるのだろうか。

        技術的には可能の様に思われる。

      * Cygwin 上では (もしくは bash-5.0 以降では) coproc を使った実装に切り替
        える? disown しておけば問題は起こらないだろうか? その場合には親シェルで
        coproc を実行する必要がある。fd を取得する為に。或いは coproc で生成し
        たジョブの中で更に & を開始して、ジョブ自体は即終了するという手もある。

        % 取り敢えず cygwin 上で試してみる事にする。動いている。named pipe は動
        % かないけれども coproc は動くという事? 或いは named pipe も実は今は動
        % く様になっている可能性?
        %
        % →今 cygwin を試してみたら実は named pipe でも動く様になっていた。つ
        % まり、coproc が動くからと言って昔の bash/cygwin でも coproc が動いた
        % かどうかというのは保証がない。他の cygwin/mingw も動作を確認する。
        % MinGW 64bit で試してみてもちゃんと動く。cygwin 32bit でも動く。もしか
        % すると動かないのは process substitution の時だけだろうか? うーん。
        % process substitution でも動く。
        %
        % 改めて Qiita の記事を確認してみたら動かないのは exec 9<> fifo; read
        % -t <&9 をした時である。先に書き出しの側のプロセスを起動しておけば問題
        % ない。つまり、今回は先に必ず sqlite3 のプロセスを起動しているので問題
        % は起こらない筈なのである。

        つまり fifo による実装は Cygwin でも問題なく動く筈なので敢えて Cygwin
        で除外する理由もない。msys2 では動くが msys1 では動かないという問題に関
        しては、msys1 では mkfifo の時点で失敗するのでそれを以て判定する事がで
        きる。

      よく考えたら既にユーザーが coproc を作成している時に coproc を開いてしま
      うとユーザーが作成した coproc が閉じられてしまって大変な事になる。かと言っ
      てサブシェルで coproc を作ってもその fd を親シェルに渡す方法がない。と考
      えると fifo に頼らざるを得ない。

    * done: 途中でデータベースファイルを切り替えられる様にする。

      処理中の exec がある時に切り替えると変な事になるので全て完了した時点で切
      り替えを完了させる。通常は複数の exec が設定される事はないので実際上の問
      題が生じるかは分からないが。

      対応した。

2023-01-24

  * [自然解消] 2022-02-03 complete: 補完している時に勝手に変数の中身が展開されてしまう事がある [#D1924]

    展開する条件をより制限する事はできないか。或いは、展開せずに置換できるパター
    ンを増やす。

    最たる場合が echo $_ble_base_cache/mandb[TAB] である。曖昧一致によって遡っ
    て置換が起こるが、それによって変数展開の中身まで展開されてしまう。少なくと
    も / で区切ってできるだけ展開せずに一致する様にできないだろうか。

    ? 曖昧一致に於いて変数展開から得られた文字列は塊で取り扱う?

      というかよく考えたら変数の中身に対してまで曖昧一致で一致させるのは変な気
      がする。曖昧一致は元の原始的な構成要素に対しては塊で一致する様にするべき
      なのではないか。と思ったが 'aaa' の中身の様にユーザーが手で入力した内容に
      ついてはやはり曖昧一致であって欲しい。という事を考えると曖昧一致で塊とす
      るとしてもその対象は変数展開だけに限られてくるのではないか。

    2023-01-24 #D1923 で曖昧一致によって遡って書き換わって展開される場合につい
    て対応した。勝手に変数の中身が展開されるパターンがこれだけなのかは分からな
    いが、取り敢えずは解決した事にする。暫く使って勝手に展開されてしまう他のケー
    スに気づいたらその時に新しく項目を立てて対応する事にする。

  * complete: パス名の曖昧補間でできるだけ各種展開を保持したい [#D1923]

    現在の実装では quote-insert で生成候補が COMPV に文字列を追加した物の場合に
    は COMPV の部分については COMPS で置き換える様になっている。しかし、遡った
    置換がある場合には問答無用で全体が展開されてしまうので、曖昧補間が起こった
    時には必ず全体が展開されてしまう。

    COMPS を unquoted / 毎に切って、eval して対応する部分 compv を生成して、最
    長一致するものについて部分 comps で置き換える。unquote / 毎に切るのは個別の
    quote-insert でやっていたら大変なので、事前に処理しておく事にする。

    quote-insert.batch で awk で処理する場合にどうするのかについては微妙。awk
    の内部で unquote / 毎に切るのを実装するか或いは外で切ったものを何とかして
    awk に渡すかする。外で定義したものを渡す方が見通しが良いと思われる。

    ToDo 2022-02-03 に関連項目がある → #D1924

    unquoted / で区切るのは既存の
    ble/syntax:bash/simple-word/evaluate-path-spec をそのまま使えば良い。

    * reject: あらゆる単語について判定を行うと大変なので CAND が既存のファイル
      名に一致する時にだけチェックをおこなう? 未だ存在しないファイル名を候補と
      して生成する可能性はあるだろうか。例えば Makefile target 等。うー
      ん。-o$HOME/ 等の様に short option の optarg として指定している場合等も考
      えたら例え存在していなかったとしても一致するかのチェックはするべきの気が
      する。

    うーん。fixed part との兼ね合いがどうなるのか分からない。取り敢えず
    evaluate-path-spec は noglob で呼び出す事にしてチルダ展開・パラメータ展開等
    文脈に依存しない物のみを実行する事にする (コマンド置換、算術展開などは元よ
    り simple-word ではないので対象ではない)。

    ? quote-insert.initialize で実行するべきか或いは COMPV を評価する時点で
      evaluate-path-spec で展開しておくべきか → COMPV を評価する時点で同時に評
      価してしまうべきの気がしてきた。

    結局 fixed part を拡張する形で実装する事にした。既存の変数である
    comps_fixed 及び quote_fixed_comp{s,v}{,_len} 等を配列に拡張して第1要素以降
    に部分パスの展開前・展開後を格納する事にする。

    実装した。取り敢えずは動いている気がする。

  * 2023-01-02 complete: コマンド名(パス名)の曖昧補間・部分一致など [#D1922]

    現在の実装だと PATH に見つかっているコマンドについては曖昧補間が有効である
    が、パスを指定して補完している時にはそれが無効になっている。関数名について
    は / が入っていてもちゃんと生成できている。

    補完対象に / が含まれている場合にはファイル名補完と同様にパターンで候補生成
    を行って、その結果を [[ -x file ]] でフィルタする様にするべきなのではないか。

    ? ok: チルダ展開が展開されてしまう。調べてみると compgen -c の場合にはちゃ
      んと ~ が保持される。なので、おそらくチルダ展開の復元などを処理していなかっ
      たのだろう。

      実はディレクトリ名に関しても同様に処理する必要があったのでは。

      →何故展開されるのかについて調べてみたら ~ を復元するのは $CAND ==
      "$COMPV"* の時だけだが、曖昧補完の時にはこれが常に不成立の為に復元しない
      という事。これに真面目に対応しようと思ったら COMPS を unquoted / 毎に切っ
      て、eval して対応する部分 compv を生成して、最長一致するものについて部分
      comps で置き換えるという処理にする必要がある。これは面倒である。

      そして、これについては通常引数の曖昧補間についても同様にチルダ展開が展開
      されてしまう。もし対応するとしたらまとめて対応する必要がある。これは独立
      した項目にする事にした。


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-@ が消滅している。これは単にマクロが内
    部的に null-terminated string で表現されている為である。

    更に同様の状況を考えてみると C-x C-@ も正しく検出できていない。また M-C-x
    (in bash-4.2, emacs binding) もその瞬間に検出できていなくて遅延が生じる。実
    際にその場で入力を検出できていないという事を確認した。

    取り敢えず M-C-@, C-x C-@, M-C-x (bash-4.2 -o emacs) を修正した。

    ? reject: これは bash の側で修正するべきなのだろうか? 然し、bash は null
      terminated な raw string でマクロを補完していて、これを変更するのは難しい
      し其処までする理由もない様な気がする。取り敢えずは現在の workaround を保
      持して、bash には何も要求しない方向が妥当の気がする。

  * highlight: パス名着色において ls_colors が動いていなかった (reported by qoreQyaS) [#D1919]
    https://github.com/akinomyoga/ble.sh/issues/263

    どうも type=g:* の形で指定した後にそれを外側で g に反映させる事になっている
    のが反映させていなかったのが問題であった。いつ壊れたのか確認した。3f1f472d
    #D1095 で type == g:* の時の特別の処理が削除されている。実に3年半も動かない
    状態で放置されていた事になる。

    ディレクトリ名に関しては単純に今まで対応していなかった。

    ble/syntax/highlight/ls_colors の値の返し方自体を変更する事にした。この関数
    は今迄二箇所でしか呼び出していなくて、両方で呼び出し側で同様に色の合成など
    を行っていたので、その色の合成も ble/syntax/highlight/ls_colors に統合する
    事にした。そして直接に g に書き込む様に振る舞いを変更した。その上で / の前
    のディレクトリ名の ls_colors による着色にも対応した。動いている。

2022-12-11

  * colorglass: オプションで指定した時に256色(またはより少ない色に)に減色する機能? [#D1918]

    →よく考えたら bleopt term_true_colors が設定されていなければ自動的に減色さ
    れるのではないか。実際に実装を確認してみた所そうなっている。この事を
    colorglass の説明に書いておくべきではないか? → 記述した。これで十分である。

  * README: RET や C-RET 等について 3.1.1 及び 3.3.6 に対するリンクを含めておく [#D1917]
    https://github.com/akinomyoga/ble.sh/issues/262

    取り敢えずリンクと説明を書いた。

  * _ble_term_TERM (comment): wezterm の commit id は 8 文字では足りない (requested by SuperSandro2000) [#D1916]
    https://github.com/akinomyoga/ble.sh/commit/486564ad314cef3f95317e88cf26879378dae507

    うーん。行(特に120列)に収まり切らない様な気がするが面倒なので気にしない事にする。

  * github/workflows: 何故か grep が windows-latest でクラッシュする [#D1915]

    別のリポジトリで試しに実行してみたがやはり再現する。最終的に以下の単純な
    workflow の定義ですらクラッシュするという事が分かった。

    ---- .github/workflows/build.yml ------
    name: grep-in-windows
    on:
      push:
        branches:
          - master

    jobs:
      check:
        runs-on: windows-latest
        steps:
          - name: Check out
            uses: actions/checkout@v3
          - name: Check
            run: echo 'GNU Awk' | grep -Fi 'GNU Awk'
    ---------------------------------------

    grep -i や grep -F だけでは問題は発生しない。 grep -Fi や grep -F -i 等、-F
    と -i を組み合わせた時にクラッシュする様だ。grep の version は GNU grep 3.0
    (2017) の様である。よく分からないが面倒なので grep を使わずに実装する事にす
    る。head -1 による処理も一緒に sed で処理すれば良い。

2022-12-08

  * ble-reload した時に M-z が効かなくなる [#D1914]

    何とそもそも ble-reload にて blerc が読み込まれていない。確認してみると
    --rcfile=/dev/null という事になっている。何も指定していない時には
    _ble_base_arguments_rcfile は空になっている。なので空の時にはやはり何も指定
    せずに source ble.sh するべきであって、何か特定の blerc は指定しない様にす
    る。

    ? 或いはもしかすると元々指定したかったのは _ble_base_rcfile ではないか?
      うーん。そんな気がする→その様に修正した。

  * 2021-09-08 complete: sabbrev (magic-space) vs auto-complete [#D1913]

    auto-complete で履歴から候補が表示されている時には sabbrev が効かない。そも
    そも sabbrev 展開が発生するかどうかも分からないので毎回 auto-complete を抜
    けるというのも変な感じがする。理想的には sabbrev が起こった場合は再び
    auto-complete を実行し、sabbrev が起こらなかった時には従来の auto-complete
    と同様にカーソル位置を一つ進める事を試行する。

    うーん。この問題は自動候補の先頭文字が空白の時にのみ起こる。それ以外の時に
    は auto-complete を抜けて再度 SP が実行されるのでちゃんと sabbrev も呼び出
    される。

    2022-12-09 然しそもそも一つ上の keymap で SP に magic-space が割り当てられ
    ているのかどうかも非自明である。うーん。やはり SP に対しては一旦
    auto-complete を抜けるのが自然な気がする。

    或いは一つ上の keymap の SP に magic-space が割り当てられているかどうか判定
    する? うーん。ESC に関してはひとつ上の keymap の情報を参照している物があっ
    た様な気もするが何だったか。うーん。ESC や M- で検索しても関係ありそうな物
    は見つからない。→分かった。bleopt decode_isolated_esc=auto の処理である。
    decode.sh の ble/decode/uses-isolated-esc で判定が行われている。

    さて実際に magic-space に bind されているという事が分かったとして、どの様に
    処理するべきか。その場でいきなり magic-space を呼び出す事を考えたが、そうす
    ると auto-complete によって補正されている内容が壊れてしまう。特に
    _ble_edit_mark 等の位置も変わってしまう可能性がある。また、magic-space は現
    在の keymap を見て振る舞いを変えているので一旦 auto-complete から抜けるか抜
    けたふりをする必要がある。色々考えるとやはり本当に一旦抜けて通常の状態に戻っ
    てから処理するべきの気がする。

    →その様に修正した。

    x 今度は magic-space による空白挿入の後に auto-complete が再開しない。よく
      考えたら self-insert は登録しているけれども magic-space に関しては登録し
      ていない。登録するべき気がする。登録した。試した。ちゃんと期待どおりに動
      いている。

  * 2021-02-28 magic-space で alias 展開する機能があっても良いのでは? (requested by telometto) [#D1912]

    というか magic-space で何を展開するかの集合を設定できる様にするべき?
    bleopt edit_magic_expand=sabbrev:history:alias という具合に。
    流石にコマンド置換等まで展開するのはやりすぎの様に思われる。

    2022-12-08 https://github.com/akinomyoga/ble.sh/discussions/260

    まず最初に bleopt を実装する事にする。実装した。

    alias expansion についても sabbrev expansion を元にして実装した。

    ? ok: ところで他の discussion でも同様の物があった様な気がする。

      https://github.com/akinomyoga/ble.sh/discussions/138

      ここにある。と思ったが、これは alias expansion ではなくて、magic-space を
      コマンド実行時にも呼び出すという話なのだった。というかこの項目が todo に
      なかったので新しく項目を作って置く事にした。と思ったら項目自体はあって単
      に GitHub#138 へのリンクが記録されていなかっただけだった。

    x auto-complete が有効になっていると ' ' が magic-space として働かない。
      →これは別に項目が存在していた筈なので別に処理する事にする。

    * done: blerc/wiki: bleopt edit_magic_expand の説明。

  * 2022-12-03 menu-complete: 一時挿入をしない設定 (requested by DUOLabs333) [#D1911]
    https://github.com/akinomyoga/ble.sh/discussions/252#discussioncomment-4293518

    * done: complete_auto_after_complete はやはり廃止してより一般のオプションと
      して complete_auto_complete_opts=suppress-after-complete とする事にした。

    * done: blerc/wiki: update complete_auto_complete_opts

    * done: blerc/wiki: add complete_menu_complete_opts

    * done: temp-insert -> insert-selection

    取り敢えず動いている気がする。多分大丈夫。

  * 2022-10-04 refactor(edit): 適当な一時ファイルを作っているのを assign/.mktmp に置き換える [#D1910]

    暫く dev にあって邪魔なので些末な修正に過ぎないがもう master に入れる事にす
    る。他には特にその場で生成してその場で使用済みになるファイルは存在していな
    い様な気がするのでOK。

  * term: wezterm が DA2 を変えている。対応する [#D1909]

    DA2R が 1;277;0 になっている。xterm との区別ができない気がする。うーん。或
    いは 277 だったら wezterm に決め打ちにする? しかし、wezterm である事を利用
    しているのは、現状ではどうやら DECSCUSR に対応しているかどうかの判定のみで
    ある。然し、xterm も元々 DECSCUSR に対応しているので、その意味でわざわざ
    1;277;0 (xterm:277) を wezterm と敢えて判定する必要もない。

    念の為、現状での wezterm の DA2 の変更履歴について確認する。

    コミット [1] (2022-04-07) で今迄の "0;0;0" から "1;277;0" に変更している。
    wezterm のバージョンはどうやら日付と時刻の様である。取り敢えず
    _ble_term_TERM では日付だけ考える事にする。このコミットは 20220408 のバージョ
    ンで最初に入っている。どうやら vim でマウスを使う為の変更の様である。

    [1] https://github.com/wez/wezterm/commit/ad91e3776808507cbef9e6d758b89d7ca92a4c7e

  * contrib/fzf-key-bindings: C-r で呼び出した fzf で modifyOtherKeys の状態が変 (reported by SuperSandro2000) [#D1908]
    https://github.com/akinomyoga/ble.sh/issues/259

    xterm ですらちゃんと動いていない。以前はちゃんと動いていた筈なので
    regression の可能性が高い。うーん。ちゃんと hook はできている。つまり、
    modifyOtherKeys のシーケンス自体を正しく出力できていない可能性? 内部でどの
    ように設定しているかを出力しつつ振る舞いを調べる必要がある。

    * うーん。今振る舞いを確認してみた所、xterm でも CSI >4;1m を指定した後で
      C-x であっても特殊なシーケンスを送るという事が判明した。うーん。もしかし
      て xterm は昔から 4;1 で C-x に対して特殊なシーケンスを送っていたという事
      なのだろうか? xterm -v の結果は 371 である。改めて他の xterm についても調
      べてみる事にする。

    * xterm 322 では 4;1 の時 C-p は通常のシーケンスを送信していた。

    * と思ったら直接 xterm 371 を起動して \e[>4;1m を指定しても特に変な事は起こ
      らない。うーん。別の箇所で何か modifyOtherKeys が変更されている可能性?

      うーんわかった。ble/util/buffer にキャッシュされていて端末に対して出力さ
      れていない状態だった。修正した。

2022-12-05

  * README: fzf-integration について記述する (motivated by SuperSandro2000, tbagrel1) [#D1907]
    https://github.com/akinomyoga/ble.sh/issues/259
    https://github.com/akinomyoga/ble.sh/issues/261#issuecomment-1346450426

    * display-shell-version にも integration が入っていない時にメッセージを表示
      する様にする。fzf についてはメッセージを出力した。

    その他 (bash-preexec, zoxide) については必要になった時点で自動的にロードさ
    れる事になっているので、その場で未だロードされていなくてもそのままにしてお
    く事にする。と思ったが zoxide がない。

    * done: zoxide についても情報を表示する事にする。

      zoxide の初期化スクリプトで一番古い関数は何だろうか。

      __zoxide_hook は以下のコミット (2020-09-16) で _zoxide_hook から改名され
      ている。この関数は最新版の zoxide でも存在している。

      https://github.com/ajeetdsouza/zoxide/commit/f4525db02fde1efa77f56f9f50b27cc1830d4912

      _zoxide_hook は以下のコミット (2020-03-13) で導入されている。

      https://github.com/ajeetdsouza/zoxide/commit/9c8e8da71a03f5c3c070247f5b0bffd971a70f62

      _zoxide_precmd は以下のコミット (2020-03-11) で追加されている。これが
      bash 対応の最初と思われる。

      https://github.com/ajeetdsouza/zoxide/commit/f0c5e28fd7e56d7cec045a40154ab4768339da44

      取り敢えず __zoxide_hook を使って判定する事にする。

    * done: 動作を確認してみた所 _z という関数が存在しない。つまり、zoxide の側
      で変更があったという事だろうか。以下のコミット (2021-12-29 v0.8.1..) によ
      ると _z から __zoxide_z_complete に改名された様である。

      https://github.com/ajeetdsouza/zoxide/commit/d106f4e3580d5594d8f1c96c256a8f085e2781a4

    2022-12-13 更に bash_completion を先にロードしておくべきという事についても
    記述した。

  * colorglass: saturation (彩度) についての設定を追加する (motivated by auwsom) [#D1906]
    https://github.com/akinomyoga/ble.sh/issues/258

    24-bit color のサポートがない時には256色に減色する機能もつけようと思ったが
    自動で検出するのは困難である。既定で256色にして指定した時にだけ256色にする
    というのだと、既定では色が思うように変化しなかったり急に変わったりして使い
    にくくなる。指定した時にだけ256色に減色するというのもありかもしれないが、其
    処までする必要は今の所は感じられない。→取り敢えず項目は作る事にした。

    * fixed: contrast -100..100 の境界値も許容する様に修正した。

    * fixed: 色がすぐに PS1 に反映されない問題を修正した。trace_hash に
      clear-g2sgr cache の回数を含める事にする。

    * reject: ble-face で face 設定を変更した時にも clear-g2sgr を呼び出す事に
      する? それ程頻繁に変更する事もないので大丈夫だろう

      x と思ったが face -> g に関しては毎回完全に計算していてキャッシュしていな
        いので g2sgr キャッシュをクリアする必要もない。特に g2sgr は重くなる可
        能性があるので余り頻繁にクリアはしたくない。実際に vim-airline が編集す
        る度に face を変更しているのでこれでキャッシュをクリアするのは割に合わ
        ない。

      * それよりはプロンプトの計算が face に依存しているのにプロンプトのキャッ
        シュがクリアされないという所が face 更新における問題である。vim-airline
        の時には背景色を変更していたが背景色は _ble_lib_vim_airline_mode という
        変数で決まっており、更にこの変数は prompt/unit の枠組み経由で更新してい
        た。なので何れにしてもプロンプトが更新されるので気にしなくても良かった。

    * done: brightness についても対応した。

2022-12-03

  * README: bashrc 設定の背景に対するリンクを載せる (motivated by telometto) [#D1905]
    https://github.com/akinomyoga/ble.sh/discussions/254#discussioncomment-4284757

    日本語の説明はないが仕方がない。

  * contrib/README: PATH に fzf が見つかれば _ble_contrib_fzf_base は設定しなくて良い (reported by Strykar) [#D1904]
    https://github.com/akinomyoga/blesh-contrib/issues/9

    修正した。というか手動で指定したとしても fzf を PATH の中に見つける事ができ
    なければ結局動かないのではないか? と思ったが fzf-initialize の中にちゃんと
    PATH を追加する処理が組み込まれていた。

    と思ったが、存在しないディレクトリを追加していたりしないか? →している。こ
    れはディレクトリが存在する時にだけ PATH に追加する事にした。

  * prompt: bind 'set show-mode-in-prompt on' が何故か PS1 の後に表示される? (reported by Strykar) [#D1903]
    https://github.com/akinomyoga/ble.sh/discussions/256
    https://github.com/akinomyoga/ble.sh/discussions/257

    実際に試してみるとそうなっている。変なミスである。。。修正した。

2022-12-01

  * contrib/colorglass: 実験的に実装したものを追加する事にした [#D1902]
    少なくともこれでテーマを自分で作るのが以前よりは簡単になった気がする。
    但し調整の仕方は普通のユーザーに対しては少々難しいかもしれない。
    同時に自分でフィルターを設定できる様にもする。

  * complete: TAB completion の直後でも auto-complete が表示されるのは変だ (reported by DUOLabs333) [#D1901]
    https://github.com/akinomyoga/ble.sh/discussions/252

    * done: うーん。確かに言われてみれば変な気がする。これは単にバグの気がする。
      調べてみる。

      ble/complete/auto-complete.idle では _ble_decode_widget_last が
      self-insert 等の時にだけ auto-complete が実行される事になっているが、よく
      見ると ble/widget/complete または ble/widget/vi_imap/complete の時にも明
      示的に auto-complete を誘起する様になっている。これには理由があったのだっ
      たか。

      関係しているのは 63ddeffd #D0736 と 6081e0a9 "complete: support "bleopt
      complete_ac_delay"" (議論なし?) である。うーん。周辺の議論を確認したが、
      やはり関係する議論はないし、done.txt で delay についても mention されてい
      ない。次の項目番号が #D0727 で auto-complete が導入されたのが #D0724 なの
      で、#D0725 か #D0726 以前のどちらかが関係していそうだが、どちらも異なる。

    うーん。やはり当初から意図した振る舞いの様な気がしてきた。少なくとも使って
    いて問題が起こった事はない。menu-complete に入れば当然モード判定があるので
    勝手に auto-complete が混ざって変な事になるという事もない。うーん。オプショ
    ンを追加する事にする。実装した。

    * done: blerc.template
    * done: wiki

    ? reject: 既定値を変更するべきか。うーん。少し使ってみる事にする。うーん。
      考えて見るにこれを有効にしていたのは単語補完ではなく過去の履歴に自動補完
      で一致する可能性を残しておきたかったからだと思われる。一律で無効にしてし
      まうと履歴に依るコマンド挿入ができなくなってしまい不便なことがあるかもし
      れない。元々明示的に有効にしていたのは他にもそれなりの理由があったのでは
      ないかという気がする。というか delay の導入と一緒に導入されていたのだから、
      待っていたらコマンド履歴による補完が起動しそうだという期待があったからか
      もしれない。更に続く #D0736 では vi でも同様に動く様にわざわざ変更してい
      る。そもそも表示していても別に問題はない気がするのでやはり既定では補完を
      実行する事にする。

  * complete: `#advice: _parse_usage is not a function.` というエラーメッセージ (reported by nik312123) [#D1900]
    https://github.com/akinomyoga/ble.sh/issues/251

    bash_completion の新しい version を使っていると発生するのかもしれない。と思っ
    たがそうでもなかった。まだこれらの関数は bash_completion の内部で改名されて
    いない。つまり、_parse_help や _longopt を勝手に定義しているが _parse_usage
    を定義していない外部の補完ライブラリが存在する。

    ? no: もしくは、古い bash_completion には _parse_usage は存在していなかった?
      と思って調べてみたが _parse_usage も _parse_help も bash_completion
      68f6f1c68 で同時に導入されているので片方だけが定義されていたという時期は
      存在しない様に思われる。

    何れにしても _parse_help という関数を勝手に定義する場合を考えると、勝手に他
    の関数も定義されていると想定する訳には行かない。単にエラーを suppress する
    事にした。

  * 2022-10-24 rename to blerc.template [#D1899]
    https://github.com/akinomyoga/ble.sh/issues/244#issuecomment-1288439503

    書きぶりから blerc を直接編集すれば良いと勘違いしているのかもしれないと思っ
    たが別にそういう事ではなかった。しかし、それでも勘違いする人がいるかもしれ
    ないので blerc のファイル名を変える事にした。blerc.template という名前にし
    ておけば直接編集すれば良いと勘違いする人もいないだろう。

    README の該当する部分も更新する。wiki には言及されていない様なので更新しな
    くて良い。

    * 何処かでリンクされていたのに対して通知した方が良いかもしれない。

  * 2022-10-24 複数 widget を実行したい時: Q&A や wiki にも説明を書く (motivated by micimize) [#D1898]
    https://github.com/akinomyoga/ble.sh/discussions/241#discussioncomment-3937949

    * done: wiki の Q&A を編集した。

    README では直接説明をしているが、特に他の部分には記述しない事にした。

    というより [編集関数の作成] が wiki における主要な解説部分だが英語版がない。
    然し翻訳するのも面倒だし今回の質問のレベルだとこれ全体を翻訳する程のことで
    はない。将来的にそういった細かい仕様についての質問が出てきた時に翻訳すれば
    良い気がしている。

  * 2022-10-24 cancel line by C-c in vi mode (motivated by micimize) [#D1897]
    https://github.com/akinomyoga/ble.sh/discussions/241

    * done: C-c in blerc
    * done: gg & G in blerc

  * 2022-10-24 delete word by M-backspace (motivated by KiaraGrouwstra) [#D1896]
    https://github.com/akinomyoga/ble.sh/issues/243

    * done: blerc に追記した for emacs

    * done: vi_imap rlfunc の更新

      後 vi_imap の backward-kill-word が widget:kill-backward-uword になってい
      たが実際に plain bash で動作を確認する限りはやはり emacs と同じ様に
      widget:kill-backward-cword になっている気がする。実際に試してみても uword
      は振る舞いが異なる。vi_imap での対応を変更する事にした。

    * done: blerc 追記 for vi

2022-11-28

  * posix: sh --login at MinGW で沢山エラーメッセージが出て segfault (reported by rashil2000) [#D1895]
    https://github.com/akinomyoga/ble.sh/issues/237

    % どうも set +p posix してもその効果が次の実行時に消滅するのが原因の様だ。
    % Linux などで sh --login をしても再現しない。Cygwin では再現した。Cygwin
    % と MinGW だけで今のところ再現している。

    取り敢えず set +ev している箇所で +o posix も指定したら問題は発生しなくなる
    様である。と思ったが MinGW では問題は起こらなくなるものの Cygwin では依然と
    して駄目だった。manual attach でも prompt attach でも Cygwin では動かない。

    →何と sh --login で起動した場合は起動時には non posix だがその後で posix
    に変化する様だ。

    * 一方で Linux で問題が発生していなかったのは単に bashrc が読み込まれていな
      かった為である。

      また、PROMPT_COMMAND の中から set +o posix した時には問題が生じていない様
      にも見える。然し実際に prompt attach を実行してみると問題が生じる。追加で
      PROMPT_COMMAND で set +o posix を設定すると問題は生じなくなる。
      PROMPT_COMMAND における set +o posix の位置を attach よりも後に変更してみ
      ると問題が発生する。

      うーん。何らかの瞬間に adjust bash options の制御が変になっている可能性?
      そもそも adjust-POSIXLY_CORRECT の呼び出しにまで至っていない気がする。こ
      れはユーザーコマンドを実行する瞬間に呼び出される。

      1 うーん。元々 ble-attach でもちゃんと adjust は呼び出しているが、そもそ
        も既に adjusted の状態になっている為にわざわざ adjust を実行していない
        という事の様だ。

        そして source ble.sh の時点で調整に入っているのでその後での変更に対して
        ちゃんと確認しなくても良いという判断である。というかこれだとユーザーが
        自分で set -o posix を設定した時にも問題になる。代わりに他の
        bash-options と同じタイミングで restore/adjust するべきなのではないか。

        →と思って確認してみた所ちゃんと restore している気がする。と思ったがど
        うやら条件判定に失敗して restore がちゃんとされていなかった様だ。これを
        直したらちゃんと動く様になった。

      % 2 また、何故かこの時点で既に posix モードではなくなっている。或いは関数
      %   の中でだけ posix モードが自動で消えるなどの仕組みがあるのだろうか。と
      %   思ったら単に確認用のスクリプトが間違っていた。

    * ble-attach を明示的に呼び出した時にも現在の対策だけで動くのだろうか。或い
      は +ev と同様に改めて設定する必要があるだろうか。

      % うーん。そもそも +ev と同じ箇所で再調整をしたとしても失敗している。
      % segfault する。.hook とは別の場所で調整する必要がある? 取り敢えず
      % ble-attach は無事に完了している事は確認した。問題は何処で一番最初に
      % ble.sh の処理に突入するかという事である。自然に考えると .hook の筈であ
      % る。

      →と思ったら単に +ev している箇所が二箇所あったというだけであった。修正し
      たら segfault も直った。つまり、何れにしてもこの処理は必要になるという事
      である。

    * もしこれが問題なのだとすると以前の修正で +ev としていたのは不要だったので
      はないか? と思ったが +ev の設定に関しては source ble.sh してから変わると
      も思えないし、関係ない? 或いは+ev が必要になったのはユーザーが自分で -ev
      を指定した時?

      51113237 #D1832 の説明を読むと、これは寧ろ ble-attach を明示的に指定した
      時の問題であって、今回の restore し忘れの問題は関係ない。何れにしても
      restore はしないのだ。bash -e で起動すると bashrc の読み込み後に設定が変
      わるという事の様に見える。なのでやはり必要な気がする。

      何れにしても上の項目で +o posix は実行する必要があると判明したので +ev も
      保持するのは確定である。

  * 2022-10-13 ble/canvas/trace: rps1 の位置の問題 (reported by rashil2000) [#D1894]
    https://github.com/akinomyoga/ble.sh/issues/239

    * どうも gbox の計算にバグがある。\nworld を指定すると高さ1になっている。
      foo\nworld はちゃんと2になっている。というかそもそも終点 x,yの時点でバグ
      がある。

      PS1 でも同じ様な事が起こるのではないかと思ったがそういう訳でもない。
      relative にすると駄目という事なのか。或いは measure-gbox の時にのみ起こる
      事なのか。或いは right alignment によって変な事が起こっているのか。align
      right が怪しい。

      ? invalid: 何と rps1 の中でデバグの為に状態を /dev/tty に出力しようとする
        とクラッシュする。history に何かを追加しようとしているが謎 → と思った
        が typo で failglob を発生させていた。つまり変な所で ble.sh の動作がク
        ラッシュしていたのが原因の気がする。

      \n\nbar に対して振る舞いを見てみるとどうも行番号 y がリセットされている様
      である。このリセットは最初の \n に対してのみ発生する様である。\n の呼び出
      し回数に関しては問題ない。

      どうも2回目の end-line の呼び出しの際に y が 1 から 0 に戻ってしまう様だ。

      見つけた。どうも最初の行の情報を消去せずに early return している所為で2行
      目が1行目と勘違いして処理されている様であった。ちゃんと最初の行の情報をク
      リアする様にしたら問題なく動く様になった。というかこれで完全に動く様になっ
      たのではないか。

      取り敢えずこの問題に対する対処は此処までとする。

    * done: テストを追加する。追加した。以前は失敗して今回は成功する事を確認し
      た。

    * done: 然し starship での問題が完全に解決したかどうかは分からない。そもそ
      も被っている場合には rps1 は表示されないのでは? 実際の環境で確認する必要
      がある。

      % →結局どの環境で以前試したのか分からない。と思ったら chatoyancy の
      % ble.sh の中に issue239 という名前のディレクトリがあってそこでテストを実
      % 行していた。

      新しく chatoyancy 上で再現させて動作確認もした。取り敢えずちゃんと設定す
      れば動く。

  * 2022-10-28 edit: display-shell-version を直接実行できる様にする (reported by DhruvaG2000) [#D1893]
    https://github.com/akinomyoga/ble.sh/issues/246#issuecomment-1294843777

    直接 ble/widget/display-shell-version を実行すれば良い。C-x C-v が
    効かない端末でもOK。例えば報告者の環境では C-v が「貼り付け」に奪
    われていた。

    * done: 直接実行しても表示が壊れない様に ble/widget/print を修正した。
    * done: issue template を修正した。
    * reject: wiki に関しては確認してみたがそもそも C-x C-v の指示も書
      いていなかった。敢えてここで新しく解説を追加する必要もない気がす
      る。

  * 2022-10-28 edit: display-shell-version で git/gmake/gawk の情報を表示 [#D1892]
    https://github.com/akinomyoga/ble.sh/issues/246#issuecomment-1294893636

    git, gmake 及び gawk の version も表示する? 変な生成のされ方をして
    いないか確認する時にこの情報があった方が良い。

    これは生成に用いた物の version なので生成時に埋め込むべきの気がする。

  * 2022-10-13 github/workflows について (reported by Harduex) [#D1891]
    https://github.com/akinomyoga/ble.sh/pull/240

    ? cpio -pd を使えば良いのではないか。と思ったが cpio がどのシステム
      でも使えるとは限らないし、そもそも cpio のオプションとして何が使え
      るかもシステムに依存するのかもしれない。という事でやはり cpio に依
      存するというのは避けたい。結局 POSIX cpio には -p はないみたいなの
      で (むしろ異なる意味のオプションの様である) GNU cpio の non-POSIX
      option を使うのだったら、そもそも GNU tar の -x を使うところなので
      ある。

      →改めて ble.pp を見てみたら cp -Rf を使っている。これに倣う事にした。

    * それとは別に現在 ble-nightly* としているディレクトリ名を何とかした
      い。

      a done: うーん。そもそも ble-nightly でダウンロードする人は細かい
        version 等を気にするとは思えないし、そうでなくとも標準的な手順に
        従うと結局ディレクトリの version 名は移動した時に失われてしまう。
        なので、初めから単に ble-nightly というディレクトリにしてしまえ
        ば良い気がする。→ 変える事にした。

      b ユーザーに直接ディレクトリ名を指定させる? しかしそうするとしても
        ディレクトリ名は毎回変わるし commit id が含まれているので README
        に載せられない。なのでユーザーにその都度 ls などで確認してもらう
        必要があって、その為には結局 ble-nightly* などとしてもらう事にな
        る気がする。

    後は README, wiki 等を更新する。というか wiki に nightly version の
    記述はあっただろうか。なかった気がする。追加する必要はあるだろうか。
    追加しなくて良い気がする。

    % 2022-11-28 ble-nightly.tar.xz 展開後のディレクトリ名について毎回
    % 全てを入力するのは大変である。なので、ble-nightly に生成する事に
    % する。ディレクトリ名に version が記録されない事になるが、そもそ
    % も ble-nightly をダウンロードしている時点で細かい version は気に
    % していないのだし、直後に削除する事を想定しているのだから気にして
    % も仕方がない。何れにしても ble.sh 本体の内部には記録される。
    %
    % →これは実質的に 2022-10-13 の議論と同じである。

    2022-11-28 所で、これに関しては master に直接変更を push するので
    はなく、向こうの branch に push して確認するしかないのでは。と思っ
    たが、別に独立に変更をしてから向こうの branch を調整しても良い気が
    する。どちらでも良い。取り敢えず dev の上で作業して後で移し替えて
    すぐに merge してしまえば良い。

    と思ったが既にその様に変更を実施済みである。うーん。後は README を
    更新すると書かれている。

    * done: README を更新した。PR は何故か curl 版だけしか更新していな
      い。関連する物は全て更新するべきである。また日本語の README も更
      新した。

    * done: ble.pp でも ble-nightly で検索を実施している。これについて
      も修正を行う。

      というか今までのこのコードは set -f に対して対策はしていたのだっ
      たか? failglob と nullglob しか設定していない気がする。<del>何れ
      にしても最早パス名展開は使わなくなったので気にしなくて良い。
      </del> と思ったがよく見たら昔に展開した結果の始末や cp -Rf 本体
      でもパス名展開を使っているのでやはり set +f, -u failglob, -s
      nullglob はつけておく必要がある。後、cp -Rf で変な事が起こらない
      様に -u nullglob に変更する事にする。

2022-11-12

  * test: テストで用いている rm が alias によって rm -i になって失敗する [#D1890]

    これはテストの方を修正する事にした。他に類似の箇所はなかった。これは単独修
    正で良い。但し #D1889 のcontrib の更新も含める。

  * fzf-completion 経由で補完した path の特別文字が正しく quote されない (reported by MK-Alias) [#D1889]
    https://github.com/akinomyoga/ble.sh/issues/250

    fzf-completion.bash の中で noquote をしているのが原因の様である。noquote を
    つけた経緯について調べる。syntax-raw を付加したのは fb145dea (contrib) であ
    る。そして noquote をつけた箇所を確認しようとしたがどうも contrib の
    initial commit から noquote がついていた様である。つまり、色々の報告があっ
    た間も全然修正されなかった振る舞いという事である。なので余り深く考えられて
    いる訳でもない気がする。

    contrib を導入したのは f2901158 #D1335 (2020-04-16) の様である。contrib の
    最初の commit では補完関数の advice は以下の様になっていた。

    function _fzf_complete.advice {
      [[ :$comp_type: == *:auto:* ]] && return
      compopt -o noquote
      COMP_WORDS=("${comp_words[@]}") COMP_CWORD=$comp_cword
      COMP_LINE=$comp_line COMP_POINT=$comp_point
      ble/function#push printf '[[ $1 == "\e[5n" ]] || builtin printf "$@"'
      ble/function#advice/do <> /dev/tty >&0 2>&0
      ble/function#pop printf
      ble/textarea#invalidate
    }

    そんなに深く考えられている様には思われない。単に noquote を外してしまって良
    い気がする。

2022-10-02

  * README: Guix の package 一覧に追加する (motivated by kiasoc5) [#D1888]
    https://github.com/akinomyoga/ble.sh/issues/235
    https://guix.gnu.org/en/packages/blesh-0.4.0-devel2/
    https://guix.gnu.org/ja/packages/blesh-0.4.0-devel2/

  * make: GNUmakefile の contrib/.git に対する依存性を削除する? [#D1887]
    https://github.com/NixOS/nixpkgs/pull/185866#issuecomment-1264567117
    https://issues.guix.gnu.org/57659#2

    どうも nix 系統は package の git を fetch する際に .git を削除する様である。
    なので特別に git submodule を GNUmakefile から削除したり、或いは空の .git
    ディレクトリを生成したりしている。然し、そもそも .git がなくても正しく動作
    する物なのかという疑問もある。

    少なくとも親ディレクトリの .git は存在していないとバージョンを決定する事が
    できない。contrib/.git には実は余り依存していない気がする。うーん。試してみる。

    * done: どうも contrib/contrib.mk の中にある contrib/.git も削除する必要がある。

      取り敢えずこれで問題なく動いている様である。そもそも何故 contrib/.git に
      対する依存性を持たせていたのかはよく分からない。存在確認だけしかしていな
      いのであればそれが最新になっているかどうかを保証できない。そして .git の
      存在確認をするだけなのであれば、それによって何を期待しているのかも謎であ
      る。

      ? 或いは、contrib.mk が存在していながらそのファイルが存在しない (が .git
        が存在すれば大丈夫保証される) という事態を想定している? と思ったが、そ
        もそもファイル一覧を生成するのに wildcard を使っているのでファイルが存
        在していないという事はありえない。。

      ? 或いは .git の更新時刻を確認しているのだろうか、と思ったが | の右側に
        contrib/.git を指定していたので更新時刻は全く関係ない。存在確認しかして
        いない。

      ? 或いは単にコピーする前に contrib 最新に更新したかっただけかもしれない。
        然し、単に contrib/.git の存在を要求するだけだと更新はされないので意味
        がない。今まで更新されなくて問題がなかったのだから気にしなくて良いので
        はないか。

      やはり contrib/.git の存在確認をする理由がよく分からないので単純に削除す
      る事にする。取り敢えずこれだけ修正したら .git がなくても動く様になった。

    ? .git が存在していない状態で make をすると何が起こるのか。依然として make
      が成功するのだろうか? 以下の二つの変数の値を決定するのに git を使っている。

        _ble_init_version
        _ble_base_branch

      実際に値を確認してみると以下の様になっていた。エラーが出ていても make の
      失敗にはならない。

        _ble_init_version=0.4.0-devel3+
        _ble_base_branch=

      release version ではこれらの変数にどのような値が設定されていたのだったか。
      もし、ここに固定の値が入っているのだとすれば .git がない場合にはそれと一
      貫した固定した値でも良いのかもしれない → うーん。release version でも、
      nightly version でもちゃんと branch 及び hash は生成されている。ble-0.3.0
      についても BLE_VERSION に hash が含まれている。

      という事を考えるとやはり version/branch に適切な値を入れないという選択肢
      はない様な気がする。何れにしても debug の時の情報がかけてしまう事になる。

    * done: git commit id の取得失敗時に ble.sh 生成を明示的に失敗させる

      GNUmakefile で明示的に .git を要求する様にしてみたが、これだと依然として
      ダミーの .git を作って無理やり通そうとする人が現れるのは必至である。やは
      りちゃんと hash が取れる事を要求するべきの気がする。hash を取得するのに失
      敗したら ble.pp の変換自体を失敗させる仕組みが必要の気がする。

      現在は #%$ にその様な機能はない。或いは一旦は #%[] で受け取ってその後で処
      理する? と思ったがそもそも #%[] を使っていたとしてもその場で変換を失敗さ
      せる仕組みはない様な気がする。

      1. 取り敢えずは #%error の様な directive が必要の気がする → と思ったら既
        にあった。

      2. 更に #%$ の結果を取得する方法か、或いはそのコマンドの失敗に対して即座
        に変換が失敗するオプションの様な物が必要ではないか。というかそもそも
        gawk でそれが可能なのかも分からない。取り敢えず確認する事にする。以下の
        ページによると終了ステータスを gawk から実行したコマンドで取得すること
        はできない様だ。なのでコマンド内部で色々して終了ステータスを標準出力に
        流す等の事をする必要がある。

        https://stackoverflow.com/questions/21296859/how-do-i-get-the-exit-status-of-a-command-in-a-getline-pipeline

      今回の場合には hash が空だったら失敗する様にすれば良い。branch については
      detached の状態にあって空になることもあるのでチェックしない。取り敢えず実
      装した。動いている。system() という関数を mwg_pp.awk に実装した。

      ? 更に外側の関係ない .git の commit を拾ってしまう可能性もあるのではない
        か? うーん。その様な場合を考えだしたら限がないので考えない事にする。

    * ok: GNUmakefile の .git で .git を要求されたらエラーメッセージを表示する
      事を考えたが、わざわざ変な事をしなくても良い気がしてきた。もし無理やりダ
      ミーの .git を作る人がいても今度は ble.sh の方が失敗する筈。なので、.git
      を要求するだけで良い。

    * done: 失敗しても壊れた ble.sh が生成されてしまうのを何とかできないか。GNU
      make が失敗時にファイルを削除したりしなかったりするが、その条件は何だろう
      か。と思ったら .DELETE_ON_ERROR というルールがある様だ。ble.sh を其処に指
      定する事にした。

2022-09-28

  * benchmark: -o KSH_ARRAY の中のコードが外と同じの気がする [#D1886]
    これは fe751acb の最初に benchmark.sh を追加した時からそのままである。
    実際 zsh の振る舞いを調べてみると KSH_ARRAYS を設定していると match の中身はずれる 。

    2022-11-11 実際に zsh の上で使おうとしたらたくさんの修正が必要になっ
    た。取り敢えず現状で分かっている分を追加修正した。

    2022-11-28 ksh で動かそうとしたら全然駄目だ。ksh は local を始めとして違い
    が大きすぎる。取り敢えず動く様にはしたが、色々違いが大きいので mwg_pp で別
    途 ksh 用に修正した物を生成する事にした。

2022-09-26

  * vte で unsupported modifyOtherKeys のシーケンスが画面に表示されてしまう (reported by dongxi8) [#D1885]
    https://github.com/ohmybash/oh-my-bash/issues/360#issuecomment-1256927443

    一旦は解決したと思ったが駄目の様だ。調べてみると vte:* の時には無効化してい
    る。実際に Ubuntu 16 LTS で GNOME terminal で試してみると再現した。どうも起
    動時に表示される様だ。それ以降は特に何も表示されない。つまり、端末情報を未
    だ取得し終わっていない段階で表示されてしまうのが問題という事。

    これに対してはどの様に対策したら良いだろうか。例えば端末情報が初期化される
    までは modifyOtherKeys は設定しない? 端末情報が出揃った段階で改めて
    modifyOtherKeys を設定する。しかし、そうすると端末情報を返答しない端末に於
    いて modifyOtherKeys が決して有効化されないという状況になるのではないか。と
    思ったが、modifyOtherKeys に応答する現代的な端末では常に DA2 に対しても反応
    すると仮定して良いのではないか。

    x と思ったが本当だろうか。例えば alacritty は DA2 に対応していなかった気が
      する。現在は対応している様だ (v0.11.0)。

      https://github.com/alacritty/alacritty/blob/1df32309fe69d4e8113813a3e9049a7039650f44/alacritty_terminal/src/term/mod.rs#L1170
      https://github.com/alacritty/alacritty/commit/0dfd8601c92666c45d0c2e056bd68f600a4cbe47
      https://github.com/alacritty/alacritty/issues/3100

      然し、実は alacritty は modifyOtherKeys の方に対応していない。

      https://github.com/alacritty/alacritty/issues/3101

    ? DA2 の後に modifyOtherKeys を有効にするというアプローチで問題ないだろうか。
      kitty では DA2 を受け取った後に再度 modifyOtherKeys を設定している。なの
      で、それが動いているのであれば他の端末についても問題ない筈。

      唯、現在の実装だと有効・無効の判定と端末の判定が別々になっている。ユーザー
      が internal/external を指定している時には端末のサポートに関係なく強制的に
      modifyOtherKeys を出力している。auto の時にのみ端末判定を行っている。これ
      で正しく端末状態を設定するにはどうしたら良いだろうか。

    うーん。取り敢えず DA2 を受け取る迄は modifyOtherKeys を設定しないように変
    更したが本当にこれを実行するのか。或いは bleopt で無効化する様にお願いすれ
    ば良いだけなのではないか。そもそも古い vte を使っているのが悪いのであって、
    その vte のバグの為にその他の端末についても制限を課すのは変な気がする。一方
    で、現実的に DA2 に対応していないが modifyOtherKeys に対応している端末とい
    う物が存在するのかというのはまた別の疑問である。うーん。正直 bleopt で各自
    無効化してもらうので良い様な気もするが、面倒なのでやはり ble.sh の側で対策
    するという事にする。

    2022-10-02 テスト: Ubuntu 16 LTS の上での gnome-terminal では問題が直る事を
    確認した。Fedora 35 の上の gnome-terminal, kitty, alacritty で問題がない事
    を確認した。そもそも gnome-terminal と alacritty は modifyOtherKeys に対応
    していないので余りテストの意味はない。chatoyancy (Fedora 36) の上では
    terminology, terminator はそもそも modifyOtherKeys に対応していない。xterm,
    mlterm は modifyOtherKeys に対応していて問題はない。mintty も問題ない。
    恐らく特に問題はないだろうと思われる。

  * 2022-09-23 prompt-git: rebase や  merge 等の状態を表示したい [#D1884]

    色々方法は考えられるがどうやら git-prompt.sh の __git_ps1 で使われている判定方法を用いれば良いらしい。
    https://stackoverflow.com/questions/30733415/how-to-determine-if-git-merge-is-in-process
    https://stackoverflow.com/questions/3921409/how-to-know-if-there-is-a-git-rebase-in-progress
    https://stackoverflow.com/a/3922581/4908404

    取り敢えず以下を元にした実装にする。
    https://github.com/git/git/blob/4fd6c5e44459e6444c2cd93383660134c95aabd1/contrib/completion/git-prompt.sh#L452-L475

  * global: return $? IFS [#D1883]

    未だ残っている? もしくは新しく増えた物かもしれない。修正する。
    make scan でも $? を検索する様に変更する。

2022-09-25

  * test: sha256sum がないというエラー @ macOS [#D1882]

    元々 Linux の上で動かす事を想定していたので色々問題が出てくる。

    test-util.sh の関数一覧 ToDo も序でに更新する。

  * github: GitHub#227 CI tests in macOS/Windows (reported by aiotter) [#D1881]
    https://github.com/akinomyoga/ble.sh/pull/227

    * macOS の sleep の実装は此処にある。特に変な事をしている訳でもない。
      https://github.com/apple-oss-distributions/shell_cmds/blob/main/sleep/sleep.c

    * macOS の CI ではテストをスキップする様にする方法について模索する。

      https://docs.github.com/ja/actions/learn-github-actions/environment-variables

      の環境変数 RUNNER_OS を参照すれば良い。github workflow の中で動いている事
      を確認する為に、CI == true 及び GITHUB_ACTION についても確認する。

    * macOS で問題が発生した時に誰が解決するのかという問題が生じる気がする。修
      正に時間が掛かるし実際の macOS で試してみないと分からない事もある。誰かを
      頼ろうと思っても誰に頼んだら良いのかも分からないしすぐ応答してくれるとは
      限らない。

      その間 nightly が全くビルドされなくなる。という事を考えるとやはり nightly
      と macOS のテストは少なくとも分離するべきである。

      また直る迄の間ずっと X がならぶ事になる。直す事ができないとずっと失敗する
      という事になる。うーん。一方で時々確認しておくという事はしたい気もする。
      確認する時だけ macOS をテストに含めるという使い方もあるだろうか??

    * PR に対しては一応実行しておきたい気はする。と言っても minor change や
      rebase に対して毎回テストを実行していたら clone stat が大変な事になる。テ
      ストを実行する時に approve をする機能があるみたいなので、それをどの様にす
      れば良いか確認する。

    * msys のテストで色々失敗している。GraphemeCluster に関して調べてみようとし
      たが、そもそも msys2 bash の上では $'\U1F6D1' が1文字ではなく2文字とカウ
      ントされる様である。

      $ a=$'\U1F6D1'
      $ echo "${#a}"
      2

      確認してみた所、実は Cygwin でも同様の問題があるという事が判明した。うー
      ん。これは Bash の側で修正するべき事の気がする。或いは Cygwin の側で修正
      するべき事の可能性もある。後で調べる事にする。

      うーん subst.c:8046 の MB_STRLEN を呼び出している。そしてこの MB_STRLEN
      は include/shmbutil.h で

      #define MBSLEN(s)       (((s) && (s)[0]) ? ((s)[1] ? mbstrlen (s) : 1) : 0)
      #define MB_STRLEN(s)    ((MB_CUR_MAX > 1) ? MBSLEN (s) : STRLEN (s))

      の様にして定義されている。mbstrlen は lib/sh/shmbchar.c で定義されている
      関数である。中では mbrlen を呼び出している。これは標準ライブラリから来て
      いる。

      -------------------------------------------------------------------------

      cygwin の上で mbrlen を呼び出すコードで再現した。newlib-cygwin の
      newlib/libc/stdlib/mbrlen.c (mbrlen) は単に mbrtowc を呼び出している。
      newlib/libc/stdlib/mbrtowc.c (mbrtowc) は wchar_t に変換する関数である。
      一方で windows では wchar_t は 16bit である。なので surrogate を読み取る
      しかないという事。うーん。この状況だとどのように直すのが正しいのか不明である。

      * mbrlen の実装を弄って mbrtowc ではなくて Unicode code point を読み取っ
        た時のバイト数を返す様に変更すると、今度は他の箇所で mbrtowc との不整合
        が問題になる可能性もある。

        そもそも bash ですら途中で wchar_t に変換して行う処理があった筈なので問
        題が起こる可能性が高い。

      * 或いは mbrtowc に変わる mbrtoc32 的な物があれば良いのだが。然し
        char32_t は C++ の物だし、もし一連の関数を提供するとしても bash の側で
        も大幅な変更と検証が必要になるので色々難しい気がする。

      だとすると ble.sh の側で上手に surrogate も処理できる様にする? 然し、
      UTF-8 で表されている文字列を bash でちゃんと切り取る事ができるのかも謎で
      ある。切り取る事ができたとしてもちゃんと処理できるのだろうか。。。

      -------------------------------------------------------------------------

      一つの手は Grapheme Cluster の判定に Surrogate pair も考慮に入れるという
      事。或いは既に考慮に入っている? →確認してみたが考慮には入っていない様だ。

      GraphemeClusterTable を確認すると surrogate pair U*D800..U+DFFF は全て 0
      になっている。つまり通常文字として取り扱われている。これを取り敢えず新し
      いカテゴリとして登録する事にする。

      取り敢えず実装したが、実際に Cygwin の上で動かすと動かない。どうも
      surrogate pair の後半に対して ble/util/s2c を実行しようとしても常に 0 に
      なってしまう。これは printf '%s' に渡す前に文字を切断する必要があるが、文
      字を切断する時点で空文字列になってしまうから? 調べてみると ${s:i} で切断
      した時点で 4byte 中の 3byte が処理された状態になっていて UTF-8 の最後の文
      字が切り出されるという事態になっている。

      -------------------------------------------------------------------------

      うーん。また変な振る舞いを見つけてしまった。これは bash の側で修正した。

      s=$'\U1F6D1'
      printf '%d ' "'$s" "'$s" "'$s"
      printf '%d ' "'$s" "'x" "'$s" "'x" "'$s"
      echo

      https://lists.gnu.org/archive/html/bug-bash/2022-09/msg00055.html

      他にも色々振る舞いについて修正などが必要だったが取り敢えず通る様になった。

2022-09-16

  * canvas: Unicode version 更新 [#D1880]
    15.0.0 が出ている。各テーブルを更新したが、更にversion 判定ロジックを改めて
    更新する必要がある。

    既存の判定用テーブルは #D1668 にある。これを更新する。うーん。このテーブル
    を生成するのに使ったスクリプトがある筈。だが見つからない。と思ったら

      make/canvas.c2w.list-ucsver-detection-codes.sh

    であった。うーん。U+1B132 (平仮名の小さな「こ」) を採用する。更新されたテー
    ブルは以下の様な感じ。

                   | -----Unicode EAW+GeneralCategory-------------------|musl
    ws[0]  U+09FBC | -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
    ws[1]  U+09FC4 | -1 -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
    ws[2]  U+031B8 | -1 -1 -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2 | 2
    ws[3]  U+0D7B0 | -1 -1  2  2  2  1  1  1  1  1  1  1  1  1  1  1  1 | 2
    ws[4]  U+03099 |  2  2  2  2  2  2  2  0  0  0  0  0  0  0  0  0  0 | 0
    ws[5]  U+09FCD | -1 -1  2  2  2  2  2 -2  2  2  2  2  2  2  2  2  2 | 2
    ws[6]  U+1F93B | -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  1  1  1 | 1
    ws[7]  U+0312E | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  2  2 | 1
    ws[8]  U+0312F | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  2 | 1
    ws[9]  U+16FE2 | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2 | 1
    ws[10] U+032FF | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2 | 1
    ws[11] U+031BB | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2 | 1
    ws[12] U+09FFD | -1 -1  2  2  2  2  2 -2 -2 -2 -2 -2 -2 -2 -2  2  2 | 2
    ws[13] U+1B132 | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2 | 1

  * mandb: longname の説明に対応する short option 名を併記するう (suggested by bbyfacekiller) [#D1879]
    https://github.com/akinomyoga/ble.sh/issues/231

    これはもしかすると実際に short flag も選択できる様にして欲しいという要求か
    もしれないとも思ったがよく分からないので、取り敢えず作ってみて見た目だけ見
    せたらそれで良いというのでそのまま採用する事にする。

  * color: term_index_colors を優先する様に変更 (motivated by StavromulaBeta) [#D1878]

    これで強制的に減色したい時にユーザーが term_index_colors を設定できる。

  * [棄却] neovim terminal / vim-autocomplpop で i/a を入力した時の問題 [#D1877]
    https://github.com/akinomyoga/ble.sh/issues/232

    変な文字列が挿入・実行される

    # これは報告者が使っている AutoComplPop というプラグインが古いのが原因だった

    neovim は nvim というコマンドで起動する様だ。

    再現しない。nvim-0.7.2, bash-5.2-rc2, としても再現しない。

    * plain vimrc? .vimrc をコメントアウトして試したが再現しない。

    * reject: 或いは i, a に対する delay が関係している可能性? 実際に操作してい
      てい ESC がちゃんと即座に処理されていない気がする。
      https://vi.stackexchange.com/questions/16148/slow-vim-escape-from-insert-mode
      と思って ttimeoutlen や timeoutlen を短い値に変えてみたが振る舞い(遅延)に
      変化は見られない。これらの設定は関係ないという事か?

    * 27_feedPopup() という文字列が挿入されている。9_feedPopup で検索すると vim
      の中にある自動補完の仕組みが関係している様な気がするが詳細はよく分からな
      い。これでエラーが出ているという事は、実際に ble.sh がこの文字列を受信し
      ているということである。vim の保管機能が意図しない形で ble.sh に対して送
      信されて、変な文字列が挿入されると共に実行まで開始されている。

      https://askubuntu.com/questions/382407/vim-autocomplpop-issues

      このページを見る限り AutoComplPop という何かが関係している?
      元々のページ at bitbucket は消滅している?

      https://github.com/vim-scripts/AutoComplPop

      ここを見ると最後に更新されているのは12年前。runtime path 以下にファイルを
      コピーしろと書かれているが runtime path が何か分からない。検索すると
      runtimepath という変数に入っているみたいだが、今度は runtimepath という変
      数の値を取得する方法が分からない。と思ったら ":set runtimepath^M" で良い
      様だ。set で右辺を指定しなければ現在の値が表示される。実際に表示してみる
      と以下の様になっている。

      # runtimepath=~/.config/nvim,/etc/xdg/nvim,~/.local/share/nvim/site,
      # ~/.local/share/flatpak/exports/share/nvim/site,
      # /var/lib/flatpak/exports/share/nvim/site,
      # /usr/local/share/nvim/site,/usr/share/nvim/site,/usr/share/nvim/runtime,
      # /usr/share/nvim/runtime/pack/dist/opt/matchit,/usr/lib/nvim,
      # /usr/share/nvim/site/after,/usr/local/share/nvim/site/after,
      # /var/lib/flatpak/exports/share/nvim/site/after,
      # ~/.local/share/flatpak/exports/share/nvim/site/after,
      # ~/.local/share/nvim/site/after,/etc/xdg/nvim/after,~/.config/nvim/after,
      # /usr/share/vim/vimfiles/

      取り敢えず .config/nvim に入れる。

      OK 再現した。うーん。何故これが発生しているのだろうか。

      うーん。然し、そもそも ble.sh をロードしていなかったとしても i または a
      を押すと最後に実行したコマンドが強制的に実行される様である。これは変であ
      る。そもそも ble.sh だけの問題ではない気がする。

      検索すると https://github.com/othree/vim-autocomplpop/issues/9 で同じ現象
      が報告されている。というかこれが acp の最新版なのではないか。これを入れて
      みたところ、今度は ***** L9 library must be installed! ***** というメッセー
      ジが表示される。検索してみたらこれは行番号ではなくて "L9" という名前のラ
      イブラリらしい。同じエラーメッセージについての質問があった。

      https://stackoverflow.com/questions/22902141/l9-library-must-be-installed-error-occurred

2022-09-14

  * prompt: clear-screen 後は same-dir でも transient prompt を残しておく [#D1876]

    transient same-dir で起動後の一番最初のプロンプトは全部残しておくべきである。

    と思って試して見たがちゃんとそうなっている。或いは clear-screen した時にディ
    レクトリ名が消えてしまうという事だったか。これは振る舞いを修正しても良い。

    p10k の方の振る舞いを見てみたが clear-screen しても same-dir で trim されて
    しまう様である。なのでそういう意味では ble.sh も気にしなくても良いのかもし
    れないが、やはり clear-screen した後は残っていて欲しい気がする。

  * hook: blehook | cat がデフォルトで着色になっている [#D1875]

    bleopt ble-bind ble-face ble-sabbrev 等は問題ない。常に auto の振る舞いである。
    これは blehook の read-argument が悪い。修正した。

2022-09-13

  * HISTCONTROL に trim 的な物を追加しても良いのではないか (motivated by aiotter) [#D1874]
    https://github.com/akinomyoga/ble.sh/issues/226#issuecomment-1243759012

    bash のソースを見たら stringlib.c に strip_{leading,trailing} というのがあ
    るので trim ではなく strip を名前として使う事にする。

    取り敢えず bash の patch も作ってみる事にする。
    https://gitlab.com/akinomyoga/bash/-/commit/d43c167e9ec150d1fe4a730475a590d48a4cc9cd

2022-09-06

  * decode: ble-bind --cursor で設定したカーソルが反映されない [#D1873]

    vi のモードを遷移した時にしか反映されない。set -o emacs や set -o vi を実行
    してもそのままである。調べたら keymap#{push,pop} の時にしか cursor を設定し
    ていない気がする。base を変更した時や ble-bind で cursor を設定した時にも設
    定を反映するべきではないか。

    * 現在キーを受け付けている状態かどうかをどうやって判定するか。現在表に出て
      いる時にだけ cursor 設定をその場で変更する。それ以外の時には記録してある
      状態を書き換える、という具合にすれば良いだろうか。

      →これは ble/term/cursor-state/set-internal を指定すれば良いだろうか。
      実際、keymap/{push,pop} ではこの set-internal を指定している。

      他の箇所で一時的に cursor を書き換えていたりはしないか。つまり、同じ
      keymap であっても別の要因で別の cursor を表示しているという事はあるだろう
      か。→調べたがその場所はない。基本的に keymap/{push,pop} でしか cursor
      shape は変更していない様だ。

    * base map を設定している箇所を確認する。恐らく reset-default-keymap だけだ
      ろう。他は ble-bind -P で INITIALIZE_DEFMAP をしているがここでは
      _ble_decode_keymap はしていない。改めて確認したが _ble_decode_keymap を変
      更しているのはやはり decode.sh の中では keymap/{push,pop} と
      reset-default-keymap だけである。

    * ble-bind で cursor を設定した時にもその場で反映したい→対応した。動作も確
      認した。

    また、以前の xterm.js の為に指定した workaround が動いていないのではないか。
    結局 term enter する時に unknown を設定してしまっている。そして、コメントを
    見る限りはこれは vim がカーソルの状態を残したまま終了してしまう事に対する対
    策の様である。

    うーん。これに対してはどの様に対処するべきだろうか。vim の設定が悪いのだと
    思えばわざわざ直さなくても良い。と思ったが元々これは ble.sh の中で keymap
    の cursor を設定しているのにも拘らず vim の実行後にその設定が変わってしまう
    というのが問題なのであった。

    default と unknown という値を区別する事にして、ble.sh が cursor 設定を変更
    していない時は default という事にしてユーザーコマンドが変更した cursor につ
    いては関知しない事にする。

2022-08-31

  * 2022-08-23 complete: progcomp 引数について [#D1872]
    https://github.com/scop/bash-completion/issues/790
    https://github.com/scop/bash-completion/issues/791

    ? ok: そもそも現在の ble.sh の実装だと = などが存在した時の単語の分割の仕方
      が異なる。これはやはり Bash に合わせた方が良いのだろうか。と思ったが、

      $ test1 a=[TAB]
      $ test1 a=b[TAB]

      の両パターンの一貫性を考えれば現在の ble.sh の分割の仕方の方が自然だし、
      後者を実装しているのであれば前者についても ble.sh の分割の仕方で自然に動
      作しそうな物である。という事を考えると、敢えて bash の変な振る舞いに合わ
      せる必要はない様に思われる。

    * ok: 更に報告された振る舞いで問題になっているのは、分割文字 = の直後で補完
      した時に、何故か新しい単語ではなくて = に対する補完になっているという
      Bash の振る舞いがそもそもの問題である様な気もする。それを回避する為に $2
      に空文字列を設定するというのも何だか変な実装である。

      然し一方で分割文字 = 自体を書き換えたいという場合も考えられるので遡って書
      き換えられる様に "=" の単語の中に含めて補完するというのもそれはそれで理解
      できる。なので Bash 自体に振る舞いの変更を実装して解決するという訳にも行
      かない。

    ? ok: 所で "echo aaa [TAB] bbb" とした時に ble.sh はどの様に振る舞うのだっ
      たか。bash では変な分割のされ方と CWORD の設定のされ方になっているとして
      文句が出ていた物である。

      →これは ble.sh ではちゃんと途中に空文字列を作成している。OK

    ? done: コマンド名自体が COMP_WORDBREAKS で分割される場合にはどう振る舞うべ
      きか。Bash の振る舞いを確認してみた所、COMP_* を作成する時点でコマンド名
      も COMP_WORDBREAKS に従って分割されてしまっている。一方で、補完関数の $1
      に渡される文字列は分割前のコマンド名の様である。

      その様に実装する。

    bash-completion#791 の実装を単に移植する事にした。

    * reject: うーん。そもそも bash の振る舞いを厳密に再現する必要もない様な気
      はする。特に simple-word/is-simple-or-open-simple 等を使ってより良く判定
      できるのではないかという気がする。然し、取り敢えずは Bash の動作に厳密に
      一致する様に振る舞う事にする。そもそもこの振る舞いを便利に使っている補完
      があるとも思われないので。

    x fixed: そもそも現在の ble.sh において COMP_WORDBREAKS が正常に動作してい
      ない気がする。

      確認してみた所 ble/syntax:bash/simple-word#break-word に引数を渡し忘れて
      いる? ここに単に $wordbreaks を渡せば良いのではないか。

      ? 或いは、既定の値 (:=) を使う理由が何かあったのだろうか? 調べる。変更は
        6c6bae5 で行われている。これは #D1098 である。この時の議論を確認してみ
        たが特にこの部分で特別な取り扱いをするという議論はない。寧ろ
        COMP_WORDBREAKS に対応する為の議論なので wordbreaks 変数を全く使ってい
        ない現在の実装は変である。

      分割子として "$wordbreaks" を指定する様に修正した。

    x fixed: 新しく実装した cur が全く反映されない。と思ったら helper-prog (-C)
      の方だけ対応していた。helper-func (-F) の方も対応する。動作も確認した。

    ? ok: bash の COMP_WORDBREAKS による単語分割は @ や $ や \ に対しても他の分
      割文字と同様に働くのか? つまり独立した subword を形成するのだろうか? →
      試してみた所、ちゃんと独立した subword になっている。つまり abc@def が
      "abc" "@def" と分割される等の特別な事は起こらない。特別な取り扱いは $2 限
      定の様だ。

    * 何と $2 には現在の単語だけが設定される訳では無い様だ。COMP_WORDBREAKS に
      よる分割の前の単語が全て入る可能性がある。

      $ test1 abc@def
      declare -a COMP_WORDS=([0]="test1" [1]="abc" [2]="@" [3]="def")
      <test1><@def><@>

      これにもちゃんと対応した。

2022-08-29

  * 2022-08-23 blehook HOOK+= を HOOK!= に統一する [#D1871]

  * 2022-08-14 nix develop が保存された EPOCHREALTIME を復元しようとしている [#D1870]
    https://discourse.nixos.org/t/nix-print-dev-env-command-shows-some-assinments-to-readonly-variables/20916
    https://github.com/NixOS/nix/pull/6800

    一方で ble.sh は EPOCHREALTIME が勝手に別の機能に置き換えられると動作が全く
    おかしくなるので (そしてはそれは他の EPOCHREALTIME を参照しているスクリプト
    も同様であろう)、勝手に EPOCHREALTIME の機能を消去させられてしまっては困る。

    * そもそも Bash では EPOCHREALTIME をそのまま上書きしても意味がない。一旦
      unset しなければならない。実際に上書きしている箇所で unset をしているのか
      どうかまでは明言されていないが、報告されているエラーメッセージを観察する
      限りは unset は試みられていない。unset が最初に試みられていたのであれば、

      bash: unset: EPOCHREALTIME: cannot unset: readonly variable

      というエラーメッセージになっていた筈である。

    * もし unset してまで固定した時刻にしたかったのだとすれば、そして実際にそれ
      をやったとしたら ble.sh の内部の時刻関連の制御が滅茶苦茶になる。場合によっ
      ては固まってしまうかもしれない。

      というかもし対話シェルで使っているなのだとしたら

    ? というかそもそも何故対話シェルの設定と print-dev-env 的なコマンド的な設定
      が混ざり合っているのだろうか。

      % ? 会話を見ると print-dev-env は単に現在のシェル変数を出力するのに使って
      %   いるだけの様に見える。sed でフィルタ等するという話をしている。なので、
      %   対話シェルとして動作するとも思えない。
      %
      % ? nix develop でエラーメッセージが表示されると書いている。nix develop
      %   を調べてみると、 nix shell + 開発用のコマンドという環境に入るらしい。
      %   なので bashrc を読み込む。問題は print-dev-env が何故同じシェルで呼び
      %   出されるのかという事である。特に直接 print-dev-env を自分で明示的に呼
      %   び出しているのではなくて、nix develop を実行した時に自動で実行される
      %   のだという事を書いている。謎だ。
      %
      % ? 仮に ble.sh が --lib で読み込まれるのだとしても、それを bashrc から読
      %   み込むというのも変な話である。もし ble.sh の関数を個別のシェルスクリ
      %   プトで使いたかったとしても、それは使うシェルスクリプトの中で個別に
      %   source するべきなのであって、bashrc で一括して読み込むという使い方は
      %   想定していない。
      %
      % ? 或いは print-dev-env というのはシェル関数なのだろうか。

      % https://github.com/NixOS/nix/blob/master/src/nix/develop.cc を見ると、
      % どうも print-dev-env と develop は内部のコードを共有しているという事の
      % 様だ。つまり、develop の中で呼び出された print-dev-env が EPOCHREALTIME
      % を触ってのではなくて、nix develop のコード自体が EPOCHREALTIME に触ろう
      % としているのである。更に、print-dev-env も develop も単に現在の値を出力
      % しているだけであって、明示的に EPOCHREALTIME に値を設定するコードが含ま
      % れているという訳では無い様な気がする。
      %
      % そういう事を考えると、そもそもこの現在の値を出力するコードの時点で、
      % EPOCHREALTIME, EPOCHSECONDS, SECONDS, LINENO, BASH_LINENO, FUNCNAME,
      % BASH_SOURCE, BASH_VERSION, BASH_VERSINFO, BASH_COMMAND 等の変数に値を代
      % 入しようとしているのが間違っている。

      develop.cc のコードを確認した。先ず、print-dev-env は、実質的に nix
      develop を中で呼び出してその環境における変数を出力するという様な処理を行っ
      ている。そして、正にそれが目的なのだろうという気がする。

      nix develop は何処かに .json で保存されている変数を読み取ってそれを bash
      に設定しようとしている様に見える。その .json に EPOCHREALTIME が記録され
      ているのは恐らく何か別の用途にも使われる事を想定しての物だろう。一方で、
      nix develop で使う時には幾ら何でも全ての変数を復元するのは変である。
      BASH_* は避けるべきだし (もしかするとこれらは既に保存する時点で除外されて
      いるのかもしれない)、その他の FUNCNAME や LINENO 等も復元を試みるのは滅茶
      苦茶である。

      BASH_VERSINFO は bash が readonly にしていてこれに関しては警告が出ていな
      いというのは BASH_* は除外しているという事なのだろうという気がする。

    ? NixOS/nix #6800 も謎である。error ではなく warning だったと言って閉じてい
      るのも謎だし、zsh では readonly だからと言って bash で動く nix develop の
      上でスキップするというのもよく分からない。

    * 色々 develop.cc を読んだりして思った事は TLATER の 99% sure と言っている
      内容はかなり怪しいという事だ。恐らくこの TLATER は何も分かっていなくて出
      鱈目な事を書いている。

      或いは実際に何処か別の箇所で EPOCHREALTIME も明示的に保存しているのだろう
      か。でもコードを見る限りは ignoreVars でブラックリスト式にしているし、恐
      らく全ての変数を出力しているのだろうという気がする。

      やはり TLATER は出鱈目を書いている。もし本当にそうなのだというのであれば
      わざわざ 99% sure などと書かないし、というか 100% sure とも書かずに、断定
      で書くはずである。I'm sure なんとかとか書いている時点で勝手に推測をしてい
      るのに過ぎない。

      そもそも本当に build environment を同一にしたいのであれば、単に変数の値を
      変更したとしても意味がない。システムの時刻自体を固定しなければならないの
      ではないか。そもそも最近の bash の機能である EPOCHREALTIME を参照してビル
      ドを行うシステムがどれだけ存在するのかというのも謎である。そしてシステム
      の時刻を固定しているのであれば、わざわざこの様な処理は必要がない筈である。


      →と思ったがこの json はもしかすると各 derivation の作者が手書きで用意す
      る物なのだろうか。なのだとしたら EPOCHREALTIME を誤って設定している人がい
      ても不思議ではないのかもしれない。然し検索してみてもその様な物は見つから
      ない (とは言いつつ GitHub の検索は余り当てにならない。経験上最近検索され
      たページに含まれている文字列しか検索対象になっていないような気がする)。

      https://github.com/NixOS/nix/search?q=EPOCHREALTIME
      https://github.com/NixOS/nixpkgs/search?q=EPOCHREALTIME

    2022-08-29 これは結局 nix の側で修正されたので OK
    https://github.com/NixOS/nixpkgs/pull/185866
    https://github.com/NixOS/nix/pull/6944

  * ok: 2022-08-26 何と bash の regex は ^ で文字列の戦闘ではなくて行頭に一致してしまう? [#D1869]

    と思ったがそうでもないようだ。特別な条件で発生する。

    rex='^b'; [[ $'a\nb' =~ $rex ]]; echo $?    ... 一致しない (OK)
    rex='^[^a]'; [[ $'a\nb' =~ $rex ]]; echo $? ... 一致しない (OK)
    rex='a^'; [[ $'a\nb' =~ $rex ]]; echo $?    ... 一致しない (OK)
    rex='.^'; [[ $'a\nb' =~ $rex ]]; echo $?    ... 何故か一致してしまう?????
    rex='.^'; [[ $'ab' =~ $rex ]]; echo $?      ... 一致しない (OK)
    rex='^.^'; [[ $'a\nb' =~ $rex ]]; echo $?     ... 一致しない (OK)
    rex=$'\n^'; [[ $'a\nb' =~ $rex ]]; echo $?     ... 一致する!
    rex=$'a\n^b'; [[ $'a\nb' =~ $rex ]]; echo $?     ... 一致する!
    rex=$'^..^b'; [[ $'a\nb' =~ $rex ]]; echo $?     ... 一致する!

    この変な振る舞いは 3.0..5.2 まで全てで再現する。或いは Linux/glibc 側の問題
    の可能性もある。

    何れにしても .^ や \n^ の様な (single line regex では) 意味のない正規表現で
    しか問題が起こっていないので取り敢えずは何もしなくて良い。うーん。例えば ^
    より前に何かが存在する時に限り ^ は multiline mode に変更されるなど? もしか
    すると関連して現実的な正規表現でも問題が起こる可能性があるかもしれないが。

    だとしたら ^$ で空文字列にしか一致しない様にしているのは不味いのではないか?

    $ a='x\n\ny' r='.*^$'; [[ $a =~ $r ]]; echo $? ... 一致しない (OK)
    $ a='x\n\ny' r='.+^$'; [[ $a =~ $r ]]; echo $? ... 一致しない (OK)
    $ a='x\n\ny' r='.*(^$)'; [[ $a =~ $r ]]; echo $? ... 一致しない (OK)
    $ a='x\n\ny' r='.+(^$)'; [[ $a =~ $r ]]; echo $? ... 一致しない (OK)

    と思ったがこの場合には問題は起こらない様だ。不思議だ。

    取り敢えず問題にはならないとは思われるが、一応注意点として記録はしておく。

  * [自然解消] refactor: TRAPRETURN の中に余分な i=1 が残っている [#D1868]

    結局関連するコードは #D1867 の際に消滅した。

  * trap: gexec による DEBUG の処理を ble/builtin/trap に統合する [#D1867]
    * trap DEBUG, ERR についても関数呼び出しに従った構造を記録する。

    x 統合する上での問題は trap の中で trap が走った時に
      _ble_builtin_trap_postproc 等の変数が混ざって問題にならないかという事。
      (そもそも trap の実行中に trap が走るのかどうかもよく分かっていない) →
      実際に試してみた所、やはり trap の中で DEBUG trap は走る様だ。

      Ref. memo/D1867.recursiveTrapWA-stub.patch (試験的な実装)

      これは実は RETURN でも同様なのではないか。trap handler の中で RETURN が発
      生するのでは?

      a 混ざらない様にするには trap 毎に別の変数に trap_postproc を保存する?
        と思ったが RETURN の中で呼び出される RETURN などの状況を考えると単に
        trap 毎に変数名を変える方法では対応できない。

        % * 以前 RETURN の中で RETURN が呼び出されるというので無限ループ
        %   になった事がある気がする
        %
        %   →と思って今試してみたらやはりそういう事は起こらない様である。だとす
        %   れば単に trap 毎に保存すれば良いだけなのではないか。
        %
        %   以前の議論を探してみた所、実際に以前これについて調べていた (#D1350)
        %   がその時調べた結果は RETURN は RETURN 以外の trap では発生するという
        %   事。RETURN 内部で RETURN は発生しないという事。この時調べたのは、無限
        %   ループにならないかというのが心配になったからだったという記憶が微妙に
        %   残っていただけだろう。

      b というか単に trap の nest level を変数に入れておけば良いのでは? そして
        _ble_builtin_postproc[_ble_builtin_trap_depth] を参照する。

        と思ったが全てを handler に入れておく必要もない気がする。要するに
        .handler を呼び出した直後に postproc を評価するのだから、.handler の最後
        で postproc を設定すれば良いだけなのでは? と思ったがやはりそう簡単でもな
        い。.handler を呼び出した後に eval "${postproc}" を実行する間に別の trap
        が走る可能性もあるのである。

      c という事を考えると、

        depth++; .handler; eval postproc; depth--

        の様な具合にしなければならないのではないか? 然し depth-- を保証する方法
        がない。

      d 或いは

        depth=depth+1 eval '.handler; eval postproc'

        という具合にするしかないのだろうか。と思ったがこれも駄目な気がする? 否、
        例え .handler と eval の間に別の handler が入ったとしてもその handler
        が中途半端に終了しない限りは大丈夫の筈。


        _ble_builtin_trap_depth=$((_ble_builtin_trap_depth+1)) builtin eval -- "${_ble_builtin_trap_handler/SIGNUM/1}"
        _ble_builtin_trap_handler='ble/builtin/trap/.handler SIGNUM "$BASH_COMMAND" "$@"; builtin eval -- "..." \# "..."'

        うーん。これで行けると思ったがやはり駄目だ。eval を入れ子にすると $_ が
        変わってしまうので駄目。なので eval を入れ子にしない方法を考えたいが…
        或いは trap によって lastarg が変わらないという事にしてしまって一番外側
        の eval に \# "${_%%$_ble_term_nl*}" を渡すという手もあるかもしれない。


      e 或いは handler の中で local inc したらどうなるだろうか。

        handler() { local depth=$((depth+1)); postproc[depth-1]=設定; }

        問題が起こるとしたら

        ? handler が呼び出されて local depth を実行する間に DEBUG が走った場合?
          然しこの場合には実のところ DEBUG の処理が終わったらまた元の状態に戻る
          筈なので気にしなくて良い。とにかく postproc を触る前までに depth を
          inc して置けば良い筈。

        ? 或いは handler が終了してから eval postproc[depth] する間に DEBUG が
          走った場合? 実はこれについても特に問題は発生しない様に思われる。

          →うーん。やっぱり駄目だ。handler が終了した時に postproc[depth] には
          handler が設定した物が入っているが、この時に別の trap が走るとそれが
          上書きされてしまう。

          代わりに push/pop 方式にするとしても pop せずに抜けてしまった時に、よ
          り外側の handler が誤って内側の物が設定した postproc を実行してしまう
          事になる。

      f 或いは別の方法で trap の入れ子レベルを知る事ができれば良い。と思ったが
        難しい。FUNCNAME の中に含まれる ble/builtin/trap/.handler を数える方法
        を考えたが、これだと結局 handler ... eval の間に走る trap に対して対処
        できない。というか eval の入れ子レベルを取得する方法はないにだろうか。
        PS4 の最初の文字を複製する回数でもあるが、これをもっと普通の方法で取得
        する方法がないのは何故だろうか。

      g うーん。或いは postproc を設定してからそれを評価する迄の間に発生した
        trap は全て無効化するという可能性?

        x しかしこれも何らかの拍子で postproc が実行されずに終わってしまうとそ
          れ以降の全ての trap が実行されなくなってしまう。

          然し、実際にそれが発生する事はあるのだろうか。先ず INT は塞いでいる。そ
          もそも trap の内部で INT は発生しない気がする。trap の内部で発生する可
          能性があるのは DEBUG, RETURN ぐらいの物である。errtrace が設定されてい
          れば ERR も発生するかもしれない。

          * DEBUG と RETURN には介入している。一方で、ERR には介入していない。
            DEBUG と RETURN に関しては無効化すれば良い。ERR で return などが実
            行されて trap 終端処理がスキップされた時に問題になる。

          その他の理由で実行がキャンセルされる事はあるだろうか。

          * 外部からのシグナルの場合には trap handler の実行中には何も起こらな
            い。trap handler の実行が終わった後に実行される筈である。
          * readline の timeout (TMOUT) に関しては ble.sh は無効化して自前で実
            装しているので問題にならない筈。
          * KILL を受け取ったら何れにしても終了するので関係ない。
          * exit で trap の中から終了する場合…と思ったがこれは起こり得ない。今
            ble.sh の trap string を実行しているのだからその他のコマンドが実行
            される余地はない。

          うーん。別の方法で trap を実行している事を検知する方法はあるだろうか。

          * reject: 例えば bash-4.4 以降では trap 実行中に return の戻り値が変
            わる事を以て現在 trap の内部かどうかを判定できると思ったが、入れ子
            の trap の場合には 2 重か1重かを判定しなければならないのでこの方法
            は使えない。そもそも使えたとしても、この振る舞いは議論の対象であり
            将来的に変更されるかもしれないし古い bash では使えない。

        恐らくこれで基本的に問題ない。

        1 DEBUG に対しては postproc 直前の発火に対しては無視する。

        2 RETURN に対しては trap/.handler RETURN について無視する。

          うーん。これは元からそうなっているのでは? と思ったがそうでもない様
          だ。現在は trap 内部の RETURN しか無視していない。これに加えて
          blehook/invoke.sandbox | blehook/invoke | ble/builtin/trap/.handler
          に対して発火した RETURN も無視したい。

        3 ERR に関しては trap/.handler が失敗しない限りは大丈夫の筈。

        但し、何らかの拍子に postproc が設定された儘になってしまった時の為に、
        随時 postproc をクリアする。例えばトップレベルで呼び出された
        ble-decode/.hook でクリアすれば良いのではないか。少なくとも trap
        handler の中でトップレベルで ble-decode/.hook が呼び出される事はない。

    改めて考え直してみたが同じ trap が入れ子で呼び出される事はやはりないと仮定
    して良い気がする。だとすれば a の方法で実装すれば良い。一方で g.2 の
    [RETURN 以外の trap についての trap/.handler に対する RETURN] の発火は無視
    する事については対処したい。

    * RETURN 以外の trap/.handler に対する RETURN を無視する事について。

      というか現在の実装の blehook/invoke.sandbox | blehook/invoke |
      ble/builtin/trap/.handler のスキップは全て無視して単に BLE_TRAP_FUNCNAME
      を参照すれば良いのではないか?

      と思ったがそれだけだと駄目である。先ず trap/.handler は内部で色々な関数を
      呼び出している。RETURN を extdebug で設定しているとこれらの全ての関数に対
      して RETURN が発火して面倒な事になる。

      うーん。exit 時に RETURNが呼び出されると思ったが、これは unload で元の
      RETURN を復元した後に発生している物である。

    * _ble_builtin_trap_{postproc,lastarg} を trap 毎に記録する様に変更する。

      _ble_builtin_trap_lastarg については基本的に2つの関数でしか使われていなかっ
      たのですぐに修正できた。_ble_builtin_trap_postproc も殆ど同様だったが、但
      し edit.sh で DEBUG trap の postproc/lastarg 抽出に使用されていた。これは
      _ble_edit_exec_TRAPDEBUG_postproc の代わりに
      _ble_builtin_trap_postproc[_ble_builtin_trap_DEBUG] を使う様にすれば良い
      だけである。

    * #D1853 で最近行った修正について気付いたのだが、実は既に lastarg に改行が
      含まれる場合については既に trap/.handler の内側で対処済みであった
      (#D1757)。trap string 内の無駄な $_ble_term_nl に関係する消去は除いた。

    * _ble_edit_exec_TRAPDEBUG_lastarg も同様に処理する様に変更するべきなのでは
      ないか。というか今はどの様に処理しているのだったか→取り敢えず似た様に修
      正する事にした。

    x fixed: TRAPDEBUG を early return する時に lastexit を復元していなかった。
      これは問題である。修正した。

    以降は少しずつ TRAPDEBUG の機能を trap/.handler に移植して行く事にする。

    * TRAPDEBUG では通常であればユーザートラップは関数の外で postproc を用いて
      実行している。一方でこの機能は現在の trap/.handler には存在していない。

      この手法の問題はユーザートラップによって設定される lastarg が失われてしま
      う事。と考えるとやはり handler の中で実行した方が良いのだろうか。然し、意
      図的に trap によって $_ を書き換える事も考えにくいので、やはりこの様にし
      て $_ が変わらない様に評価するというのの方が良いのかもしれない。或いはこ
      れはオプションで切り替えられる様にする。

    * user trap を呼び出す時に ble-attach している時には LINENO を設定している
      がどういう事か。これは恐らく LINENO を以前 unset していた為に、trap の中
      で LINENO が変な値になってしまう問題があったのだろう。然し現在は LINENO
      の機能を上書きしない様にしている。とは言いつつ ble.sh の内部で LINENO を
      実行すると関数内部でも一番外側における LINENO が表示されてしまうという問
      題がある。

      この振る舞いと consistent にする為に今までの様に一番外側の LINENO を設定
      していたと考える事もできるが…うーん。どう振る舞わせるのが良いだろうか。

      本来の bash における LINENO at trap string は trap/.handler の中では
      BASH_LINENO[1] を参照すれば取得できる。但し、これが top-level context の
      場合には、 _ble_edit_LINENO を代わりに参照する必要がある。というか、単に
      BLE_TRAP_LINENO を修正すれば良いだけなのでは。

    * DEBUG も install-hook する? →但し inactive にて。と、思ったが DEBUG の場
      合には inactive ともまた微妙に振る舞いが異なる。現状の edit.sh でやってい
      る処理のままで良い。

      もしかすると DEBUG でやっている様な trap の仕掛け方についても将来的には
      ble/builtin/trap に組み込んでも良いかもしれないが今ではない。

2022-08-25

  * trap: ユーザーが INT を設定している時は INT によるキャンセルはしない [#D1866]

    INT によってコマンドがキャンセルされるのを防ぐ為に trap '' INT としても意味
    がない。結局コマンドが中止される処理が走る。

  * trap: user trap handler 内で $@ を復元する [#D1865]

    2022-08-29 テストが動かなくなった。何故→これは単純なミスだった。shift を実
    行したが、それよりも後で $1 を参照している箇所があった。修正した。

  * trap: refactor and fix ble/builtin/trap [#D1864]

    * ble/builtin/trap 及び blehook 関連のコードが util.sh の中で肥大化して、他
      の util 内の関数に対する依存性が問題になってきている。より後ろで定義され
      ている関数に依存しているので初期化を遅延させるなどしなければならず不都合
      である。コードをもっと後ろに移動する代わりに、ファイルを分離する事にした。

    * fixed: 元からあった trap は出力されるのか

      これは実装を確認してみると出力されない気がする。実際に試してみるとやはり
      出力されない。修正した。

    * fixed: そもそも ble/base/unload した時に元の trap を復元するべきなのでは
      ないかという気がする。と思って確認してみた所、元から復元する様になってい
      た。然しちゃんと動いていない。

      * fixed: 然し、trap - INT という設定が外側に伝播しない様だ。EXIT はちゃん
        と解除されるが INT と WINCH は外側へ行かない。

        と思ったら単に $sig を参照する所を存在しない変数 $index を参照して trap
        に渡すシグナル名を決めていたのが原因だった。修正した。

      * fixed: というか復元するコードでカスタムシグナルに対しても勝手に trap が
        呼び出されてしまう。これは修正するべき。特に install-hook 等を通して設
        定された物だけを復元する。

    * ok: ble-reload した時に元々ある _ble_builtin_trap_handlers を保持するべき
      なのではないか? 現在は上書きしてしまっているので install-hook 経由で設定
      されている hook 等は消滅してしまう気がする。

      →これは ble/base/unload の際にちゃんと builtin trap を復元する様にしたら
      動く様になったので良しとする。

    * done: trap CUSTOM なども trap -p で出力

2022-08-24

  * trap: RETURN trap はちゃんと動くのだろうか [#D1863]

    現在の trap の実装で RETURN はちゃんと設定できるのだろうか? → 試してみた所、
    ちゃんと意図した箇所で RETURN trap が呼び出されているが、関係ない場所でも
    RETURN が呼び出されてしまっている。更に、設定した関数を抜けた後でも RETURN
    が呼び出されている。

    本来の Bash の実装を見ると trap RETURN を設定した関数 (追記: とその呼び出し
    元) のみで trap RETURN が発火する様である。但し、trap -p / trap -p RETURN
    すると何故か関数が抜けた後でも関数内部で使用した RETURN trap が出力される。
    然し、trap -p で出力されていてもこれは決して呼び出される事はない様だ。

      bash$ function a { trap 'echo RETURN a' RETURN; a2; echo a; }; function a2 { echo a2; }; a; trap -p
      a2
      a
      RETURN a
      trap -- 'echo RETURN a' RETURN
      ble.sh$ function a { trap 'echo RETURN a' RETURN; a2; echo a; }; function a2 { echo a2; }; a; trap -p
      RETURN a
      RETURN a
      a2
      a
      RETURN a
      trap -- 'echo RETURN a' RETURN
      RETURN a

    と思ったが、RETURN a が発火している関数を調べてみた
    所、_ble_edit_exec_gexec__TRAPDEBUG_adjustだった。そしてこれは declare -ft
    を設定している関数なのであった。

    % * というか試してみたが実は RETURN は元からそんなに賢い実装ではない様だ。
    %
    %   bash$ function a0 { echo a0; a1; }
    %   bash$ function a1 { trap 'echo "RETURN:a1"' RETURN; echo a1; a2; }
    %   bash$ function a2 { trap 'echo "RETURN:a2"' RETURN; echo a2; }
    %   bash$ a0
    %   a0
    %   a1
    %   a2
    %   RETURN:a2
    %   RETURN:a2
    %   RETURN:a2
    %
    %   先ず、内側の関数で設定された trap が外側の関数で定義された trap を上書き
    %   してしまって、関数を抜けた後でもそれが復元される事がない。次に、内側の関
    %   数で設定された trap が外側の RETURN を設定しなかった関数でも実行される。
    %
    % * RETURN trap が ble/builtin/trap に対しても呼び出されてしまう問題に関して
    %   は、単に RETURN trap の側で上手に処理してもらうべきなのではないか。という
    %   のも、元から設定した関数とは別の関数で呼び出される可能性があるのだから、
    %   ちゃんと関数を判定してから実際の処理を行う様に実装してあるべきだからであ
    %   る。
    %
    %   と思ったが本当だろうか。trap - RETURN をちゃんと実行するようにしていれば
    %   RETURN が復元されるのではないか。そうでなかったとしても trap - RETURN と
    %   だけしておけば本来ちゃんと動いたのではないか。
    %
    % →試してみたらそうだった。RETURN trap の中でちゃんと trap を解除している
    %   限りは各関数の RETURN trap が各関数で呼び出されるという形になる様だ。
    %
    %   bash$ function a0 { echo a0; a1; }
    %   bash$ function a1 { trap 'echo "RETURN:a1"; trap - RETURN' RETURN; echo a1; a2; }
    %   bash$ function a2 { trap 'echo "RETURN:a2"; trap - RETURN' RETURN; echo a2; }
    %   bash$ a0
    %   a0
    %   a1
    %   a2
    %   RETURN:a2
    %   RETURN:a1

    RETURN trap の中でちゃんと 'trap - RETURN' で trap を解除している限りは、
    RETURN trap はちゃんと設定した関数の中だけで実行する振る舞いになる。これは
    明らかに ble.sh の中では壊れてしまう。

    "trap - RETURN" を関数内で実行してもちゃんとその効果は外に持続するだろうか?

      $ st() { trap "echo '[RETURN:$1]'" RETURN; }
      $ us() { trap - RETURN; }
      $ f1() { st f1; echo f1; us; }
      $ f1; trap -p
      [RETURN:f1]
      f1
      [RETURN:f1]
      trap -- 'echo '\''[RETURN:f1]'\''' RETURN
      $ trap - RETURN; trap -p
      $ st() { trap "echo '[RETURN:$1]'" RETURN; }
      $ us() { trap - RETURN; }; declare -ft us
      $ f1() { st f1; echo f1; us; }
      $ f1; trap -p
      [RETURN:f1]
      f1

    うーん。駄目持続しない。逆に declare -ft を実行すると削除されるがうーん。もっ
    と現実的な設定で実験しないと分からない。

    * memo/D1863.RETURN-recursive.sh

      意外と簡単にちゃんと動く様にできた。interactive でもスクリプトでも両方と
      も期待どおりに動く事を確認した。これと同じ様に実装する事を考える。

    うーん。install-hook 等の枠組みを通じて修正するのではなくて RETURN は
    RETURN で特別に実装するのが良い気がする。RETURN を設置する時には既存の user
    trap を気にする必要もない。単に trap, ble/builtin/trap 内部で発生する
    RETURN をスキップするだけで良いのでは? と思ったがスキップする為には結局
    trap/.handler の様な複雑な仕組みが必要になる。

    実は単に install-hook RETURN inactive にすれば良いという可能性もある? → そ
    の様にして見たら各関数ごとに記録されている trap が消滅して駄目だった。trap
    を各関数呼び出し階層に対して記録する必要があるのだった。

    * どの様に記録してどの様に取り出すかについて落ち着いて考える必要がある。


      取り敢えず trap - RETURN されない限りは内側で設定された trap はずっと残る
      という事。全ての階層について記録しておいて一番深い階層で記録した物をいつ
      も取り出しておくという実装で良いのだろうか。

      ? しかし A->B->C1 と呼び出して C1 で設定した trap は A->B では有効である
        が、A->B->C2 と更に呼び出した別の関数の中では (C2 が -t を持っていない
        限り) 無効の筈である。なので B に戻った時点で C1 のレベルに設定した
        handler を除去して B のレベルに再設定するべきではないだろうか。

        x と思ったが B に戻った時点を特定する手段がない。結局そのように実装した
        としても C2 で有効になってしまうのではないか。

        o と思ったが、もし本当に継承されないのだとしたら C2 の中でそもそも
          trap/.handler は呼び出されないので気にしなくても良いのではないか。も
          し C2 の中で trap/.handler が呼び出されるのだとしたらそれは別の
          handler が明示的に設定されたという事であり、その時点で handler が上書
          きされてなくなっていると期待して良いのではないか。

        ? C2 が -t を持っている場合 (C2/t) や、extdebug/-T が設定されている場合
          はどうだろうか。この場合には結局 C1 が設定した handler を呼び出すのが
          期待される振る舞いなので handler が C1 のレベルに残留していても特に問
          題はない。

      ? trap - RETURN した時に別の文脈で設定された handler をどう処理するべきだ
        ろうか。基本的には自身のレベルよりも高いレベルの物は全て削除するという
        ので良い気がする。然し、別の子関数で設定された物も一緒に削除してしまっ
        ては駄目である。

        例えば A->B->C1 で設定された handler を A->B->C2/t で trap - RETURN し
        た時には

      ? というかそもそも A->B->C1 で handler を設定して、その後で A->B->C2 でも
        handler を設定して最後に trap - RETURN する場合を考えたら、元々
        A->B->C1 に設定した handler は A->B の階層に移動して置かないと問題にな
        るのではないか。

        と思ったがこれに関しては C2 で handler を新しく設定する時に C2 の階層に
        ある handler を B に移動すれば良い? とも思ったがそれだと同じ C2 の呼び
        出しで設定した物と区別が付かない。

      * extdebug や -T についても確認しておく必要がある → 対応した。

    実装した。動いている気がする。FUNCNAME 等が色々面倒な事になるので
    BASH_TRAP_{FUNCNAME,SOURCE,LINENO} という変数も提供する事にした。本当はもっ
    と色々なパターンでテストするべきの気がするが、

      source memo/D1863.RETURN-recursive.sh

    が取り敢えず plain Bash と同様に動くのでそれで良い事にする。

  * trap: EXIT trap が subshell で発火しない [#D1862]

    これは恐らく subshell の中で改めて trap を実行しないと有効にならないのが原
    因である。

    a subshell の中で初めて trap を実行した場合には改めて同じ trap で trap を実
      行する。

    b 現在は trap -p の結果と設定しようとしている trap が同一の場合には trap を
      スキップしようとしているが、そうではなく毎回ちゃんと実行する様にする。

      そもそも同じ trap_command を用いていたからと言って builtin trap の実行を
      省略したとしても、そもそも trap 処理自体そんなに思い処理という訳では無い。
      なので実行を省略せずに単に毎回実行すれば良いのである。

      * done: と思ったが builtin/trap の処理を custom で処理している
        ble/builtin/trap:DEBUG 等の関数についてはどうすれば良いのか。うーん。こ
        れは ble/builtin/trap:DEBUG 等の関数が存在する時に限ってはちゃんと設定
        するという事にすれば良い。

      * ok: 然し、その時に疑問なのは DEBUG や ERR や RETURN の様な関数の外側に
        対して効果を持たないものがどう振る舞うかという事。うーん。これは落ち着
        いて考えたら実は気にしなくても良いかもしれない。

        うーん。trap を関数内で実行した時に外に設定が反映されないかもしれないと
        いうのが以前の問題だった。一方で、今回は余分に trap を実行した時に外に
        影響を与えないかという事である。これは外に影響を与えたとしても与えなかっ
        たとしても結局振る舞いは同じ筈なので問題にならない筈である。

      * done: WINCH 等の様に readline が介入する物についてどうするのか。これに
        関しては subshell で実行している限りは、元々の bash の時点で readline
        の hook が設定されないと思われるので気にしなくて良いのではないか。

        * done: 確認してみたらそもそもそのような trap/hook に対しては subshell
          かどうかの判定を install-hook の時点で行っている。今、新しく trap の
          中でも builtin trap を再設置するという様に変更した時、同様の判定が必
          要になるのではないだろうか。つまり、subshell の外で実行している時には
          readline の介入を破壊しない為に再設置を抑制する。

          subshell の中では元々 readline の介入を期待できない (恐らく) ので気に
          しなくて良い。

    c subshell の中で実行する trap の場合には実は ble.sh による介入は不要になる
      のでは。だとすれば単にそのまま builtin trap すれば良い。

      EXIT は後述の様に EXIT で ble.sh の終了処理をする為に用いている。

      INT はコマンド実行時に ble.sh の処理までキャンセルしてしまわない為に用い
      ている。問題の処理は親シェルで行う物なので subshell の中では特に特別な事
      はしなくて良い。

      % WINCH についても read の中で subshell で使ってはいるが、~~中で改めて設
      % 定を行うので~~ trap は自分では実行しないので問題ない。結局設置済みの
      % trap WINCH から blehook internal_WINCH 経由で処理を行っている。と思った
      % が本当だろうか。本当に read の中で WINCH は呼び出されるのだろうか…と思っ
      % たが、やはり確認してみたところちゃんと read の中で install-hook を呼び
      % 出しているのでやはり改めて設定はしているのだろう。

      WINCH についても親シェルで設定している WINCH への介入を ble.sh でもすると
      いう事はない気がする

      ? 但し、子プロセスが WINCH を受け取って親シェルがそれを逃した場合には何が
        起こるのだろうか?)。

        ble-bind -x C-t 'x=$(sleep 5);echo hello;sleep 1'

        試してみた所、ちゃんと再配置計算が subshell の外で呼び出される様である。
        中で WINCH が呼び出されている気がする。なので子プロセスが受け取ったもの
        を更に自分で親シェルに伝達する等という処理は必要ない気がする。

    上記は b を採用した。

    * そもそも blehook EXIT は親シェルの終了時に呼び出される事を想定して作って
      いた。なので、今 subshell の中でも EXIT trap が走る様に変更すると変な事に
      なってしまう。

      Note: ble/base/unload は ble/builtin/trap/.handler から直接呼び出されてい
      る (#D1797)。他に ble/history:bash/TRAPEXIT が登録されている。逆に言えば
      subshell EXIT では ble.sh による介入は不要である。

      ? blehook EXIT を subshell で使おうと思っても、trap EXIT をユーザーが
        subshell で実行しなければ、そもそも subshell の中では有効ではないのでは
        ないか。なので blehook EXIT は subshell の中で使えない様にするべきでは
        ないのか。

        a うーん。この様に微妙な振る舞いになるのだとしたら EXIT は元よりユーザー
          には提供しないという事にするべきか。でもそれだとユーザーは trap EXIT
          を使わなければならず、一個しか登録できないので自前で色々管理しなけれ
          ばならない。blehook はその管理の煩雑さを解決する為に導入した物なので
          やはり機能として保持したい。

        b 或いは BASHPID 毎に blehook EXIT の内容を記録する事にするか。blehook
          に変更があった場合には改めて builtin trap を実行する。

        c 或いは開き直って blehook SIGNAL は親シェルのみで発火するという事にし
          ても良い。一方で internal_EXIT 等の方については subshell でも実行する
          というので良い。そうでないと WINCH 等の処理ができなくなってしまう。

          ユーザーが subshell で WINCH を受信したいという状況はあるだろうか? と
          思ったが、そもそも subshell に WINCH は元から継承されないし、改めて
          trap WINCH をする事になっている。代わりに、"改めて blehook WINCH を設
          定する" 方式にしたとしても元から存在している hook をどうしたら良いの
          かなど、色々と面倒な事が存在する。という事を考えると、やはり WINCH で
          あっても subshell 内では blehook WINCH を一括で呼び出すという様な事は
          しない事にする。

        うーん。blehook EXIT や blehook INT については c が現実的な気がしてきた。
        もしそうだとすればやはり UNLOAD は不要なのではないかという疑惑。と思っ
        たが物事は単純ではない。

        実際にユーザーに需要がありそうな物は EXIT である (親シェルでしか呼び出
        されないとしても)。一方で、ble.sh の内部処理はユーザーの blehook と分離
        しておきたい。だとすれば internal_EXIT に登録すれば良いのかというとそう
        でもない。何故なら 1) internal_EXIT は EXIT の前に実行されるが、処理の
        順序でユーザーの EXIT を実行する前に ble.sh の終了処理をする訳には行か
        ない。 2) internal_EXIT は今迄の議論だと subshell かどうかに関係なく実
        行するという事になっている。これは blehook EXIT だけでなく通常の trap
        EXIT の処理の前処理でもあるからである。という事を考えると内部処理用の
        unload hook を用意するのが良い。

        →c で実装することにした。

      ? ok: 更に上記の事は INT など他の trap でも同様でないか確認しておきたい →
        うーん。INT の場合に試してみたがどうも C-c を送ると親シェルがそれを受け
        取って処理するのでサブシェルの trap INT は元々呼び出されない様だ。

        つまり個別に考えるべきの気がしてきた。

      * EXIT の代わりに unload という blehook を導入する事にした。今までの終了
        処理は unload で実行する事にして blehook EXIT は trap EXIT と等価な物と
        いう事にする。また ble/base/unload は親シェルの中にいる時だけ
        trap/.handler から呼び出す。

        →と思ったら既に unload は存在していた。しかし誰も使っていない。今まで
        history が unload を使わずに EXIT を使っていたのは何か理由があったのだ
        ろうか。特に理由もないし寧ろ unload で実行するべき気がしたので単にそれ
        を使う様に変更した。

        更に、ble/base/unload の subshell かどうかの判定も、既に
        ble/base/unload の中に存在していた。

    * reject: wiki: EXIT や INT などの blehook は親シェル (main shell) でしか呼
      び出されない。WINCH についても → 改めて確認してみたがそもそも INT や
      WINCH は wiki に記述されていなかった。EXIT は既に記述として Bash が終了す
      る時に呼び出されるとしているので変更しなくて良い。

    ? subshell で本当に INT は継承されないのか?

      % 先程試した時はコマンド置換 $() でしか試していない。
      %
      % $ (trap 'echo INT2' INT; echo do;sleep 5;echo done)
      % do
      % ^CINT2
      % done
      % $ trap 'echo INT1' INT; (trap 'echo INT2' INT; echo do;sleep 5;echo done)
      % do
      % ^CINT2
      % done
      % $ trap 'echo INT1' INT; (echo do;sleep 5;echo done)
      % do
      % ^C
      %
      % →やはり外側の INT は継承されない様だ。
      %
      % 一方で subshell 内部で改めて設定した trap は有効になる。これはコマンド置
      % 換の時とは違う。コマンド置換の時には内側の INT の前に外側の trap が INT
      % を捉えてしまい、コマンド置換自体を別の方法で強制的に終了してしまう。或い
      % は SIGPIPE か SIGTERM が呼ばれていたのかもしれない。と思って色々試したが
      % どうもいかなるシグナルも受信していない様だ。もしかすると単純に sleep 5 が
      % 中断されるだけで続きの物も実行されるのかと思ったらそうだった。
      %
      % $ echo $(for sig in INT QUIT TRAP ABRT PIPE ALRM TERM; do trap "echo $sig >/dev/tty" "$sig";done;echo do >/dev/tty; sleep 5; echo done >/dev/tty)
      %
      % というかその振る舞いは通常の subshell も同じだった。subshell ではなくて一
      % 番上で実行しても同じなのであった。というか sleep を実行中に受信した INT
      % は結局 bash 側では全く処理されないのであった。

      sleep 5 だと sleep が INT を食ってしまって bash の trap INT が呼び出され
      ない事があるのでので正しく振る舞いを調べられない事が判明した。改めて busy
      wait 等を用いてそれに対して INT を送信して試す必要がある。

        # see memo/D1862.INT-in-subshell.sh

        $ set_trap;process_something
        do
        ^CINT

        $ (set_trap;process_something)
        do
        ^CINT

        $ echo $(set_trap;process_something)
        do
        ^CINT
        done
        $ set_trap;(process_something)
        do
        ^C
        $ set_trap;echo $(process_something)
        do
        ^C
        INT (これは単に外側のシェルで発生した trap INT である)

      うーん。直接・サブシェル() の場合には INT で中断する事ができる。コマンド
      置換の時には trap は発動するが kill -INT $BASHPID によって自身を中断でき
      ていない。そして、外部で設定された trap は何れにしても subshell の中では
      発火しない。

        # see memo/D1862.INT-in-subshell.sh

        $ echo $(set_trap; process_something)
        start
        ^CINT
        end

        $ echo $(set_trap; process_something)
        start
        ^CINT
        end

        $ (set_trap; process_something)
        start
        ^CINT

        $ echo $(process_something)
        start
        ^C

      うーん。コマンド置換の内部で INT に処理を追加しつつ自身を中断させる方法が
      謎。trap を設定していなければその場で INT で終了する。trap INT を単に設定
      しただけだと当然 INT による中断は発生しない。一方で trap - INT して kill
      -INT $BASHPID しても何故か何の効果も発生しない。

      これは bash-dev 特有の問題だろうか。調べてみた所、先ずスクリプトでは発生
      せず interactive session で発生する。4.3 まではちゃんとその場で終了する。
      4.4 と 5.0 では何故かコマンド置換はその場で終了するが、裏でプロセスが走っ
      ていて後になって "end" が出力される。5.1 と dev ではコマンド置換の実行が
      待たされる。変な振る舞いだが仕方がない。

2022-08-21

  * blehook: wildcard @ に対応する [#D1861]

    bleopt, ble-face が対応しているのに blehook が対応していないのは混乱の元。
    実際に使いたくなるので対応する。

  * history: blehook history_* を blehook history_onchange に統合する [#D1860]

    history_{delete,insert,clear} は何れも同じ箇所でセットで登録している。だと
    したらわざわざ別の hook にしている意味もない。逆に一貫性を考えたら一つの登
    録で全てを一貫した方法で処理しなければならない。

    統合した hook の名前については結局 history_change にする事にした。結局 on
    をつけ始めたら殆ど全てに on を付けなければならなく成るので余り付けても意味
    がない。同様に history_onleave も history_leave に改名する事にする。

  * util (ble-import): 調整する [#D1859]

    * done: source 時の引数の継承についてチェックする
    * done: 既にロード済みのファイル一覧 --list, --list-imported → これは -q,
      --query という名前で登録した。
    * done: ble-import --help でもっとちゃんとした説明を表示する (wiki も参考)
    * done: wiki update. -f の説明がない。-q の説明も追加する。

  * blehook: ERR 関連の動作が怪しい [#D1858]

    x fixed: 更に ble/builtin/trap 経由で設定した通常の trap が
      ble/builtin/trap 経由で削除できていない気がする。USR2 等、他の通常シグナ
      ルに対してはちゃんと削除できているので、これは EXIT 等の特別 trap に特有
      のバグの気がする。

      取り敢えずこれを最初に修正する事にする。

      振る舞いを調べてみた所、どうやら関数内部から外側の trap ERR を削除する事
      ができない様である。

        $ function trapERR { builtin trap "${1--}" ERR; trap -p; }; declare -ft trapERR
        $ trapERR 'echo trap ERR'; trap -p
        trap -- 'echo trap ERR' ERR
        trap -- 'echo trap ERR' ERR
        $ trapERR; echo x; trap -p
        x
        trap -- 'echo trap ERR' ERR
        $ declare -pf trapERR
        trapERR ()
        {
            builtin trap "${1--}" ERR;
            trap -p
        }
        declare -ft trapERR

      declare -ft をしても駄目だった。set -T でも駄目。bash-dev でも駄目。
      bash-3.0 でも駄目。set -E を設定していれば OK。但し、trap - ERR を実行す
      る瞬間だけ set -E をしていても意味はない。

        $ function trapERR { set -E; builtin trap "${1--}" ERR; set +E; trap -p; }
        $ trapERR 'echo trap ERR'; trap -p
        trap -- 'echo trap ERR' ERR
        trap -- 'echo trap ERR' ERR
        $ trapERR; echo x; trap -p
        x
        trap -- 'echo trap ERR' ERR

      仕方がないので ERR を削除したい時に限っては代わりに空文字列を
      trap string として設定する事にする。

    ? trap ERR を設定すると ble.sh の内部処理に対しても trap が呼び出される。特
      にコマンドが失敗した後の何らかの処理に対して複数回呼び出されている。成功
      したコマンドの後では呼び出されていない様なので、これはちゃんと実装すれば
      回避可能な物なのではないだろうか。或いは ERR の実装を誤っているか。

      また失敗したコマンドに対して重複して ERR trap が実行されているのも気にな
      る。これは調べる必要がある。

      ? というよりそもそもこの ERR は SIGERR と同じ物を意図して追加した物なのだ
        ろうか。zsh の hooks を確認してみると、その下に TRAPERR と TRAPZERR が
        言及されていて、これらは trap の物と大体同一である様だ。つまり各リスト
        に対して実行される。

      うーん。然し、改めて考えて見るにコマンド実行後の ERR の場合に使う ERRと、
      各トップレベルコマンドの設定に使う ERR は区別するべきの様な気がする。どち
      らもあった方が良い様な気がするのは難しいところではある。

      取り敢えず現状の実装では blehook ERR に登録しても SIGERR に対しては発火し
      ない実装になっている。一方で、blehook ERR は SIGERR を誘導する様になって
      いる。

      * done: うーん。ERR がユーザーによって設定されている時に限って builtin
        trap を設定する仕組みを整えたい。install-hook だと強制的に必ず設定を行
        う様になっているが → 実装した。動いている。

      * done: エラーが起こった時に呼び出される hook は ERREXEC に改名する事にする。

      * done: internal_NAME から通常のシグナルの実行をキャンセルする仕組みを整
        える。ble.sh 内部の ERR に対しては user ERR trap を発火しない様にする。

        取り敢えず実装したが bash-3.2 で無限ループになっている。何故だろう。
        と思ったが発火しない処理を追加したら問題は発生しなくなった。

      * done: trap に対して BASH_COMMAND を伝播する。bash-3.0,3.1 はそもそも
        trap による BASH_COMMAND には対応していない様なので設定しなくて良い
        →代わりに _ble_edit_exec_BASH_COMMAND を設定する事にした。

      ? ok: 無限ループの最中に発生した ble/builtin/history: unknown option --
        は何だったのか? 少なくとも history -- 1 等はちゃんと動いている。うーん。
        もしかすると history -xx-yy の様な引数が渡されたという事なのかもしれな
        い。何れにしても今は発生していない問題なので気にしない。

      * done: wiki: blehook ERR を ERREXEC に改名。

        * reject: 改名に関する枠組みを整える必要はあるだろうか? うーん。ble-0.4
          は開発版だし、特に ERR に関しては trap ERR を意図して設定した物と
          ERREXEC を意図して設定した物が混ざって混乱の元なので、改名についての
          提案はしない事にする。

    ? done: history の呼び出しを確認した所 history 1 を builtin なしで直接呼び
      出している箇所があるようだ。確認して修正が必要なら修正する。→これは単純
      な builtin つけ忘れだったので修正した。

    変更点

    * TRAPERR は廃止した。以下の場所で言及があるが廃止された旨をコメントする。
      https://superuser.com/questions/1512618/autocompletion-background-colour-in-ble-sh

    * blehook ERR は trap ERR と分離して ERREXEC に改名した

  * 2022-07-13 blehook: blehook の出力結果を init.sh にそのまま載せている人がいる [#D1857]

    これだと += なので重複してハンドラーが登録されてしまう。

    設定を保存・復元する為に a=$(blehook) として後で eval "$a" する様な使い方も
    考えられるので、最初の項目については += ではなく = にするべきではないか。うー
    ん。然しそれだと後で設定を merge する時に不便なのではないか。色々考えるとど
    うするのが便利なのかは非自明になってくるが、やはり自然な実装という事を考え
    たら設定を完全に復元するのに使えるコマンドという事で、最初の項目が = で追加
    が += という形にするべきである。

  * 2022-07-13 blehook: 内部 hook はユーザーに見えない様にするべきの気もする [#D1856]

    つまり同名の小文字 hook を用意してそちらに登録する。hook の発火については呼
    び出し元で両方とも呼び出す。入れ子にするという手もあるが色々変な事が起こる
    と嫌なので並列にする。

    内部使用の trap について確認する。contrib 等によって設定される物は、ユーザー
    から見えても良いので、除外する。

    * done: blehook DA2R='ble/color/initialize-term-colors'

      これはそもそも内部的に使用する hook であって、全て大文字なのは導入時の偶々
      の決定だった。後で大文字 = public という事になったので、初めから public
      にする意図があった訳では無い。undocumented でもある。なので、これは
      term_DA2R に改名してユーザーからは見えない様にする。

    * done/checked: blehook ERR='ble/builtin/trap/invoke ERR'
    * done/checked: blehook PRECMD='ble/keymap:vi/update-mode-indicator'

      * 実は今まで必ず PRECMD が設定されている事により状態 (PS1) の待避・復元が
        毎回実行されるという事態になっていた。つまり、本来はユーザーによって設
        定された hook もしくは PROMPT_COMMAND がある時にのみ必要だった退避処理
        が毎回実行されていたという事。今回新しく internal_PRECMD と PRECMD を分
        離した事により待避が必要な時にのみ実行される様になった。

        改めて確認した所、待避・復元されている状態は既定では PS1 だけだったので
        大した違いはないかもしれない。但し、bleopt
        prompt_command_changes_layout が設定されている時には再描画等の複雑な処
        理が実行されていた (が、もしユーザーがこの設定変数を設定しているのであ
        れば恐らく PROMPT_COMMAND が設定されているので何れにしても再描画は毎回
        実行されたのだろうという気はする)。という事を考えるとこの事は大した影響
        はなかったと思われる。

    * done/checked: blehook EXIT='ble/history:bash/TRAPEXIT'
    * done/checked: blehook INT='ble-edit/exec:gexec/.TRAPINT'
    * done/checked: blehook WINCH='ble-edit/attach/TRAPWINCH'

    * blehook ERR+='ble/function#try TRAPERR'

      これは削除しても良いのではないか。undocumented でもある。うーん。取り敢え
      ず ERR についての別項目でまとめて対処する事にする。

2022-07-29

  * test: cd -P . / README からリンク for nixpkgs (reported by aiotter) [#D1855]

    - blesh-share を実行するとスクリプトのファイル名が返される。実際に動かそう
      と思うと色々他にも変な所がある。修正するべき。

    - LC_ALL が設定されている…。これは大丈夫なのだろうか→調べてみたが ble.sh
      の関数は全て LC_ALL に対する対策が個別に為されている様なので気にしなくて
      良い。

    取り敢えず cd -P . だけは追加して後は nixpkgs 側は変更を依頼する。所で
    nixpkgs の各パッケージについての問い合わせ方法・問い合わせ先はあるのだろう
    か。maintainer の情報は埋め込まれているが連絡先は書かれていない。

  * edit: display-shell-version (C-x C-v) で /etc/os-release も参照する [#D1854]

    /etc/os-release の中の NAME= と VERSION= を見れば良さそう?

    OpenSUSE は VERSION が何故かコメントアウトされている。PRETTY_NAME はある。
    VoidLinux は NAME=void である。VERSION は存在しない。PRETTY_NAME はある。
    Arch も VoidLinux と似たような物である。
    FreeBSD も実は /etc/os-release を持っている。

    - Solaris は /etc/release を持っているが中身はシェルスクリプトではなくテキ
      ストファイルである。一番最初の行を抜き出して trim したら OS の名称になる
      だろう。

    - Minix にも /etc/release があってこれはやはりテキストファイルだった。然し
      何故か NetBSD 3.3 と書かれている。もしかして Minix は Minix kernel の上に
      NetBSD のパッケージを載せているという事なのか? 調べてみたら Minix 3.2 以
      降では NetBSD technology を導入するという様な記事があった。

      逆に言えば NetBSD でも /etc/release があって一行目にその情報が書かれてい
      るという事だろうか。

    * 取り敢えず OS 名は抽出する様にした。

    * done: 更に待避した locale 変数も元の状態をできるだけ再現する様にして表示
      する事にする。

2022-07-24

  * edit: starship (DEBUG trap) がある時に $_ が正しく復元されない [#D1853]
    https://github.com/akinomyoga/ble.sh/issues/215

    starship で再現。starship の DEBUG trap の処理後に $_ の再設定ができていな
    い。以前に関連する項目があった筈。

    * 現在の実装を見たら DEBUG に関しては lastarg の復元を諦めていて、その他の
      trap の場合には eval に \# つきで渡していた。その他の trap の時に lastarg
      の2行目以降が eval によってコマンドとして実行されてしまうという問題がある
      のではないか。この問題は認識していた筈である。不完全な状態で放置されてい
      たという事だろうか。

    何故今中途半端な実装になっているのか、過去の記録について洗ってみる。

    * ToDo 2022-02-20 に複数行 lastarg に対する処置の方法の可能性についての言及
      がある。と思ったが具体的に heredoc でどの様にこれを再現するのか? 当時何を
      考えていたか思い出せない。

      例えば以下の様な形にするという事を考えていた様な気がする (32 は使われそう
      にない fd)。

        eval 32<<xxx \# xxx
        yyy
        zzz

      然し、この方法も最終行の内容が "単語" の形をしている時にしか使えない。そ
      れに毎回無駄なパイプまたはファイルを開くのは嫌な感じがする。

    * 時期と内容的に #D1782 の対処の時にこの対策を部分的に実装したと思われるが、
      見る限りは #D1782 ではこれについての議論は行っていない。

    * と思ったが blame して確認してみると dfc62211 (#D1757) で変更されている。
      議論 #D1757 のコメントを見たが複数行 lastarg で発生しうる問題については言
      及されていない。この時点 (2022-02-02) では気づいていなかったという事なの
      だろうか。

    結局、DEBUG 以外の trap で複数行 lastarg の場合に問題が起こるのは、単に気づ
    いていなかっただけ + 後で気づいたが ToDo に入れて放置していただけである。

    取り敢えず暫定的な対策としては lastarg の最初の行までだけを復元するという事。
    本当に対策しようと思ったらどの様にするのが良いのかは不明である。(1) DEBUG
    の中で return/continue/break 等の制御コマンドを実行した場合に正しく動作しな
    いか、(2) $_ を正しく復元できないか のどちらかを選ぶしかない。DEBUG の本来
    の目的を考えると制御コマンドは使えないと変である。一方で本来の使い方とは異
    なるおかしな使い方が世に蔓延っている。

  * ble-reload の時に最初に指定した rcfile, norc を反映するべきではないか [#D1852]

    --norc を指定して起動したセッションでも ble-reload をした時に ~/.blerc を読
    み込んでしまっている。

    元の引数を全て保持する様にしようと考えたが微妙かもしれない。というのも、元
    の引数には --norc 等の引数も指定されているかもしれない。これは bashrc の中
    で別に ble-attach を呼び出す事を前提としている物なので ble-reload の時にま
    で継承するべきではない。更に --test や --lib 等の別の引数が指定されていた時
    にもどの様に取り扱うのか微妙である。

    という事を考えると、特定の予め選んだオプションについてだけ記録して再指定す
    るべきである。というか特に blerc だけ復元すれば良い気がする。

  * starship ble-reload で無限ループ (reported by tars0x9752) [#D1851]
    https://github.com/akinomyoga/ble.sh/discussions/212#discussioncomment-3205291

    自分の手許でやってみた範囲では発生していない。starship を先に初期化してから
    ble.sh を有効にしている時に発生する。ble.sh を先に初期化してから starship
    を初期化しても再現しない。source ble.sh --noattach, eval starship init,
    ble-attach, ble-reload の順番で実行しても再現しない。

    nightly を使っているそうなので ble.sh の version の違いではないだろう。

    問題のファイルを開きすぎですのエラーが出ている箇所で関数呼び出しスタックを
    確認してもらった所、以下の様な結果になった。

    | ble/function#advice/before:ble/util/assign
    | ble/function#try
    | ble/function#advice/.proc
    | ble/util/assign
    | ble/builtin/trap/install-hook
    | ble-edit/attach/.attach ble-edit/attach
    | {
    |   ble/base/attach-from-PROMPT_COMMAND
    |   ble/function#lambda/0 starship_precmd
    |   _ble_prompt_update__eval_prompt_command_1
    |   ble/prompt/update/.eval-prompt_command
    | } * 沢山繰り返し
    | ble/base/attach-from-PROMPT_COMMAND
    | ble/function#lambda/1
    | blehook/invoke.sandbox blehook/invoke
    | ble-edit/exec:gexec/invoke-hook-with-setexit
    | ble/prompt/update ble/application/render
    | ble-edit/bind/.tail
    | ble-edit/exec:gexec/.end

    うーん。再帰呼び出しを防ぐ様な仕組みがあった様な気がするがそれはどうなった
    のだったか。改めて確認してみる事にする。うーん。確かにその仕組はあるが、再
    帰的に呼び出した際には再帰的に実行される様である。

    % 自分の手元で改めて再現を試みているが再現しない。starship の他にも更に別の
    % PROMPT_COMMAND を触る設定も読み込んだ時には発生するという事なのではないか。
    %
    % * 再現はしないが何が起こっているかは分かっている。此処での疑問は何故毎回
    %   eval-prompt_command を実行する必要があったのかという事である。
    %
    %   入れ子で呼び出す時に…うーん。これは以前の PROMPT_COMMAND を利用した開始
    %   時刻の判定などの為の可能性もある。改めて過去の議論を確認する。
    %
    % * #D1778 が多少関係しているのではないか。そもそも eval prompt_command を此
    %   処で実行する必要性がよく分からない。
    %
    %   →もし PROMPT_COMMAND 経由で attach が呼び出されるのだとしたら、ここで
    %     eval prompt_command を実行しなくても更に外側で PROMPT_COMMAND の続きの
    %     処理が実行された時に必要な処理が行われるのではないか。然し、これは
    %     PROMPT_COMMAND の後続の設定で PS1 の設定などが行われている時に問題であ
    %     る。更に、PROMPT_COMMAND の中から様々の出力や端末に対する問い合わせの
    %     seq 等を送出するという場合にも問題になるかもしれない。
    %
    %   なので、やはり少なくとも一回は eval prompt_command を此処で実行する必要が
    %   ある。一方で、入れ子で呼び出された回数だけ実行する必要性は謎である。うー
    %   ん。普通に考えて不要に思われる。
    %
    % * 然し改めて再帰呼び出しのコードを見ると save_index を指定して
    %   PROMPT_COMMAND を呼び出している。つまり、save_index による無限ループが発
    %   生しない限りはこの様な事にはならない筈なのである。うーん。不思議だ。
    %
    %   とここまで来て分かった様な気がする。save_index を使っている時は
    %   PROMPT_COMMAND に値を設定して古い PROMPT_COMMAND の実行を行っている。もし
    %   この時に他の PROMPT_COMMAND[] 要素にも値が設定されていたらどうなるか。そ
    %   れらも一緒に呼び出されてしまう。特に starship がそこから既存の
    %   PROMPT_COMMAND を呼び出そうとした時に其処に attach-from-PROMPT_COMMAND が
    %   入っていると無限ループが発生する。
    %
    %   然し、そもそも save_index を使うのは array PROMPT_COMMAND が使えない時で
    %   はなかったか。つまり、bash 5.0 以下。然し一方で starship がもし bash-5.0
    %   以下であるにも拘らずに PROMPT_COMMAND 配列に何か設定した場合には何が起こ
    %   るか? Fedora 36 の starship (1.2.1 2022-02) で
    %
    %     $ starship init bash --print-full-init
    %
    %   の結果を見ても PROMPT_COMMAND は scalar だと思っている様だ。或いは最近の
    %   starship で配列 PROMPT_COMMAND に対応する様になったのかもしれない。
    %
    %   実際に報告によると使っている bash は bash 5.0 の様だ。

    うーん。ここまで来て bash 5.0 で試したら再現した。starship の出力を見る限り
    は別に PROMPT_COMMAND に配列で設定を行っている訳でもない。具体的に何が起こっ
    ているのか確認する。

    何が起こっているのか何となく分かった。最初に

      starship_precmd -> attach-from-PROMPT_COMMAND 0 -> empty

    が設定される。然し、ble-reload の際に

      attach-from-PROMPT_COMMAND 0 -> starship_precmd

    が設定されるが、以前の attach-from-PROMPT_COMMAND 0 が starshop_precmd の中
    に保存されているので starship_precmd がそれを呼び出して、その事によって無限
    ループになっている。

    うーん。unload する時に starship_precmd の中に記録されている前回の attach
    用のコードを除去しなければならないが、それができていないという事。この時に
    どうすれば良いか。。うーん。

    ? そもそも入れ子で attach-from-PROMPT_COMMAND を呼び出す事を許可しているの
      は何故だったか。また入れ子になった呼び出しの各階層における PROMPT_COMMAND
      の書き換えをちゃんと追跡しているのは何故だったか。そもそも複数回の
      install-prompt-attach を実行していなければ複数の
      attach-from-PROMPT_COMMAND が起こる事はないのではないかという気がするが、
      何故その様な事を考慮に入れていたのだったか。

      或いはそれこそ ble-reload をした時に前に設定されていた内容が消滅してしま
      わない様にする為だったかもしれない。つまり、
      _ble_base_attach_PROMPT_COMMAND に格納された元の PROMPT_COMMAND が
      ble-reload した後に使えなくなってしまうと行けないが、PROMPT_COMMAND は既
      に更に別の物によって上書きされてしまっている為に単純に復元できない。その
      時は unload するとしても attach-from-PROMPT_COMMAND はそのままにして、昔
      の _ble_base_attach_PROMPT_COMMAND を引き続き呼び出させる。という具合になっ
      ているのではないか。

      なのだとすると、初期化の際に _ble_base_attach_PROMPT_COMMAND を上書きして
      クリアしてしまうという実装が誤っているという事。

    * check: 元々この仕組は #D1650 (39ebf533) で導入された。然しこの時から既に
      記録用の配列はロード時に空に初期化してしまっていた。本当に当初の意図は複
      数回の ble.sh のロードだったのだろうか。

      →この時の記録を見てみると別に複数回のロードの事を考慮した訳ではなくて、
      単に念の為に「何らかの要因」で複数回設定された時に無限ループを防ぐという
      物だった様に読める。然しその何らかの要因として ble.sh の複数回ロードは想
      定していなかったし、従って複数回のロードに跨って記録配列を保持するという
      事は考えていなかったという事である。

    * done: PROMPT_COMMAND 配列が bash 5.0 以下で設定されている時の対策をする。

      これは報告にあった物とは関係ないがこれも対策しておくべきである。これは
      PROMPT_COMMAND と lambda が一致している場合でも横着せずに毎回
      PROMPT_COMMAND を local 変数として設定して処理する様にした。一致している
      場合には unlocal した後に改めて値を設定し直す事によって処理する。

  * util: starship で ble-reload した後に C-d で抜けると滅茶苦茶沢山のログが出る [#D1850]

    declare が無引数で呼び出されているという事だろうか。ble-reload していない時
    には関係ない。EXIT trap を先ず確認するのが良いだろう → blehook EXIT= とし
    ても同様に問題が生じる。trap - EXIT とすると問題は発生せずに exit する事が
    できる。

    どうも trap handler に "set" という文字列が登録されている様だ。何故? 実際に
    trap handler の配列を見てみると以下の様になっている。

      declare -a _ble_builtin_trap_handlers=([0]="set")

    因みに starship init bash の出力には trap も set も含まれてはいない。うーん。
    実際に値を設定している箇所は一箇所しかない様な気がする。確認する。確認して
    みた所、実際に ble/builtin/trap -- set EXIT という呼び出しが行われている。

    これは元々設定されていたtrapを再設定する時に、元々設定されていたtrapの抽出
    に失敗しているという事だろうか。ble/builtin/trap の呼び出し元を確認すると

      ble/builtin/trap/install-hook

    であった。やはり既存設定の抽出に失敗しているという事だろう → うーん。何故
    か builtin trap -p EXIT の結果が本当に trap -- set EXIT になっている様だ。
    何事だろうか。unload の差異に set を設定する様になっている可能性? というの
    も変な気がする。だとしたら starship と関係ないはず。

    どうも ble/base/unload-for-reload に於いて trap -- set EXIT が設定されてい
    る様である。つまり、元々の trap を設定する際に誤って set を設定してしまって
    いる。

    これは結局単純なミスだった。

  * main, util: make check が nix-build @ macOS で失敗する (reported by aiotter) [#D1849]
    https://github.com/NixOS/nixpkgs/pull/181963#issuecomment-1193125126

    * fixed: 他に sh -c 'echo -n $PID' において echo が -n を特別に解釈していな
      い事によってそのまま出力してしまっている問題があった。これは元々自分の環
      境で動かす事を想定していた為に適当にしていた事が悪い。修正した。

    * done: readlink が期待通りに動作していない。nix-build の外でも発生している。

      うーん。これは readlink が一体どの実装を選択しているのかに依存する。

      * nix-build @ macOS で一体何が選ばれるのか確認したい。と思って実装を確認
        したがこれは実際にどう動作するか確認するまでもなく .resolve-loop 一択で
        ある。なので、.resolve-loop のテストを実行すれば良い。

      * 先ずそもそも $PWD 自体が symlink だった時にどの様に振る舞うべきなのか?
        うーん。これはちゃんと考えていなかった。

        readlink -f の振る舞いを見ると現在のディレクトリがリンクだった時に、そ
        れについても全て解決している。ble/util/readlink の目的を考えると其処ま
        でする必要はないが、実装毎の差異を吸収する為には其処までしなければなら
        ないのだろうか。

        と思ったがこれはテストを実行する時に cd -L . をしておけば良いのでは。
        →というか ble/test/chdir で移動する時に cd -L "..." で移動すれば良い。

      改めて実装を確認してみたが、そもそも実装自体が怪しい気がしてきた。確かめる。

      実際に代替実装の動作を確認してみた所 Linux の上でも動いていない。動作を確認する。

      * fixed: resolve-physical-directory の実装が怪しい。取り敢えず設定されていないか
        もしれない pwd を参照しているのはおかしい。修正は必要だがどの様に修正し
        て良いのか分からない。

        * done: check: mshex の実装を確認する → mshex の実装は古い実装しかなかっ
          た。コメントにある taken from はもう古いので削除するべきなのかもしれな
          い。念の為再度 grep -r で検索してみたがやはり readlink の実装は単純な物
          しかない。

        * done: check: #D1720 以前の readlink の改良の時の議論を参照する。これは
          #D1720 だった。うーん。しかしここには大した説明は書かれていない。元の参
          考にした qiita の記事とその repository も見てみたが、其処にも余りコメン
          ト等は書かれていないし、其処から大きく書き換えてしまっているので参考に
          はならない様だ。結局改めて動作について確認する必要がある。

        恐らく元の resolve-physical-directory の実装で元のディレクトリ名ではな
        くて cd -L . した後のディレクトリ名に移動しているのは、現在ディレクトリ
        が改名された場合等にも正しいディレクトリに戻る為である。実験してみる事
        にする。

        Ref: D1849-cd-physdir.sh

        分かった事。

        1 pwd の結果は最後に cd を実行した時のそのディレクトリのパスになってい
          る。PWD を書き換えたとしても変化しない。また現在ディレクトリが他者に
          よって改名されたとしても変化しない。新しく現在ディレクトリの位置を取
          得し直すという訳では無い様だ。

        2 PWD は cd した時のディレクトリのパスに設定されるが当然後から自由に書
          き換える事ができる。

        また、当然の事ながら PWD の値が信用できるのかという事もある。ユーザーが
        勝手に変な値に設定しているかもしれない。pwd の結果を読み取るという手も
        あるがファイルに一旦書き込んでそれを読み取るというコストがある。なので、
        cd -L . した後に PWD を読み取るというのは確かに一つの手である。

        実装を修正して Note を残しておく事にした。

    * 先ず初めに nix-build environment では locale が全くないという疑惑。元々の
      locale が utf-8 でない上に、そもそも en_US.utf8 を設定するのですら失敗し
      ている。どの locale が利用可能かについて調べてもらう必要がある。

      これはどうしたら良いのか分からない。取り敢えず locale がどうなっているの
      かについて尋ねるのが良い。特に、en_US.utf8 がそもそもないという所を見ると
      locale を正しく設定してもらう所から始まる様な気がする。

2022-07-21

  * 2022-07-06 syntax: "function word1 word2 word3 word4()" [#D1848]

    % word1 がオプション形式の場合何故か word2 まで関数名として認識される。
    % word3 に対して type が走ってエラーメッセージが表示されて表示が乱れる。文
    % 法構造が一体どういう事になっているのか確認する必要がある
    % →どうも関数名として認識される問題とエラーメッセージが表示される問題は独
    % 立な問題の様だ。後、オプション形式化どうかは関係ない。

    * 関数名として着色される問題。以下のコマンドの形の時に再現する。

      $ function aaa bbb()

      どうやら a は文法エラーにはちゃんとなっている。然し、単語着色によって
      FUNCDEF が上書きされている様だ。

      →うーん。分かった。function -t a() と記述すると function -t { a(); } 的
      な解釈になっていて、本来は関数名の直後には複合コマンドしか来れないが、コ
      マンドがそのまま来てしまっていると解釈されている。一方で、コマンドが来て
      は行けない文脈であってもコマンドとしての単語着色が有効になってしまってい
      るのがいけない。

      然し、本来文法的に其処にコマンドが来ては行けない文脈に於いては単語着色も
      有効にならない筈なのに有効になってしまっているのは何故か。例えば "if
      true; then false; fi echo" とすると echo は文法エラー的なコマンドであり、
      そしてちゃんとエラー着色のままである。

      うーん。通常のエラーの場合には単語の種類自体が _ble_attr_ERR になっている。
      関数定義の場合にはそれを上書きして消去してしまっているのが原因?

    * エラーメッセージは auto-complete の中で発生している様である。

      $ function aaa bbb ccc ddd

      ddd を入力している時に "ccc" に対してコマンドではないというエラーメッセー
      ジが発生する。

      →これは結局最終的には bash-completion の _function が悪かった。これはま
      た別に bash-completion に出す。

      但しそれとは別にそもそも function aaa bbb ccc ddd に対して "function ccc
      ddd" に対する補完を試みているという事も変ではある。

      a そもそも bbb がエラーになっているのだから、extract-command の時点で bbb
        をコマンドとするtべきなのでは?  然し、その他の別の理由でエラーになった
        単語が含まれているかもしれない。なので bbb をコマンド名と解釈するのも変
        である。

        望ましいのはやはり "bbb ccc ddd" に対して補完が実行される事であるが、そ
        れを正しく実行する方法はあるだろうか。うーん。やはり extract-command で
        エラー単語をスキップせずにコマンドとみなす方法しかない? 然し、エラー単
        語が文法的に引数を取らないコマンドに指定された引数の可能性もある。例え
        ば、[[ ]] aaa や (( )) aaa など。

      b 現在は aaa を単語として登録していない。然し、aaa も単語として登録する様
        にすれば良いのでは? 然しそうだとしても "function aaa ccc ddd" に対して
        補完が試みられる事になって結局不自然である事に違いはない。

      うーん。或いはエラー単語も全て extract-command で生成する引数に含めて、更
      に関数名も単語として登録して一緒に抽出する様にする? その方が自然の気がす
      る。

      と思ったが echo hello (aaaa) bbbb 等の場合にはどの様にするべきだろうか。
      実際に現在どの様に抽出されているかを確認してから考える。

    * 2022-07-16 改めて考えるに bbb を単なるエラー単語としてではなくエラーコマ
      ンドとして登録するべきの気がする。

      →どうやら wtype を ATTR_ERR にしているのはコマンドの文脈しかない様である。
      なので extract-command で ATTR_ERR が見つかったらそれをコマンドとして取り
      扱って良いのではないだろうか。(或いは、ATTR_ERR ではなくて別の新しい分類を
      作った方が分かりやすいだろうか。)

      更に "[[ ... ]] word" の様な場合には attr には ATTR_ERR を設定していたが
      実は文法的にはエラーとしていなかった為、word が既存のファイル名に一致した
      りするとエラー着色が解除される等していた。取り敢えず現在の所は此処も新し
      いコマンドが開始する物として良い様な気がする。他に ARGX0 が設定される文脈
      はあるだろうか

      a 新しく CTX_CMDX0 を導入して概ね CTX_ARGX0 と同様に取り扱う。wtype に
        CTX_CMDX0/CTX_ARGX0 を設定する? 着色は ATTR_ERR のまま。extract-command
        では CMDI, ARGI の他にこの CMDX0 と ARGX0 も考慮に入れる。

        うーん。CTX_ARGX0 は設定する必要ない?

      ? wtype で CMDI と CMDX0 を区別する必要はそもそもあったのだったか

        →CMDI だと普通に着色を実行してしまう気がする。では単に全て CMDI とい
        う事にして、attr が ERR だったらコマンド着色をスキップするという手も可
        能なのではないかという気もする。うーん。然し単語情報と attr は格納位置
        が異なるし、現在の実装では恐らく単語の判定に元々の色を参照している例は
        ない。単語に内部構造がある場合等も考えると余り robust でもない様な気が
        する。

        やはり取り敢えずは CMDX0 を使って単語自体を区別する様にする。

      * 取り敢えずは CMDX0 を定義する事にする →定義した。

      * lib/core-syntax.sh:3711: elif ((ctx==CTX_CMDXE)); then で ctx=CTX_ARGX0
        を設定している。この文脈は { { echo; } >/dev/null } 等の文脈である。こ
        の } は CTX_ARGX0 ではなくて別の文脈で読み取るべきの気がする。

        やはり CTX_CMDX0 的な物を新しく導入するべきだろうか。その方がすっきりす
        る様な気がする。

        その場合には現在の ARGX0 を指定している箇所の多くは CMDX0 に変更した方
        が良いのかもしれない。例えば (()) ... や () ... や [[ ]] ... 等。うーん。
        本当だろうか。これらはやはりそのままで良い気がする。但し補完は発生しな
        い様にしなければならない。

        2022-07-20 うーん。今改めて確認した所 redirection で別にエラーになって
        いる訳でもない。うーん。どう修正したのだったか確認する。CMDX0 にしてい
        る。なのに何故エラー着色が消えているのだろうか。

        2022-07-24 現在はちゃんとエラーコマンド・エラー着色になっている。制御構
        造の終端としても取り扱わない様にしている。これで良いと思われる。

      ? ok: CPATX0 についてはどうするのか。これについてもちゃんと考えておきたい。

        →これは特に今まで通りで問題ない。元々 wtype = ATTR_ERR を設定した単語
        をコマンド名として extract-command するとした案の時に問題が起こる可能性
        を考えていた。然し今は CMDX0 を新しく導入して、エラーコマンド名に関して
        は wtype として CMDX0 を使って区別する事にした。なので、CPATX0 の単語に
        対して ATTR_ERR で単語登録しても問題は生じない。

      ? ok: エラーコマンドに対して補完は実行するのか? →これは補完しない様にす
        るのが自然の気がする。

        →現在はコマンド名は補完しない。一方でエラーコマンドの引数に関しては、
        エラーコマンドのコマンド名に従って引数補完を実行する様になっている。こ
        の振る舞いで良いだろう。

    * aaa を単語として登録するかどうかはまた別の問題で、これは function aaa
      [TAB] とした時の補完を progcomp で提供するかどうかという事に関係して来る
      様な気がする。

      * bash-completion は既存の関数の内容を挿入する事になっているが、その他の
        物を挿入したいという可能性はあるだろうか。他にない気がするので現在の関
        数定義を挿入するという事で決め打ちで良い気がする。

      * また関数定義は複数行からなるが、現在の progcomp の仕組みだと複数行の候
        補は全て分割されてしまうので、何れにしても bash-completion を使ってもちゃ
        んと動かない。これを回避するには compgen を自前で実装し直すしかない様な
        気がする。或いは compgen -0 の patch が取り込まれれば新しい bash では大
        丈夫になる。然しそれはまた独立な話題である。

      * またこの方針だと func() [TAB] の時に同様の機能を提供できない。

      そう思うと補完は progcomp とは別に実装するので良い気がする。そして、もし
      そうするのだとしたら aaa を単語として登録する意義は薄いのではないか。これ
      は func() [TAB] 及び function func [TAB] の補完の実装時に考えれば良い事で
      ある。

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]
    https://github.com/rsteube/carapace-bin/issues/1219
    https://github.com/akinomyoga/ble.sh/issues/204

    % と思ったが、よく考えるとそもそも空文字列でオプションも含める様にしたのは
    % ちゃんと絞り込みで候補を絞った時にオプションも表示する様にする為だった。
    % 空文字列での補完に対してオプションを生成しなかった時に何が起こるのか改め
    % て確認する必要がある。

    改めて確認したが別にオプション名はソートによってファイル名よりも先に来てい
    るのではなく、単に生成する順序に従って先に来ているだけだった。"-" で始まる
    補完の時にはオプションを先に表示して、空文字列に対する補完の時にはファイル
    名よりも後にオプションを生成する様に変更した。

    * 2022-07-12 空文字列からの補完によるオプション生成の時は説明を表示しない。
      https://github.com/akinomyoga/ble.sh/issues/204#issuecomment-1181743592

      これは本当はその内に詳細に設定できる様にしたいが、色々考えてから実装した
      い。然し、今回の場合は確かにその方が良さそうな気がするので既定の動作とし
      て採用してしまって良い。

  * kitty の keyboard protocol を terminal multiplexer 越しに有効化する (motivated by ferdinandyb) [#D1845]
    https://github.com/akinomyoga/ble.sh/issues/209#issuecomment-1179994203

    取り敢えず一番外側の kitty に送るのは実装した。

    ? pane を切り替えた時に kitty の keybaord protocol が有効になったままになる
      事によって問題が発生するのではないか。更に途中で detach した時にも問題に
      なるのではないか。

      % →これに関しては kitty keyboard protocol は普通のキー操作 (C-b など) に
      % ついては通常通りに送信して、C-S-a 等の従来のシーケンスで区別できなかっ
      % た物だけについて異なるシーケンスを送る物の筈だから問題ないのではないか。
      % 一方で通常の modifyOtherKeys に関しては深刻な問題が起こるのでこの方法は
      % 使えない。
      %
      % これは本当にそうなのか確認する必要がある。一応試した感じではそうだった様
      % な気がする。改めて確認する。
      %
      % →これは確かめて見た所駄目だった。

      つまり、中途半端な状態で抜けると外に抜けた時にまともに操作できないという
      事になる。特に kitty は keyboard protocol に関して push/pop を数えている
      ので外側が ble.sh だったとしても駄目な事になってしまう気がする。

    ? 端末マルチプレクサにも modifyOtherKeys を送るべきだろうか。これについては
      端末マルチプレクサの振る舞いによる。もし tmux が受信したキーシーケンスを
      翻訳して単純なキーシーケンスしか送らない様にしてしまうのであれば tmux に
      もちゃんと modifyOtherKeys を送る必要がある。一方でもしそのまま通過させる
      のであれば特に設定は必要ない。

      これについても tmux, screen の両方について振る舞いを確認する必要がある。

      * うーん。tmux について ble.sh なしで直接 printf して振る舞いを確かめよう
        としたが tmux 自体が何かを送信しているせいか kitty の設定が解除されてし
        まっている? よく分からないので ble.sh つきで確認する事にする。

        と思ったがどうやら tmux は extended-keys を on にしても always にしても
        kitty の送ってくるキーを正しく認識する事ができない様だ。kitty は余分に
        flag 128 を加算している為に tmux が解釈できない function key
        modification と判断して裸の文字にしてしまう。例えば C-r を入力すると
        133=128+4+1 という function key modification になるが tmux はこれを解釈
        不能として 0 にしてしまう。結果として唯の文字である "r" が入力される事
        になってしまう。

      * screen に関しては完全に透過してしまうので modifyOtherKeys 的な入力を
        ble.sh で受け取るのには問題ない。然し、逆に screen が modifyOtherKeys
        に全く対応していないので、外側の kitty の設定が全ての window に対して適
        用される事になる。つまり window を切り替えた時に ble.sh の外側と内側の
        齟齬があると全く動かないという事になる。

        うーん。これは実験的機能として封じて置く必要があるだろうか。

    * tmux に伺いを立ててみる必要があるのではないか。

      * 一方で kitty に関してはどの version からこういう事をするようになったの
        かの確認もしておきたい。或いはずっと前からこの様にしていたのだろうか。
        過去の version をコンパイルするのは面倒なのでソースコードの変更履歴を追
        う必要がある。

      取り敢えず tmux のソースコードを確認してみる。一体何処でこれを処理してい
      るのか。これは意外と簡単に見つかった。然し疑問点が幾つかある。

      * 7 の時だけ IMPLIED_META を付加していないのは何故か。
        https://github.com/tmux/tmux/blob/dc6bc0e95acc04cdf43e869294ecba897a11d850/tty-keys.c#L954

        うーん。IMPLIED_META の説明を読むとどうも ESC による Meta と function
        key modification Alt による Meta を区別する為という様に見える。という事
        を考えると、modifiers 7 で IMPLIED_META が抜けているのは単なるミスでは
        ないか。
        https://github.com/tmux/tmux/blob/dc6bc0e95acc04cdf43e869294ecba897a11d850/tty-keys.c#L114-L118

        更にこちらの配列ではちゃんと IMPLIED_META が付加されている。
        https://github.com/tmux/tmux/blob/dc6bc0e95acc04cdf43e869294ecba897a11d850/tty-keys.c#L258

      * 9 に対しても Meta を付加しているが元からそういう物だったか? 9 は super
        なのではないか。これはもしかすると古い DEC のマニュアルの間違いを引きずっ
        ているのかもしれない。後で調べる必要がある。

        →恐らく問題の変な割当をしているのは xterm のマニュアルだったと思ったが
        今確認すると 8 しかない。という事は 9 は一体何処から出てきたのだろうか。
        他の端末でこの辺りをもっと aggressive に parse していた物がある筈。例え
        ば iTerm2 か vte だった様に思う。それらの実装も確認する必要がある。

        うーん。然し他にもこの様な変な事をしている端末がある様な気がする。

        * vte について調べてみたがこれは 0,2-8 を hardcode していた。
          super/hyper も認識していない。

        * iterm2 については以下の部分で flag を生成している?
          https://github.com/gnachman/iTerm2/blob/698b83ec79d882ee5acb25b7e358680f9db47e01/sources/iTermRawKeyMapper.m#L48-L83

          と思ったが色々と様子がおかしい。lshift, rshift, loption, roption,
          lcontrol, rcontrol,... という具合に bit を割り当てている。これだと滅
          茶苦茶にずれるのではないか。

        * xterm について確認するのが良い気がする。と思ったらここにちゃんと表が
          ある。そして 8 は Meta という事になっている。
          https://github.com/ThomasDickey/xterm-snapshots/blob/13e30fcb98357d456660fdfc74fc86725a49934f/input.c#L358-L373

          向こうにはこの表を提示しておけば良いだろう。

      * kitty の実装について確認を取る。ソースコードが滅茶苦茶なので何処に何が
        あるのかよく分からないがようやく見つけた。どうやら 128 は NumLock だった様だ。
        https://github.com/kovidgoyal/kitty/blob/4c2800b294a4b1189a6f0dfaa236f52d5380bb70/kitty/key_encoding.py#L290
        https://github.com/kovidgoyal/kitty/blob/4c2800b294a4b1189a6f0dfaa236f52d5380bb70/kitty/key_encoding.c#L55-L61

        * done: numlock を解除したらちゃんと普通の数字の範囲で値を返してくれるという事が分かった。

        さてこの numlock がいつ実装されたのかというのを調べてみると 2021-04 で割合最近だ。
        https://github.com/kovidgoyal/kitty/commit/4c644b855649f9de29be4feac89cfeae1b981541

      * mintty で modifier の割当をどうしているのかも確認しておく
        https://github.com/mintty/mintty/blob/b939fa6231ab7f9b5606821135e63d0d22ee3b2e/src/config.h#L7-L8

        | vte    | S, M, C                             |
        | xterm  | S, A, C, M                          |
        | mintty | S, A, C, Win, s, H                  |
        | kitty  | S, A, C, s, H, M, CapsLock, NumLock |

        これについて contra の escseq.html にも追記しておく事にする。

      取り敢えず tmux に変更を提出しておいた。好感触なので何れ merge されるだろう。

    * done: wiki: set -g extended-keys について記述する
    * done: wiki: 新しいオプションについて記述する。注意事項も含める必要がある。
    * done: blerc: 新しいオプションについて記述する。

  * wiki: named prompt sequences についても記述するべきなのではないか [#D1844]

    ./keymap/emacs.sh:138:function ble/prompt/backslash:keymap:emacs/mode-indicator {
    ./keymap/vi.sh:512:function ble/prompt/backslash:keymap:vi/mode-indicator {
    ./src/edit.sh:1016:function ble/prompt/backslash:position {
    ./src/edit.sh:1024:function ble/prompt/backslash:row {
    ./src/edit.sh:1031:function ble/prompt/backslash:column {
    ./src/edit.sh:1038:function ble/prompt/backslash:point {
    ./src/edit.sh:1042:function ble/prompt/backslash:mark {
    ./src/edit.sh:1046:function ble/prompt/backslash:history-index {
    ./src/edit.sh:1050:function ble/prompt/backslash:history-percentile {

    取り敢えずユーザーも使える事を想定したものは記述した。vim-airline の物は本
    来内部使用を意図して実装された物なので省略。

  * vi: status_line ではなく mode indicator 自体を変更する方法を与える (motivated by ferdinandyb) [#D1843]

    mode indicator の部分をプロンプト設定として提供する事にした。

    * done: うーん。vi のモードが変わった時にしか更新されないので、モード以外の
      情報を表示しようとしても次にモードが変更される時にしか更新が走らない。
      仕方がないので PRECMD に update-mode-indicator を登録する事にした。
    * done: emacs の方も同様に設定できる様にするべきの気がする。

    * done: blerc, wiki に記述
      * done: wiki: prompt_emacs_mode_indicator
      * done: wiki: prompt_vi_mode_indicator
      * done: wiki: pointers to prompt_*_mode_indicator in §Edit

2022-07-11

  * term: kitty の keyboard protocol が有効になっていなかった [#D1842]
    https://github.com/akinomyoga/ble.sh/issues/209

    返信を書いている時に kitty の振る舞いを確認していて気づいたのだがちゃんと
    kitty Keyboard Protocol が有効になっていなかった。"push keyboard mode" の分
    岐の条件が反転していた。

2022-07-10

  * complete: "g add newdir/z[TAB]" とするとファイル名が消える [#D1841]

    % 既に登録されているファイルの場合には問題は起こらない様だ。既に登録されて
    % いるファイルがあるディレクトリの中の新しいファイルであっても、そのファイ
    % ルが登録されていない場合にはやはりファイル名が消える→というか改めて試し
    % た所既に登録されているファイルでもやはりファイル名が消える。

    "git add newdir/z[TAB] " の時には問題は生じない。

    これは分かった。COMP_POINT が正しく更新されていない。

      declare -- COMP_LINE="git add lib/i"
      declare -- COMP_POINT="11"
      declare -a COMP_WORDS=([0]="git" [1]="add" [2]="lib/i")
      declare -- COMP_CWORD="2"

    そしてこれは comp_line,comp_point の更新が正しく出来ていない事によると思わ
    れる。と思ったがそうでもない様だ。comp_line, comp_point の時点では変な事に
    はなっていない。つまり最初のコマンドを差し替える時点で COMP_POINT を更新す
    るのを忘れているという事。うーん。と思ったが

      declare -- comp_line="g add lib/i"
      declare -- comp_point="11"
      declare -a comp_words=([0]="git" [1]="add" [2]="lib/i")
      declare -- comp_cword="2"

    となっていて comp_words と comp_line で不整合が生じている。コマンド名を置き
    換える時にちゃんと comp_line, comp_point も置き換える様に修正した。

      declare -- comp_line="git add lib/i"
      declare -- comp_point="13"
      declare -a comp_words=([0]="git" [1]="add" [2]="lib/i")
      declare -- comp_cword="2"

    * 実装してから思ったが単に .compline-rewrite-command を呼び出せば良いだけで
      は。→その様に書き換えた。ちゃんと動作しているのでOK。

  * command-help (ble/widget/command-help/.read-man): ble/util/assign/.rmtmp を忘れている [#D1840]

    0.2 backport 中に気づいた。これは単純に追加すれば良い。

  * encoding:C: 初期化出来ない。大量のエラーメッセージ [#D1839]

    0.2 backport 中に気づいたのだが encoding:C で既に削除された関数
    ble/init:bind/bind-s が使われている。実際に input_encoding=C にして開始して
    みると大量のエラーメッセージが表示されて変な文字列が入力される。
    これは単に改めて関数を追加する事にした。

  * complete: zoxide completion が動かない (reported by ferdinandyb) [#D1838]
    https://github.com/akinomyoga/ble.sh/issues/207

    zoxide も fzf と同様の戦略を用いている。

    * ok: zoxide については (以前試した時の fzf と違って) stdout/stderr をちゃ
      んと繋ぎ変えている様だ? 或いは単に中で呼び出している最新の fzf が
      stdout,stderr を /dev/tty に繋ぎ変えているだけかもしれないが。

    * ok: zoxide は中で \builtin bind や \builtin printf を用いているので振る舞
      いを上書きするのは困難である。builtin を上書きしようにも \builtin local
      も使われている事からこれを関数の中で実行する訳にも行かない。

      或いは printf, bind を enable で一時的に削除するという事も可能かもしれな
      いが色々テストするのが面倒である。

      というより stdout は封じているのだし、bind は特に悪さをするという訳でもな
      い様な気がするので単にそのまま放置していても特に問題は起こらないのでは。
      →取り敢えずそのままにしておいても特に問題は生じていない様な気がする。

    x 生成した候補がちゃんと反映されない。何故だろうか。

      と思ったら分かったかもしれない。何か端末に送信している為に端末からの返答
      が届いていて is-stdin-ready に引っ掛かって補完がキャンセルされている。

      % うーん。そしてそれは恐らく 1 ではなくて独自に開いた /dev/tty 経由で送信
      % されているので抑制する方法がない。

      % → \builtin printf をコメントアウトしたら動く様になった。というか既定で
      % は stdout/stderr は抑制していなかった様な気もする。然し、builtin printf
      % を抑制する方法がないので困る。と思ったが全体を >/dev/null としてしまえ
      % ば良いのでは? 実際にその様にして見たら動く様だ。

2022-07-09

  * fzf kill completion が動かない (reported by ferdinandyb) [#D1837]
    https://github.com/akinomyoga/ble.sh/issues/206

    実際に動かしてみると確かに動かない。呼び出し時の ADVICE_WORDS 及び COMP_*
    の値についても確認してみたが特に違いは見られない。もう一つの違いは呼び出し
    後に COMP_WORDS が書き換えられているという事。

    うーん。_fzf_complete_kill の実装を確認してみると COMP_WORDS を書き換える事
    になっている。つまり、何故か書き換えたか或いは書き換えたのにそれが反映され
    ていないという事になる。もう少し詳しく振る舞いを調べてみる事にする。

    →うーんちゃんと書き換えは発生している。しかし折角書き換えたのにその後でま
    た状態が元に戻ってしまっている様だ。と思ったら分かった。advice を付加した関
    数を入れ子で呼び出しているので、外側で設定した COMP_WORDS が内側で呼び出さ
    れる時に上書きされてしまう。COMP_WORDS が上書きされる事を想定していなかった
    のが原因である。

    x fixed: それでも未だ動かない。と思ったら内部で caller 0 を呼び出している。
      advice を付加した事によって caller がずれているという事。caller のずれは
      修正した。実に 5 段も余分に実行している様だ。更に caller 自身の置き換えも
      含めて 6 段先の caller を参照する事にする。

    x fixed: それとは別に何故か ps で生成しているプロセスのリストの代わりに現在
      のディレクトリ以下にあるファイルのリストが表示されている。

      と思ったが分かった。_fzf_complete の場合は標準入力に候補を流し込んでいる
      事があるので、勝手に /dev/tty に書き換える訳には行かない。使用箇所を確認
      してみた所、_fzf_complete の場合には常に標準入力に対して候補を流し込む使
      い方しかしていない様なので、_fzf_complete の時は標準入力はそのままにする
      事にした。取り敢えず動いている。

2022-07-08

  * history: HISTFILE が空の時は履歴ファイルは無効化する [#D1836]

    HISTFILE が設定されていない時は既定の位置 (.bash_history) に書き込むのでは
    なくそもそも履歴ファイルが無効化される様だ。今まで .bash_history に対して読
    み書きしていたのを修正する。

  * 整数が IFS に含まれている可能性もあるので ${#...} や $((...)) や >&$fd も quote する [#D1835]

    redirection も word-splitting の対象である。今まで数字は空白でないから大丈
    夫と考えていたが IFS に数字が含まれている可能性もある。ble.sh は内部では
    IFS を調整しているとは言え、ユーザーから呼び出した場合なども考えると一律で
    ちゃんと quote する様にするべき。

    grc '[<>]&\$'

    実は $(()) も同様である。現状では $(()) は数字だから quote しなくて良いと考
    えて裸で記述しているが、やはり任意の IFS の可能性を考えると quote するべき
    である。これは物凄く沢山ある。

    grc ' \$\(\('


    grc '([ (])(\$\(\(([^()]|\([^()]*\))*\)\))([; )]|$)' --exclude=docs
    grc '( |=\()(\$\{#([^{}]|\{[^{}]*\})*\})([; )]|$)' --exclude=docs

  * complete: command_not_found_handle が自動補完で呼び出されて操作不能になる (reported by telometto, wisnoskij) [#D1834]
    https://github.com/akinomyoga/ble.sh/issues/203
    https://github.com/akinomyoga/ble.sh/issues/192

    stdin に [y/n] を要求するが ble.sh が stdin をブロックしている為に補完が終
    了できず操作不能になる。

    ? というか入力が受け付けられなくなったとしても C-c だけは効く様にして良いの
      ではないか。

      x 一方で、C-c をそのまま有効にすると ble.sh の処理自体がその場で止まって
        しまう事になる。C-c を trap で捕まえて適切な stack frame まで戻るにして
        も再び DEBUG トラップで複雑な事をしなければならない。

      x そもそも外部コマンドの C-c を正しく検出できるのかという問題もある。C-c
        で外部コマンドだけが終了したとして、その後補完スクリプトがそのまま走っ
        た時に変な事にならないかというのは非自明である。

      x 更に補完の度に stty を呼び出して C-c の状態を変えなければならない。失敗
        すると次に stty を調整する迄 C-c を ble.sh で受信できなくなる。

      うーん。色々考えると C-c を一時的に有効にするというのも余り良い選択肢では
      ない様に思われる。取り敢えずは command_not_found_handle を一時的に無効に
      するしかない。

    * bash-completion の側でも修正するべきか。もし plain Bash では progcomp の
      最中には command_not_found_handle が無効化されるという事であれば
      bash-completion の側で修正は必要にはならない。

      command_not_found_handle() { echo "$FUNCNAME is called"; }


      既に bash-completion で報告されていないか確認する。

      https://github.com/scop/bash-completion/pull/390

      ここで既に議論されている。scop は upstream bash に request できないかとい
      う事を提案している。他にも色々の箇所でそういうのがあるとも述べている。

      と言っても将来的に Bash の側で off にする機能ができるとしても、古い Bash
      は依然として存在するので取り敢えず個別に対応していくべきなのではないかと
      いう気がする。

    取り敢えず command_not_found_handle は function#push する事にする。

    * 2022-07-09 未だ直っていないという (reported by telometto)
      https://github.com/akinomyoga/ble.sh/issues/192#issuecomment-1179191747

      先ずは PackageKit をインストールして動作を確認しようと思ったら既にインス
      トールされている。然し /etc/profile.d/PackageKit.sh を確認してみても存在
      していない。dnf search で検索してみると PackageKit-command-not-found とい
      うのがあったのでそれを入れてみると入った。再現した。

      確かに command_not_found が呼び出されて固まっている。然し、
      command_not_found は一時的に無効化している筈。command_not_found_handle の
      中から呼び出しの構造を調べてみた所、どうやら ble.sh が独自に
      __load_completion を呼び出していてその時に command_not_found_handle が走っ
      ている様だ。つまり、__load_completion を呼び出す時にも workaround で
      command_not_found_handle を無効化する必要があるという事。

      ? __load_completion を呼び出す時には別に tty を封じてはいなかった様な気が
        するが固まるのは何故だろうか。うーん。不思議だ。確認した所、&>/dev/null
        で寧ろ入力ではなくて出力の方を組み替えている。なのに出力は出来て入力は
        できないというのも変な事である。

    * 2022-07-09 使っていたら元から command_not_found_handle が定義されていなかっ
      た時に pop 時に問題が発生する。これは ble/function#{push,pop} の実装の問
      題である。

      これは function#push 時に関数定義を与えなかった時に関数を unset する機能
      を導入した時の手落ちと考えられる。調べてみるとこれは a41279e (#D1720) に
      おける変更である。この時に一応 function#pop に対しても対応する変更がなさ
      れているが、それが不完全だったという事。

    * 2022-07-10 "bash: return: echo: numeric argument required"
      https://github.com/akinomyoga/ble.sh/issues/208

      これはミスだ。修正する。

2022-07-07

  * main: fd 0, 1 が TTY かどうかのチェックが常に偽になっている [#D1833]
    Ref #D1749

    ble-0.3 に 711c69f (#D1749) を backport している途中に気づいた。今までは
    /dev/tty もチェックしていたので、このチェックに失敗しても問題が表面化してい
    なかっただけ。ble-0.3 で /dev/tty のチェックをスキップする様にしたら問題が
    表面化した。ble-0.3 に対して行ったのと同じ修正を適用する。

2022-07-06

  * main, decode: ble-attach & set -e [#D1832]

    bash -e で開始した時は寧ろ --attach=prompt でないと駄目な事が分かった。
    ble-0.3 及び ble-0.4 で再現した。--attach=prompt を指定していても bashrc 内
    部で手動で ble-attach すると失敗する。

    うーん。これは ble/decode/.hook で set +e したら回避できるだろうか→どうや
    ら回避できる様だ。-e も勝手に無効にはなっていない。

    x これは文法エラー等によって状態回復に失敗した時に次の ble-decode/.hook の
      呼び出しの時に set -e が消滅する原因になり得るが、その様な事は余り起こら
      ないし起こったとしてもそもそも対話セッションで set -e を設定する事の方が
      変だから基に思案くても良い?

      a 或いは attach した直後だけは set +e を実行する様に変更する? 然し、
        attach した直後かどうかを判定するのにまた処理時間を食う気がするし、微妙
        な気がする。

      b 或いは別の hook に登録するという可能性もある。

      c 周りのコードを見渡してみたら既に set +v をしている部分がある。#D0930 が
        対応する項目である。確認してみたら今回の -e と同様の事が書かれている。
        うーん。前回のコマンドで解除に失敗した時にどうなるのかは非自明だが取り
        敢えずここに set -e を追加しておけば良い気がする。

        前回のコマンドで解除に失敗した時にはそもそもその場で errexit して終了し
        てしまう筈なので、再び .hook が呼び出される事もない気がするので気にしな
        くて良い気がする。

      取り敢えず c の方針を使う様に修正した。改めてちゃんと動くか確認する→OK

2022-07-05

  * bash: history timestamp に問題がある時に history の初期化が正しくない (reported by johnyaku) [#D1831]
    https://github.com/akinomyoga/ble.sh/issues/202

    bash がエラーメッセージを出力する (bash-5.0+) または segfault する
    (bash-4.4-)。現状ではエラーメッセージがそのまま履歴に混入してしまっている。
    うーん。stderr も読み取ってしまっているのかと思ったが実際に試してみるとエラー
    メッセージが stdout に出力されている。

    % これは後で bash に提出する。
    %
    % * reject: bug-bash: HISTTIMEFORMAT=%s history でエラーメッセージが stdout
    %   に混入するエラーメッセージは stderr に出力するべきなのではないか。
    %
    % と思ったがこの文字列はエラーメッセージとしてではなく履歴時刻の文字列の代
    % わりに埋め込まれているという事が判明した。という事はやはり history の出力
    % の中にメッセージを埋め込むべきという事なのかもしれない。

    取り敢えず問題のエラーメッセージは正規表現によるパターンで除去する事にする。

    * fixed: 更に履歴を書き込む時にも問題になっている。これも修正した。

    * done: 履歴読み込み時に invalid timestamp を検出したらそれを vbell で報告
      する様にする。

    これで bash-5.0+ 以降でエラーメッセージが履歴に紛れ込むのは修正した。一方で
    bash-4.4 以下で segfault してしまうのに対する対策は難しいのではないか。一応
    終了ステータスを確認する事で segfault した事は検出できるが、もし検出したと
    してどの様に対処するのが良いか。例えば、HISTTIMEFORMAT なしで改めて履歴を読
    み直す事にする? 履歴行の境をどの様に判定するべきだろうか。或いは、エラーを
    検出した時に vbell に表示してしまって、history の状態は壊れた状態でも仕方が
    ないという事にする? それが良い気がする。

    * 実際にエラーになった時に問題の行を指摘したい。

      どの様な形式の時にエラーになるのか調べようとしたがよく分からない。先ず、
      そもそも数字でない場合には timestamp 行として認識されない。数字の後にごみ
      が入っていてもそれらは単に無視される。得に巨大な数が指定された時に於いて
      問題が生じる様である。問題が起こる最小の整数を探索すると
      67768036191644399 であった。これは16進数で見ても特に特別な数ではない
      (0xf0c2ab7c542aef)。検索してみたらどうもやはり時刻関係で特別な数字の様で
      はある。

      > https://mevius.5ch.net/test/read.cgi/unix/1590454119/
      >
      > 115名無しさん＠お腹いっぱい。2020/06/01(月) 17:52:40.57
      > macos での限界
      > $ date -r 67768036191644399
      > 2147485547年 12月31日 水曜日 23時59分59秒 JST
      > $ date -r 67768036191644400
      > date: localtime: Value too large to be stored in data type

      実際手許の date で試してみても同様である。

      $ date --date=@67768036191644399
      $ date --date=@67768036191644400

      これは一体何が決めているのだろうか。と思ったらどうも 2147485547 年という
      のは1900 + 0x7FFFFFFF らしい。つまり localtime で時刻構造体に変換する時に
      代入できないという状態になるという事だ。

      https://www.wdic.org/w/TECH/21%E5%84%844748%E4%B8%875548%E5%B9%B4%E5%95%8F%E9%A1%8C

      67768036191644399 で検索して日本語のページが幾つかしか出てこないのは
      upper bound が TZ に依存するからである。

      さて、TZ に依存するのだとすればこの数値を threshold に選ぶ事はできない。
      それに正規表現で判定できなければ問題の行の検出に於いて不都合である。更に、
      この上限の値は time.h の実装にも依存するのではないだろうか。

    更に bash-3.2 以下では無限ループになる。関係ない無限ループかもしれないと思っ
    たが実際に履歴の timestamp に問題がある時にのみ無限ループになる。何処で無限
    ループになっているか確認する。

    →実際に ble.sh なしで試して見た所、単に history を実行しただけで無限ループ
    になって固まってしまう。これに対する対策は難しい気がする。。builtin history
    を呼び出すあらゆる操作で問題が起こる可能性があるという事になるのであるから。

    * done: bash-3.2: history の読み出しに使っている部分だけ conditoinal-sync で呼び出す。

      conditional-sync で timeout を設定してみたがやはり 100% になってしまう。
      という事は関係ない別の history -n 等でも全て無限ループになっているという
      事か。と思ったが手許で実行している限りは特に無限ループにはならない。

      →と思ったら分かった。.get-min で history | head -1 を呼び出している。こ
      の history で無限ループになっている。

    ? ok: 実際に conditional-sync で呼び出してみたところ timeout よりも断然早く
      中断する。何かと思ったら conditional-sync 経由で呼び出した時には無限ルー
      プにならずに 300ms 程度でちゃんと終了する様である。何故だろうか。

      もしかすると conditional-sync を使わなくても subshell ならばちゃんと終了
      する可能性? と思ったが、元より問題になる箇所では subshell を使っていた。
      なので、bg で動かした時にだけ無限ループにならないという事だろうか。だとし
      たらやはり conditoinal-sync 経由で呼び出して置くのが楽である。

    取り敢えず bash-3.2 でも固まらなくなった。OK

  * edit: プロンプト評価時に LINENO は一時的に現在の行番号に設定するべき [#D1830]

    →これは DEBUG を PREEXEC に使っている設定でも重要になる。
    うーん。DEBUG trap を呼び出す時にも設定するべきだろうか。
    →DEBUG trap を呼び出す時にも LINENO を設定する事にした。

2022-06-28

  * contrib/prompt-git: untracked content は赤ではない色で表示する for submodule [#D1829]
    →untracked files in submodule は単に無視するオプションがあったのでそれを使う事にする。

  * contrib/config/execmark: 同じ行に errexit を表示していると気づきにくい [#D1828]
    →分けて表示する様にした。

  * global: awk -v var=value を介して任意の文字列を渡さない [#D1827]

    awk の -v で任意の文字列を渡すことはできない。"" の中であるかのように \? が
    処理されてしまうので。文字列をそのまま渡したければ ENVIRON を使うしかない。

  * util: ble/string#split-words 最適化 [#D1826]

    どうも頻繁に呼び出される割に其処まで早い訳でもない様なので速度について確認
    する。うーん。多少弄ったら結構速度が変わったので採用する事にする。

    * 既存の呼び出しで引数を複数渡している場合はあるだろうか? →ない様なので分
      割文字列の引数は一つしか渡されないと仮定して良い。

    * ble/string#split も同様に最適化する。ble/string#split に関しても対象文字
      列の引数は必ず単一の様なので、それを仮定する。

    * 序に ble/util/assign & ble/string#split-words のパターンは関数にしてしま
      う。

    * done: refactor: ble/debug/profiler/{end => stop}
    * done: ble/debug/profiler: varleak nline
    * done: ble/debug/profiler: $prefix.line.txt の行番号の形式変更

    * 古い benchmark のスクリプトも追加する事にした。

2022-06-27

  * util (eval-pathname-expansion): bash-4.0以下で shopt *glob がクリアされる [#D1825]

    ble-0.3 backport で見ていたら気づいた。BASHOPTS (Bash 4.1+) を使って shopt
    の状態を記録しているが、Bash 4.0 以下に対する分岐がない。0da0c1c で埋め込ま
    れたバグである。visible-bell 消去時に glob 関連の shopt が全て unset されて
    しまう事になる。修正した。

    * 他の BASHOPTS 使用箇所は問題ないか → 他には ble.pp で使っているだけであ
      る。そして ble.pp の使用箇所ではちゃんと分岐している。

2022-06-26

  * debug: profiling 機能 (motivated by SuperSandro2000) [#D1824]

    LINENO を先ず何とかする。LINENO=... eval '...' とすれば一時的に LINENO を置
    き換える事が可能なのではないか。と考えたが、どうやら以前発見した bash の
    bug である tempenv=... builtin eval -- 'echo;echo $tempenv' で tempenv が消
    滅するバグの為に期待通りに動かない様だ。

    うーん。workaround の方法はあるだろうか?

    a ここの eval は builtin を使わずに呼び出す? → eval の上書きを現状では許可
      しているがこの対応を除去する必要がある。これは避けたい。バージョンごとに
      この対策を切り替えるのも面倒である。

    b eval を二重にしたら回避できる可能性はあるだろうか → 駄目だ。うーん。駄目。

      $ e=1234 builtin eval 'builtin eval ":;echo \$e"'
      $ e=1234 builtin eval 'e=1234 builtin eval ":;echo \$e"'

    c adjust-builtin の restore を遅延させて eval の内部で実行する可能性? → と
      思ったら既にその様になっていた。なので builtin eval にしなくても良い。

    時間を合計するプログラムを書いてみたが何だか振る舞いが変だ。そもそも関数呼
    び出しをしているのに + の数が増えていない気がする。うーん。説明を見ると
    levels of indirection と書いてあるがこれは何か確認する必要がある。→動作を
    見たら関数呼び出しでは増えない様だ。つまり、eval 等の数しか数えないという事。
    入れ子をちゃんと処理する為には + の数に加えて FUNCNAME の要素数も数える必要
    がある? FUNCNAME は関数の内部でしか有効にならず関数内に入るとトップレベルコ
    ンテクストの名前 (main) と共に要素数が2増えるので、代わりに常に存在している
    BASH_LINENO の要素数を数える事にする。

    * done: 関数毎の統計も取る
    * done: 前回の記録を最初に読み出す
    * done: % を表示する
    * done: 前回の記録が複数の物を cat した物の場合にも対応
    * done: PS4, bleopt の設定を待避・復元する → この為には ble/base/xtrace で
      hook する必要がある →

      a bleopt の設定については勝手に色々変わるのも変なので弄らない?

        PS4 はユーザーが使いたいかもしれないので待避するのは確定。bleopt の設定
        については xtrace/{adjust,restore} の度に動的に変わるのも変なので、やは
        り ble/debug/profiler/start した時に設定してそのままにしておくのが良い
        のではないか?

        →然しそうすると profiling 中にユーザーが間違って debug_xtrace{,_ps4}
        を設定した時に動作が変になるのでは。しかし、ble/debug/profiler を動かし
        ている最中にこれらの設定を勝手に変更するのがおかしいとも言える。特に
        ble/debug の同じ名前空間に属していると思えば ble/debug/profiler を介し
        て debug_xtrace{,_ps4} を動かしていると思っても良いのかもしれない。

      b 或いは profiler が設定されているかどうかの変数を ble/base/xtrace で見て
        処理を切り替える?

      c 或いは blehook xtrace_{adjust,restore} を追加する? →これは overhead が
        増えるし、もしこれで実装するとしても bleopt をその場で切り替える様な実
        装になって何だか変な気がする。其処までする必要もない。

      ble/debug/profiler で bleopt debug_xtrace_{,_ps4} を書き換える実装で良い。

    * done: blerc, wiki

2022-06-20

  * history: bind のエラーメッセージ in 非対話シェル (reported by wukuan405) [#D1823]
    https://github.com/akinomyoga/ble.sh/issues/200

    これは単に bash が警告を出しているだけである。念の為、確認してみたが、bind
    set 及び bind -v は共に動作している。

2022-06-19

  * history: erasedups を制限する機能 (motivated by SuperSandro2000) [#D1822]
    https://github.com/akinomyoga/ble.sh/issues/198

    * done: 初期化時の履歴の個数を記録しておく。

    うーん。これを実装する為には一時的な erasedups の除去がちゃんと history -s
    の動作に反映されている必要がある。そして反映されないという変な事がある様に
    は思われない→実際に動かして試してみたが特に変な振る舞いはしない。ちゃんと
    その時の HISTCONTROL に従って動作していると見て良いだろう。

    * done: history_erasedups_limit に従って探索の範囲を決定する。

    実装した。動作確認した。ちゃんと動いている様な気がする。意外と高速に動作す
    る。探索範囲が 20k/100k ぐらいになって漸く awk よりも遅くなる。現実的には一
    つの session で 20k もコマンドを打つ事はないだろうから気にしなくて良いだろう。

    2022-06-20 コードを眺めていたら無限ループのパスがある。関数名を書き換える時
    に修正し忘れていた。直す。

  * decode: ble-bind -P の出力で -c binding が変だ。引用符が余分についている [#D1821]

    ble-bind -m 'vi_nmap' -c C-z \'fg\'

    v0.3 では特に問題はない様だ。修正した。

  * decode (bind): inputrc に含まれる # の処理 [#D1820]

    % 変数によって処理したり処理しなかったりの様だ。特に文字列を受け取るオプショ
    % ンに関しては # 以降の削除はされない。一方で on/off のオプションの場合には
    % '#' 以降は無視されている様に見える。→と思ったが違った。単に最初の空白で
    % 切っているだけだった。

    Bash-5.1 以降では on/off オプションについては空白で区切った最初の単語だけを
    見る。Bash-5.0 以前は (# が含まれていたとしても) 全体を見る。うーん。ble.sh
    内部では勝手に '#' 以降を削除してから処理しているがこれは正しくない。後で修
    正する。これは 0.3 以前に遡って適用する。

  * util: rlvar enable-bracketed-paste off に対応する (motivated by ArianaAsl) [#D1819]
    https://github.com/akinomyoga/ble.sh/discussions/199

    rlvar を直接使う事にすると古い bash で設定を保持できないので bleopt で管理
    する事にして、bind enable-bracketed-paste は別名として取り扱う事にする。

    * done: bleopt 変数は rlvar とは独立に既定の値を持つ。初期化時に rlvar が既
      定と異なる値を持っている場合にはユーザーが設定したと見做してその設定を読
      み取る。

    * done: Bash が enable-bracketed-paste に対応している時には、bleopt の側の
      変数への設定時に同時に enable-bracketed-paste の値を調整する。

    * done: bind は既に上書きしているので enable-bracketed-paste に値を設定する
      のに介入するのも実装できる。enable-bracketed-paste に対する値の設定は
      bleopt への設定に読み替える事にする。rlvar は bleopt 経由で書き換える事に
      する。

    * done: この仕組を一般化して他の rlvar についても bleopt alias を作成できる
      様にする。これは一旦 enable-bracketed-paste に対応した後で考えれば良い。

    * done: wiki (skip-completed-text は更新)
    * done: blerc

2022-06-18

  * emacs: MULTILINE mode メッセージの改善 (motivated by ArianaAsl) [#D1818]
    https://github.com/akinomyoga/ble.sh/discussions/199

    * done: Q&A に書く。

    * done: MULTILINE モードの表示をしない様にする設定
      →keymap_emacs_show_multiline という設定変数名を追加した。

      * やはり MUTILINE モード名自体を設定する設定項目にする方が良い。
        keymap_vi_mode_string_nmap との一貫性により。設定変数名は
        keymap_emacs_mode_string_multiline に変更する事にした。

    * done: MULTILINE モードの表示メッセージを binding によって変える

    * rlvar enable-bracketed-paste の設定の alias bleopt を作成してそれを上書き
      する。この方法はその他の補完設定に対しても適用するべきなのではないか。独
      立した項目で全体的に対応する事にする。

2022-06-17

  * util: erasedups 高速化 (motivated by SuperSandro2000) [#D1817]
    https://github.com/akinomyoga/ble.sh/issues/198

    一旦ファイルに書き出して awk で処理してから読み出す方式を試してみた。然し単
    に配列を走査するよりも遅くなってしまった。

    計測してみると awk による処理自体は高速だが書き出しと読み取りの両方で滅茶苦
    茶時間がかかっている。printf '%s\n' "${arr[@]}" は遅いのだった。また、
    mapfile -d '' も内部では1文字ずつ読むモードに切り替わってしまうのか遅い。こ
    れは bash-5.2 以降でしか高速ではないのだった。

    過去に同様の事をした気がする → #D1522 が対応する議論であった。

    awk による処理は十分に高速の様だ (45ms)。読み取りは nlfix にすれば無視でき
    るぐらいコストを小さくできる筈 (改行が大量に含まれていない限り)。

    * done: 書き出しの高速化に関して。

      printf '%s\0' が遅いので writearray を実装した筈なのに
      writearray を確認してみたら遅い。これは別項目で考える事にする。

      或いは history の出力を改めて解析した方が余程早いのではないか。と思ったが
      history の出力が編集されていると微妙である。基本的には history の出力を使っ
      て _ble_history を作っているのだから (そして勝手に Readline の編集が起こっ
      ていなければ)、_ble_history の内容と history の出力結果は一致している筈で
      ある。一方で、_ble_history_edit の内容に関しては結局配列として出力しなけ
      ればならない。_ble_history の書き出しと _ble_history_edit の書き出しを並
      列で実行するのだとしたら、_ble_history の側だけを history の出力を使って
      高速化しても余り意味がない。

    うーん。どうにも書き込みは並列で書き込むとしても精々 170 (printf) までしか
    減らせない。更に bash-5.2 では printf は 455 もかかる。mawk でも 434 である。
    なので、bash-5.2 だと絶望的である。元々直接ループを回していた時で 790 であ
    る。高速化はしているが、結局大して高速化は期待できないのではないか。特に
    5.2 以降で高速化しないのであれば古い ver で頑張る意味もない。

    * done: 5.2 未満では nlfix で読み取らせる事にした。以下テスト用コード

      {
        ble/debug/stopwatch/start
        ble/debug/stopwatch/stop 'save-data' >/dev/tty
        ble/debug/stopwatch/start
        ble/debug/stopwatch/stop 'proc-data' >/dev/tty
        ble/debug/stopwatch/start
        ble/debug/stopwatch/stop "load-data (${#_ble_history[*]}, ${#_ble_history_edit[*]})" >/dev/tty
        # DEBUG
        local dup=$( ( ( time ble/builtin/history/option:s/erasedups "$cmd"
                         declare -p _ble_history _ble_history_edit | sha256sum)
                       ( time ble/builtin/history/option:s/erasedups.awk "$cmd"
                         declare -p _ble_history _ble_history_edit | sha256sum) ) | uniq -u)
        ble/builtin/history/option:s/erasedups "$cmd"
        if [[ ! $dup ]]; then
          echo "${#delete_indices[@]}: ok"
        else
          echo "${#delete_indices[@]}: ng"
          echo "$dup"
        fi >/dev/tty
      }

    * done: awk0 が使えない場合には書き出しも nlfix にしてしまう?

      →その様に実装してみた。nawk は遅くなる。mawk と gawk は十分な速度が出て
      いる。それでも \0 の時よりは遅くなる様である。というか、mawk と gawk は結
      局 \0 に対応しているので、この nlfix は実際の所使われる事はないという事に
      なる。

    * 別の可能性として erasedups で探索する範囲を制限するという事も考えられる。
      Bash の erasedups は一時的に off にして、手動で見つかった項目を Bash のコ
      マンド履歴からも削除するということ。探索範囲については、例えば起動時の
      history の大きさを記録しておいて、それ以降に追加された項目のみを検査する
      等。うーん。これは別項目として独立させる事にする。

  * util: ble/util/writearray 最適化 [#D1816]
    Ref. #D1817

    やはり巨大な配列になると書き出しが最も遅い。

      printf '%s\0' "${_ble_history[@]}"       ...  365ms
      ble/util/writearray -d '' _ble_history   ... 1387ms (mawk だと速い?)
      ble/util/writearray --nlfix _ble_history ... 1397ms

    と思ったら mawk を使っている場合には writearray も高速なのであった。nawk
    と gawk ではとても遅い。#D1522 を見たら多少改善したと書かれているがそうで
    もなかったという事だろうか。改めて注意深く計測してみる事にする。→うーん。
    単に mawk がコンパイルに失敗して動作していないだけだった。

      bash-5.1
      [  0.170960 sec] write by printf
      [  0.035244 sec] write by declare -p
      [  0.236600 sec] write by ${_ble_history[@]@Q}
      [  0.677771 sec] write by nawk
      [  0.428015 sec] write by mawk
      [  1.804527 sec] write by gawk
      [  0.689799 sec] write by nawk --nlfix
      [  0.421999 sec] write by mawk --nlfix
      [  1.806602 sec] write by gawk --nlfix

      bash-5.2
      [  0.455534 sec] write by printf
      [  0.023524 sec] write by declare -p
      [  0.690759 sec] write by nawk
      [  0.434321 sec] write by mawk
      [  1.810687 sec] write by gawk
      [  0.693987 sec] write by nawk --nlfix
      [  0.423758 sec] write by mawk --nlfix
      [  1.832763 sec] write by gawk --nlfix

    a writearray の awk 高速化?

      うーん。やはり writearray の awk を高速化できないだろうか。何処で時間が
      かかっているのかを確認する。

      % 先ず全ての文字列を連結しているがこれが遅い可能性は?
      %
      %   連結部分の時間
      %   [  0.041765 sec] write by nawk
      %   [  0.061284 sec] write by mawk
      %   [  0.032100 sec] write by gawk
      %
      % 無視できる訳でもないが全体の処理時間に比べればずっと小さい。これの最適化
      % も考えたい気がするが、これは後でも良い気がする。
      %
      %   declare除去終了時刻
      %   [  0.049391 sec] write by nawk → 8ms
      %   [  0.062445 sec] write by mawk → 1ms
      %   [  0.036025 sec] write by gawk → 4ms
      %   全体quote除去 終了時刻
      %   [  0.059244 sec] write by nawk → 10ms
      %   [  0.062717 sec] write by mawk → 0ms
      %   [  0.045702 sec] write by gawk → 9ms
      %   bashバグ調整 終了時刻 (Bash 5.1 では何もしない筈)
      %   [  0.059713 sec] write by nawk → 0ms
      %   [  0.062856 sec] write by mawk → 0ms
      %   [  0.045834 sec] write by gawk → 0ms
      %   変数名除去等 終了時刻
      %   [  0.079104 sec] write by nawk → 10ms
      %   [  0.078687 sec] write by mawk → 16ms
      %   [  0.136127 sec] write by gawk → 91ms
      %
      % この文字列の全体処理の時点で
      %
      %   [  0.079104 sec] write by nawk →  38ms
      %   [  0.078687 sec] write by mawk →  17ms
      %   [  0.136127 sec] write by gawk → 104ms
      %
      % だけ処理に時間がかかっている。うーん。これはもっと短くできる気がする。末
      % 尾の処理に関しては最後にならないと分からない。先ずは入力を結合せずに配列
      % に保持するなどして、結合する前に適用するのが良い様な気もする。これは何れ
      % にしても結合部分を最適化してから考えるのが良い気がする。
      %
      % →よく考えてみれば、そもそも declare -p は1行しか出力しないのでここで
      % 実際に連結が大量に行われるという事はない。なので、この最初の部分をもっ
      % と小さな文字列に分解して処理するという方向での高速化はできない。

        dq判定直前
        [  0.079104 sec] write by nawk
        [  0.078687 sec] write by mawk
        [  0.136127 sec] write by gawk
        dq判定直後
        [  0.089831 sec] write by nawk
        [  0.076440 sec] write by mawk
        [  0.146535 sec] write by gawk
        split直後
        [  0.211504 sec] write by nawk → 122
        [  0.091142 sec] write by mawk → 15
        [  0.230322 sec] write by gawk → 84

      うーん。後は普通に loop に時間がかかっているという事

        配列添字の除去直後でcontinueした場合
        [  0.443631 sec] write by nawk → 232
        [  0.130103 sec] write by mawk →  39
        [  0.348103 sec] write by gawk → 118
        matchループ直後でcontinueした場合
        [  0.657334 sec] write by nawk → 214
        [  0.412463 sec] write by mawk → 282
        [  1.758804 sec] write by gawk → 1410

      うーん。これの高速化は難しい様な気がする。正規表現をやめて一文字ずつ処理
      する様にしたら更に悪化しそうな気がする。

      * reject: 微妙に弄ってみる事にする。元々の時刻を測っておく。

        [  0.698775 sec] write by nawk
        [  0.424295 sec] write by mawk
        [  1.823190 sec] write by gawk

        うーん。split を /" / で実行したら良いのではないかと考えたが
        [1]=$'...' の形式等もあるので /" / だけで分割するという訳にも行かない。
        だからと言って /['"] / で分割してしまうと、其処にあった文字が ' だっ
        たのか " だったのかの情報が失われてしまう。なので、この案は駄目だ。

        一応、結果が変わってしまうが /" / で分割して処理した時の時間を見てお
        く。一応高速化はちゃんとする様である。

        [  0.391338 sec] write by nawk
        [  0.269026 sec] write by mawk
        [  1.267509 sec] write by gawk

      やはり writearray の awk をこれ以上高速化する方法はない様な気がする。既
      にほぼ最速の実装になっているという気がするのである。

      * 先に数十の単位で連結を行って多少復元してから処理を行う? それでも連結
        コストはかかるしうーん。どうなのだろうか。

        元のコード

          function analyze_elements_general(decl, _, arr, i, n, str, elem) {
            nlfix_indices = "";
            nlfix_index = 0;
            n = split(decl, arr, / /);
            for (i = 1; i <= n; i++) {
              str = arr[i];
              sub(/^\[[0-9]+\]=/, "", str);
              elem = "";
              while (1) {
                if (match(str, /'"$rex_dq"'|'"$rex_es"'|'"$rex_sq"'|'"$rex_normal"'|^\\./)) {
                  mlen = RLENGTH;
                  elem = elem unquote(substr(str, 1, mlen));
                  str = substr(str, mlen + 1);
                } else if (str ~ /^[$"'\''\\]/ && i + 1 <= n) {
                  str = str " " arr[++i];
                } else {
                  break;
                }
              }

              _process_elem(elem);
            }
            if (FLAG_NLFIX)
              printf("%s\n", nlfix_indices);
            return 1;
          }

          [  0.723085 sec] write by nawk
          [  0.430691 sec] write by mawk
          [  1.822919 sec] write by gawk

        N個ずつ処理する時

          function analyze_elements_general(decl, _, arr, i, n, str, elem) {
            nlfix_indices = "";
            nlfix_index = 0;

            n = split(decl, arr, / /);
            str = "";
            elem = "";
            first = 1;
            for (i = 1; i <= n; i++) {
              str = str " " arr[i];
              if (i % 5 != 0 && i != n) continue;
              while (1) {
                if (sub(/^ (\[[0-9]+\]=)?/, "", str)) {
                  if (first)
                    first = 0;
                  else
                    _process_elem(elem);
                  elem = "";
                } else if (match(str, /'"$rex_dq"'|'"$rex_es"'|'"$rex_sq"'|'"$rex_normal"'|^\\./)) {
                  mlen = RLENGTH;
                  elem = elem unquote(substr(str, 1, mlen));
                  str = substr(str, mlen + 1);
                } else {
                  break;
                }
              }
            }
            _process_elem(elem);

            if (FLAG_NLFIX)
              printf("%s\n", nlfix_indices);
            return 1;
          }

          5個ずつ処理する時
          [  0.729255 sec] write by nawk
          [  0.368347 sec] write by mawk
          [  1.642443 sec] write by gawk
          10個ずつ処理する時
          [  0.714652 sec] write by nawk
          [  0.347246 sec] write by mawk
          [  1.636028 sec] write by gawk
          100個ずつ処理する時
          [  0.727583 sec] write by nawk
          [  0.371555 sec] write by mawk
          [  1.678000 sec] write by gawk

        "]=" で分割する作戦

          "]=" で分割する時
          [  0.438765 sec] write by nawk 39% speedup
          [  0.303779 sec] write by mawk 30% speedup
          [  1.378912 sec] write by gawk 24% speedup
          "]=" で分割する時/2個ずつ
          [  0.443567 sec] write by nawk
          [  0.305656 sec] write by mawk
          [  1.368339 sec] write by gawk
          "]=" で分割する時/5個ずつ
          [  0.456370 sec] write by nawk
          [  0.306033 sec] write by mawk
          [  1.400369 sec] write by gawk

          ループの仕方を多少工夫
          [  0.385840 sec] write by nawk
          [  0.283110 sec] write by mawk
          [  1.295154 sec] write by gawk

          この方法で思ったよりは高速になった。

      * unquote_dq の最適化

          gawkでgensub を使う様に変更
          [  0.388626 sec] write by nawk
          [  0.282651 sec] write by mawk
          [  1.015230 sec] write by gawk
          gsubによる実装に変更
          [  0.356890 sec] write by nawk
          [  0.218238 sec] write by mawk
          [  1.016223 sec] write by gawk
          unquote判定の簡略化
          [  0.348118 sec] write by nawk
          [  0.213385 sec] write by mawk
          [  0.990123 sec] write by gawk
          [  0.367019 sec] write by nawk
          [  0.211183 sec] write by mawk
          [  1.001340 sec] write by gawk
          [  0.346388 sec] write by nawk
          [  0.211842 sec] write by mawk
          [  1.005543 sec] write by gawk

    b reject: ${_ble_history[@]@Q} を解析する可能性?

      うーん。或いは declare -p は諦めて ${_ble_history[@]@Q} の結果を解析する
      方が簡単で良い? と思ったがこれはこれで処理に時間がかかりそうな予感がする。
      何より split が非自明である。

      a 単に /' \$?'/ で split すれば良いのか、というと違う気がする。うーん。或
        いは実はそれで行ける? 落ち着いて考える…やはり駄目だ。これだと $ があっ
        たかどうかの情報が失われてしまう。

      b /' '/ で split して更にその後で /' \$'/ で split する? うーん。問題は関
        係ない物を誤って split してしまわないかという事。例えば 'a'\'' ' 'b' と
        なっていた場合違う所で split してしまう。結局繰り返し match が必要にな
        るので処理が重くなる気がする。

        或いは先に '\'' を適当に処理してしまう (置換して別の文字にするなど)? と
        思ったが今度は $'\n\'\'' 等に於いて関係ない '\'' をひっかけてしまう。

      更に ${_ble_history[@]@Q} の評価自体も別にそれほど高速という訳でもない。
      200ms かかっている。やはり declare -p の 35ms には勝てないのである。

    c 或いは高速化の為に C で処理するプログラムを書いてしまうのも手なのかもしれない。
    d もしそうするのであれば寧ろ bash loadable builtin にしてしまう?

      これらの処理を実装するのだとしたらもっと広範に渡って bottleneck を C /
      builtin 実装に置き換えたい気がする。

    以下テストに用いたコード

    {
      # 計測結果
      (
        ble/debug/stopwatch/start
        printf '%s\0' "${_ble_history[@]}"      >| "$itmp1"
        ble/debug/stopwatch/stop "write by printf" >/dev/tty

        ble/debug/stopwatch/start
        declare -p _ble_history >| "$itmp1"
        ble/debug/stopwatch/stop "write by declare -p" >/dev/tty

        ble/debug/stopwatch/start
        echo "${_ble_history[@]@Q}" >| "$itmp1"
        ble/debug/stopwatch/stop "write by \${_ble_history[@]@Q}" >/dev/tty

        ble/bin/awk() { "$_ble_bin_awk_type" -v AWKTYPE="$_ble_bin_awk_type" "$@"; }
        for _ble_bin_awk_type in nawk mawk gawk; do
          ble/debug/stopwatch/start
          ble/util/writearray -d '' _ble_history >| "$itmp1"
          ble/debug/stopwatch/stop "write by $_ble_bin_awk_type" >/dev/tty
        done

        for _ble_bin_awk_type in nawk mawk gawk; do
          ble/debug/stopwatch/start
          ble/util/writearray --nlfix _ble_history >| "$itmp1"
          ble/debug/stopwatch/stop "write by $_ble_bin_awk_type --nlfix" >/dev/tty
        done
      )

      #_ble_bin_awk_type=nawk
      #_ble_bin_awk_type=mawk
      _ble_bin_awk_type=gawk
      ble/bin/awk() { "$_ble_bin_awk_type" -v AWKTYPE="$_ble_bin_awk_type" "$@"; }
      ble/util/writearray -d '' _ble_history      >| "$itmp1" & local pid1=$!
      ble/util/writearray -d '' _ble_history_edit >| "$itmp2"
      wait "$pid1"
      cat "$itmp1" "$itmp2" | tr '\0' '\n' > 1.txt
      printf '%s\0' "${_ble_history[@]}"      >| "$itmp1" & local pid1=$!
      printf '%s\0' "${_ble_history_edit[@]}" >| "$itmp2"
      wait "$pid1"
      cat "$itmp1" "$itmp2" | tr '\0' '\n' > 0.txt
      command diff -u 0.txt 1.txt > 1.diff
      command rm 0.txt 1.txt
    }

  * [実装済] 2018-03-14 emacs: C-w を続けて実行すると kill-ring に追記にするべき [#D1815]

    古い項目。これは既に実装されている。

2022-06-15

  * github/workflows: nightly build (contributed by uyha) [#D1814]
    https://github.com/akinomyoga/ble.sh/pull/197

    色々勝手に建て増しした。nightly build のページに情報を載せた。nightly build
    の ble-update ではnightly build を取得する様にした。動作確認もした。
    file#hash の取得に使うコマンドは動的ではなくて初期化時に freeze する様にし
    た。序でに ble/util/getmtime -> ble/file#mtime に改名して初期化を遅延させる
    様にした (これで初期化時の fork/exec は一つ減っただろう)。

2022-06-13

  * util (fd#alloc): fd の上限に達した時にどうするか。無限ループになるのではないか [#D1813]

    取り敢えず 1024 の探索上限を入れた。探索範囲に見つからなかった時には、元々
    の _ble_util_openat_nextfd の上に開く事にする。

    2022-06-15 見ていたら誤りを見つけたので追加修正する。

  * test: CI にテストを載せる上で既知の false error は全て潰しておく必要がある [#D1812]

    今まで CI テストを実行すると clone stats に影響が出ると思って敢えて対応はし
    ていなかったが、最近では clone count が多くなって来たのでmasterへのpushにつ
    き1回程度のcheckout であれば特にclone stats に影響を与える事もないだろう。
    特に今回 nightly build の提案があったので同時にテストも実行してしまうのが良
    い気がする。

    macOS で今までテストした事はなかったし、そもそも macOS 上で動く様にテストを
    書いていなかった。macOS の上でも動く様に調整するべき。

    更に、make scan も一緒に実行してしまうのが良い。make scan については色々
    false error が出ているので潰す。

2022-06-10

  * [棄却] 2021-05-23 main: BASH_XTRACEFD による set -x 出力の抑制? [#D1811]

    | | 更に set -x についてもまた駄目になっているかもしれない。→試してみた所
    | | attach 部分で無駄なメッセージが沢山表示される様になっていたが実行自体には問
    | | 題はない様である。然し、BASH_XTRACEFD を使った方が良いのではないか。これに
    | | ついてはまた別の機会について考える事にする。
    |
    | 現在の抑制の手法だと必要なエラーまで抑制してしまうし、標準エラー出力を抑制す
    | る為に結構無理な事をしている。BASH_XTRACEFD を使って実装した方が綺麗になるの
    | ではないか。然し、また色々と実装上の不都合が生じるかもしれないので取り敢えず
    | 後でゆっくり対処する事にする。
    |
    | →改めて確認してみたが、BASH_XTRACEFD は代入すると元々設定されていた fd が勝
    | 手に閉じられてしまう。
    |
    | a なので元々設定されていた fd を保存する等の対処が必要になるがその為には様々
    |   なコマンドを呼び出す必要がある。だとすると結局現在の位置よりも上に
    |   BASH_XTRACEFD の書き換えのコードを移動することはできないので、現状使ってい
    |   る { ... } 2>/dev/null による set -x 対策を置き換えるには至らない。
    |
    | b BASH_XTRACEFD が設定されていなかった時にだけ BASH_XTRACEFD を使って set -x
    |   を抑制する
    |
    |   % この様にしても BASH_XTRACEFD が既に指定されていた場合の為に { ... }
    |   % 2>/dev/null の対策は外す事ができない? と思ったが、既に BASH_XTRACEFD が設
    |   % 定されているのだとしたら {} 2>/dev/null としても意味がない (つまり 2 に出
    |   % 力される訳ではないので結局全て BASH_XTRACEFD に書き込まれてしまう)。
    |
    |   うーん。然し、BASH_XTRACEFD を一時的に /dev/null に設定するとしても、どの値
    |   に設定するのかというのが結局問題になる。下手な fd を設定してしまうと変な所
    |   に書き込まれて問題になる。自分で fd を開くにしても空いている fd を探す必要
    |   がある。探す為には結局色々とコマンドを呼び出す必要がある。
    |
    | 色々考えると、単に BASH_XTRACEFD に値を設定するという話ではない。元々設定され
    | ている BASH_TRACEFD を待避するのにも、出力先の /dev/null を開くのにも、空いて
    | いる fd を探すのにコマンドを呼び出す必要がある。という事を考えると、結局現在
    | set +x を実行している位置までは { ... } 2>/dev/null に頼る必要がある。なので、
    | 現在行っている対策を減らす効果はない。
    |
    | 一方で必要なエラーまで抑制してしまっている事についてはどうか。例えば { ... }
    | 2>/dev/null を単に除去してしまう。そうすれば set -x の出力も通常のエラーも全
    | て表示される様になる。然し、結局 set -x の出力を抑制する方法が他にないので、
    | やはり現在の位置までは { ... } 2>/dev/null で対策しておくしかない。

    [結論] 当初使えるかもしれないと思ったのは BASH_XTRACEFD への設定が (設定に影
    響を受けない) 変数代入だけで行えると考えたからであったが、その前に空いている
    fd を探索して更にその fd に対して /dev/null を開く為に builtin を呼び出す必要
    がある。従って adjust-builtin-wrappers 以前は結局今までの対策を使う必要があり、
    それは現在の対策範囲と変わらない。

  * 2022-04-15 ble.sh 内部に対する xtrace (set -x) を有効にする方法 (requested by SuperSandro2000) [#D1810]
    https://github.com/akinomyoga/ble.sh/issues/186#issuecomment-1099696862

    うーん。取り敢えず無理やり実装してしまって良い気がする。

    * 設定 interface をどうするか

      と思ったが interface をどのようにするかが微妙である。取り敢えず提案された様
      に BLESH_DEBUG 等の環境変数経由で設定する事にするべきか。と思ったが、bleopt
      で設定するべきの気がする。例えば、以下の設定がある時には set -x をしないと
      いう事。

      bleopt debug_xtrace=ファイル名

    うーん。これに対応する為にはユーザーの設定した BASH_XTRACEFD を何処かに保存し
    ておく必要がある。そしてその為にはファイルディスクリプタの探索等を実装する必
    要がある。などなど色々考えると、ロードした瞬間に実行するには処理として複雑す
    ぎる。そう思うと BASH_XTRACEFD は切り替えずにそのままユーザーが設定した物に出
    力するというので良いのではないか。

    * というより元々の 2021-05-23 の項目の意図は set -x の抑制を BASH_XTRACEFD を
      使ってできないかという事だった様な気がする。つまり、今回の ble.sh に対する
      デバグの目的で BASH_XTRACEFD を設定するという話とは違う話なのではないか。

      とは言いつつ set -x を抑制する為に /dev/null に設定するのを、debug_xtrace
      が指定されている場合には代わりにそのファイルに BASH_XTRACEFD を設定するべき
      だろう。という事を考えれば全く関係ない訳でもない。

      取り敢えずこちらを先に対応してから、2021-05-23 の項目に対して set -x 対策で
      強制的に抑制している範囲を減らす事ができないか検討するという事で良い気がす
      る。

    取り敢えず簡単に作って試してみた。あっという間に数百MBに達するので実際にこれ
    を使って debug する事が現実的なのかは疑問であるが、本当にクラッシュする時など
    には便利かもしれない。然し、幾らか問題点がある。

    * fixed: 元々 BASH_XTRACEFD に設定されていた fd を別の番号に dup しておく必要
      がある。何故なら BASH_XTRACEFD が変更される瞬間にその fd は閉じられてしまう
      から。然しその為には空いている fd を確実に探し出す必要がある。

    * fixed: 現在 context を switch する度にファイルを開いているが、debug_xtrace
      が設定された時に fd を開いておいて以降はそれを dup するべきなのではないか。
      毎回開き直すのは大変だし、ファイル名が相対パスで指定されていた場合、ディレ
      クトリ毎にファイルが作られて面倒な事になる。

    x 実際に試してみると set -x した時の抑制に失敗している → 何かと思ったら
      adjust/restore options は入れ子で呼び出す事を許容しているのだった。対応した。

    もっと複雑化と思ったが上記に対応したら原理的な問題ももうない気がする。

2022-06-09

  * compat: Oh My Posh と組み合わせると動かないという質問が reddit にある (reported by abyss6166) [#D1809]
    https://www.reddit.com/r/linuxquestions/comments/v43hek/oh_my_posh_theme_and_blesh_not_playing_well/

    * 保留: oh-my-posh の設定で vertical-offset -1 を指定すると表示位置をずらす事
      ができる。これによって ble.sh の内部でプロンプト領域が上に1行拡張されるのは
      仕方がない。これは意図した動作であるし説明すれば分かってくれるのだろうと考
      えている。

    * oh-my-posh の right prompt の位置計算がうまく行っていない。これの原因は分かっ
      た。oh-my-posh は全てのシーケンス毎に \[\] で囲んでいる。ここで rprompt の
      幅が分かっている場合に以下の様にしている。

      \[\e[1000C\]\[\e[10D\]

      一方で ble.sh では \[\] はカーソル位置を変えないという想定をしつつ、また、
      各シーケンスを現在のカーソル位置情報に基づいて再構築している。結果として、
      例えば幅 80 の端末では上記は

        (初期位置0,0)
        \e[1000C → 右に 79 列進む (位置0,89)
        \] → (位置0,0)
        \e[10D → 何もしない (これ以上左に行けないので)

      と解釈されて "\e[79C" に翻訳されてしまう。もっと簡単に言うと \[\e[1000C\]
      はカーソル位置を変えないので \e[10D は位置(0,0)で実行されると解釈される。本
      来は rprompt の為に出力しているシーケンスの全て(文字列も含めて)を \[\] で囲
      んで欲しいのである。

    ? rprompt (vertical shift なし) ではどの様に描画されるのだろうか。

      うーん。この時点で既に変な振る舞いをしている left の newline: true を削除す
      るとちゃんと表示できない 。。

      と思ったが、どうやらユーザー設定において rprompt の後には必ず left が来て
      newline を指定しなければならないようだ。themes の中の設定は全てその様になっ
      ている。なので、設計がおかしいとはいえ、これをバグとして報告しても仕方がな
      い。

      また、端末によって右端での動作が異なるのだという事を考えれば、rprompt で右
      端に1文字余裕を持たせて、更に改行を強制的に実行するというのは妥当な選択肢で
      ある。但し、その場合には rprompt の側で改行を入れるのが自然な実装だと思われ
      るが。

      テストをする上では取り敢えず newline: true は入れる事にするのである。

    ? bash の \[\] の説明はどうなっているのかというのを見たら単に non-printing
      characters を囲むのに使うとしか書かれていなくて、確かにその観点からすると
      omp の実装は正しい事になる。なのでこの方面から "正しくないから修正してくれ"
      と要請するのは難しい。

    * うーん。変更してくれないかと依頼するよりは自分で修正でも出した方が良いので
      はないか。と思ってソースコードを確認してみたらどうやら \[\] はハードコード
      されている様だ。

      https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/src/color/ansi.go#L77-L78

      そもそも a.right 自体を \[\] で囲むという発想が誤っている様な気がしないでも
      ないが、然し一方で実際にカーソル移動を誘起する場合には \[\] で囲もうが囲ま
      まいが何れにしてもカーソル位置のずれは発生するのである。

      a ちゃんとした修正を行うにはシーケンス毎に \[\] で囲むのではなくて、最終的
        に戻ってくる前提の一連の移動全体を囲むという事になる。然し、そもそも現在
        の omp の設計からして right は元に戻ってこない設計になっていて、次の left
        で newline: true する事によって問題を解決する仕組みになっている。そして、
        それはユーザーの設定項目として公開されているので下手に仕様を修正する訳に
        も行かない。

      b うーん。一つの workaround は \]\[ のペアを出力時に削除するという事。

        \]\[ を置換するには? 出力する箇所で置換するべきという気がする。

        Engine.console (strings.Builder) に書き込んで後で Engine.string() で中身
        を取り出している様だ。この取り出す時に修正を行えば良いのではないかという
        気がする。更にこれは e.print() 経由で文字列に変換して返されている。他に
        PrintTooltip 及び PrintDebug でも利用されている。という事を考えると、
        e.string() で処理するべきの気がする。

      取り敢えず PR を出した。この PR だと完全に問題は解決していなくて、依然とし
      て OMP は \[\] の中でカーソル移動を行っているが、これはこれで仕方がないのだ
      ろうという気がする。

  * history: 終了時の履歴保存の際にエラーメッセージが発生する [#D1808]

    これは apple nawk による問題のテスト中に発見した問題である。

    | 正しくコンパイルできていない apple awk で起動した際に、↑カーソルキーを3回押
    | して C-d で抜けると以下のメッセージが発生する。↓だと発生しない。つまり、履歴
    | を遡っていて、その履歴に含まれる項目が処理に混入している可能性もある。
    |
    | bash: ((: 1*: 構文エラー: オペランドが予期されます (エラーのあるトークンは "*")
    | bash: ((: 1*: 構文エラー: オペランドが予期されます (エラーのあるトークンは "*")
    | bash: ((: 1*: 構文エラー: オペランドが予期されます (エラーのあるトークンは "*")
    |
    | ここで何が起こっているのかについては上の事は置いておいても不思議である。
    |
    | →うーん。どうもこれは↑を3回押すと履歴項目の一番上の内容が消去されてしまう様
    | だ。これによって history の結果の履歴番号に dirty mark として * が付加されて、
    | 最終的に履歴番号を算術式で処理する時にエラーが発生するという事の様だ。
    |
    | 実はこれはもっと一般的な問題なのではないか。history の結果を解析する時にこの
    | * の可能性を考慮に入れて処理する必要がある → 改めて確認した所、殆どの箇所で
    | は既にちゃんと履歴番号の後に "*" が来る場合を考慮に入れていた。今回問題になっ
    | たのとは別に1箇所だけ問題が見つかった。

    結局原因は history の出力結果の履歴番号の後ろに * という文字が付く場合がある
    という事を考慮に入れていない箇所があったということだった。既に殆どのコードで
    はちゃんとこの事が考慮に入っていたが、一部のコードで見落としていた。

2022-05-13

  * complete: scp の補完で固まる (reported by iantra) [#D1807]
    https://github.com/akinomyoga/ble.sh/issues/193

    これは前から気になっていた事である。問題は何処に介入するのかという事である。
    補完関数全体を subshell で実行する様にしてしまうと 124 を返して再実行した時
    に無限ループになってしまう。他にも変数に対する修正が適用されない等の問題が
    生じる。なので、もっと内側で conditional-sync を実行する必要がある。

    _scp_remote_files を subshell で実行しようとも思ったがそうすると COMPREPLY
    を渡すのが面倒だ。というか scp, ssh 等に介入すれば良い。どうせこれらは他の
    プロセスを起動するのだから。実際に _scp_remote_files は ssh を呼び出してい
    る:

    https://github.com/scop/bash-completion/blob/6f1bbda3c66814befa8025d49363b4070ef20008/completions/ssh#L435

    と思って実装したが動かない。どうやら $(...) の中で conditional-sync をした
    場合、$() が結局本体のプロセスが死ぬまでブロックしてしまうのが原因の様だ。
    本当のプロセスを kill -9 しても駄目の様だ。どうも更に子プロセスが起動してい
    るのが原因だ。

      PGID を確認してみたが command substitution の中で & で呼び出しても固有の
      PGID を作成する訳では無い様だ。なので PGID に対して kill を実行すると外側
      も含めて予期しない所まで kill されてしまう。

      仕方がないので ps を使ってプロセス一覧を取得して其処から kill を実行する
      事にする。

    * dnf も遅い。dnf に関しては _dnf_commands_helper に介入すれば良さそうだ。
      然し、遅延ロードされる関数に確実に介入するには遅延ロードした時に上書きす
      る必要がある。うーん。一応 bash-completion に関しては 124 により一旦制御
      を返すので介入はできる気がする。

    2022-06-02 conditional-sync のミスを push する。暫く手元に置いていたがずっ
    とこのままにしておくのは好ましくない。

2022-05-01

  * 日本語を含むディレクトリに入ると化けてしまう事に気づいた [#D1806]
    Ref #D1798 a9551e5

    これは \w, \W, etc 対策の副作用である。修正した。

2022-04-10

  * BSD make で実行しようとする人対策 (question by lu9dce) [#D1805]
    https://github.com/akinomyoga/ble.sh/issues/184

    FreeBSD で make でコンパイルしようとしている人がいる。面倒なので BSD make
    用の Makefile も用意して make で実行しても代わりに gmake を呼び出す様にする
    事にした。

    shebang が #!/bin/bash であるのが原因だと勝手に言っていたが、これは関係ない。
    今後も似たような御節介の誤った報告が来るかもしれないので shebang 自体を削除
    してしまっても良いのかもしれない。或いは -*- mode: sh; mode: sh-bash -*- に
    する。然し、これだと自分の所の設定でしか Bash モードが有効にならないという
    問題がある。取り敢えずは現状のままという事にする。今後も何か指摘してくる人
    が居たら全部 shebang を削除する事にする。

  * blehook に引数が渡されなくなっている (reported by SuperSandro2000) [#D1804]
    https://github.com/akinomyoga/ble.sh/issues/185

    調べたら invoke.sandbox 経由で呼び出す時に引数が継承されていない。
    invoke.sandbox を導入したのは最近である。6fdabf32 が該当する変更である。
    https://github.com/akinomyoga/ble.sh/issues/179#issuecomment-1048416510

2022-04-05

  * progcomp: cobra で生成される補完が説明を混入させる (reported by SuperSandro2000) [#D1803]
    https://github.com/akinomyoga/ble.sh/issues/183

    正直 cobra は bash-completion でも問題を起こしているし。元よりとても質が悪
    いので余り対応したくないが、だからといって upstream に手を加えるのもまた対
    応が遅くてどうしようもないという事が分かっている。不本意ながらこちらで
    workaround を加える→取り敢えず対応した。一応動く。

    改めて V2 の実装を確認したがやはり bash スクリプトとして質が悪い。

    ? そもそも説明を候補に含めるのは hack に過ぎないし、これに依存していると
      bind 'set show-all-if-ambiguous' 等の時に正しく動作するのかも怪しい→と思っ
      て確認してみたが一応大丈夫の様だ。

      以前 bash-completion で make に対して起こったのは一体何だったのか。以下で
      ある。

      https://github.com/scop/bash-completion/issues/544
      https://github.com/scop/bash-completion/pull/546

      うーん。調べてみるとこの時とは条件が異なる。この時は COMP_TYPE が 9 or 37
      の時には候補を勝手に変更しない様にしていた。これは挿入される候補の始まり
      部分を省略できるかどうかの判定であり、少しでも挿入されたら困るので 9 も排
      除している。42 は手落ちであろう。一方で今回は始まり部分は変えないので曖昧
      の時には後ろに自由に勝手な文字列を追加する事ができる。という事により
      37|42 の時にだけ気をつければ良い。

2022-03-19

  * menu-complete: 補完候補に含まれる制御文字の反転は xor で行う [#D1802]

    prompt seq \w, \W, \s で制御文字の反転を toggle する様にしたが、補完候補の
    表示でも同様に toggle した方が良い気がする。#D1798, #D1801 のテストの最中に
    実際に制御文字を含むディレクトリを作成して補完を実行した時にやはり気になっ
    た。当初は #D1801 の一部として対応したが別項目に分けた方が良い様に感じるの
    で分ける事にした。

    * done: menu-complete: 特殊文字を含む候補の反転と選択時の反転が重なって見に
      くい。反転は重ね書きではなくて toggle にするべきなのではないか。

      新しい \e[9807m で対応できるかと思って実装を確認したが trace は使っていな
      くて直接画面に出力するのに使うシーケンスを sgr を直接指定することで構築し
      ていたので使えなかった。その代わりに反転に使う sgr などをそもそもその場で
      g|_ble_color_Revert 等として構築していたのでその | を ^ に置き換える事で
      簡単に対応する事ができた。

    一方で編集文字列に含まれる制御文字についても気になったがそもそも反転してい
    ないので関係ないのであった。

    * ok: 更に編集文字列本体についても同様に toggle するべきなのではないか? と
      思ったがそもそも現在の実装だと編集文字列に含まれる制御文字は特に反転など
      していないので関係ないのであった。

      今から新しく対応しようにも現状の実装だと反転の toggle を実装するのは簡単
      ではない様なので取り敢えずは対応しない事にする。もし今後必要性を感じた時
      に改めて対応する事にすれば良い気がする。一応項目として残しては置く。

2022-03-12

  * prompt: bash-5.2 では \w, \W に加えて \s についても escape する様だ [#D1801]
    Ref #D1798

    bash がなかなか実装しないと思ったらこちらが \w, \W に対する実装を push した
    4日後に対応が入った。どうも \s についても escape が入ったという様に commit
    message には書かれている。

    \s は "bash" という文字列の様だ。これに制御文字が含まれるとは一体どういう状
    況だろうか。これを気にするのであれば \h, \H, \u も気にするべきなのではない
    か。取り敢えず全てに大して対策を加える事にした。

    ? bash-5.2 では ${PS1@P} でもちゃんと \w, \W を escape してくれるのか→ちゃ
      んと escape してくれている。

    * done: bash-4.4 以上では escape が起こった時に @P を使わない自前実装に切り
      替える必要がある。

    * bash-5.2 の実装についても改めて確認する。\t はそのまま特殊文字のまま出力
      する様だ。その他については zsh の様に \n だとか \t の様な表現には置き換え
      ず一貫して ^X という形で表現している。改行は ^J になっている。

      \s 以外にも対応している物がないか確認する。

      bash-5.2 の対応では sh_backslash_quote_for_double_quotes に手を入れる事に
      よって対応が行われている。この関数は本来は eval する時に変な事が起こらな
      い様に $`"\ 等を escape するのが目的だったのだと思われるが、同時にエスケー
      プまで実行してしまうという算段である。

      特にこの機能が有効になるのは第二引数に bit 1 を指定した時で以下が該当する。

      ./parse.y:5745:         temp = sh_backslash_quote_for_double_quotes (temp, 1);
      ./parse.y:5822:           temp = sh_backslash_quote_for_double_quotes (t_string, 1);

      そしてこれは正に commit msg にある様にそれぞれ \s と \w\W に対する処理で
      あった。なので \s, \w, \W 以外に関しては対策は実装されていない。

      ? うーん。 ^\ に大して何か変な事が起こったりするのではないか…。例えば
        ^\$(echo hello) が実行されてしまう可能性はないのだろうか。試してみたら
        問題を再現できてしまった。

        $ mkdir $'\034$(echo hello)'
        $ cd !$

      ? これは shopt -u promptvars でもちゃんと実行されるのだろうか? →試してみ
        たがちゃんと動いている様だ。OK

      2022-03-19 これは bash に PATCH を送ったら今日適用されていた。OK

    * bash-5.2 では META_CHAR に対しても escape を実装している様だ。うーん。
      ble.sh でも対応するべきだろうか。と思ったがよく考えてみたら ble.sh ではそ
      もそも編集文字列であっても 80..A0 に対して特別な文字は割り当てていない様
      な気もする。これはそれも含めて再考する必要がある。

      →と思ったが改めて確認してみたところ
      _ble_unicode_GraphemeCluster_ControlRepresentation という配列にちゃんと登
      録しているのだった。この新しい実装でもこの配列を参照するべきである。

      と思ったが _ble_unicode_GraphemeCluster_ControlRepresentation は単にキャッ
      シュしているだけなので代わりに ble/unicode/GraphemeCluster/.get-ascii-rep
      を呼び出すべきである。その様に実装し直した。

2022-03-04

  * 2021-10-26 ble/builtin/read: status が表示されている気がする [#D1800]

    更新はされていないので実際に表示する時の問題である。然し、vi_cmap 等の時に
    表示されるのは特に問題ない動作である。という事を考えると、その意味で status
    が有効になっていると考えても良いのだろうか? 特に read を widget の中で使っ
    ている時には status の高さも考慮に入れて上書きしてしまわない様にするべきな
    のではないか。という事を考えると status を有効・無効にする条件を考える必要
    がある気がする。

    現状で既に read をどの様に表示するかを呼び出している状況で区別していなかっ
    たか。つまり、どの panel で表示するかを切り替えていた様な気がする。確認した
    所、特に切り替えてはいなくて常に _ble_textarea_panel=1 に表示している様だ。

    右プロンプトについても同様に問題が生じそうな気がするのにも拘らず問題は起こっ
    ていない。調べてみると右プロンプトに関しては _ble_textarea_panel=0 の時にだ
    け有効化されて、有効な時にだけ表示される様になっている様だ。

    * fixed: 一方で、prompt_xterm_title 等は read に対しても有効の儘になってい
      る気がする。これは出力しない様にするべきなのではないか。或いは、read の中
      で一時的に別の値に設定するべきだろうか。

      ble/textarea を read 以外の textbox 等に使う場合も考えると、xterm_title
      等についてもやはり _ble_textarea_panel=0 の時にだけ表示する様にするべきの
      気がする。

    * fixed: _ble_prompt_rps1_data[12]=$rps1_enabled という行があるが現在は
      [12] は使っていないのではないか。

      f6af802c で rps1_enabled を用いて update-textmap の計算を更新する様に変更
      したが、これは [12] とは関係ない様だ。

      元々 [12] に値を代入する様になったのは cf8d9493 である。此処では
      update-textmap で rps1 が有効になっているかどうかを参照する為に [12] に情
      報を格納している。然し、先述の f6af802c に於いて最早 rps1_data[12] は参照
      されなくなった。

      という事を考えると rps1_data[12] に今現在代入しているのは削除して良い。
      (或いは現在 rps1_enabled にしているのを rps1_data[12] に代入しても良い気
      はするが、一応決定している箇所が異なる様に思われるので現状の儘にする)

    うーん。実は status_line は ble/propmt/update とはまた別の管轄の様である。
    ble/canvas/panel/render から呼び出された時に表示している気がする。特に
    ble/prompt/status#panel::render が呼び出された時に、正しく表示されるべき時
    は表示し表示されない時は表示されない様に実装されているのか。特に getHeight
    で変な値を返していないかだとかが気になる。

    どうやら _ble_edit_layout が normal に戻ってしまっている様だ。本来
    _ble_edit_layout はずっと command のままであるべきであるのにも拘らず。何処
    で _ble_edit_layout が設定されるのは、特に command 以外の値に設定されるのは
    leave-command-layout だけである。確認してみるとどうやら
    ble/application/render で leave-command-layout が呼び出されている様子である。

    * できるだけ明示的に enter-command-layout と leave-command-layout を対にし
      て実行する事にした。

    * .insert-newline で enter-command-layout をしているが、それに対応する
      leave-command-layout を正しく記述する必要がある。

      .insert-newline の呼び出し元。確認してみたがとても沢山ある。

      ./src/edit.sh:1491:    _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:6687:  _ble_complete_menu_active= ble/widget/.insert-newline "$opts"

        ./src/edit.sh:6701:  _ble_edit_line_disabled=1 ble/widget/.newline keep-info
        ./src/edit.sh:6750:    ble/widget/.newline keep-info
          keep-info を指定している時には問題ない。

        ./src/edit.sh:6782:  ble/widget/.newline
          これはコマンド実行
        ./src/edit.sh:6865:    _ble_edit_line_disabled=1 ble/widget/.newline
          ble/widget/edit-and-execute-command.edit
          これは最終的に ble-edit/exec/register に至る。

      ./src/edit.sh:6760:    _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:6770:      _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:9219:      ble/widget/.insert-newline
      ./src/edit.sh:9221:      _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:9871:  _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:9880:  _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./src/edit.sh:9905:  _ble_edit_line_disabled=1 ble/widget/.insert-newline
      ./keymap/vi_test.sh:424:  _ble_edit_line_disabled=1 ble/widget/.insert-newline

      うーん。一旦 disable して出力して再び描画するというパターンが多い気がする
      のでこれは関数にするべきなのではないかという気がする。と思ったが、出力に
      用いるコマンドが色々なので、eval の様な形になるだろうか。少々面倒の気がする。

    * done: ble/edit/info refactor

      aplication/render で leave-command-layout を実行しているのは info をこの
      時点で表示させるのが目的だった可能性? 恐らく高さの計算は info/render を呼
      び出さないと分からないので先に計算させているのだろうという気がする。

      これは本来 getHeight の段階で正しく計算して返すべきである。現在の設計では
      info 自体は自身が有効化されているかどうかを把握していなくて外部から表示・
      非表示を制御する構造になっているのがいけないのではないか。

      というよりそれを言い出すと textarea も同様なのではないか。textarea の表示
      非表示はどの様に制御されているのだったか → _ble_textarea_panel が一致し
      ていれば更新する。もし一致していなければそのままにする。もしくは "0:現在
      の高さ" を返しているので潰れてしまう事は許容している (_ble_textarea_panel
      が復元した時に改めて再描画するという事なのだろう)。そういう意味で
      _ble_textarea_panel=-1 等にする事によって textarea を完全に off にする事
      も可能である。或る意味、自身で表示・非表示・(現在の状態を保持) の状態を保
      持していると言える。info についてもその様な状態を保持させて管理するべきの
      気がする。それは getHeight の段階でちゃんと参照する様にする。

      改めて確認したが問題はそんなに簡単ではない様な気がする。そもそも render
      の段階では info の内容は決定されない。そういう意味に於いて別に問題は起こ
      らない筈。問題が起こるのは、ble/edit/info/reveal を実行する事によって内容
      を改めて構築し直す必要があるという事の気がする。何故そうなっていたのかと
      いうと enter-command-layout に入る時に info の内容を消去しているから。

      * 現状では既に leave-command-layout が何処かで呼び出されている前提なんで
        改めて info/reveal を呼び出す必要はない。leave-command-layout が呼び出
        された時点で info の内容も再構築されている筈だから。

      x と思ったら起動時に info が表示されなくなってしまった。うーん。改めてど
        ういう条件で再描画が必要になるのか整理して、再描画が必要になった箇所で
        必ず invalidated を設定する様に修正する必要がある。

        うーん。何だか分かった様な気がする。高さが 0 だとそもそも invalidated
        のチェックすら来ないという事なのではないか? と思ったがそれも変である。
        例え invaldiated であっても panel::getHeight は呼び出される筈だから。

      改めて info が一体どの様にして状態を管理しているのか確認するべきである。
      或いは再設計する。_ble_edit_info はもし info が表示されていたとしたら表示
      されている内容である。_ble_edit_info_default は既定の内容であってこれは
      scene が default になる時に表示される内容である。現在はどうも info が表示
      されていないという状態も _ble_edit_info で取り扱おうとしているのが混乱の
      原因になっている気がする。

      * ok: ble/edit/info/hide を使っている箇所はあるか → 一箇所しかない。これ
        は info#collapse に置き換えたと思って良い。

    * うーん。構造的にもっと別の方法にした方が良いのかもしれないとも思われる。

      ! つまり、render の側でコマンド実行中かそうでないかで動作を切り替える。コ
      ! マンド実行中でない時には何れにしても leave-command-layout はコマンド実
      ! 行終了後に有効にする。

      コマンド実行中にだけ command-layout にするというのの方が正しいのではない
      か。とも思ったが、enter-command-layout の時点で実はプロンプトや status,
      info 等を削除して command-layout に入っている。という事を考えると、やはり
      現状の実装の方が正しい様な気もする。

      例えば、仮にその場でだけ command-layout になって、一旦はまた通常 layout
      に戻って、それからその後でまた command-layout になってコマンドを実行する
      とどうなるのだろうか。

    x 空のコマンドしか実行しない状態になっていると leave-command-layout の実行
      が抜けてしまうのではないか。

      a 空のコマンドがあるかどうかは呼び出し元でちゃんとチェックする前提として、
        gexec の側ではスキップは行わない。

      b 空のコマンドしかない場合でも leave-command-layout は必ず実行する様にす
        る。

        然し、そうするとこれは .end の後で実行するしかなくなるが、.end の中で
        .tail まで呼び出しているので、.end の後で leave-command-layout を実行し
        ても意味がない。改めて .tail 及び再描画を呼び出す必要があって無駄である。

        或いは、空のコマンドしか無い場合は特別扱いで leave-command-layout と
        .tail を両方呼び出す様にする?

      うーん。a の方法の方が良い気がする。

      結局 ble-edit/exec/register の側でもチェックを入れる事にした。一部でチェッ
      クが重複する事になるが、その方が安全であるし、論理的にすっきりしている。

    x fixed: と思ったが複数のコマンドを実行して一部は leave-command-layout を実
      行して一部は実行しないという状態になったら一体何が起こるのだろうか。。一
      番最後に実行した物が leave-command-layout を実行していると何だか変な事に
      なる気がする。

      或いは、_ble_app_render_mode として panel の他に command も用意して、
      command の時には reveal を実行せずに ble/canvas/panel/render を実行する?
      panel の時には leave-command-layout を強制的に呼び出す様にする。コマンド
      を実行している間は _ble_app_render_mode=command とする。その方が今迄の実
      装に近いしすっきりしている様な気もする。

      然し、論理的に正しい事をしているのかどうかというのは良く分からない。

      うーん。これに関しては enter/leave で単に既に command かどうかを判定する
      のではなくて、enter/leave の深さを数える様に変更する事にした。

2022-03-03

  * [解消] 2021-11-21 bash-3.2 で syntax highlighting がロードされるのが遅い [#D1799]
    もしかして遅延している?

    Ref #D1731 重複

  * 2022-01-19 PS1 のディレクトリ名に特殊文字が含まれている場合の取り扱い [#D1798]
    https://lists.gnu.org/archive/html/bug-bash/2022-01/msg00051.html

    これは不要な互換性の問題を防ぐために Chet がどの様に対処するのかを見てから
    それと同じ様に実装するのが良い。

    またその他の文字列についても同様に注意が必要なのではないかと思われる。
    と思ったが他に任意の文字列を出力する様な状況もない様な気はする。

    2022-03-03 これは結局何の修正も入らない様だ。うーん。勝手に ble.sh の側で対
    応してしまっても良い。

    zsh は ^J や ^I に対しても特別な表示にするのだろうか。それともこれらはその
    まま表示するのだろうか。と思って試して見た所、単に \n や \t に置換して表示
    する様だ。\001 に対しては ^A と表示する。ESC は ^[ と表示する。

    やはり反転する等して強調した方が良い様な気がする。本当にそういう名前を持っ
    たディレクトリ名と区別が付かない。新しく trace に SGR(9807) という反転状態
    を toggle する番号を追加する事にした。

  * main: ble/base/unload 後に ble/util/assign 一時ファイルが残留する [#D1797]

    ble/base/clean-up-runtime-directory で毎回 rm が実行されている。どうやら前
    回の session が最後に assign に実行をしてそれで一時ファイルが作成されている
    様だ。

    ble/base/unload を実行した後に trap/.handler で joblist.check を呼び出して
    いるのが原因である。或いは、joblist.check は unload 状態にある場合には実行
    しなくても良いのではないか。然し、改めて確認すると unload の状態にあるかど
    うかを記録している変数はない様だ。そう思うと EXIT の時だけの特別扱いとして
    joblist.check をスキップするという可能性? 或いは、unload を実行した時点で
    ble/util/assign を使わない実装に切り替える?

    a ble/util/unload は trap/.handler 以下で直接実行する。結局勝手に削除されて
      は困る物だし、最も重要な物の一部でありモジュールを疎結合にする必要性も薄
      い。という事を考えると、unload は特別扱いしても良いのかもしれない。

      然し、そもそもの問題として trap handler を jobs で囲んでいた理由を考える
      と、やはり unload であっても囲んで実行した方が良い可能性はあるのだろうか。

      ? というよりそもそも何故 jobs で囲んでいたのだったか。

        思うに、trap handler の中等で外部コマンド等を実行するとその分だけ job
        項目が累積してしまう問題を防ぐのが目的だった気がする。今正に終了しよう
        としている段階で jobs を表示する機会はない気がするので気にしなくても良
        いのではないだろうか → 2回目の joblist の呼び出しは正に
        ignore-volatile-jobs で呼び出しているので無視するのが目的である。

        問題が起こるとすれば user trap の中で jobs を呼び出した時にごみが沢山表示
        される可能性があるという事だが、其処で変な物が表示されても大した問題では
        ない様な気がする。というより、そもそも ble.sh がジョブ一覧を管理している
        時点で user が実行した jobs からは特定の項目が受け落ちている筈だから、な
        い筈の物があるぐらいならそれに比べれば大した問題ではないのでは? という考
        え方もできるかもしれない。

      ? user trap を jobs で囲む必要性はないのだろうか。

        これは本来は user trap の中で発生した余分な jobs entry も削除してしまっ
        て良い気がするが、もしかすると本当に job を投げるという事があるかもしれ
        ないので、その項目が意図せず消滅しない様に囲むのはやめたのだろうという
        様に思われる。何れにしても今回は関係ない。

      ? そもそも EXIT の中から終了をキャンセルする事は可能なのだろうか。或いは、
        他の要因によって終了がキャンセルされる可能性はあるのだろうか。考えて見
        るにその様な方法は存在しない気がする。という事を考えると、jobs の情報を
        収集しても仕方がないのではないかという気がする。

      o ユーザーが登録した何かが ble.sh に依存しているという可能性もあるのでは
        ないか。という事を思うと、やはり unload は外側で一番最後に実行するべき
        の気がする。

    b 或いは、EXIT の時だけは joblist.check はスキップする。或いは unload して
      いる事を何処かに記録するなどして、それに応じて joblist.check をスキップす
      る。

    c 或いは unload の際に ble/util/asign を書き換えてコマンド置換を使う様にす
      る → 然し、そうすると環境に影響を与える事を前提としている
      ble/util/assign の呼び出しに対して正しく対処できなくなる。特に今回問題に
      なっている joblist.check の呼び出しは環境に対する影響を前提としているので、
      この方法では正しい解決方法にはならない気がする。

      また、この方法だと結局 fork の回数が終了時に余分に増える事になるので合計
      では実行時間は減らない。寧ろ、複数回の ble/util/assign がある様なので、そ
      れによって合計時間は増えてしまっている。(但し、終了時なのでユーザー体験を
      損ねる事はない様に思われる。)

      現在の文脈を変える為に >/dev/null に繋いで現在の環境でも実行するという事
      もできるかもしれないが、もしそのコマンドがファイルシステム等に副作用を齎
      す物だった場合、二回実行する事によって結果が変わってしまうし、また実行時
      間も二倍になるし良い事は何もない。

    d 或いは unload している時には何か別のファイルを一時ファイルとして
      ble/util/assign を利用する? 然しもしその様なファイルを簡単に安全に作れる
      のであれば始めから ble/util/assign は必要ないのでは。

      或いは unload している時は ble/util/assign/.rmtmp に於いて rm を明示的に
      実行する様にする。然し、これだと結局 fork の数は増えるので意味がない。然
      し、少なくとも動作が変わってしまう c よりは現実的な方法である。

    # ? 所で here document 等を一時ファイルの代わりに使う事はできるのだろうか。
    #   と思ったが、最近の bash では here documents は一時ファイルではなく pipe
    #   になってしまっているので使えない。
    #
    #   試しに以下を試してみたらファイルの読み書きが出来てしまった。
    #
    #   $ bash-4.4 -c '{ echo check world > /proc/self/fd/0; cat /proc/self/fd/0; } <<< hello'
    #
    #   然し、bash-5.0 以上では失敗する。bash-5.0 以上でファイルにする為には大
    #   量のデータで初期化しなければならないので非現実的な気がする。その他に
    #   bash が一時ファイルを生成しそうな場合はない気がする。プロセス置換は
    #   pipe である。
    #
    #   更に本当にどのシステムで動くのかも定かではない。どうやら bash は一時ファ
    #   イルを早々に unlink してからコマンドを実行する様である為。

    結局 a の方法で、ble/base/unload は別枠で trap handler の最後で実行する事に
    した。

2022-03-02

  * 2022-02-03 edit: もしかしたら stty sane の頭に空白を置くと良いのでは [#D1796]

    先頭に空白を置いたコマンドの履歴登録をなしにする設定にしている人がいる。

    或いは勝手に stty sane を HISTIGNORE に設定するという手もある? と思ったが、
    それだとユーザーが本当に自分で stty sane を実行した時に履歴に残らないし、或
    いは HISTIGNORE を一旦保存して復元する仕組みを作ったとしても何かの拍子に実
    行できなかった時にやはり困るし、余り信頼性が高いとは言えない。

    これた簡単だが採用する。

  * history: detach 状態で終了すると履歴に記録されない [#D1795]

    detach 状態で終了した時、また detach している間の履歴が記録されなくなってい
    る気がする。EXIT が呼び出されていないのだろうか。また後で確認する。

    どうも ble/builtin/history/option:a 迄はちゃんと呼び出して実行しているが、
    rskip, wskip の更新が思う様に振る舞っていない様だ。rskip は現在のファイル内
    の読み取り位置で、wskip は現在の Bash プロセス内の履歴の書き込み開始位置
    (次にファイルに書き込むべき項目の位置) を管理している。history/option:a の
    中で呼び出した check-uncontrolled-changes で wskip が先端位置に移動して、そ
    の為に何も書き込まれないという状態になっている様に思われる。

    そもそも detach 状態で終了した場合、detach 前に実行していたコマンドですら書
    き込まれずに終了してしまっている。

    * そもそも prevmax!=max だからと言って wskip..prevmax 迄はちゃんと履歴に残
      すべきなのではないか。と思ったがそれを記録する手段がない様な気がする。否、
      subshell で適当に -r してそれから書き込めば良いのだろうか。

    取り敢えず対応した。

    * 履歴が倍加する問題が新しく発生していないか確認する。
      一応 "history -a;history -c;history -r" に対しては問題は起こっていない。
      bashrc で history -r をしても変な事は起こっていない。恐らく大丈夫。

  * complete: BUG cygwin$ pdflatex [TAB] で /usr/bin/cat: '': No such file or directory というエラー [#D1794]
    Ref #D1637

    chat では再現しない。bash-completion はロードされていない。

    うーん。これは 2365e09c によるバグである。今迄5ヶ月間ずっと mandb を正しく
    抽出する事ができていなかったという事になる。今迄何故気付かなかったのだろう。
    不思議である。或いは、また別の方法によって抽出できていたという事か? → そう
    いう事だ。つまり、Linux 等では man -w 等を使ってファイルを決定できていたの
    で問題がなかったのである。

  * edit (exec_elapsed_mark): やはり既定で時・日などの分解能の表示にも対応する [#D1793]

    長時間ログインしていた後等にはやはり長い時間経過している事がある。
    その時に常に分で表示されると分かりにくい。

  * canvas: BUG 何故か2回目の char_width_@=auto がちゃんと動いていない気がする [#D1792]
    Ref #D1669

    何故だろうか。後で確認する。

    改めて試してみたがゆっくりやれば何度やっても問題はない。auto を代入してから
    急激に RET 等を実行するとそれ以降は常に west, 7.0 にしかならなくなる。CPR
    応答の順序がずれてしまっている可能性? 何処かのタイミングでずれを修正したら
    治るのだろうか。

    * _ble_term_CPR_hook に何か変な物が残存している可能性を確認。

      →分かった。逆だった。timeout のコードが悪さをしていた。timeout 時刻の更
      新を行っていなかったので常に timeout する状態になっていてまともに CPR が
      受信できなくなっていた。 west, 7.0 というのは CPR 応答がなかった時の既定
      の値という事だろう。

    ! ? そもそもどの様にしてずれが起こるのか。初めのずれが起こらない様に調整でき
    !   るのではないか。

    結局 #D1669 の単純なバグだった。修正した。

  * blehook -+= は入力しにくいし見にくいので != を一意追加として対応する [#D1791]

    * done: !=  ... 未だ登録されていない時に追加する
    * done: -+= ... 後ろに持ってくるという意味に変える。
    * done: +-= ... 前に持ってくるという意味で追加する。

    * update wiki

  * complete: sabbrev を削除する機能がない [#D1790]

    削除の仕方としては以下の2種類が考えられる。

    ble-sabbrev -r a # bind, complete と同様
    ble-sabbrev a=-  # trap と同様

    後者は本当に "-" に展開させたい時 (実際そういう場合が存在するのかは謎だが)
    と衝突するので前者の方が良い気がする。

    また、前者を採用するとしたら -r に対して optarg を要求するのか、或いは -r
    に対して optarg を要求するのかで振る舞いが変わってくる。

  * progcomp: ble.sh 既定の候補を生成しない機能 (motivated by rsteube) [#D1789]
    https://github.com/rsteube/carapace/issues/431

    > prevent default file completion when no values returned

    このオプションを提供する事にする。

    現在 "候補が生成されていたら" という意味で生成候補数を参照している箇所を全
    て書き換える必要がある気がする。

    後 core-complete の中から公開 interface を決めてそれを説明する必要がある気
    がする。

    * 拡張 comp_opts をまとめる。prog-trim, syntax-raw, filter_by_prefix,
      no-mark-directories

      現在参照している comp_opts は以下の通り。

      $ grc '(comp_opts|DATA):? =='

      元から bash に存在しているオプションは以下の通り:
      bashdefault default dirnames filenames noquote nosort nospace plusdirs

    * done: 拡張オプション名は分かる様にした方が良いのでは。例えば ble- で始め
      る。或いは、- で始める。もしくは -ble- で始める。

      " a -prog-trim, -syntax-raw, -filter-by-prefix, -no-default
      "
      "   うーん。- だけだと結局ユーザー的には混乱の元であるというより、すぐにそ
      "   れが "ble.sh" 特有の機能であると理解しにくいのではないかという気がする。
      "   然し一方で "-" で始まっている時点で非標準の機能であるという事は明らかで
      "   ある。
      "
      " b ble-prog-trim, ble-syntax-raw, ble-filter-by-prefix, ble-no-default
      "
      "   ble- だけでも十分の気がするが、これだと名前空間的になっていて、もっと細
      "   かく分類したくなってしまう。
      "
      " c -ble-prog-trim, -ble-syntax-raw, -ble-filter-by-prefix, -ble-no-defualt
      "
      "   CSS の vendor prefix の様に -ms- だとか -moz-, -webkit-, -o- の様にして
      "   いる物を真似て -ble- だとか -mwg- だとかで良いのではないかという気がす
      "   る。-mwg- は今迄使った事がないので ble.sh には組み込まない様にしておき
      "   たい。
      "
      "   然し、一方で、他の compopt の枠組みが今後出てくる様にも思われないし、対
      "   応していない物を bash に渡したら何れにしてもエラーになるので、結局汎用
      "   の補完を作成するとしても呼び出し元で場合分けする事になる。なので vendor
      "   prefix の様な物を設定して場合分けに使える様にする必要があるのかも分から
      "   ない。この様に名前を分けるのは主にユーザーの側でこれが非標準であるとい
      "   う事が分かる様にする為の物である。
      "
      " どれにすれば良いか分からないが、長いものを採用する上で憚りになるのは、単
      " に無駄な prefix がついていると読みにくいという事、冗長になるという事であ
      " る。一方で、ユーザーや他の人の意見も聞いて最終的に決定するとなると、何れ
      " にしても "ble" は入れた方が良いという様に要請されるのは明らかである。
      "
      " 然し、既に様々の ble.sh の独自機能に使われている opts では ble- 等の
      " prefix は使っていないし、今後使う必要も全く無い。その様な物との整合性を考
      " えると、やはり特別な prefix は特につけなくても良いのではないかという気も
      " してきてしまう。一方で compopt はやはり本来は Bash の機能なので名前空間を
      " 乱すのも変である。
      "
      " うーん。面倒なのでやはり何も新しい prefix は付けずに manual で説明・注意
      " 喚起するだけで十分なのではないかという気がしてきた。うーん。本当だろうか。
      "
      " うーん。- で始まる prefix はそれ単体でオプションの様でもあるからやはり混
      " 乱の元の気がする。と思えば prefix を設定するとしても "ble-" 一択の気がし
      " てきた。
      "
      " d 或いは compopt -o prog-trim ではなくて compopt --bleopt prog-trim だと
      "   か、compopt -O prog-trim だとか、compopt -s prog-trim の様な形の別の指
      "   定の仕方をさせるという手もある。内部的には -prog-trim 等で良いのだろう
      "   という気がする。compopt は実質的に -o, +o だけしかオプションがない (一
      "   応 -DEI もある)。或いは prog-trim=on 等でも良いかもしれないと考えたが、
      "   これは compopt を適用する対象のコマンド名と区別がつかなくなるので駄目。
      "   飽くまでオプションの形をしていなければならない。オプションの形をしてい
      "   る物については仮にそのオプションが存在していなかったとしてもちゃんと知
      "   らないオプションとしてエラーになる様である。
      "
      "   compopt -s prog-trim; compopt -u prog-trim
      "   compopt -O prog-trim; compopt +O prog-trim
      "   compopt -o prog-trim; compopt +o prog-trim
      "   compopt -o ble-prog-trim; compopt +o ble-prog-trim
      "   compopt -o -prog-trim; compopt +o -prog-trim
      "
      "   うーん。やはり奇を衒った様な事をするのではなくて単に -o/+o を流用するの
      "   が自然の気がする。"-" で始まるのも混乱の元である様に思われる。
      "
      "   compopt -prog-trim; compopt +prog-trim
      "
      "   これは短オプションの集合と区別が付かないので却下。
      "
      " e もう少し異なる名前付けで区別する可能性
      "
      "   compopt -o _prog_trim
      "   compopt -o progTrim
      "   compopt -o ProgTrim
      "
      "   これらは Bash のオプションとは違うという雰囲気は出るかもしれないがやは
      "   り ble に関連するという事が明白ではないし、中途半端に違いを出しても仕方
      "   がない。
      "
      "   いっその事、関数名に倣って / で分けるというのも手である。
      "
      "   compopt -o ble/prog-trim
      "   compopt -o ble/filter-by-prefix
      "   compopt -o ble/syntax-raw
      "
      "   よくある設定の様に "." で名前空間を分けるというのも有効である。
      "
      "   compopt -o ble.prog-trim
      "   compopt -o ble.filter-by-prefix
      "   compopt -o ble.syntax-raw
      "
      "   うーん。contrib 等との整合性も考えると / で分けるのが良い気がしてきた。
      "   つまり、既に "名前 + /" を vendor prefix の様に使って来たのだからそれを
      "   踏襲するのが良い。新しい option は ble/no-default という事にする。

      結局 "ble/*" で統一する事にした。

    [実装]

    取り敢えず実装した。

    * ok: うーん。然し、もし source:argument をキャンセルしたとしても、結局また
      別の source が候補を生成するのではないかという気がする。全ての source を
      キャンセルする必要があるだろうか。或いは、また別の source は別の種類の補
      完に相当するので気にしない? うーん。気にしないで良い気がしてきた。

      それに、候補が複雑な場合には何れにしても source:argument は何も候補を生成
      しなくなるが、その時に意図しない別の種類の補完が起動したという記憶はない。
      従って、実際の所 source:argument をキャンセルするだけで大体補完は終わるの
      ではないか。つまり、argument を跨ぐ様な補完 source は現在はないので
      source:argument が一番最後の source であり、だとすると source:argument を
      キャンセルするだけで良い。

      もし argument を跨ぐ様な補完の可能性があれば、それはまた完全に独立した補
      完なので progcomp によって補完がキャンセルされる言われもない様な気がする。
      これは今後実際にそういう要望が (仮に) 出た時に考えれば良い。

2022-03-01

  * complete (action:command): function の description の quote が邪魔 [#D1788]

    最初の2行と末尾の } は削除して良い。また、quote ではなくて trace-text と同
    様の表示の仕方にしたい気がする。

    trace-text と同様の文字列に変換する関数は既になかったか?

    うーん。ble/unicode/GraphemeCluster/.get-ascii-rep という関数があるがこれは
    内部的にしか使用されていない。一方で、うーん。というか
    ble/canvas/trace-text をそのまま呼び出すべきの気がしてきた。そもそもその為
    の関数の筈である。

    或いはファイル名と行番号を表示した方が有益の気もする。取り敢えず両方表示す
    る事にした。ファイルパスは長くなるので最後の名前だけ表示する事にした。

  * complete: --optarg= に対して progcomp が走らない (motivated by rsteube) [#D1787]

    これは "--optarg=" 全体に対する引数補完よりも = の右辺 "" に対する優先順位
    が高いから。

    [導入経緯確認]

    然し、この様に引数の途中に = が含まれる時に rhs 補完も実行する様にしたのは
    何か別の理由があった様な気もする。その時の記録を確認する必要がある。遡る。

    da384044 #D1701 で変更されているがこれで導入された訳ではない。と思ったが
    #D1701 よりも前は以下の様になっていて argument でない時にのみ rhs を設置し
    ていた。

    local word=${text:istat:index-istat}
    if ble/syntax:bash/simple-word/is-simple-or-open-simple "$word"; then
      # 単語が istat から開始している場合
      local src
      for src in "${source[@]}"; do
        ble/syntax/completion-context/.add "$src" "$istat"
        if [[ $src != argument ]]; then
          local rex="^([^'\"\$\\]|\\.)*="
          if [[ $word =~ $rex ]]; then
            word=${word:${#BASH_REMATCH}}
            ble/syntax/completion-context/.add "$src" $((index-${#word}))
          fi
        fi
      done

    つまり、やはり #D1701 によってこの取扱が導入された事になる。

    * reject: と、思ったが上記のコードはそもそもおかしい。source には大体複数の
      文脈が登録されているので結局 rhs は argument の有無に関係なく大体複数生成
      される事になる。と思ったが、そうではない。 add rhs ではなくて add "$src"
      としているので、 argument 以外については = 以降からでも同様に生成するとい
      う取り扱いになっている。

    * #D1701 の議論を確認したが大した事は書かれていない。特にこの取扱の変更に関
      しては全く触れられていない。然し、実際に source 配列の中身を見ると option
      という物が追加されている。これが理由なのではないだろうか。つまり、option
      という項目を追加したが、option が = の続きから挿入されるのは変である。な
      ので、option も argument と同じく途中から文脈設定する必要性がない。他に
      variable:= という物もあるが、これも途中から挿入するのは変である。command
      も sabbrev も同様である。結局、途中からの挿入を許すのは source:file だけ
      である。という事を考えれば最初から file を固定して = の後の位置に補完開始
      点を設置するのは自然である。

    然し、そもそも unquoted な = の位置から補完を開始する選択肢を加えたのはどの
    時点だろうか。

    先ず 2f2f0eb6 (#D0941 eval の引数・変数代入の対応) の時点で既にあった。どう
    やら e9ba343f (#D0744 a=[TAB] が a=a=b になる問題に対する対処) で最初に導入
    された様だ。この時点でのコードは以下の形をしている。

      if [[ $source != argument ]]; then
        local sub=${text:wbeg:index-wbeg}
        if [[ $sub == *[=:]* ]]; then
          sub=${sub##*[=:]}
          ble-syntax/completion-context/.add "$source" $((index-${#sub}))
        fi
      fi

    この時は source は配列ではなかった。つまり、$source != argument は実際に
    source に argument が含まれていないという事の確認になっていたのだった。後の
    変更で source が配列になった時にこの条件がそのまま放置されたのは恐らくバグ
    である。

    [修正方法]

    a "virtual starting point" 的な物を導入してそれに基づいて補完文脈の優先順位
      を決定する。

    b rhs の補完開始点は飽くまで単語の先頭にして、しかし補完を実際に行う時に =
      以降について候補を生成する様に調整する。この時、source:file 等を内部から
      呼び出しているが、この source:file に中途半端な位置から補完を開始する仕組
      みを取り付ける? と思ったが、COMPV, COMPS 等既に計算済みの物をちゃんと正確
      に切り出せる事を保証しなければならないなど、暗黙の仮定を色々持ち込む事に
      なり余りすっきりしない。

    c 或いはこう言った物は argument の側で全て処理するべきなのではないか?

      実際に rhs をなくしてもちゃんと動いている様に見える。うーん。だとしたら完
      全に削除してしまっても良い? これについてはやはり導入経緯を確認する必要が
      ある→うーん。どうも現在 argument と rhs の両方が生成されているのはバグの
      気がする。バグと判断して良い。そもそも argument の側でもちゃんと同様の =
      生成を実行している。

    どうも rhs と argument の両方が生成されているのは歴史的に見て元々意図した物
    ではなかった様に思われる。従って、"c" の様に argument を生成している時には
    rhs は生成しない様に修正してしまって良い。

  * complete (requote): --prefix='a b c d e' の様に prefix 部分は requote から除外 [#D1786]
    Ref #D1787

    全体を quote し直す時にオプション的な部分・もしくは変数代入的な部分は除外す
    る様にする。例えば --option=hello\ 1\ 2\ 3 が '--option=hello 1 2 3' になる
    のではなく、--option='hello 1 2 3' になって欲しいという事。

  * edit: 古い terminator で表示が乱れる (reported by dongxi8) [#D1785]
    https://github.com/ohmybash/oh-my-bash/issues/314

    要するに Terminal 0.98 が使っている vte では DECSCUSR に対応していない。そ
    れにも拘らず TERM=xterm にしているので _ble_term_Ss に値が設定されている。

    https://bugzilla.gnome.org/show_bug.cgi?id=720821#c33
    此処によると DECSCUSR は vte 0.40 で導入された様だ。

    古い version の vte で DECSCUSR を無効化するコードを追加する事にする。所で、
    vte version と値の関係がどうなっているのか調べる必要がある。うーん。vte
    0.28.2 という事なのだろうか。。。そういう気がする。実際に一番最近の
    Terminator で vte:66xx になっていて、GitLab 上の最新版は 0.67.x なので、や
    はり vte 0.28.2 という事なのだろうという気がする。vte の番号を使って判定す
    る事にする。

2022-02-23

  * edit: bash-it から detach するとプロンプトが壊れた状態になる [#D1784]
    Ref #D1772

    # #D1772 に関係はしているが直接の原因ではない。元々 PS1 が退避された状態で
    # ble-detach になってしまうのだったが、(1) PROMPT_COMMAND は待避していなかっ
    # た (2) PS1 を "待避" した後も通常の場合は PS1 の元の値をそのままにしてい
    # たという二重の理由で問題が起こらなかったのである。#D1772 によって両方の振
    # る舞いを壊した為に問題として発現した。

    oh-my-bash から抜けても同じ状態になる。nix-shell の場合には大丈夫。

    どうやら PROMPT_COMMAND に何か設定されているとこうなる様だ。何故
    PROMPT_COMMAND があるかどうかで変わるのだろうか。因みに
    PROMPT_COMMAND も退避されたままになっている。

    うーん。何故か ble-detach/message の中から ble/textarea#render が呼び出され
    ている。この時に PS1 adjust が走ってそのままになっている。そもそも何故
    ble-detach/message の中で render が呼び出されているのか? うーん。恐らく
    stty の設定の為に Bash に制御を戻しても Bash が prompt を表示してくれないの
    が問題。その為に ble-detach/mesasge を介して態々プロンプトを描画しているの
    である。

    a eval-PROMPT_COMMAND の前後の PS1 adjust/restore は attached の時にだけ実
      行する? と思ってこれで実装したが…。

      そもそも textarea#render を detached 状態で呼び出して問題は発生しないのか。
      特に、既に様々の bash option 等を設定した状態で正しく ble-detach/message
      を呼び出す事ができるのかすら非自明である。

      と思ったが ble-detach/impl は実は restore option までは未だ実行していない
      状態の様だ。単に detached state に移行するだけである。

    b 或いは ble-detach/message を表示してから ble-detach/impl を実行するべきな
      のではないか。

      うーん。ble-detach/impl の中で何か出力されたりする可能性はあるのだろうか。
      エラーメッセージなど。確認すると、呼び出されているのは以下の 3 項目である。

      blehook/invoke DETACH
      ble-edit/detach
      ble/decode/detach

      後ろの2つはともかくとして最初の1つでユーザーが何かメッセージを出力したい
      という事があるかもしれない。うーん。という事を考えるとやはり後で
      ble-detach/message を実行するべきなのだろうか。

    やはり a の方針で修正する事にした。restore-PS1 は本来 ble-edit/detach から
    呼び出される物であって、其処で管理している状態は _ble_edit_attached 変数に
    格納されているので、この変数の値に基づいて PROMPT_ATTACH の周りで
    adjust/restore を行う事にした。

    修正した。PROMPT_ATTACH を設定した状態でも問題が生じない事を確認した。また
    bash-it, oh-my-bash による動作確認もした。

  * [棄却] bashrc: .bashrc.bash-it-minimal から実行するとエラーメッセージが出る [#D1783]

    PROMPT_COMMAND に ';:' という文字列が設定されて PROMPT_COMMAND を実行する度
    にエラーが発生する。或いは、ble.sh 自体の prompt-attach に失敗している?

    →と思ったらこれは単に .bashrc.bash-it-minimal の問題だった。このファイルを
    作成した当時は --attach=prompt の時、必ず PROMPT_COMMAND に文字列が設定され
    るという事を想定してよかった。現在は bash-5.1 以上では配列を用いて第2要素以
    降に設定するので、単に ';:' という文字列を付加するとエラーが発生するのだっ
    た。

2022-02-20

  * edit: work around exit called from EXIT trap (reported by SuperSandro2000) [#D1782]
    https://github.com/akinomyoga/ble.sh/issues/179#issuecomment-1046122787

    nix-shell の内部で exit を実行すると2回 [ble: exit] が表示される。これは
    nix-shell が設定する EXIT trap の中で再度 exit が呼び出される為である。
    ble.sh は独自に trap を処理しているし、また blehook EXIT も実行したいので、
    勝手に EXIT の中から本当に exit されると困る。なので、trap handler 実行中に
    ble/builtin/exit が呼び出された時には DEBUG trap を設定して、trap の呼び出
    し元まで制御を戻して続きの処理を実行することにする。呼び出し元まで戻った時
    に exit が trap handler の中で呼び出されたという事を記録しておいて、trap
    handler の処理の終わりに元々呼ばれた exit を呼び出し直す。

    * exit を trap handler の中で実行した時にはそのまま終了するのではなくて、
      trap の処理が完了するまで待ってから終了するべきなのではないか → その様に
      実装した。既存の TRAPDEBUG の枠組みにコードを追加して実現した。

    x fixed: exit 1 2 の様に余分な引数を指定した時、exit の準備をして [ble:
      exit] まで表示した後に exit: too many arguments のエラーが発生して exit
      がキャンセルされる。事前に引数の問題はチェックするべきである。

    取り敢えず実装して 3.0, 3.2, 5.0 で動作確認した。期待通りに動いている。以下
    のコマンドなどを使ってちゃんと全ての EXIT handler が実行される事を確認した。

    $ trap 'exit 5' EXIT; exit
    $ trap 'echo trap EXIT' EXIT; f1() { echo "$FUNCNAME $*"; exit "$1"; }; blehook EXIT+='f1 2 hello' EXIT+='f1 3 world';exit

    ? 関係ないが jobs がある時にユーザーが exit をキャンセルした時、後続の処理
      が実行されるのは問題ではないか? これに対しても何らかの対処が必要になるの
      ではないか?

    ? もし現在の TRAPDEBUG の枠組みが信用できるのであれば try/catch の枠組みを
      整備しても良いのかもしれないという気がする。その方が見通しも良いのでは。
      然し同じ commit でやるのは大げさな気がする。

      上記の exit キャンセルの際の振る舞いに関してはその枠組が整ってから対応す
      るのが良い気がする。

    →上の2つは別項目で処理する事にした。

    x bash-5.2 以降で EXIT trap の stdout が /dev/null になっている。これはどう
      したら良いのだろうか。うーん。EXIT trap の時だけ stdout/stdin を繋ぎ直す
      のが良いだろうか。

      調べてみた所 bash-5.2 以降では exit も EXIT handler も現在の関数の内部で
      行われる様だ。これは bash-5.1 までの top-level で実行されていたときと振る
      舞いが異なる。と思ったが、bash-4.4..5.1 の振る舞いが変だっただけの様だ。

      うーん。builtin exit を呼び出す時の redirection を削除するか? と思ったが、
      それだとやはり余分なエラーメッセージが出るのが心配である。という事を考え
      ると、元々の stdout/stdin を何処かに記録しておくべきなのだろうという気が
      する。

    2022-02-20 exit を DEBUG return で再現しようとしても　DEBUG trap の対象であ
    る "現在のコマンド" は必ず実行されてその後で return/continue 等の効果が現れ
    る。なので blehook 内での exit は意図した動作をしない。

    % blehook の中で exit をしても trap の実行が其処で終了しない。continue が実
    % 行されている筈なのに効いていないのは何故だろうか。うーん。eval の中から
    % continue を実行しても効かないのだろうか。
    % →それとも bash の特定の version を使っている事によるバグだろうかと思って
    % 振る舞いを確認したが、4.0..dev まで全て同じ振る舞いである

    →うーん。振る舞いを調べて分かったのは、DEBUG trap が呼び出された対象のコマ
    ンドは結局何れにしても実行される様だという事。例えば continue を trap 内部
    で実行すると、確かにその場で continue によって制御が変更され、trap 内の続き
    の処理も実行されない。そしてtrap の外側にあるループを抜ける。然し、その前に
    DEBUG trap の対象であるコマンドはちゃんと実行される様だという事。

    ? このコマンド実行をキャンセルする方法はないのだろうか。extdebug が設定され
      ていれば trap の戻り値によって振る舞いが変わるらしい。特に 2 を返せばその
      場で return を実行する事ができる。然し、continue をその場で実行する方法は
      不明である。continue が成功すれば戻り値は 0 になるので DEBUG 対象のコマン
      ドは結局実行される。逆にそれを阻止する為に戻り値を 0 以外にしようとすると
      continue を失敗させるしかなく、それだと次のループに移る事ができない。或い
      は BASH_COMMAND を書き換えたら実行するコマンドを書き換える事ができると言っ
      た事はないのだろうか。

      実際に extdebug を設定して試しても見たが、マニュアルから予想される通り、
      continue が成功すればコマンドも実行するし、コマンドの実行をキャンセルする
      には continue を実行する訳には行かない。continue 直前の終了ステータスを変
      更しても何の効果もなかった。つまり、continue 自体の戻り値が使われる。

      他に次のコマンドを無効にする手法はないのか? というか次のコマンドを無効に
      したとしても更にまた次のコマンドが実行されるというのだと際限がない。なの
      で、やはり extdebug を一時的に設定して 2 を返す事によって実行を中断させる
      しかないのだろうか。

    * extdebug を一瞬有効にして return (終了ステータス 2) でトップレベルまで戻
      るしかない気がする。

      ? extdebug は trap の中で無効化した場合でもその trap に対して失効するのだ
        ろうか。これについては振る舞いを確認する必要がある。→やはり trap の中
        で shopt -u extdebug すると即座に extdebug の動作はしなくなる様だ。ちゃ
        んとどの bash の version でも同様である事を確認した。

        だとするとどの時点で extdebug を off にするのかについて確認が必要になる。
        然し取り敢えずは sandbox の中で実行しているのであればその呼出元で解除す
        る様にすれば良い。※という事は、sandbox の中では未だ DEBUG trap は
        clear はしないという事になる。

      うーん。取り敢えず実装した。動いている。というかそもそも元々 continue を
      hook の中で実行する事を許していたのが変な気もする。或いは、continue 及び
      return を使って他の hook の処理に干渉したりできるというのも一つの機能だっ
      たかもしれないが、それならそれで別の枠組みを提供するべきの気もする。或い
      は、もし return continue を使うとしても trap sandbox の様に終了の仕方を検
      出して制御を決めるのが良いのだろうという気がする。

      現在は現状のままで良い気がしている。

2022-02-19

  * 2022-01-20 \C-x\C-v で bash-completion や terminal ID 等の情報も出力する [#D1781]

    bash-completion や oh-my-bash の version と terminal ID について C-xC-v で
    出力したい。

    * それを issue 報告に貼り付ける様にお願いする。

    * terminal ID / version をちゃんと検出する様にする。DA2R も一緒に出力するべ
      き。

    * bash-it には version 等は存在しないのだろうか。うーん。だからといっていき
      なり要求するのも違う気がする。

    2022-02-19 取り敢えず実装した。基本的には過去に ble.sh に対して問題を起こし
    た物を検出して表示する事にするのが良い。

    他の候補として oh-my-bash, bash-it, sbp, bash-preexec, starship 等がある。
    全てを検出して表示するのは変な気もする。oh-my-bash, bash-it については現在
    の theme (及び有効化しているモジュール) も表示すると良いのだろうという気が
    する。oh-my-bash については古い物だと version が存在していない。

    * done: bash-preexec は是非検出するべきである。

    * done: oh-my-bash の検出は upgrade_oh_my_bash 等を使うのが良い様に思われる。

    うーん。個別の設定を ble.sh 本体に入れるのも変なので contrib に含めようと思っ
    たが、然し、それはそれでどういうファイル名にしたら良いのかが分からない。こ
    れはユーザーが新しく設定を追加するという形の物ではなくて、逆に ble.sh から
    blesh-contrib に依存するという形になるので取り扱いが難しい。やはり取り敢え
    ずは ble.sh 本体に含めておくのが良いのだろうか。或いは init-*.sh の様に補助
    スクリプトとして保持するのが良いのかもしれない。うーん。

    →取り敢えずは ble.sh 本体に埋め込む事にする。肥大化してきたら
    blesh-contrib に新しくこう言った振る舞いの制御の為のディレクトリでも作って
    其処に登録する事にする。

    * done: starship
    * done: bash-it
    * done: sbp
    * git: gitstatus

    取り敢えず思いつく物は全て登録したのでOK。

2022-02-19

  * trap: 初期化時に既存の trap がある時にエラーメッセージが出る (reported by SuperSandro2000) [#D1780]
    https://github.com/akinomyoga/ble.sh/issues/179

    初期化時に以下のメッセージが出る。

    $ nix-shell -p hello
    bash: ble-edit/exec/save-BASH_REMATCH: No such file or directory
    bash: ble-edit/exec/restore-BASH_REMATCH: No such file or directory

    これは一番最近の commit で起こった事だった。新しく既存の trap　を保持する様
    に修正したが、その時に既存の trap は

    * そもそも trap の内部で使うのだから {save,restore}-BASH_REMATCH は移動するべきでは。

      →ble.pp に移動した。また同時に source ble.sh 直前の BASH_REMATCH を保持する様に修正した。

    * reject: ble/builtin/trap を実際に呼び出す必要はなくて単に値を代入すれば良
      いのではないか? その他にしなければならない操作などがあるだろうか。確認す
      る。と、思ったが解析するのも面倒である。という事を考えれば、やはりそのま
      ま実行する方が良いのではないか。一応 eval して配列に代入すればその3番目の
      単語として trap_string を取得する事はできる。

      うーん。やはり {save,restore}-BASH_REMATCH さえ移動すれば今の実装で良い気
      がする。下手に自前で実装するよりも既にある実装を使った方が (効率は悪いか
      もしれないが) コードの管理という点では良い。また、この部分は到底ボトルネッ
      クではないので速度を重視する必要も全く無い。

    * ble.pp でも BASH_REMATCH を保持する様に修正するべきでは。

    [動作確認]

    x fixed: source ble.sh の前後で BASH_REMATCH が保持される事を確認する。

      と思ったら保持されていない。どうやら restore-BASH_REMATCH の数がバランス
      していない様だ。元々 BASH_REMATCH の復元にはチェックが入っていなかった。
      という事は、これは意図的に重複して retore-BASH_REMATCH を呼び出す様になっ
      ていたということではないのか。gexec での使い方について改めて確認する。

      うーん。別に余分に実行しているという事もない。単に ble-attach で adjust
      し忘れているのが原因に思われる。

      →ble-attach に追加した。更に {adjust,restore}-bash-options と同じ箇所で
      ちゃんと呼び出す様に全体をチェックして追加した。

      →また _ble_bash_BASH_REMATCH_level が負になっていたので、負にならない様
      にチェックを追加する。

2022-02-18

  * command-help: 関数の help として関数が定義されたファイルを表示する [#D1779]

    関数の定義位置を DEBUG trap 等を使って抽出する事が可能なのではないか?

    これは bash_completion の debug の時にも便利である。というか、
    bash_completion の version を表示するのにも使える。

    と思ったら shopt -s extdebug; declare -F 関数名 で普通に取得できるのだとい
    う事が判明した。
    https://www.cyberciti.biz/faq/how-to-find-bash-shell-function-source-code-on-linuxunix/

2022-02-17

  * main, edit: 起動時に無駄に PROMPT_COMMAND が実行されるのを防げないか [#D1778]

    PS1 に含まれるコマンド置換も同様である。画面サイズが変わる等しない限りは再
    計算する必要はない筈である。

    今試してみたがそれほど無駄に実行している訳でもない様に思われる。

    * 但し、_ble_history_count が初期化される前と初期化された後で
      PROMPT_COMMAND が再計算されていたのは修正する事にした。これで恐らく起動時
      刻も短くなったのではないかと思われる。これで1回実行が減少した。

    * 実は #D1772 の時点で既に1回実行を減らしている筈である。PROMPT_COMMAND を
      待避した事によって減っていると期待する。しかし本当にこれで減ったのだろう
      か。怪しい → 試して見た所 manual attach の時に回数を一回減らす事ができて
      いると判明した。

    これで合計で4回実行されていた #D1772 の状況を再現できた。更に減らす事は可能
    だろうか。現在 prompt-attach を使っているが、ble-attach の時にはもっと減っ
    ても良いのではないか? → 確認してみると manual attach の時には
    _ble_history_count が bashrc の中で 1 で、その後で実際の数に増えるという事
    の様である。

    * うーん。そもそも PROMPT_COMMAND の決定に _ble_history_count が影響を与え
      るのだろうか。というのは疑問である。実は PROMPT_COMMAND に関しては
      _ble_history_count に関係なく version を決めて良いのではないか?

      →その様に変更する事にした。これで manual attach ならば唯1回の
      PROMPT_COMMAND の実行になった。

      一方で PS1 の評価に関しては history count が影響を与えるので
      _ble_history_count が変化したらちゃんと再評価しなければならない。これが二
      重に評価されるのは仕方がないと諦める事にする。

    * prompt attach の場合には依然として二重に PROMPT_COMMAND が実行されている。
      うーん。PROMPT_COMMAND が書き換えられて直接削除できない場合は仕方がないと
      して、内部で実行している場合には呼び出しを省略できないのか。と思ったが、
      PROMPT_COMMAND 配列の時には結局 bash は全てを実行するし、或いは、内部で保
      持している物についてはその場で実行しておかないと bash-preexec.sh の様に内
      部で PROMPT_COMMAND を書き換える様な物に対して矛盾のない動作を提供する事
      ができない。或いはもっと注意深く考察すれば何かできるのかもしれないが。

      或いは逆に ble-attach の中で実行している PROMPT_ATTACH の方を省略させる?
      と思ったが、

      x その場合 PROMPT_COMMAND 配列でより後にある PROMPT_COMMAND の実行結果が
        反映されない事になるし、ble-attach の処理が終わった後に続きで実行される
        PROMPT_COMMAND を阻止する事は結局できない。

      とは言いつつも scalar PROMPT_COMMAND (他によって修正されていない) または
      "配列 PROMPT_COMMAND かつ最終要素" の場合には、続きで別の処理が走らないと
      いう事は保証できるので、ble-attach の内部で走る PROMPT_ATTACH は省略でき
      る。

    2022-02-19 うーん。bash-it のプロンプトが prompt attach で初期化されなくなっ
    た。どうやら bash-preexec precmd 経由で bash-it は設定を行っている様で、
    bash-preexec が ble.sh によって置き換えられた事によって precmd が実行されな
    くなっているのが原因の様だ。うーん。precmd は実行しておくべきの気がしてきた。
    →取り敢えず PRECMD を呼び出す様にしたら期待通りに動く様になった。

  * 2020-09-01 trap: ble.sh を unload する時に復元する仕組みがあっても良いのではないか [#D1777]
    #D1775 と同時に対応した。

  * 2020-09-01 desolved: trap: ble.sh で上書きする時に元々存在していた trap はどうなっていたか [#D1776]
    Ref #D1775

  * util: DEBUG trap 以外についても元からあった trap を拾う様にしたい [#D1775]
    Ref #D1772

    RETURN と ERR 以外については中から普通に trap を見ることができる筈なので、
    そのまま中から値を抽出するというので良い。現在使用しているのは EXIT, WINCH,
    INT である。他に bash3 等で USR1 も使っていた筈。

    実際に trap を設定しているのは ble/builtin/trap/install-hook の一箇所のみで
    ある。ここで trap を読み取って ble/builtin/trap の枠組みで再設定すれば良い。
    対応した。

  * bash-3.0 でコマンドを実行するとプロンプトの前に変な文字列 '' が出力される [#D1774]

    うーん。家に帰ったら再現しなくなった。と思ったら再現の仕方が変化した。C-c
    でモードを変更すると '''' という無駄な文字列が表示される。これは一体何処か
    ら出てきている物だろうか。

    ようやく突き止めた。_ble_term_Ss が余分な引用符で囲まれている。然し何故だろ
    うか。調べると cache には含まれていない。だとすれば、blerc かもしくは内部の
    端末判定である。

    belrc を読み込まない様にしたら表示はされなくなったが、それは単にカーソルの
    設定をしていないのでカーソル切り替えシーケンスが出力されていないだけだった。
    実際に _ble_term_Ss の値を確認したら引用符が混入していた。という事は端末判
    定直後の代入の際に引用符が混入している事になる。

    分かった。 bash-3.0 には "${...#$'...'}" が '...' に展開されてしまうバグが
    ある様だ。これはチェックの対称に追加する事にする。

    ? そもそも他の "${pat#"..."}" 等も大丈夫なのだろうか? 動作を確認する必要が
      ある。以下は一応ちゃんと期待通りに動作する様である。

      $ v=1
      $ echo ${v//"1"/hello}
      $ echo "${v//"1"/hello}"
      $ echo "<${v#"1"}>"
      $ echo "<${v#'1'}>"
      $ echo "<${v#1}>"
      $ echo "<${v#"1"}>"
      $ echo "<${v/#"1"/hello}>"

      そんなに気にしなくて良い気がしてきた。

2022-02-15

  * 2022-01-23 [解消] 元々存在した DEBUG trap を保持する [#D1773]
    Ref #D1772

  * exec: 既存の DEBUG trap を保持する (motivated by ammarooo) [#D1772]
    https://github.com/akinomyoga/ble.sh/issues/176

    * 然し、上記で報告されている物を修正するには PROMPT_COMMAND の実行時にも
      DEBUG trap を有効にしなければならない。これは ble.sh の想定していない事で
      ある。うーん。面倒であるが有効化する事にした方が良いだろうか。と、思った
      が局所的に有効化して後で削除する事はできただろうか。同じ関数 scope 内で削
      除すれば良いのだったか。何れにしても既存の DEBUG trap は捕まえる事にする。

      速度を計測して問題なければ PROMPT_COMMAND 実行時に DEBUG trap を有効にす
      る事にする。その時には ble.sh の内部で直接実行している時にはユーザー trap
      は無効になる様に調整する。

      時間を計測して無視できないという判断の場合には bleopt で有効化できる様に
      する。

    →attach 時の既存 trap かそれとも ble.sh load 時の trap か。load した時には
    既に trap は置き換えられているので、それ以降 attach 迄に設定された物に関し
    ては気にしなくて良い。というか単に無視するしかない。なので、ble.sh load 時
    に設定されている trap を復元する方向で考える。

    * ble-reload した時にもちゃんと上書きして塗り潰さない様に注意する。一つの手
      は trap を復元する事の気がする。これは ble/base/unload で実行すれば良い。

    取り敢えずロード時の DEBUG trap を記録する事にする。他にもロード時の INT 等
    を保持する様にしたい。

    | うーん。trap -p DEBUG を実行すると最初のコマンド実行まではちゃんと存在して
    | いる。然し、コマンドを実行した時点で消滅してしまう。
    |
    | という事を考えると、何処かの時点で消えているという事になる筈だが、実際に
    | trap DEBUG を上書きする瞬間で trap -p DEBUG を実行しても何も表示されていな
    | い。或いは関数の中からだと外側の trap -p を読み取る事ができないという事なの
    | だろうか→試してみるとサブシェルの中からだと見えないが本体のシェルからは例
    | え関数内であったとしても読み出す事ができている。
    |
    | * うーん。何処で trap が削除されているかは分かった。一方で ble/util/assign
    |   の中だと DEBUG の trap string は正確に読み取れていないという事が判明した。
    |
    |   何故だろう。eval があると DEBUG が伝播しないという事なのだろうか。
    |
    | ? ble/util/assign で DEBUG trap の中身を取得できない理由について調べる。うー
    |   ん。

    色々試したがどうやらそもそも関数の中から trap DEBUG が取れるというのは幻だっ
    た様だ。一番外側で設定されている DEBUG trap を読み取る場合、全ての呼び出し
    階層の関数に -t 属性が予めついている必要がある (呼び出しの最中に -t 属性を
    付加しても無駄である。これは set -o functrace についても同様である)。

    これが意味する所は何だろうか。うーん。

    * ble.sh が最初に DEBUG trap を上書きしようとする時までに外側の DEBUG trap
      を読み取る必要がある。source ble.sh した瞬間には、ble.sh の一番外のレベル
      であれば ble.sh が source された文脈での trap DEBUG を取得できるかもしれ
      ないが、ble.sh 自体が関数内で source された場合には読み取る事ができない。

    a reject: という事を考えると、やはり一番最初に DEBUG trap を設定しようとす
      る機会に読み取るのが良い気がする。基本的に DEBUG trap を設定するのはコマ
      ンド実行の直前であり、コマンド実行は一番外側の文脈で行われるからである。
      (然し、将来的に line-editor のプロセスとコマンドを実行するプロセスを分離
      した時にどうしたら良いのかについては不明である。というか分離した時には
      trap 関連は全て再設計する必要があるので今ここで気にしても仕方がない気がす
      る)。

      と思って改めて調べてみたが、builtin trap DEBUG が初めて設定されるのは、ユー
      ザーが ble/builtin/trap DEBUG を呼び出した時かまたは C-c を押した時である。
      従って必ずしも通過するとは限らない。問題点は実際に DEBUG trap が設定され
      ているかどうかに拘らず .epilogue 及び .end で trap -- - DEBUG trap を除去
      しようとしている事である (但し、.epilogue / .end で実行している trap -
      DEBUG は結局何の効果もない)。

      a1 そう考えると例えば TRAPDEBUG/enter に関しては毎回コマンドが実行される
        前に呼び出されるので、初回にこれが実行された時点で、この中で trap -
        DEBUG を読み出すという事が考えられる。

      a2 でもそうなって来るとそもそもコマンド実行時に DEBUG trap を読み取る必要
        すらない。初回の ble-decode/.hook の直後か直前に読み出してしまえば良い
        のではないか?

        と思ったがそもそもコマンド実行直前である必要すらない。

    b reject: やはり ble.sh がグローバルで読み出された時にはその時点で既存の
      trap を読み取るのが安全である。もしグローバルでなかったら代替手段に頼る。

      実際に実装してみたが動かない。試しに ble.sh の先頭に以下を記述してみた所、
      実は source の中ですら DEBUG は伝播しないのだという事が判明した。

      | echo ble.sh:1
      | builtin trap -p DEBUG
      | echo ble.sh:2

      駄目だ。この方法はそもそも使えなかったのである。改めて man bash を確認し
      てみる。set -T の説明を読むと、これが設定されていなければ基本的には、関数
      もコマンド置換もサブシェルも DEBUG を継承しないと書かれている。然し
      source に関しては述べられていない。何故だろう。実際に改めて小さなスクリプ
      トを作って試してみると、やはり source の中では DEBUG trap は見えない。
      functrace を設定すると source の中でも見える様になる。functrace は man に
      は書かれていないけれども source についても DEBUG が継承される様になる。

      うーん。ble.sh の外側で set -T を実行させる様な方法は存在しないし、やはり
      source ble.sh の中から元々の trap DEBUG を読み取るのは困難である。

      結局一旦は実装した以下の変更はなかった事にする。

      | diff --git a/src/edit.sh b/src/edit.sh
      | index c32bed0..29c96c4 100644
      | --- a/src/edit.sh
      | +++ b/src/edit.sh
      | @@ -5769,6 +5772,17 @@ function ble/builtin/trap:DEBUG {
      |      ble-edit/exec:gexec/.TRAPDEBUG/trap
      |    fi
      |  }
      | +function ble/builtin/trap:DEBUG/.initialize {
      | +  builtin unset -f "$FUNCNAME"
      | +  if ((!_ble_bash_loaded_in_function)); then
      | +    local tmp=$_ble_base_run/$$.trap.DEBUG ret
      | +    builtin trap -p DEBUG >| "$tmp"
      | +    source "$tmp" # ble/builtin/trap に処理させる
      | +    ble/util/put '' >| "$tmp"
      | +  fi
      | +}
      | +declare -ft ble/builtin/trap:DEBUG/.initialize
      | +ble/builtin/trap:DEBUG/.initialize
      |
      |  function ble-edit/exec:gexec/.TRAPINT {
      |    local sig=130

      或いは functrace を on にしてもらうしかないのだ。然し常に functrace を on
      にする訳にも行かないし、だからと言って勝手に ble.sh の中から functrace を
      off にすると本当に functrace を on にしたい場合に使えなくなる。そうすると、
      ble.sh を呼び出す前後で set -T set +T を実行してもらう事になるが、其処ま
      でするぐらいであれば、普通に先に ble.sh を先に source してもらうべきであ
      る。また、一回でもキー入力をすれば治るのだが最初の一回だけは我慢してもら
      うしかないと諦めるのである。

      functrace を on にしてもらう様にお願いするのはおかしいとしても、ユーザー
      が偶 functrace を on にしていたらそれを利用するべきなのでは? そういう意味
      でやはり上のコードは一応含めて置いて良いのではないか?

    c 最初のキー入力の直後に解決するという手がある。

      グローバルで実行する必要があるので _ble_decode_bind_hook に指定する必要が
      ある。然し、他の箇所からも同時に _ble_decode_bind_hook を実行しようとした
      時に問題になる。うーん。確認してみた所 _ble_decode_bind_hook に値を設定し
      ているのは現在一箇所だけである。なので今までは何も気にする必要はなかった。

      c1 _ble_decode_bind_hook には追記式でコマンドを書いていく方式にする可能性。
        そして複数の箇所から書き込む事を許す。

      c2 _ble_decode_bind_hook を現在書き込んでいる箇所 (gexec/.setup) で処理す
        る。

      c3 reject: 或いは通常のコマンドとして最初に登録してしまう? と考えたがそう
        するとコマンドのカウントが余分に増えてしまうので駄目の気がする。

        % 他にも C-x C-v 等、コマンド実行として取り扱っている物があるのではなかっ
        % たか。そういった物についてはコマンドのカウントが乱れない様になっている
        % のか? と思って確認したがこれらは実は gexec で実行してはいなかった。その
        % まま関数の中で実行していた。その時に必要に応じてシェル状態の保存・復元
        % をその場で実行して処理しているのだった。

      上記 c2 の方法が現状で一番綺麗の気がする。今後、もっと様々な箇所から bind
      hook を設定したいという状況になったら c1 の様な方式にすれば良い。

    % 取り敢えず、上記の b と c の方法を組み合わせる事にする。先ずは b から実装す
    % る事にする→と思ったら b は不可能な事が判明してしまった。

    仕方がないので c の方針で実装する事にする。とにかく未だ DEBUG trap が存在し
    ていない時にそれをチェックするのが目的。

    というか最初のキー入力の時にようやく DEBUG trap を読み取る事ができるという
    のが意味する事は…最初のプロンプトの表示の時点では DEBUG trap を正しく動作
    させるのは無理という事になるのでは。うーん。もしそうだとすれば報告を受けた
    場合に関しては、結局 PROMPT_COMMAND を実行させるしかないという事になる。

    或いは、attach した時の DA2 等の返答の際に取得はできる。とは言いつつ DA2 の
    返答が戻ってくるまで PROMPT_COMMAND の実行を遅延させる訳にも行かない。とい
    う事を考えると、やはり最初の一回は必ず失敗するという事は認めてもらうしかな
    い。或いは、最初に ble.sh を source して貰ってそれから最後に attach すると
    いうのを徹底してもらうしかない。

    * done: 取り敢えず c の方針で早く実装する。実装した。というか b の実装で用
      意した関数をそのまま呼び出せば良いのだった。

    * done: PROMPT_COMMAND で TRAPDEBUG を有効にする。

    * done: functrace も待避・復元オプションに含める。

      追加した。これで特に問題が起こるとは思えない。DEBUG で余分に何か呼び出さ
      れるという事はあるかもしれない。

    ? [保留] bash-4.4..dev まで tmpenv の builtin eval の中から見える値が変。と。これ
      は実は既に知っている問題なのではないか。

      うーん。逆に bash-4.3 で問題が起こるという事は判明した。bash-4.4 以降では
      ちゃんと値が見える筈である。それにも拘らず実際の ble.sh の中では逆に 4.4
      以降で値が見えなくなっていた。これは一体どういう事だろうか。

      →うーん。これはどうもまた別のバグの様だ。再現した。以下で再現させる事が
      できる。これは trap 関連でしか再現しないのだろうか。分からない。

      | function print { echo "v=${v:-(not found)}"; }
      | function trapdebug { echo "$FUNCNAME:1:v=($v)"; }
      | builtin trap 'trapdebug' DEBUG
      | v=xxxx eval print
      | v=xxxx builtin eval print

      と、思ったが、もしかすると DEBUG trap の中からは意図的に tmpenv が見えな
      い様になっているのかもしれない。然し、builtin eval の時と eval の時の振る
      舞いを比べるとやはり異なるのでこれは意やはり意図したものではない。

      これは別項目にする事にする。今は取り敢えず Note だけ残して放置する事にす
      る。

    [動作確認]

    * C1 取り敢えず動作はしている。然し微妙な振る舞いが色々ある。

    x C2 fixed: 何故か起動した時に点滅する様になってしまった。一旦表示がクリア
      されている?  →これはコマンド実行をした時は bind/.tail をコマンド実行後に
      実行する為に bind/.tail を抑制するのが原因。今回 DEBUG initialize でも
      return 0 をする様に変更してしまったので、DEBUG initialize の時にも
      bind/.tail が省略されてしまってしかし DEBUG initialize の場合は自分で
      bind/.tail が呼び出されないので、bind/.tail が欠けて bash -x によるプロン
      プトの消去が発生して点滅していた。

      DEBUG initialize だけの時は return 1 を返す事にした。

    x C3 fixed: 後から ble.sh を source した場合、エラーメッセージが出る事も問
      題であるが、最初のコマンドの実行時間がシェル開始時刻からコマンド終了時刻
      までの時間になってしまっている。

      ble.sh なしだと期待通りに時間を計測する事ができている。先に ble.sh を
      source した場合でも特に問題は起こっていない。

      これは何故だろうか。先に trap を実行しているとどういう事になるかというと、
      bashrc の中で time_start されて timer が設定される事になるが最終的に
      PROMPT_COMMAND が呼び出されて timer は clear される事になる。然し、その後
      で様々の処理が走ってその過程で改めて timer が設定される? と思ったが何によっ
      て設定されるのかは謎である。ble-attach した段階で DEBUG は解除されている
      のではないのか。と思ったが、違う。実際に解除されていないのだ。それでは全
      然駄目だ。恐らく最初の ble-decode/.hook の瞬間に DEBUG trap が呼び出され
      て結果として時間にずれが生じているという事だろう。

      というか、trap - DEBUG で解除すれば良いのではないか?
      →OK. これで治った。

    x C4 fixed: 最初に ble.sh を source した場合でもエラーを検出している。これ
      はどういう事か。うーん。最初の PROMPT_COMMAND を実行する時点で未だ attach
      が完了していないから DEBUG trap の設定が省略されているという可能性? しか
      し、それだとエラーが画面ではなく vbell に出力されている理由が分からない。
      これは要するに bash が取り敢えず裏で実行した PS1 の評価によって引き起こさ
      れているのではないか。

      と思ったが、bash が裏で PROMPT_COMMAND を実行するという事があるのだろう
      か…。あー。分かった。PS1 については待避しているが、PROMPT_COMMAND につい
      ては待避していないのである。

      PROMPT_COMMAND が二重に実行されている問題は別枠で修正するべきの気がする。
      これは ble-0.3 にも適用する必要がある。と思って動作確認したが二重実行され
      るのは最初に呼び出した時だけなので内部で処理する事にする。これは軽微な差
      異なので 0.3 に適用する必要はない。

      * PROMPT_COMMAND が ble.sh と bash で二重実行される事について

        特に PROMPT_COMMAND を待避していた記憶はない。という事は PROMPT_COMMAND
        が裏で二重に実行されているのではないか。更に言うと、裏の PROMPT_COMMAND
        によって裏の PS1 が設定されてしまっているのではないか。

        現状で実際にその様になってしまっているかどうかを確認する事にする。→確
        認してみたが別にそういう困った事にはなっていなかった。よく考えてみたら
        PROMPT_COMMAND はコマンドが実行された後に実行されるのであって、bash の
        枠組みの方でコマンドを実行していないのだから余分に呼び出される事はない
        のである。

        但し、初回の PROMPT_COMMAND に限っては bash によって実行されるという事
        に留意しなければならない。PS1 を待避・復元している所で PROMPT_COMMAND
        も待避・復元すれば良いのではないだろうか。但し、初回だけで良い。否、
        ble-attach の時に何回 PROMPT_COMMAND が呼び出されるか分からないので、何
        回かは実行する必要があるだろうか。これは実際に試して何回実行されるか確
        認すれば良い。

        確認した所4回呼び出されている。これは確かに呼び出し過ぎである。その内の
        1回は bash から直接呼び出されている。残り3回が何処から来ているかは確認
        する必要がある。一番最後の物は端末テスト後の再配置だろうと思われるが、
        再配置の時に改めて PROMPT_COMMAND を呼び出す必要もないだろうという気が
        する。

        ? そんなに重い処理でなければ PS1 と一緒に毎回保存・復元すれば良いのでは?
          と思ったが、PROMPT_COMMAND 配列を保存・復元するのは面倒なのでやはり保存・
          復元は最初だけにするのが良い様に思われる。

          PROMPT_COMMAND 配列の場合には特に設定下側がどの key に対して設定した
          かを覚えているかもしれないので、key をずらしてしまうのは良くないので、
          特に key も一緒に記録する必要がある。

          保存・復元は ble/util/declare-print-definitions PROMPT_COMMAND を用い
          る方法と各要素を一つずつ保存復元する方法の二通り考えられる。前者は
          fork を沢山するので重い。後者も要素が大量になってくると大変である。

          うーん。取り敢えず各要素毎にコピーする事にする。

        取り敢えず対応した。ちゃんと動く様になった。

      * reject: 待避は bashrc の中から実行している時だけで充分なのではないか。

        そんなに重い処理でもないし PS1 を毎回待避している事を思うと
        PROMPT_COMMAND を毎回待避しても対した処理にはならないので、気にしなくて
        も良いのではないか。

        a 然し、bashrc の中から実行しているという事が分かるのであればその時にだ
          け待避するのは尤もな気がする。

          一方でその様な方法が存在するかどうかはまた別である。以前その様な方法
          を思いついた様な気もするし、結局動かなかった様な気もする。思い出せな
          い。bash のソースコードを覗いて、何かの振る舞いで interactive /
          non-interactive で振る舞いの変わる物があってそれを巧妙に組み合わせれ
          ば判定可能なのではないかと思ったが、結局異なる振る舞いを再現させる事
          ができなくて諦めた気がする。

        b もしくは attach 後の初回の PROMPT_COMMAND の評価の時だけ待避する? し
          かし、それだと複数回 attach もしくは reload を行った時に (そもそもそ
          の様な使い方は想定していないとは言え)、PROMPT_COMMAND が余分に実行さ
          れてしまう事になる。

          更にコマンドラインから直接 ble-attach した時や prompt attach した時に
          は初回でも PROMPT_ATTACH を待避する必要もない。という事を考えると初回
          かどうかというのは本質ではない様に思われる。

        c 或いはコマンドを既に一回でも実行していたら OK という考え方もある。こ
          れならば複数回 reload した時に PROMPT_COMMAND が重複して実行されると
          いうこともない。

          一方でやはり初回には余計に PROMPT_COMMAND を待避する事になるが仕方の
          ない事なのかもしれない。

        また条件によって待避したりしなかったりする場合、現在 PROMPT_COMMAND が
        設定されているかどうかを判定する方法が面倒になる。という事を考えると現
        状の様に常に PROMPT_COMMAND を待避する様にしておくのが無難の様な気がす
        る。或いは、退避はしなくて常にコピーだけはしておくという事にしても良い
        が、それだと結局コストは存在しているので中途半端な事をするよりは本当に
        待避した方が良い様に思われる。

        取り敢えずは現状の様に常に待避する事にして、後で問題になる様であれば条
        件を考える事にする。そもそもコマンド実行の時にだけ待避は起こるのだから、
        滅多に実行しない操作だし処理のコストが問題になるという事は考えにくい。
        もし問題が起こるとすればもっと別の何かのエラーが起こった時の状況復帰に
        関係する物だろうと思われる。

    ? C5 ok: PS1= とするのは bleopt_internal_suppress_output が設定されていない
      時だけになっているが、これも常に実行する様にした方が良いのでは。裏で毎回
      コマンド置換などが実行されている様な状態になっているのは無駄である。それ
      にもしユーザーが PS1= に何か破壊的な操作・副作用のある操作を実装していた
      場合やはり振る舞いが意図しない物になる気がする。なので PS1= を指定するべ
      き気がする。

      と思って振る舞いを確認してみたがそもそも PS1 は余分に評価されてはいない。
      確か端末の状態に応じて Bash はプロンプトの評価を控えるのだった。そしてそ
      れに伴って PS1 の評価も実行していない? と思ったが、そもそもコマンドを実行
      していないのだからプロンプトの内容も変わらず、従って PS1 の中のコマンド置
      換を再評価する機会もないというだけの事の気がする。PROMPT_COMMAND が二重に
      実行されない事と同様の事である。

      何れにしても PS1 を空にする理由も特にない気がするので PS1= を実行する。と
      思ったが、元々不意に ble.sh が落ちた時に不自然な振る舞いにならない為に
      PS1= を設定しているのだった。という事を考えるとやはりそのままにして置いた
      方が良い? と思ったが、現在中途半端な状態にあるという事が分かる様にした方
      が良い気もする。

      a 例えば PS2 を代わりに設定する?

        x と思ったが、PS2 は PS2 でコマンド置換を含んでいる可能性もあるし、そも
          そも異なる物なのでユーザーが意図的に何か PS2 に仕組んでいた時に変な事
          になる。

        x というか、将来的に PS2 を編集時の行番号等に用いるなどした時に棲み分け
          が改めて必要になるのでやはり変な利用方法はしない方が良い。

      b [press any key to continue] 等として変な状態にある事が分かる様にするの
        が良いのでは。

        →具体的に問題を起こしてみてどうなるか試そうと思ったが再現できない。うー
        ん。配列の添字関係で実行が停止していた気がするが…。

        echo ${_ble

        等の中途半端なコマンド文字列で無理やり実行してもちゃんと元の状態に戻る
        事ができている。コマンド実行がその場で終了してしまう様な設定が存在した
        気がするがどの様にすれば良いのだろう。

        * 例えば ${hello?world} などか → 問題なかった。
        * set -u だろうか → 問題なかった。
        * set -e だろうか → これはそもそもシェルを終了するので関係ない。
        * 算術式中の a[-1] だろうか → これも問題ない。

        何処かに記録として残っていないだろうか。

        * "for ((i=0;i<10;i++)); do sleep 1; done"<C-c> これだ

        然し試してみたがこちらで指定した PS1 が反映される訳でもない。

        ! 恐らく最初に PS1 を表示した時の計算結果がずっと残っているという事なの
        ! だろう。なので、実は中で PS1 を設定しようがどうしようが関係ないという
        ! 事。但し、bashrc で直接 attach する時に限ってはその時の PS1 に意味が
        ! ある。
        !
        ! →と思って bashrc で直接 attach する場合についても試したがそれでも駄
        ! 目だった。よく考えたら bash が変な状態になった時にプロンプトを表示す
        ! るとして、その時の PS1 の値を使って表示するのだとしたら、コマンド実行
        ! 中に失敗したのだとしたらコマンド実行中の PS1 を使って表示するのだから、
        ! 待避した PS1 が使われる事はない。という事を考えると待避中の PS1 が使
        ! われる事はない様な気がする。

        うーん。コマンド実行中の失敗の場合はコマンド実行中の PS1 が使われるので、
        待避中の PS1 の値に何を設定するかは関係ない。そもそも PS1 を待避する必
        要性があるのかどうかも何だか分からなくなって来た。

    * ok: WINCH の時に問題になるのではないか: ble.sh では WINCH した時に、
      PROMPT_COMMAND で現在の端末幅に合わせた内容を計算している可能性を考えて、
      PROMPT_COMMAND を再度呼び出す事にしている。これで問題が生じることはないか?

      →報告されたコードの場合には結局 PROMPT_COMMAND のコード自体に対して
      DEBUG trap が走る事によって問題が回避されているので、問題は起こらない筈。
      →実際に問題が起こらないという事を確かめた。

      一方で PROMPT_COMMAND が余分に呼び出される事で他の問題が生じる可能性はあ
      るだろうか。うーん。そもそも PROMPT_COMMAND がコマンド実行後に1回だけしか
      呼び出されないという想定は bash のマニュアルにも書いていないし、意味を考
      えればプロンプトの再表示時に複数回呼び出されてもおかしくはない気がする。
      具体的にそういう動作に依存している枠組みが現れる迄は気にしない事にする。

    ? C6 reject: 効率を考えたら実は TRAPDEBUG/enter の時には TRAPDEBUG ではなく
      て元のユーザーの trap を直接設定しておけば良いのでは?

      現在の TRAPDEBUG の処理 (sandbox でのユーザートラップの実行を含め) は複雑
      で重いので直接実行できるのであればその方が良い気がする。

      現在 TRAPDEBUG は ble.sh 的には INT の処理の為にしか使っていない。将来的
      にもっと別の事に使いたくなる可能性もあるが、取り敢えずは特別な処理は挟ま
      ないのだからユーザートラップを直接設定して良い気がする。

      一方で TRAPDEBUG は ble.sh の処理自体に対する DEBUG trap を阻止するという
      目的もあった。うーん。そうは言っても gexec/.{restore,save}-lastarg 及び
      epilogue 等に対する DEBUG trap 程度であれば許しても良い気がする。その直後
      に builtin trap - DEBUG で解除しているので、gexec/.end 以降に対してユーザー
      の DEBUG trap が実行される事は結局ないと思われる。

      .TRAPDEBUG/trap に於いて現在介入する必要がなければ介入しない様にする事にした。

      x と思ったら報告者の設定で問題が起こる。やはり ble.sh 内部での処理に対し
        ては TRAPDEBUG が発生しない様に制御が必要なのだろうか。

        うーん。PROMPT_COMMAND の実行の為の TRAPDEBUG に関しては DEBUG を
        filter する為に明示的に TRAPDEBUG で trap する事にした。

      * というか単にユーザートラップを実行するだけなのであれば、単に postproc
        にユーザートラップをしかければ良いだけでは? その様に実装した。但し、本
        来は user trap がなければそもそも DEBUG trap も存在しない筈ではある。但
        し、複数コマンドを実行していて最初のコマンドを C-c で殺した時に、次のコ
        マンドには TRAPDEBUG が残った状態で実行される。この時にそういう事が起こ
        る可能性がある。

      o C-c がちゃんと動くか確認する。OK 動いている。

      2022-02-16 うーん。やはり直接 trap すると問題が色々発生する。

      x 先ず初めに報告にあった物が動かなくなった。報告にあった設定だと
        PROMOPT_COMMAND より後に初めて実行した DEBUG trap で時刻が決まる。然し、
        直接 trap していると、ble-attach よりも前に設定した trap が
        ble-decode/.hook 等にも反応してしまって正しい時刻が決定できない。

        従って attach していない状態で ble/builtin/trap が受け取った DEBUG trap
        は結局 TRAPDEBUG 経由で実行するのが無難なのではないか。

      x 更に、コマンド実行で再設定している DEBUG trap についても今回は問題になっ
        ていないが、やはり問題になる可能性がある。直接 user trap を設定すると、
        exec:gexec/.* に対して軒並み発火してしまうが、本来これらに対しては発火
        して欲しくはないのである。

        なのでこの場合にもやはり user trap を直接設定するのは避ける。

    x C7 fixed: prompt-attach をした場合全く値が更新されない。これは何故だろう
      か。PROMPT_COMMAND が失われている可能性? 確認した。元からあった
      PROMPT_COMMAND が消滅している。→修正した。ble/idict#copy の引数が逆だっ
      た。

    x C8 fixed: 現在は先程まで動いていた物も動かなくなっている。何故?

      x fixed: 先ず、起動時に trap が削除できていない所為でコマンドを実行する前は表示
        される時刻が前のプロンプトを表示した時刻からの遅延になってしまっている。
        これは type=initial でも final でも起こっている。

        これの原因は簡単で user trap を直接 trap する様にした為に、ble.sh の内
        部 (具体的には最初の ble-decode/.hook) に対して DEBUG trap が動作してし
        まっている。

      x fixed: 次に、final で実行した場合にはそもそも user trap すら正しく抽出
        できていない。少なくとも2コマンド目以降には元々取得できていた筈だがそれ
        も動かなくなっている。

        これの原因は謎である。もしかすると TRAPDEBUG/.initialize が実行されてい
        ない? 先に adjusted が正しく動作しているとすると確かに
        TRAPDEBUG/.initialize は呼び出されなくなってしまう。現在の構成の場合に
        は TRAPDEBUG/.initialize と adjust は別々に処理する必要がある気がする。

        これは試しに attach で adjust を呼び出す様にした所に問題がある。attach
        の時点で user trap の初期化が終わっていないので、この時点で adjust を実
        行してしまうと user trap が失われてしまう。…と思ったが、それも何だか変
        な気がする。adjust では trap - DEBUG を実行していて ble-attach は
        declare -ft していないので、ble-attach 内部での trap 解除は外に漏れ出さ
        ない筈である。或いは、同じ文脈で TRAPDEBUG/.initialize が実行されてしまっ
        ている可能性はある?

        分かった、adjust で trap - DEBUG したのは外に伝播しないが、adjusted=1
        に設定する為に user trap 読み取りのコードが不活性化してしまっている。
        adjusted=1 になる為には user trap も読み取った後でなければならないので
        ある。

    x C9 fixed: prompt-attach (memo/D1772.bashrc type=initial-prompt) した後に
      user trap が設定されたまま残っている。うーん。ble-attach する時に削除する
      べきなのではないか。。と思ったが、それだと未だ user trap を読み取っていな
      い時に元から存在した設定を削除してしまう事になるので駄目である。

      うーん。つまり最初に読み取った時に取り敢えず trap を削除しておくべきとい
      う事なのだろうか。コマンド実行中でなければ。

      というより prompt-attach の場合、何処でユーザー trap を読み取っているのだ
      ろう。と思ったが、initial-prompt の場合には最初に trap DEBUG をユーザーが
      呼び出した時点でユーザー trap が読み取られる事になる。

      結局初回は必ず trap - DEBUG を実行する事になるという事なのだろうか。初回
      の判定はどの様にしたら良いのか。うーん。また新しく変数を増やすのか? 或い
      は既存の変数を用いて判定する事はできるだろうか。

      そもそも userTrapInitialized という変数はその場合必要になるのだろうか。こ
      の変数は実際 gexec/.setup で調整をする必要があるかどうかだけの為に用いら
      れている。という事を考えるとこの変数の意味を変えれば良い気がする。

      或いは TRAPDEBUG の adjust/restore の状態をちゃんと管理しておいて、一旦
      restore したのに未だ adjust していない状態になっていたり、未だそもそも
      adjust した状態になっていなかったら元に戻す等の対処が必要になるのではない
      か。

      →その様に修正した。これで無駄に DEBUG trap が内部で呼び出される事はなく
      なった筈。

      しかし報告された設定の場合に、初回のコマンド実行の実行時間が正しくない。
      これは一回でも無駄な DEBUG trap が PROMPT_COMMAND 実行後に実行されるとも
      う駄目なので、実は最初に現れた時点でもう正常動作しないのである。

      a そうなると attach の時点で trap を削除するべきなのだろうか。その為には
        attach で trap の削除に関係する全ての経路で declare -ft を指定しておく
        必要がある。一応どの様な経路で adjust が行われるのかについて確認してお
        く事にする。

        取り敢えず adjust-PS1 は以下の経路で呼び出されている。

          ble-edit/adjust-PS1
          ble-edit/attach/.attach
          ble-edit/attach
          ble-attach
          ble/base/attach-from-PROMPT_COMMAND

        うーん。ble-edit/attach の直下で TRAPDEBUG/adjust を呼び出してみる事に
        する。

        x 然し関数内や source 内部で ble-attach した時には結局元の trap を削除
          するのに失敗する事になる。一応一番外側が ble-attach かどうかで判定は
          できる。また set -T が有効になっている場合にも削除は可能だろう。

        他、ble-attach を呼び出す可能性のある関数は全て列挙する。

        - ble -> ble/dispatch
        - ble/base/attach-from-PROMPT_COMMAND
        - ble/base/process-blesh-arguments ... これはいきなり attach する時

        色々面倒である。ble/base/attach-from-PROMPT_COMMAND についても、これは
        PROMPT_COMMAND に設定して使う事を想定しているが、他の枠組みが何処かの変
        数に待避して関数内から呼び出した場合にはやはり trap が見えなくなってし
        まう。結局 attach の時点で確実に trap を削除しようとするのは困難である。

      b initial-attach の時に問題が起こらない様にするだけであれば、attach の外
        の状態であっても trap を実行した時には filter を入れる様にするという手
        もある。

      うーん。方針が定まらないとどの様に対処するべきか分からない。再度現状につ
      いて整理する事にする。

      "ble/builitin/trap ... DEBUG" が bashrc で呼び出された時はどの様に振る舞
      うべきか。取り敢えず、実際に ble-attach するまでは普通に DEBUG trap が動
      作するのが自然である。また、ble-attach した時に如何にして元から存在した
      DEBUG trap を不活性にするのかという事。

      ! a ble/builtin/trap でユーザーが DEBUG trap を設定した時は、未だ attach し
      !   ていなければ user trap を直接設置する。ble-attach を実行した問にそれを
      !   削除する。
      !
      !   然し、trap - DEBUG によって本当の意味で削除するのは条件が限られている。
      !   現在の関数呼び出し経路の全てに trace 属性がついているか、set -T が設定
      !   されていてかつ現在の関数呼び出し経路の全てが既知の (set -T を弄らない)
      !   関数であるという事が保証できる場合のみである。取り敢えず trap '' DEBUG
      !   とすれば削除はできる気がする。
      !
      !   従って、
      !
      !   1 ble.sh の枠組みの中で ble-attach を最終的に呼び出す可能性のありそうな
      !     関数の全てに declare -ft を付加しておく。
      !
      !   2 ble-attach が呼び出された時に既に user trap が既知の状態になっている
      !     時には trap DEBUG を削除する。
      !
      !     2a 経路上が全て DEBUG を継承していると判断できる時には trap - DEBUG
      !       を実行して直接削除する。
      !
      !     2b 経路上で DEBUG が途切れているかもしれない時には仕方がないので trap
      !       '' DEBUG を実行する。途中で別の DEBUG を設置したりしない限りはこの
      !       DEBUG trap は一番上の階層にまで適用される筈である。
      !
      !     然し面倒なので ble-attach した瞬間には常に trap '' DEBUG で良い気もす
      !     る。その様にしておけばわざわざ declare -ft 等の事を考える必要もない。
      !
      !   3 ble-attach が呼び出された時に user trap が既知の状態になっていない時
      !     は厄介である。
      !
      !     3a 経路上が全て DEBUG を継承していると判断できる時にはその場で user
      !       trap を読み取ることができる。その時には単に trap - DEBUG を追加で実
      !       行して trap を削除すれば良い。
      !
      !     3b それ以外の場合には user trap を取得できない。trap '' DEBUG で削除
      !       すると元の user trap を破壊してしまうので実行できない。
      !
      !   この方法で気になるのは様々な関数に trace 属性を設定して変な問題が起こら
      !   ないのかという事である。これは他の人が設定した DEBUG trap の侵入を許可
      !   するという事に他ならない。本来他の人が設定した DEBUG trap でその枠組の
      !   動作に干渉してはならない (したら保証外) なので気にしなくて良い筈という
      !   気もするが、DEBUG trap を使っている側がちゃんと動かない可能性は常に存在
      !   する。まあ余り気にしても仕方がないのかもしれない。
      !
      ! b ble/buitlin/trap は attach 状態にない時には TRAPDEBUG を設置する。つま
      !   り、ble.sh の外側でも TRAPDEBUG で filter しながら動作するという事。こ
      !   れはいざ ble-attach を実行した時に意図しない DEBUG を防ぐ目的がある。
      !
      !   然し、これは元から設置されていた DEBUG に対しては無力である。結局、元か
      !   ら設置されていた DEBUG に対しても対策をするのであればわざわざ DEBUTRAP
      !   経由にする必要もないのでは? → 然し、元から設置されていた DEBUG に対し
      !   ては完全な対策ができない。ble/builtin/trap 経由の時には完全な対策が可能
      !   な方法に切り替えるのは妥当である。従って、論点は元から設置されていた
      !   DEBUG に対してどれだけ完全な対策を行う事ができるかという事になる。

      c 結局 ble/builtin/trap 及び .TRAPDEBUG/restore では必ず TRAPDEBUG 経由で
        bind する事にしたので改めて整理し直す。また、現在形路上が全て DEBUG を
        継承しているかどうかを判定する関数を作成した。

        1 ble.sh の枠組みの中で ble-attach を最終的に呼び出す可能性のありそうな関
          数の全てに予め ble/function#trace を実行しておく。

        2a global DEBUG が見える状態にある時には、user trap が未知であればその場
          で読み取りを行う (__initialize)。そして DEBUG trap を削除する
          (__TRAPDEBUG_adjust)。

        2b それ以外で user trap が既に読み取り済みもしくは設定済みであれば
          DEBUG trap を削除する (__TRAPDEBUG_adjust)。

        2c それ以外の時には user trap を保持しなければならないので仕方がないが
          そのまま通過。

        この方針で行く事にする。実装した。取り敢えず動いている様に見える。後で
        制限について書く事にする。

    * C10 done: 元から設定されている trap が TRAPDEBUG の類だった時。これは無視
      する必要がある。そうしないと最悪無限ループになる。

    x C11 fixed: initial-prompt で core-dump する様になってしまった。。何故? 再
      帰 trap の可能性を疑って先に対応する事にしたが直らなかった。関係なかった
      様だ。

      取り敢えずどういう制御パスになっているかだけは確認する。

      と思ったら再帰 trap になっていた。再帰判定のコードが間違っていた。修正した。

      然し、そもそも何故再帰 trap になってしまうのかというのは謎である。あー分
      かった。ble/builtin/trap 経由で user trap を読み取ってもその後で
      ble-edit/attach から呼び出した _ble_builtin_trap_DEBUG__initialize で再び
      user trap を読み出そうとしてしまうのが問題なのである。これも修正した。

    x C12 fixed: bash-5.0 以下で PROMPT_COMMAND が消滅してしまっている。何故か。
      copy-state の使い方を間違えている?

      これは分かった。attach-from-PROMPT の時は PROMPT_COMMAND の書き換えをチェッ
      クしている。なので、中で attach して PROMPT_COMMAND を待避するとそれが保
      存されてしまう。

      と思ったがそれでも何だか変な気がする。ble-attach は何れにしてもその
      PROMPT_COMMAND の保存復元の外側で実施される筈だから。変だ。

      うーん。分かった。local PROMPT_COMMAND としていた為に異なるレベルの
      PROMPT_COMMAND を触っていて変な事になっていた様だ。unlocal をちゃんと実行
      する様にしたら問題なくなった。と、思ったがこれは本当に意図した動作なのだ
      ろうか? 新しい PROMPT_COMMAND を実行したくて lcoal PROMPT_COMMAND を実行
      していたのではあるまいか?

      改めてコードを確認する。うーん。多分大丈夫意図した振る舞いになっている筈。

    x C13 wontfix: bash-5.0 以下で type=initial-prompt (memo/D1772.bashrc) に対
      し attach 時に vbell で報告者の設定がエラーメッセージを出す。

      て、__initialize での DEBUG trap 読み取りに失敗している気がする。というか、
      initial なので直接 ble/builtin/trap を経由して trap を設定している筈で、
      間違う筈はない…。

      うーん。vbell でエラーが表示されるという事は attach した後に bash が
      PROMPT_COMMAND を実行しようとして失敗しているという事になる気がするが…。
      うーん。つまり? 外側の PROMPT_COMMAND の文字列を eval している時に、
      ble-attach の入った ble/function#lambda/0 を実行する所までは良くてその後
      に続いている timer_stop の呼び出しに於いて問題が生じているという構図であ
      る。うーん。これを回避するのは難しい。


      つまり何が起こっているかというと、本来は PROMPT_COMMAND の実行の最初に
      timer が設定されてその実行の終わりに timer_stop が呼び出されるのでそれで
      良いのだが、prompt attach の瞬間には bash の

        PROMPT_COMMAND='ble-prompt-attach ; timer_stop'

      の最初に timer が設定されるが、それは ble-attach 内部の PROMPT_COMMAND 呼
      び出しで消費される。その後で timer_stop を実行しようとするが、その時点で
      既に DEBUG trap は除去されているので対応する DEBUG trap が一度も呼び出さ
      れない儘に timer_stop が呼び出されてエラーメッセージが発生する。

      うーん。prompt attach は仕組みからして処理の実行順序を変更する事になるの
      でこれに対してどの様に処理するべきかは謎である。本当は PROMPT_COMMAND の
      最後に実際の attach 操作を持って来たいところだがそういう訳にも行かない。

      うーん。其処まで実行順序が厳密でなければならないというのは困る。というか、
      そもそも元々のスクリプトが DEBUG が必ず PROMPT_COMMAND よりも前に実行され
      る筈という前提で設計されているのがよくない。というか、そもそも DEBUG を用
      いた hack を使っている時点でよくない。然し、そうは言ってもうーん。

      例えば prompt-attach の時には DEBUG trap はその場では削除しないという事を
      考えたが、そうすると結局また問題が生じる。timer_stop が処理するまでは良い
      が、その後も DEBUG trap が有効のままなので、DEBUG trap が
      ble-decode/.hook 等に対して呼び出されて予期しない時刻になる。また、もし逆
      に timer_stop がその PROMPT_COMMAND の中で attach-fromp-PROMPT_COMMAND よ
      りも後に呼び出されなかったら結局それも DEBUG trap で設定された timer が残
      存してしまう。

      これは現状 vbell が出るだけで全く使えない訳ではないので無視する事にする。
      それに $timer ではなく timer と書いていれば特に問題もなく利用できる筈であ
      る。

    * C14 desolved: trap DEBUG より後に ble.sh を source した場合に対する対策

      最初の PROMPT_COMMAND 実行の時には特に問題にならない。然しその時に timer
      変数が削除される。2回目の PROMPT_COMMAND 実行までに trap が実行されれば問
      題は起こらないが、実際は未だ trap DEBUG は取得できていないので自前で設定
      することもないし、だからと言ってずっと関数を出ないので既に設定されている
      物が発火することもない。

    * C15 desolved: prompt-attach の場合の振る舞いについても確認する必要がある。

    x C16 ok: bash-3.2 で type=final (memo/D1772.bashrc) の時に初回のコマンド実
      行の時間がずれる

      他の 3つの attach 方法の場合には問題は生じていない。物によっては最初のプ
      ロンプトの時間が 0s になったり 1s になったり 2s になったりして、初期化の
      時間が含まれたり含まれなかったりしているがそれは対した事ではない様に思わ
      れる。

      これは何故だろうか。4.0 では特に何も起こっていない。final の時には
      ble-attach を直接呼び出して attach している。うーん。もしかして DEBUG
      trap を除去できていない?

      うーん。というか 4.0 でも 3.2 でも bashrc の内部では trap を取得できてい
      ない様だ。うーん? というか 5.1 ですらもできていない。何故だろう。
      is-global-traceable がちゃんと動いていないという事?

      →と思ったらこれは単にテスト用の rcfile の名前が .bashrc ではなかった為に
      棄却されていただけの事だった。棄却条件を緩めたらちゃんと期待通りに動く様
      になった。気にしなくて良い。

    x C17 desolved: bash-3.0, 3.1 で後に ble.sh を source した時、何回かコマン
      ドを実行してもエラーが出続ける。どうやら trap が消滅している。

      →これは今試したら再現しない。ちゃんと動いている。うーん。多分他の物を修
      正した時に一緒に直ったのだという事だと思われる。

    x C18 wontfix: bash-3.1 で後から ble.sh を source した時に最初のコマンド実行
      の時間がずれている。うーん。これは ble-attach 等が DEBUG を継承させられな
      いという事に由来する制限である。

      うーん。bash-3.1 以下で declare -ft を適用する方法はあるのだろうか。或い
      は set -T を設定するしかないのかもしれない。

      念の為先に source ble.sh したときについてはちゃんと動く事を確認した。OK

    * C19 別項目: その他の trap についても元からあった trap を拾う様にしたい。
      うーん。この commit は巨大になり過ぎたし、DEBUG trap 専用の物なので、他の
      trap に関しては別項目で対応するのが正解の気がする。

    x C20 別項目: bash-3.0 で変な文字列 '' が出力される。

      この変なエラーを直さない限り、そもそもちゃんと動いているかどうかまともに
      修正する事ができない。というかこの謎の出力は一体何処から来ているのだろう
      か。DEBUG trap 関係だろうか。

      うーん。これはそもそも今回の話と関係なく起こっている問題の様だ。これは別
      枠で修正するべき。そもそも master で、plain bash + plain ble.sh でも再現
      する事を確認した。

    x C21 fixed: bash-3.0 で結果が常に 0s

      調べてみると DEBUG trap が何故かコマンドが終了してからしか呼び出されてい
      ない様だ。更に調べると TRAPDEBUG は呼び出されている。と此処で分かった。原
      因は BASH_COMMAND が bash-3.0 で設定されていないという事だ。

      これは関数内で BASH_COMMAND を参照した時だけでない。trap string で直接
      BASH_COMMAND を参照しても同様に BASH_COMMAND には現在実行しているコマンド
      の文字列が格納されている (という事を確認した)。

      $ func() { echo heloo; }; declare -ft func; trap 'trapdebug "$BASH_COMMAND"' DEBUG; trapdebug() { echo "[$1]"; }

      これは仕方のない事である。bash-3.0 では不当に DEBUG trap が握りつぶされな
      い様にした。bash-3.0 では余分に DEBUG trap が呼び出される事になるが、これ
      は仕方がない。DEBUG trap をしかける側はいつでも大量の関係ない DEBUG trap
      を捨てる事が求められているので許容してもらう。

    x C22 fixed: bash-3.1 以下で type=final-prompt (memo/D1772.bashrc) に於いて
      trap が消滅している?

      先ず _ble_builtin_trap_DEBUG_userTrapInitialized によると初期化は実行され
      ていない。一方で builtin trap -p の時点でもう消えている。うーん。

      どうやら bash-3.0 では bind -x の top レベルでも何故か
      attach-from-PROMPT_COMMAND の中で実行している設定になっている様だ。謎。取
      り敢えず work around を加える事にした。ちゃんとトップレベルの trap を読み
      取る事ができているので OK

    * C23 done: refactor name ble/function/is-global-traceable

    取り敢えず何れの bash version でも少なくともコマンドを一回実行すればちゃん
    と動く様になった様に思われる。これで良しとする。


    * C24 一旦何処かに push して diff を観察する。

    [制限]

    最後に現状の実装の制限についてまとめる。これは何処かにまとめて置いた方が良
    い気がする。ソースコードの中に記述するのが最も分かりやすいのではないか。転
    記した。

    * 先に ble.sh を source した場合は殆どの場合動く。

      bash-5.0 以下で先に ble.sh を source して prompt-attach を行い、更に
      PROMPT_COMMAND を書き換えた場合には、PROMPT_COMMAND の中で
      attach-from-PROMPT_COMMAND よりも後に実行している処理は DEBUG trap が無
      効化された状態で実行される事になる。

    * 後に ble.sh を source した場合には以下の場合にロード直後は DEBUG trap が
      ble.sh 内部の処理に対しても有効になっている。

      - (set -T & --attach=attach の時の条件) rcfile が .bashrc でも
        .profile でも .bash_profile でもない場合 (これは現在 rcfile の
        中にいるかどうかを判定する方法が bash にはない事から、rcfile
        かどうかをファイル名と行番号だけから判定しなければならない事に
        由来する)

      - source ~/.bashrc 等の様にして手動で bashrc を読み込んだ時 (これは
        source が DEBUG trap を継承しないという Bash の制限に由来する)

      - rcfile から一旦別のファイルを source してそのファイルから ble.sh を
        source した時。または関数内から ble.sh を source した時 (これも DEBUG
        trap の継承に関する Bash の制限に由来する)

      - bash-3.1 以下の時 (これは declare -ft で trace を付加できる関数の関数
        名に対する制限に由来する)

    * というか結局報告者の提示した設定が不安定すぎるという事に尽きている様な
      気もする。この設定は例えば bash-preexec.sh と一緒に使ったとしても崩れる
      し (とはいいつつも bash-preexec.sh は他のあらゆるものを壊す気がする)、
      また、PROMPT_COMMAND+=$'\n'追加設定 を実行するあらゆる設定に対して脆弱
      である。その様ないい加減な設定を使っている時点で完全には対応しきれない。

2022-02-13

  * util: EXIT trap を設定していると実際に exit する時に return に空文字列が渡される (reported by SuperSandro2000) [#D1771]
    https://github.com/akinomyoga/ble.sh/issues/175

    これは明らかに最近書き直した trap handler 周りのの処理の問題である。と思っ
    たが return を呼び出している箇所では特に空文字列が渡されそうなコードは見え
    ない。再現はできているのでどうなっているか確認する事にする。

    →分かった ble/util/setexit に渡す引数が空になっている。と思ったら単に typo
    だった。というよりは変数名の変更漏れ。

  * [棄却] complete: ls ~/.c{onfig,1}/[TAB] としても候補が生成されない [#D1770]

    うーん。これは今迄ちゃんと候補が生成できるだろうと思っていたがそうでもない
    様だ。改めて振る舞いを調べてみるのが良い。やはり動かない。bash-completion
    の所為でもない。ble.sh の元々の機能を使っていてもやはり生成されない。

    というか寧ろ元々の機能を使っているから候補が生成されないという可能性もある?
    と思って改めて bash-completion を使って試してみたがそれでも駄目である。取り
    敢えず、bash-completion が介在しない場合について振る舞いを確認する。

    →と思ったらどうやらブレース展開の一番最後の要素を使って補完を実行する仕組
    みになっている様だ。なので、 ls ~/.c{1,onfig}/[TAB] とした場合にはちゃんと
    候補が生成される。これは単にそういう設計という事なので修正しなくて良い。

  * edit: いつの間にかに rps1 に接した時の計算が壊れてしまっている [#D1769]

    改行位置が正しく計算できていない? と思ったが、うーん。これは改行が継続する
    様にして欲しいという要望に応えた時に導入したバグの気がする。

    Ref #D1745

    改めて edit.sh で D1745 に関係している所を確認してみた所… rps1 があるかど
    うかのチェックを忘れている。→と思ったがそもそも CR を埋め込む時点でそれは
    処理していたのではないか? 確認してみた所 *:relative:* の時には CR は埋め込
    まれない様になっている筈。

    確認してみると relative が opts に指定されている時と指定されていない時が存
    在する。textmap#update の呼び出し元を確認してみると
    ble/widget/.update-textmap から呼び出している物については opts を指定してい
    なかった。実は結構な確率で ble/widget/.update-textmap 経由で更新が行われる
    という事だった様だ。何れにしてもちゃんと同じ引数で textmap#update を呼び出
    す必要があるのだった。

    * [経緯確認] というか今迄は rps1 が存在していても relative にせずに直接描画
      計算をしていたという事になるのではないか。そう思うと今迄動いていたのは偶
      だったという事になる。或いは、relative になる様にしたのは #D1745 だったの
      だったか。

      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 3009)   local render_opts=
      d84bcd8d src/edit.sh (Koichi Murase 2020-10-11 02:05:09 +0900 3010)   [[ $rps1_enabled ]] && render_opts=relative
      cf8d9493 src/edit.sh (Koichi Murase 2021-06-07 12:13:56 +0900 3011)   COLUMNS=$cols ble/textmap#update "$text" "$render_opts" # [ref] x y

      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 2483)   local render_opts=
      d84bcd8d src/edit.sh (Koichi Murase 2020-10-11 02:05:09 +0900 2484)   [[ $rps1_enabled ]] && render_opts=relative
      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 2485)   COLUMNS=$cols ble/textmap#update "$text" "$render_opts"

      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 2064)   local render_opts=
      b86709af src/edit.sh (Koichi Murase 2019-03-23 12:36:07 +0900 2065)   [[ $rps1_show ]] && render_opts=relative
      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 2066)   COLUMNS=$cols ble/textmap#update "$text" "$render_opts"

      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 1668)   local render_opts=
      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 1669)   [[ $flag_rps1 ]] && render_opts=relative
      90a8915c src/edit.sh (Koichi Murase 2019-03-09 11:40:10 +0900 1670)   COLUMNS=$cols ble/textmap#update "$text" "$render_opts"

      b2e2461a ble-edit.sh (Koichi Murase 2017-10-05 01:12:01 +0900 1669)   ble/textmap#update # text x y → x y

      これを見ると3年前からずっと relative 指定していたけれど、単に絶対移動でも
      問題が生じていなかったというだけの様である。確かに論理的には問題は生じ得
      なかったのかもしれない。ちゃんと改行は改行として処理していたので。

      因みに最初に opts を導入した時点で既に ble/widget/.update-textmap は rps1
      に拘らず opts なしで textmap#update を呼び出していた様である。同時に
      ble/widget/.update-textmap の textmap#update の呼び出しも修正しているのに
      opts を指定しなかったのは唯単に油断したからだろうか。

      opts を導入したのは #D0959 であった。そしてこれは確認してみた所、rps1 を
      最初に導入した commit だった。という事を考えると本当にずっと relative あ
      りとなしの両方で動かしていたという事になる。

  * [棄却] git submodule update は even の時にはしなくても良いのでは [#D1768]
    https://github.com/raccoonasdf/raccoonpkgs/commit/d7ec0af3db2cd473adcb12a0132e53d3c216dddf

    と思って改めて makefile を確認してみたが git submodule update は、
    contrib/.git 及び contrib/contrib.mk さえ存在していれば実行されない様な気が
    する。或いは、ble-update について話しているのかとも思ったがそれも変な気がす
    る。ble-update は結局本体の更新の為にインターネットに接続するのだから、同時
    に submodule update を実行しても特に問題になる様にも思われない。

    うーん。これはこの上のファイルを記述した人が勘違いしているだけという気がし
    てきた。つまり、makefile に git submodule init があるのを見つけて、これは
    make の時に必ず呼び出されるのに違いと思っているのではないか。実際には
    working tree に展開されていれば呼び出される事はないのだが。或いは、nix の設
    定だと submodule fetch するだけで working tree に反映しないという可能性もあ
    る。その場合には git submodule は make から呼び出される事になるが、しかし一
    方でこれは必ず呼び出さないと行けないものでもある。

    一方で現在の ble.sh gitmodules が指している commit と現在 HEAD が異なる時に
    は update を自動的に実行することもできる。と思ったが流石にそれは一時的に異
    なる物にして試したい時などにとても面倒である。という事を考えると、わざわざ
    その様な事はしなくて良い。結局 ble-update を実行した時にちゃんとした状態に
    調整される筈。

2022-02-12

  * complete: _fzf_path_completion 経由だと ~ で始まるパスのディレクトリの後に / が挿入されない (reported by SuperSandro2000) [#D1767]
    https://github.com/akinomyoga/ble.sh/issues/171#issuecomment-1030962166

    file: memo/D1760.fzf-completion.bashrc

    恐らく compopt か何かが関係しているのだろうという気がするが ~ で始まるかど
    うかで問題が再現するかしないかが変わるというのは変だ。~ は ble.sh の側で展
    開している筈。という事は ~ がある事によって問題が発生しているという事ではな
    い様な気がする。

    ? 例えば / で始まる事によって問題が発生するのではないか。或いは subdir/* の
      時に問題が発生するという事だろうか。

      → / で始めても問題は再現しない。サブディレクトリの下にあってもちゃんと動
      いている。本当に ~ で初めた時にだけ問題が起きている様に見える。更に、
      bash-completion と組み合わせた時にだけ問題が発生しているという事でもある。
      うーん。何が起こっているのだろうか。

      取り敢えず候補生成部分を確認するのが良い気がする。

    * うーん。実装を見るとやはり compopt が欠けているのが問題である様に見える。
      と思って実際に展開する部分を確認してみた所…

      CAND='~/.config' INSERT='~/.config' DATA=':noquote:filenames:'

      ちゃんと filenames は指定されている。という所で分かった…。"~/.config" と
      いう名前で候補が生成されている。これだと本当に '~/.config' という名前のディ
      レクトリが存在する時にしか / がつかない。うーん。何が起こっているのか。

    ? 先ず 何故 fzf でない場合にはちゃんと補完されていたのか? というか前から補
      完されていなかった可能性?

      そう思って bash-completion で試してみたがちゃんと動いている。そして以下の
      様にちゃんと具体的なディレクトリ名に展開されている。

      CAND='/home/murase/.config' INSERT='~/.config' DATA=':filenames:'

      うーん。勝手に fzf が ~ に置換してしまっているのが良くない。

    * 念の為、ちゃんと ble.sh の側で展開できているか確認する。

      COMP_WORDS=('cat' '/home/murase/.con')

      ちゃんと展開している。つまり fzf は勝手にこれを ~ に置換してしまっている
      という事。変な振る舞いをするものだ。一応確認する事にする。と思ったら、普
      通に fzf を起動した時にはそういう変な振る舞いは見られない。うーん。何故?

      もしかすると contrib/fzf-completion による介入が原因の可能性もある?

      うーん。これだ。

      COMP_WORDS=("${comp_words[@]}") COMP_CWORD=$comp_cword
      COMP_LINE=$comp_line COMP_POINT=$comp_point

      fzf は ** だとか展開前の特別なシーケンスを探す為、展開前の単語を要求して
      いる。従って、直接 ~/.config という文字列を渡す事になる。

      うーん。という事は fzf を使っている時には 'ba[TAB] 等に対して補完できない
      という事にはなるまいか? と思ったら勝手に quote を外された。うーん。仕方が
      ない。

    * 対策としては noquote が設定されている時にはディレクトリ名かどうかのチェッ
      クは CAND ではなくてそれの展開結果に置き換える。もしくは展開結果を用いて
      CAND に再代入する? INSERT の方に記録する。

      と思ったが、うーん。候補生成の時点では CAND の方しか記録しないのでは。
      と思って確認したがちゃんと生成時点で CAND も INSERT も決定していた。

    取り敢えず quote-insert で noquote が指定されていた時の CAND/INSERT の決定
    方法を修正した。

    x fixed: 動いていると思ったら全く候補が生成されなくなって fallback していた。
      quote-insert は終了ステータスに意味があるという事だった。

    x fixed: 改めて修正すると noquote による特別処理が動いていない、と思ったら
      count が空になっている。simple-word/eval で count を得る為には特別な条件
      が必要?  と思って確認したら opts に "count" を指定する必要があった。修正
      した。

    * OK: simple-word/eval は count も上書きする様だ → これは opts に count を
      指定した時だけの機能なので、一般の場合については変数汚染を気にする必要は
      ない。

    x fixed: メニューにフルパスで表示されてしまう。これは PREFIX_LEN の初期化を
      action:ACTION/initialize よりも後に移動すれば良いのだった。今 CAND も
      /initialize によって書き換えられる可能性があるので、書き換えられた後の値
      を参照して PREFIX_LEN を決定するべきなのである。

    x done: quote_fixed_comps に注意しなければならないのでは?

      取り敢えず quote_fixed_comps が設定されている時には CAND の書き換えは
      suppress する事にした。一方で、quote_fixed_comps が設定されている時でも上
      手にやる方法はあるだろうか。というか、quote_fixed_comps に抵触する場合に
      は今迄一体どの様に処理していたのだろうか。よく考えたらもっと後の段で候補
      を filter out しているのではないか。もしそうだとしたらここで何かしなくて
      も良いのではないかという気がする。

      と思ったが、値が先頭一致している場合にはそれに対応する部分まではちゃんと
      一致する様に生成しなければならないのではないか。

      quote_fixed_comps もしくは comps_fixed がどの様に処理されているのかを改め
      て確認する必要がある。

      うーん。brace 展開がある時に現在の実装でどう振る舞うのか不安になって来た。
      →取り敢えず簡単な場合にはちゃんと期待通りに動いている。然し何故動いてい
      るのかは謎である。と、思ったがそもそも fzf はブレース展開がある時に正しく
      候補を生成できていない。従って ble.sh の候補生成器に fallback していると
      いう事の様である。

      そもそも fzf には直接 comp_words を渡しているのだから、それでブレース展開
      を潰してしまったとしてもそれをそのまま受け入れて遡った書き換えを実行する
      のが自然の気もする。従って quote_fixed_comps を気にする必要はない。

      と思ったが fzf 以外が noquote を指定する可能性もあるのでやはり油断はでき
      ない。うーん。fzf 以外が noquote を指定した時にちゃんと comps_fixed を処
      理する様に修正する必要があるのでは。或いは fzf が指定されていたとしても
      comps_fixed を処理する。

      a うーん面倒だから quote_fixed_comps がある時は逆に reconstruct した CAND
        から INSERT を再度生成するのが良い気もしてきた。

      b と思ったが確認すると他にも色々しているのでやはり直接その場で
        quote_fixed_comps に関係する処理だけを実行する事にした。

      c 他に INSERT を解析して該当部分だけを抜き出すという事も場合によっては可
        能だが完全ではないし無意味に複雑になるし、そもそもブレース展開が存在す
        る様な文脈では quote の仕方を変化させても意味は変わらない筈なので、再度
        INSERT を CAND から再生成してしまっても問題ない気がする。

      上記の b の方法で実装する事にした。

    * done: progcomp-raw は別の名前にしたい。やはり最終的には ble.sh の拡張であ
      ると分かる様に blesh や ble.sh, ble- 等を付けるのが妥当という事になるだろ
      う。

      ble-progcomp-raw という事に取り敢えずしてみたが、そもそも compopt を設定
      するのは progcomp でしか起こらない事なので progcomp を含めるのは冗長であ
      る。然しそうすると ble-raw という事になるがこれだと一般的過ぎる気がする。
      もう少し絞る方法はないだろうか。

      類似の事を指定している箇所があった気がする。それは何でどの様に処理してい
      たか。→ "comp_type == *:raw:*" だった。reconstructed (COMPS で quote を
      閉じた物) を COMPV に設定していた。context:glob や
      context:dynamic-history の generate-sources で raw を設定していた。

      うーん。類似してはいるけれども微妙に異なる気もする。ble-syntax-raw にする
      か。然しそれだと syntax.sh 由来の物の様にも解釈できる (しかしそれはそれで
      実際正しいのではないか。extract-command の結果をそのまま渡す様に修正して
      いるのだから)。或いは単に syntax-raw にする?

  * 2022-02-02 main: やはり nix-shell の中でも有効にする [#D1766]
    Ref #D1747

    そもそも nix-shell で ble.sh が欲しい事もあるそうだ。報告がいい加減なので無
    駄な修正をした。
    https://github.com/akinomyoga/ble.sh/issues/169#issuecomment-1027096640

    * 改めて調べてみたら実際に実行するコマンドが exec になるのは ruby がコマン
      ド文字列に含まれている時のみの様である。

      # というか、ruby という部分文字列が含まれているだけで実装が切り替わるので
      # かなりいい加減な実装である。更に、単にこの四文字を探す為だけに
      # std::regex を初期化しているのもおかしい。

      実際にはユーザーによって指定された文字列 + exit を実行している様だ。なの
      で return をすると通常のシェルに入る事ができる、という事になっているのだ。

      https://github.com/NixOS/nix/blob/master/src/nix-build/nix-build.cc#L187

      # これも単に exit を付加するだけだと quoting の問題で何だか変な事になる気
      # がするが大丈夫なのだろうか。これ自体にセキュリティーの問題はないが、こ
      # れはセキュリティーの問題が起こるパターンの最たるものである。nix-shell
      # の実装はかなり怪しいと言わざるを言えない。

    うーん。これに対する対策はどうするのか? IN_NIX_SHELL が設定されている時には
    ble-attach を無効化して attach=none であっても prompt attach を強行するとい
    う風にするべきだろうか。。

    現在 bashrc の中にいるかどうかの判定はどの様にするのだったか。

    というか、もし rcfile の名前が固定なのであれば、BASH_SOURCE を使って検出す
    る事が可能なのではないだろうか。うーん。"一時ディレクトリ/rc" という形をし
    ているらしい。

    % そして一時ディレクトリは環境変数に設定されている。
    %
    % https://github.com/NixOS/nix/blob/73d5f38a47e7c3dea62994cfb8f962976194f767/src/nix-build/nix-build.cc#L428
    %
    % 例えば [[ ${BASH_SOURCE[${#BASH_SOURCE[@]}-1]} == $NIX_BUILD_TOP/rc ]] で
    % テストできるのだろうか。これは実際に nix-shell を入れてみない事には分から
    % ない気がする。
    %
    % →NIX_BUILD_TOP の中身を出力してみたがユーザーの run になっていて nix の
    % 一時ディレクトリではない。その他の一時ディレクトリも全てそうである。改め
    % て確認してみると tmpDir と TMPDIR は異なる変数だった。

    以下を観察すると nix-shell, nix-build という名前の一時ディレクトリになるらしい。

    https://github.com/NixOS/nix/blob/73d5f38a47e7c3dea62994cfb8f962976194f767/src/nix-build/nix-build.cc#L95-L101

    うーん。というか或いはそもそも IN_NIX_SHELL の時は ble-attach をしたら強制
    的に prompt attach で良いのではないかという気がする。と思ったが、そこまです
    る事もないので、取り敢えず BASH_SOURCE の末端が /rc だったら prompt attach
    を設定する事にした。

    これで一応動作はしている。

    x 2022-02-04 然し、今度は別のエラーが発生している。bind は builtin じゃない
      と出ている。誰かが無効化しているという事なのだろうか。或いは、もしかする
      と非対話シェルでは bind は常に存在していないのだろうか→うーん。確かめて
      みたが "行編集は有効になっていません" という表示が出るのみである。なので、
      nix-shell に於いては何だか怪しげな事がされている?

      調べてみると ble-attach の中で発生している。特に ble/decode/initialize の
      内部で発生している。不思議なのはちゃんと attach はできているという事。な
      ので bind が全く使えないという訳ではないという事。なのに何故 builtin は
      bind が存在しないという報告をするのだろうか。

      ble/builtin/bind/read-user-settings で問題が生じている。うーん。最初の
      builtin bind では何も問題が生じていない。という事は何処かから呼び出してい
      る builtin bind の綴を間違えているか或いは余分な文字が混入しているという
      事だろうか。

      と思ったら分かった。"$BASH" 云々 -c 'builtin bind -m emacs -p' 云々として
      既定の binding を読み取っている箇所で問題が起こっている。うーん。そうだと
      しても何故 builtin bind が使えないのか? 不思議である。

      →うーん。実際のバイナリは以下の様になっている。

      $ ls -la /proc/$$/exe
      lrwxrwxrwx 1 murase murase 0 2022-02-04 09:14:11 /proc/30092/exe -> /nix/store/xz3kkiscxh01yazxa1dk08q047mfl1fh-bash-interactive-5.1-p12/bin/bash
      $ echo "$BASH"
      /nix/store/2kh3c4v2vf6d6xg6c9n8zvfpwf3zzwca-bash-5.1-p12/bin/bash

      うーん。ちょっと何が起こっているのか分からなくなった。

      1 最初 (bashrc source 時): この時点で何故 BASH が現在のシェルではなくて
        /bin/bash になっているのか謎である。

        SHELL=/bin/bash
        BASH=/bin/bash

        うーん。SHELL に関しては外から export した物がちゃんと伝播している。
        BASH に関しては謎だ。もしかすると bash はビルド時に BASH を埋め込んでい
        る? と思ったがそうでもない様に見える。普通に

        $ /nix/store/xz3kkiscxh01yazxa1dk08q047mfl1fh-bash-interactive-5.1-p12/bin/bash

        としてログインした場合には何も変な事は起こっていない。ちゃんと自身の
        BASH が見えている。何か chroot 的な物をして bash をスタートしているのだ
        ろうか。bash のソースを見ると shell_name が相対パスでかつ login シェル
        ならばユーザー情報から BASH を初期化している。と思ったが、

        $ (PATH=/nix/store/xz3kkiscxh01yazxa1dk08q047mfl1fh-bash-interactive-5.1-p12/bin:$PATH; hash -r; bash --login -c 'echo $BASH')

        を実行してもちゃんと現在のシェルを見つけることができている。というか、
        shell_name の時点で正しく見つけることができているという事か。

      2 次に $stdenv/setup で BASH=$SHELL が設定されていると思ったが、そうする
        と最終的に BASH=non-interactive-bash になっている理由が分からない。

      3 更に最終的な SHELL の値は SHELL=interactive-bash になっている。つまり
        SHELL=non-interactive-bash になっている瞬間はない気がする。改めて SHELL
        の値について確認してみたが、これは stdenv/setup よりも後に設定されてい
        る様なので、最終的に interactive-bash にはなっていてもそれが BASH に反
        映されていなくても不思議はない。

      うーん。trace を得た。

      declare -x SHELL="/bin/bash"
      declare -- BASH="/bin/bash"
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:1: export SHELL=/nix/store/2kh3c4v2vf6d6xg6c9n8zvfpwf3zzwca-bash-5.1-p12/bin/bash
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:14: [[ -n "${BASH_VERSINFO-}" && "${BASH_VERSINFO-}" -lt 4 ]]
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:303: [ -z "${SHELL:-}" ]
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:304: BASH="$SHELL"
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:305: export CONFIG_SHELL="$SHELL"
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:309: export shell="$SHELL"
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:685: [[ -z "${NIX_SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]
      /nix/store/xcy53qbjynin70g46w1nx011gr7jw8l1-stdenv-linux/setup:689: [[ -z "${SSL_CERT_FILE:-}" && "${IN_NIX_SHELL:-}" != "impure" ]]
      /tmp/nix-shell-49112-0/rc:3: SHELL='/nix/store/xz3kkiscxh01yazxa1dk08q047mfl1fh-bash-interactive-5.1-p12/bin/bash'
      /tmp/nix-shell-49112-0/rc:3: [ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ]

      うーん。setup.sh 1行目で SHELL を書き換えている。。。まとめると、

      1 何故か分からないが nix 環境では bash は BASH の初期化に失敗して
        /bin/bash を取り敢えず BASH に設定する。

      2 $stdenv/setup は非対話シェル用(特にビルド用)の環境であり、非対話用に特
        別にコンパイルされた bash の上で動作する事を想定している。なので中で
        SHELL と BASH に無理やり固定の値 (非対話 Bash) の値を設定している。

      3 更に nix-shell の呼び出し元では SHELL を対話シェルのパスに上書きしてい
        る。此処で BASH も同様に更新するべきではないか。

    * うーん。面倒になった来たのでやはり nix 用の workaround を追加する事にする。
      つまり問題は BASH が変な値になっているのが原因である。という事は無理やり
      BASH を補正してしまえば良い。

      a 環境の補正は ble.pp で集中して行っている箇所があるので其処で調整する事
        にする。と、思ったがよく考えたら nix-shell では setup の中で BASH を勝
        手に変更していて、更に、setup は bashrc よりも後で読み込まれるのだから、
        ble.sh の初期化時に BASH を補正しても仕方がない。うーん。

      b 一つの手は ble-attach の時に BASH を補正するという事。結局 "$BASH" を使っ
        ているのは、decode の初期化であって、decode の初期化は ble-attach で呼
        び出しているのだから。そして、現在既に ble-attach に nix 用の
        workaround が入っている。

      上記の b の箇所で BASH を上書きする事にした。

2022-02-09

  * edit: exit を実行すると時間計測結果が表示されてしまう [#D1765]

    これは何? 恐らく最近のコマンド時間計測と関連しているのだと思うが。そもそも
    exit を実行した後に time の結果が表示されうる物なのだろうか。

    うーん。以下を実行すると時間が実際に表示される。

    time { echo hello; exit; }

    以下を実行した場合には特に何も表示されない (exit と単に表示される)。

    time { echo hello; TIMEFORMAT=''; exit; }

    少なくとも workaround として TIMEFORMAT= は有効であるという事。
    以下の様にした場合でもちゃんと出力は抑制される。

    function f1 { local TIMEFORMAT=''; exit; }; time f1

    然し、この時の問題はユーザーが ble.sh の中で time { ... exit; } を実行した
    時に時間表示がされなくなってしまうという事。という事を考えると、やはり外側
    で設定する時に何か工夫して外で設定した time に関しては時間測定結果が表示さ
    れない様に修正するという事。

    うーん。然し、何故これが表示されてしまうのか。本来は別の所に出力されるべき
    なのではないか。。。これは bash に報告するべきなのではないか。

    * 取り敢えずおかしな現象が起こるという事をもっと簡単な場合で証明する事は可
      能だろうか。

      実際に振る舞いとしておかしいという事も以下のコマンドで確認する事ができる。
      つまり time の出力は 2>/dev/null に吸い込まれるべきであるのにも拘らず、
      exit が実行された文脈での 2 の接続先である 2>/dev/tty に出力されてしまう。

      $ bash-5.1 --norc
      $ function f1 { { echo hello; exit; } 2>/dev/tty; }
      $ { time f1; } 2>/dev/null

    * →と思ったらどうやら 5.2 では既に修正されている様だ。更に昔の version の
      振る舞いも確認してみた所、どうやら 4.4..5.1 で発生する問題の様である。

    これに関しては exit の側で workaround をする事にする。これによって 4.4..5.1
    では、ユーザーが time { echo hello; exit; } を実行した時に何も表示されなく
    なるが、それは仕方がない。

    そもそも 4.3 以前では time { echo hello; exit; } に対して結果は出力されなかっ
    た様である。という事を思うと、実は 4.4..5.1 は time の内部で exit を実行し
    た場合でも時間を表示する様に修正する上での壊れた振る舞いだったという事にな
    る。

    x 2022-02-13 動いていない。#D1771 をテストする時にで時間計測の結果が出力さ
      れてしまう問題が未だ残存している事に気づいた。うーん。既に対策した筈だが
      動いていないという事。

      うーん。改めて試してみたが確かに全然動いていない。

      ? reject: うーん。つまり… trap handler の側の stderr に出力されていると
        いう事だろうか。EXIT trap handler は ble.sh は常に設定している。

        一応 EXIT trap handler が呼び出されなかった・設定が消えている場合に備え
        る為に ble/builitin/exit での対策は残しておく事にする。

        と思って trap handler の側で TIMEFORMAT= にしたが効かない。というより
        trap handler が呼び出されるよりも前に時間測定結果が表示されている。因み
        に EXIT handler はトップレベルで呼び出されている。

      うーん。global の TIMEFORMAT を空にしたら表示されなくなった。取り敢えずは
      それで実行する事にする。と思ったが…うーん。exit に失敗したら元に戻さなけ
      ればならないのでは。因みに global の値を取得するのは少々面倒である。

      うーん。後 global の TIMEFORMAT を unset する手段がない。取り敢えず既定値
      を代入すれば良いのだろうか。既定値は man bash にあったのでそれをそのまま
      使う事にした。

2022-02-05

  * [棄却] 2022-01-31 nix-build -A の補完が効かないという問題 [#D1764]
    https://github.com/akinomyoga/ble.sh/issues/171#issue-1113799687

    取り敢えず nix は入れたが nix コマンドや nix-build コマンドは見つかるのだろ
    うか。また nix-shell コマンドも使えるのか気になる所である。

    動かない。そもそも通常の bash で動くのだろうか。実際に単に source するとエ
    ラーが出る。bash-completion を一緒にロードしないといけない様だ。然し結局通
    常の bash で実行しても nix-build -A [TAB] で補完がされる事はなかった。

    $ bash --norc
    $ source ~/.mwg/git/scop/bash-completion/bash_completion
    $ source _nix

    一体どの様にするのが良いのだろうか。

    →これは結局よく分からないが今は動いている様である。手元でもちゃんと動いて
    いる事を確認した。向こうの勘違いか或いは他の問題と関係していたかという事だ
    ろう。

  * 2021-12-18 ble/util/import でファイル名に関数名として許されない文字が入っていた時の対策が必要では [#D1763]

    関数名として許されない文字は実はそんなに多くはない気がする。Unicode 文字の
    殆どは関数名に使える。特殊な意味を持つのは ASCII の範囲内に限られるからであ
    る。

    $' \t\n;|&<>()$`"\'\\'

    履歴展開文字 !^ に関しては一時的に履歴展開を無効にして関数を定義すれば行け
    る気もしないでもないが面倒なので考えない事にする。

    特定の文字 (例えば _) に一律に置き換えてしまって衝突は已む無しとするという
    事を考えたが、実は % (url) encoding みたいな事をすれば良いのではないかとい
    う気がする。但しその為には沢山置換を実行しなければならない。新しい
    strreplace は使えない。置換前の文字を直接使える訳ではないので。

    | a 直接ハードコードする
    |
    |   a=' '   b=%20
    |   a=$'\t' b=%08
    |   a=$'\n' b=%0A
    |   ...
    |
    | b 次の様に pack してループを回す。然し何だか変な気がする。
    |
    |   '%25' ' 20' $'\t08' $'\n0A' ';3B' '&26' '|7C' '<3C' '>3E' '(28' ')29' '$24' '`60' '"22' \'27 \\5C
    |
    | c それよりは個別にした方がすっきりするのではないか。でも対応が分かりにくい。
    |
    |   $'% \t\n;|&<>()$`"\'\\'
    |   25,20,08,0A,3B,26,7C,3C,3E,28,29,24,60,22,27,5C
    |
    |   然しこれならファイル名にこれらの文字が含まれていないかどうかの確認も簡単
    |   である。改めて文字コード順に並べる事にする。
    |
    |   chars=%$'\t\n !"$&\'();<>\\^`|'
    |   rep=(%{25,08,0A,20,21,22,24,26,27,28,29,3B,3C,3E,5C,5E,60,7C})
    |   rep=(%{25,08,0A,2{0..2},24,2{6..9},3B,3C,3E,5C,5E,60,7C})
    |
    | d 或いは次の様にする。
    |
    |   '%':%25 $'\t':%08 $'\n':%0A ' ':%20 '!':%21 '"':%22 '$':%24 '&':%26
    |   \':%27 '(':%28 ')':%29 ';':%3B '<':%3C '>':%3E \\:%5C '^':%5E '`':%60
    |   '|':%7C

    c の方針で考える事にした。実装した。取り敢えず空白を含むファイル名で試した
    ら動いているのでOK.

2022-02-02

  * render: 処理途中に WINCH が来ると途中状態のデータに対して処理が走ってデータが壊れる [#D1762]

    以下のテスト中に描画の無限ループを検出した。
    https://github.com/akinomyoga/ble.sh/issues/173#issuecomment-1028479357

    更に色々やっていると tree_node に inconsistency が発生した。というところで
    分かった。恐らく描画処理の途中で SIGWINCH が走った所為で、中途半端な状態で
    新しい描画が始まる事によってデータを破壊している。処理の途中で描画は実行し
    ない様にする必要がある。

    特に PROLOGUE と EPILOGUE の間で SIGWINCH が来た時には EPILOGUE の末尾で改
    めて再描画を実行する様にする必要があるのではないか。

    後、描画処理が終わった後のサイズ変更検知も実行するべきなのかもしれない。と
    思ったが、それは実は通常の描画の際にも毎回実行するべき事なのではないか。

  * mandb: rsync --no-while-f[TAB] で説明が一緒に挿入されてしまう [#D1761]

    DATA を挿入しているのだろうか。。或いは、単一確定の場合に postprocess が走っ
    ていなくて直接補完されている。後で確認する必要がある。

    →どうやら ACTION progcomp で生成されている様だ。--no-whole-file に対しては
    問題発生するが、--whole-file に対しては問題は発生しない。どうも CAND の時点
    で大変な事になっている。

    →OK. --no-OPTION の説明を勝手に生成した時に mandb_count++ するのを忘れてい
    た為に、mandb 処理がスキップされていたのが原因だった。

  * complete: fzf と組み合わせている時に補完の再試行がされない問題 (reported by SuperSandro2000) [#D1760]
    https://github.com/akinomyoga/ble.sh/issues/171#issuecomment-1021326168

    fzf / bash-completion を両方組み合わせている時に ssh_config から読み取ったホスト名が正しく補完されない問題。

    | 先ず普通の bash で動く様にするまでが大変だった。取り敢えず以下の順序で初期化すれば動く。
    |
    | $ bash --norc
    | $ source ~/.mwg/git/scop/bash-completion/bash_completion
    | $ _ble_contrib_fzf_base=~/.mwg/git/junegunn/fzf
    | $ PATH=$PATH:$_ble_contrib_fzf_base/bin
    | $ source $_ble_contrib_fzf_base/shell/completion.bash
    |
    | 然し、同じ順序で ble.sh を初期化したらちゃんと動く。うーん。初帰化の順序に
    | 依存するのではないか。
    |
    | つまり、bash-completion を fzf よりも先に読み込んでいない為に起こっているの
    | ではないかと推測されて、例えば ble.sh を bashrc の最初で source していて
    | blerc の中で直接 ble-import を実行しているのだとしたら、その場で fzf
    | completion.bash が読み取られる。その後で bashrc に戻ってきて
    | bash_completion を初期化しているという可能性がある。
    |
    | 然し instruction では ble-import -d を使う様にお願いしている筈だ。という事
    | を考えると bash-completion を bashrc の後で source していても問題は起こらな
    | いのではないかという気がするが…。

    * done: fzf-completion は bash-completion よりも先に読み込んでおく必要があ
      るという事を何処かに記述しておく。

    [問題再現]

    嗚呼分かった。2回目以降で動くようになるというのは既にちゃんと報告を受けてい
    た。そして実際に報告通りに初回は失敗して2回目以降はちゃんと動くという振る舞
    いになっている。

    [原因]

    | これは補完再実行の仕組みに関係しているのだろう→うーん。戻り値 124 を期待し
    | ているのにそもそも 124 を補完関数が返さなくなっているのが問題の様に見える。
    |
    | →うーん。分かった。retry は default completion の時にだけ確認する様にして
    | いたが、実は任意の補完についてやり直しが可能という事なのだろう。bash のマニュ
    | アルを見ると 124 による再試行は -D と組み合わせると便利とは書かれているが、-D
    | と組み合わせた時にしか有効にならないとは書かれていない。つまり、
    | is_default_completion でなくても再試行は行うべきである。

    fzf completion はロード時に bash-completion を検出した場合、今後の補完で
    _completion_loader による補完を呼び出そうとする。初回の _completion_loader
    呼び出し時には 124 を返して Bash に対して補完の再試行を要求する。これはどの
    コマンドの補完に対しても同様である。

    一方で ble.sh は 124 に対する補完の再試行は complete -D による補完の時だけ
    しか許さない様になっていた。従って、fzf が予め設定している ssh に対する補完
    設定については、いざ _completion_loader によって内部的に bash-completion が
    呼び出されて 124 を返したとしても、補完の再試行が行われない。というのが問題
    であった。

    [過去の関連修正]

    | ? これに関係する修正を最近しなかったか。その時の都合で現在の様な実装になっ
    |   ている可能性がないかについて確認する。
    |
    |   98835b5a lib/core-complete.sh (Koichi Murase   2021-05-17 14:52:51 +0900 3036)   builtin eval '"$comp_func" "$cmd" "$cur" "$prev"' < /dev/null >&$_ble_util_fd_stdout 2>&$_ble_util_fd_stderr; local ret=$?
    |   58e1be46 lib/core-complete.sh (Koichi Murase   2020-02-10 00:42:04 +0800 3037)   ble/function#pop compopt
    |   4df15e1e complete.sh          (Koichi Murase   2017-10-12 00:52:41 +0900 3038)
    |   4df15e1e complete.sh          (Koichi Murase   2017-10-12 00:52:41 +0900 3039)   if [[ $is_default_completion && $ret == 124 ]]; then
    |   4df15e1e complete.sh          (Koichi Murase   2017-10-12 00:52:41 +0900 3040)     is_default_completion=retry
    |   4df15e1e complete.sh          (Koichi Murase   2017-10-12 00:52:41 +0900 3041)   fi
    |   cdd38598 complete.sh          (Koichi Murase   2015-11-23 23:58:01 +0900 3042) }
    |
    |   と思ったが該当部分の判定は4.5年間変化していない。つまり、関係ないはず。
    |   では最近の問題は何だったろうか。
    |
    |   →うーん。fzf で note.txt を検索しても特に何も出てこない。
    |
    | * 分かった。これだ bash-completion に対する PR の議論だった。
    |   https://github.com/scop/bash-completion/pull/653
    |
    |   bash-completion も他の補完が設定されている時にそれを呼び出すという処理を
    |   している。その時に、これまで bash-completion は 124 が返ってきても何もし
    |   ていなかったのをちゃんと再実行する様に変更するという PR だった。
    |
    |   結局最近何か処理した気がするというのは bash-completion の話だったので
    |   ble.sh は関係ない。つまり、現在の実装になっているのには何の理由もないので
    |   単純に修正すれば良いのだという結論。

    関連する修正があった様な気がしたがそれは bash-completion の話だった。

    問題の箇所を実装した時の議論 #D0534 を確認すると、「complete -D による補完
    の時に 124 が返されたら再試行」とはっきりと書かれている。つまり仕様を勘違い
    していた事になる。

    ? 一方で報告によると auto-complete を off にしたら問題が発生しなくなったと
     している。不思議だ。うーん。一節には auto-complete でメニューが初期化され
     てその中だけで補完しようとする事によって補完内容が減少してしまっている可能
     性。然し、auto-complete ではその様な事は起こらないし、或いは表示されている
     物に惑わされて補完候補が生成されないと勘違いしている?

     と思ったがもう一つの可能性として TAB に独自の auto-complete 用の binding
     を付加している可能性もある。うーん。然し過去に SuperSandro2000 そういう議
     論を開いた訳でもない。然しそれでも何処かの説明を見て TAB の設定を追加して
     いるという可能性はある。

     これは取り敢えず向こうの設定が原因になっている可能性があるので後回しで良い。

  * complete: / が symlink に対して付加されたり付加されなかったりする (reported by SuperSandro2000) [#D1759]
    https://github.com/akinomyoga/ble.sh/issues/171#issuecomment-1021326168

    bash-completion なしでも再現する → これは分かった。bind -v で
    mark-symlinked-directories が off になっているのが原因だった。元の bash だ
    とこれが off になっていたとしても2回 TAB を押したら結局 / を挿入する様だ。
    →もう少し調べてみると ins が空の時には mark-symlinked-directories がなくて
    も / を挿入するという事らしい。

    うーん。元の bash と同じ振る舞いになる様に調整する事にした。これの判定は手
    持ちの情報で既にできたのでその様にした。

  * term: wt で 描画中のカーソル移動が気になる [#D1758]

    flush する時か、或いは描画シーケンス自体にカーソル消去・表示のコードを埋め
    込むべきではないか。

    一方で現在の表示状態はまた別の箇所で管理していた筈である。うーん。現在のコー
    ドだと cursor-state/hidden は描画とは独立に管理している。なので描画に対して
    表示・非表示を埋め込もうとすると buffering によって順序が入れ替わっておかし
    な事になる。それよりは画面に出力する瞬間に一時的に hidden にするのが良い気
    がする。うーん。buffer.flush に介入するのが一番簡単の気がする。怖いので一部
    の端末だけで試験的に実行する? と思ったがテストという観点から考えると取り敢
    えず全部 on にして試す事にする。

    →実装した。取り敢えず変な影は表示されなくなった。それでも何だか点滅してい
    る様な気がするが仕方がない事である。contra/screen では特に問題はない。また
    mintty でも特に問題は見られない。mintty/tmux でも問題は見られない。これは採
    用する事にする。

    * 序でに Windows Terminal の identification も実装する事にする。調べるとど
      うも hardcode している様に見える。取り敢えずこれに対して判定する。カーソ
      ル形状の変更にも対応している様だ。

      https://github.com/microsoft/terminal/blob/bcc38d04cef39fe9d939bf5c10bca5e3bd0a9118/src/terminal/adapter/adaptDispatch.cpp#L779-L782

2022-02-01

  * util (trap): SIGWINCH を沢山呼び出した後にどんどん重くなる (reported by SuperSandro2000) [#D1757]
    https://github.com/akinomyoga/ble.sh/issues/173#issuecomment-1026891422

    これは _ble_builtin_trap_postproc を出力したら分かった。trap handler が走る
    度にどんどん $_ の中身が長くなっている。

    > ble/util/setexit 1 ''
    > ble/util/setexit 1 'ble/util/setexit 1 '\'''\'''
    > ble/util/setexit 1 'ble/util/setexit 1 '\''ble/util/setexit 1 '\''\'\'''\'''\''\'\'''\'''\'''

    この様になっている。先ず、builtin eval の中から $_ を再設定しようとしても
    eval に渡した引数が $_ になってしまうという事が問題である。これはどの様にし
    たら良いだろうか。一つの方法は eval "postproc" '#' "lastarg" と呼び出すという事。

    x postproc に文法的に壊れた物が入っていた時に変な事になるのではないか。と思っ
      たが、postproc を設定しているのは trap handler の枠組み自身なのでちゃんと
      した物しか入っていないというのは保証される気がする。

    x lastarg に改行が含まれている場合には復元できないのではないか。これはどう
      しようもない。

    というか今回の問題を除いても $?, $_ を正しく復元できている様に見えない。
    trap handler の各ケース done, return, break, continue のそれぞれについて
    $?, $_ を正しく保存しなければならない。

    先ず return/break/continue の時の $? $_ の振る舞いについて確認する必要がある。

    $ trap 'break 1' INT
    $ for ((i=0;i<1000000;i++)); do ((a++)); done; echo "_=$_"
    ^C
    _=1
    $ trap 'break' INT
    $ for ((i=0;i<1000000;i++)); do ((a++)); done; echo "_=$_"
    ^C
    _=break

    この結果を見ると loop の外で $?, $_ を見ることができる。更に言うと break,
    continue に渡された引数ですら取得できる。 for (()) は $? $_ を書き換えない
    様に見える。

    ? break/continue に引数として許される形式は? 普通の整数はOK 負の整数もOK +1
      などもOK 少数は駄目だった。空文字列も駄目だった筈。その様な判定にした。

    取り敢えず実装してみたが全然正しく復元できていない。

    x fixed: 次に setexit が結局 $_ に設定されてしまっている。何故。と思ったら
      '#' が本当に # になってしまっていた。これは直した→すぐに動く様になった。

    x fixed: 先ず $_ で取得した lastarg には gexec に使った begin ... end が入っ
      ている。これはそのままでも良いのかもしれないし、或いはコマンド実行中かそ
      うでないかで振る舞いを変更するべきなのかもしれない。コマンド実行中でない
      時にはユーザートラップを呼び出す前に復元してユーザートラップを呼び出した
      後に保存する?

      % 或いはそもそも保存しなくても良い気がする。本来 trap が別のコマンドに影響
      % を与えるというのも変な話である。→と思ったが或る handler の影響は次の
      % handler に残っていて欲しい気もする。つまり、ユーザーコマンドに影響が残る
      % のは変な気がするが一方で同じ handler の間で $?, $_ がちゃんと保持されてい
      % なければ変だという事。やはり保存するべきの様な気がしてきた。
      →ユーザートラップによって変更された $_ はちゃんと反映させるべきの気がする。
      →うーん。結局トラップ専用の lastarg,lastexit 変数に記録する事にした。

    x おまけで ble/dispatch のモード判定にミスを発見した。修正した。

    取り敢えず制限はあるがこれで大丈夫の筈。

2022-01-24

  * edit: コマンド実行時間計測 [#D1756]

    前から気になっていたので実装する。

    * time を用いた計測? 少なくとも msec の精度は存在する。prologue にかかる時
      間などは気になるが。prologue は含めずに計測するのが良いだろう。


      現在の gexec の構造を何処まで変更できるかについて確認しなければならない。
      現在の構造に修正したのは 014d17e6 (#D0465)である。うーん。eval を跨ぐと
      $_ が継承されない? と思ったが prologue に関しては同じ eval に入れなくても
      大丈夫に見える。以下のコマンドを各 bash version で試したがちゃんと動いて
      いる。

      $ { echo hello world; time builtin eval 'echo "[$_]"'; echo $_; }

      うーん。分かった。prologue を同じ eval の中に入れるのは set -v の時の出力
      を最低限に抑える為である → 書き換えた。一応ちゃんと $_ 及び $? が復元で
      きている事を確かめた。

    うーん。ble/util/clock だとか ble/bin/date +%s%6N だとかに頼る方法を考えて
    いたが、time の結果を読み取っている現状では tot をそのまま参照すれば良い気
    がする。開始時刻に関しては date または printf または SECONDS を用いて取得す
    れば良い → 最終的にはやはり ble/util/clock または date +%s%6N に頼る事にし
    た。それを tot を用いて補正する。

    * SECONDS, EPOCHREALTIME, EPOCHSECONDS を readonly するという事? EPOCH* に
      ついては流石に間違えて上書きしたりする事はないと思われる。SECONDS は
      ble/util/clock の初期化時に readonly する事にした。EPOCHSECONDS はどうせ
      使っていないので関係ない。

    * done: カスタマイズインターフェイスについて考えた方が良い気がする。現状で
      既存の errexit とどうくっつけるのかというのが問題である。というより、本当
      は色分けをしたりしたい所だが、現状 errexit の設計が固定文字列になっている
      ので、勝手に弄る余地がなくなってしまっている。

      或いは既定値の時にはくっつけるという操作をするというのでも良いかもしれな
      い? と思ったがそれも変である。或いは、もっと別枠の設定を用意するというの
      も手なのかもしれない→うーん。両方とも無効化して自前で書くというのが良い
      気がする。という事を考えたら、現状では exec_errexit_mark と同様に
      exec_elapsed_mark を定義すれば良い。

    * done: contrib README.md
    * done: ChangeLog
    * done: blerc: new bleopts
    * done: wiki: new bleopts

    x 外部コマンドの時間が計れていない? と思ったが単に cxxmatrix に対して端末が
      遅いだけなのであった。多分測れている。子シェルを合計するかしないかの設定
      があった気がしたけれど、それは多分 times であって関係ないのだ。一応 times
      を使えば real 及び sys の子プロセスの内訳も見られる気がする…が BG で動い
      ている物が加算されるのかは謎である。

      →うーん。times はジョブが終了した瞬間に加算されるので、bg のジョブが丁度
      終了したりすると、現在実行しているコマンドの shell/sys の値を評価できなく
      なる。そもそも time で取れている情報の筈なので関係ない気もする。。と思っ
      たが、シェル本体と子プロセスの時間を区別するのには使えるのかもしれない。
      つまり自プロセスの処理時間を取得するのには使える。

    x EOF marker が動かなくなっている。確認する必要がある。と思ったがこれは単純
      に 2 が /dev/null に繋がっていたというだけの話だった。OK

  * edit: bind -x 関数の呼び出しに際しての画面クリアの振る舞いについて (motivated by SuperSandro2000) [#D1755]
    https://github.com/akinomyoga/blesh-contrib/issues/6#issuecomment-1020165711

    GNU readline は 4.4 で振る舞いを変更した様だ。それ以前はただ単純に現在の編
    集位置にカーソルを置いたまま bind -x の関数を呼び出していた。4.4 以降ではプ
    ロンプトの終了点・編集文字列の開始点の行にカーソルを置いて bind -x の関数を
    呼び出す様になった様だ。実は

      https://github.com/junegunn/fzf/issues/490#issuecomment-184402254

    でもその事が説明されている気がする (何が書かれているかちゃんとは見ていない
    が)。というよりこの振る舞いについては前にも議論した事があるような気がする。
    →うーん。#D0915 (90ca3bea) の最後の動作確認の所で微妙に言及しているだけで
    ある。これ以降は .hide-current-line も対して更新されていないし振る舞いにつ
    いては変更はなかったと思われる。その時は手元で試して振る舞いを決定した気が
    するが詳細については記録に残っていないという事。

  * patsubWA: compat42 での振る舞い [#D1754]

    それとは別に compat42 の効果についても考察する必要がある。compat42 の時には
    結局問題が生じるのではないだろうか?? quote しても無駄である。という事を考え
    ると compat42 の時は単純に実装を切り替えるというのは動作しない。とは言いつ
    つ惨事を防ぐ為にはやはり配慮が必要である。

  * patsubWA: bash-dev で \q{} が動かない [#D1753]

    うーん。これも patsub が原因の気がする。或いは bash-dev の振る舞いの変化に
    よって引き起こされている? 取り敢えず調べる → やはり patsub WA によって動か
    なくなっている。bash 側の振る舞いの変化による物ではなかった。

    実際の動作を調べる。先ずそもそも \q{} が呼び出されているのか? うーん。呼び
    出されていない。つまり @P による展開になってしまっているという事だろうか →
    否、@P による展開にはなっていない。

    うーん。どうやら \q{} はいつの間にかに \\q{} に変換されてしまっている様子。
    何故だろうか。うーん。bleopt_prompt_rps1 の値の時点で \\q{} になってしまっ
    ている。つまり、bleopt が悪い。

    うーん。引数読み取りの時点で駄目になっている。

    $ ble/array#push specs "${var[@]/%/"=$value"}" # #D1570 #D1751 WA checked
    $ ble/debug/print-variables var value specs |& cat -v >/dev/tty
    var=('bleopt_prompt_rps1') value='\q{blerc/rps1}' specs=('bleopt_prompt_rps1=\\q{blerc/rps1}')

    うーん。不思議だ。bash-5.2 のバグだろうか。うーん。これはバグである。という
    か /% 等の様にパターンが空の時には escape は処理されないのである。

      $ var= rep='&'; echo "${var/%/"$rep"}"

    うーん。Bash に報告しようと思ったが思ったよりも複雑である。続きは
    bug-report/bash/report31 で議論する事にした。取り敢えず patch は作った。最
    終的にどうなるかは分からないが取り敢えずは patch 付きでコンパイルしていれば
    今の ble.sh の実装で大丈夫のはず。

  * patsubWA: bash-4.3 で \$ になる [#D1752]

    これもつい最近までは見られなかった問題である。bash-3.0 迄影響を受けている。
    これも patsub_replacement 対策が悪さをしていると見える。

    % うーん。_ble_prompt_const_root を出力している箇所から既に問題が起こっている
    % 気がするが、_ble_prompt_const_root の値は昔から変わらず "\$" だった様だ。
    % 然し、patsub 修正よりも前にはちゃんと単一の $ になっていた。
    %
    % $ declare -p _ble_prompt_const_root
    % declare -- _ble_prompt_const_root="\$"
    %
    % →これは declare の出力の quote であって、_ble_prompt_const_root の値自体
    % は常に単一の '$' だった。

    というよりそもそも ble/prompt/print は $ を解釈しないのではなかったのか。だ
    とすれば \$ の様にする意味がない。うーん。つまり以前の実装が間違っていたと
    いう事。

    うーん。分かった。確かに以前の実装は間違っている。escape-characters に渡す
    文字集合は '$\`"' ではなく '\$`"' でなければならない。つまり一番最初に '\'
    を置換しなければ他の文字の置換結果の '\' も二重に置換してしまう事になる。こ
    の様な実装に切り替えたのは patsub の事だと思ったが

    % よく考えたらそれよりも前から二重のバグによってたまたま動いていただけに過
    % ぎない → これも勘違い。以前は '$' を正しく quote して正しく最終的に '$'
    % になっていた。
    %
    % |  function ble/prompt/print {
    % | -  local text=$1 a b
    % | -  if [[ ! $prompt_noesc && $text == *['$\"`']* ]]; then
    % | -    a='\' b='\\' text=${text//"$a"/$b}
    % | -    a='$' b='\$' text=${text//"$a"/$b}
    % | -    a='"' b='\"' text=${text//"$a"/$b}
    % | -    a='`' b='\`' text=${text//"$a"/$b}
    % | -  fi
    % | -  ble/canvas/put.draw "$text"
    % | +  local ret=$1 a b
    % | +  [[ $prompt_noesc ]] ||
    % | +    ble/string#escape-characters "$ret" '$\"`'
    % | +  ble/canvas/put.draw "$ret"
    % |  }
    %
    % と思ったがこの編集を見ると以前はちゃんと動いていた筈なのである。という事は、
    % 先ず初めに '\$' が \\\$ になって、更に評価時に \$ になる筈。不思議である。
    % うーん。以前は \$ は \\\$ になって、更に評価された時に \$ になるという仕組
    % みだった筈。

    何れにしても問題の部分を修正したらちゃんと動く様になった。

    % 然し何故これで動くのかは未だに謎である。うーん。何故?
    %
    % →ずっと遡っていくと実はずっと単一の '$' である。。そして
    % _ble_prompt_const_root も単一の '$' である。declare の出力が double
    % quoted だから \$ と表示していたけれども実は単一の $ だったという事である。
    % つまり勘違いだった。

    結局これで万事大丈夫になった。

  * patsubWA: bash-4.2 で文法エラーが発生する (bind.delay 周り) [#D1751]

    何と、bash-4.2 では "${var//xx/"yy"}" の " は literal になる。テストで検出
    された物を少し修正したが他にも沢山ありそうだ。

    $ grc '"[^"]*\$\{[[:alnum:]_]+(\[[^][]*\])?//?([^{}]|\{[^{}]*\})+/[^{}"'\'']*"[^"]*([&$]|\\)' --exclude=./test
    done: ./keymap/vi_test.sh:44:    ble/util/print "  initial  = \"$i:${in//$nl/"$NL"}\""
    done: ./keymap/vi_test.sh:45:    ble/util/print "  expected = \"$f:${fin//$nl/"$NL"}\""
    done: ./keymap/vi_test.sh:46:    ble/util/print "  result   = \"$_ble_edit_ind:${_ble_edit_str//$nl/"$NL"}\""
    done: ./lib/core-complete.sh:3432:    [[ $progcomp_prefix ]] && cands=("${cands[@]/#/"$progcomp_prefix"}") # WA #D1570 safe
    done: ./lib/core-syntax.sh:4414:        b='\`' a='`'; str="${str//"$b"/"$a"}"
    done: ./lib/core-syntax.sh:4415:        b='\"' a='"'; str="${str//"$b"/"$a"}"
    done: ./lib/core-syntax.sh:4416:        b='\$' a='$'; str="${str//"$b"/"$a"}"
    done: ./lib/core-syntax.sh:4417:        b='\\' a='\'; str="${str//"$b"/"$a"}"
    done: ./lib/core-syntax.sh:4453:    a=\\   ; b="\\$a"; ret="${ret//"$a"/"$b"}"
    done: ./lib/core-syntax.sh:4454:    a=\'   ; b="\\$a"; ret="${ret//"$a"/"$b"}"
    done: ./lib/core-syntax.sh:4455:    a=' '  ; b="$_ble_syntax_bash_heredoc_EscSP"; ret="${ret//"$a"/"$b"}"
    done: ./lib/core-syntax.sh:4456:    a=$'\t'; b="$_ble_syntax_bash_heredoc_EscHT"; ret="${ret//"$a"/"$b"}"
    done: ./lib/core-syntax.sh:4457:    a=$'\n'; b="$_ble_syntax_bash_heredoc_EscLF"; ret="${ret//"$a"/"$b"}"
    done: ./lib/core-syntax.sh:4458:    a=$fs  ; b="$_ble_syntax_bash_heredoc_EscFS"; ret="${ret//"$a"/"$b"}"
    done: ./src/util.sh:118:          ble/array#push specs "${var[@]/%/"=$value"}" # #D1570 WA checked
    done: ./src/util.sh:777:    ARR=("${ARR[@]::$2}" "${sARR[@]/#/"$4"}" "${ARR[@]:$3}")' # WA #D1570 checked
    done: ./src/util.sh:1138:  a='!' b='"\!"' ret=${ret//"$a"/"$b"}
    done: ./src/util.sh:1165:    a=$'\n' b="\$'\n'" ret=${ret//"$a"/"$b"}
    done: ./src/util.sh:1401:  builtin eval -- "${_ble_local_script//opts/"$1"}"
    done: ./src/util.sh:1405:  builtin eval -- "${_ble_local_script//opts/"$1"}"
    done: ./src/util.sh:1413:  builtin eval -- "${_ble_local_script//opts/"$1"}"
    done: ./src/util.sh:1421:  builtin eval -- "${_ble_local_script//opts/"$1"}"
    done: ./src/util.sh:1574:    ret=("${ret[@]//$_ble_term_FS,/"$_ble_term_FS"}") # WA #D1570 checked
    done: ./src/util.sh:5371:  ble/util/put "${_ble_term_visible_bell_show//'%message%'/"$sgr$message"}" >&

    取り敢えず全て修正した。一応動作はしている。

  * prompt: wezterm shell-integration が PRECMD で何かを出力するがずれる [#D1750]

    先ず precmd を呼び出す瞬間のカーソル位置が前回のプロンプトの後になっている
    ので、この時点でずれが生じる。これは bash に倣って次のプロンプトの最初にカー
    ソルを移動してから呼び出すべきという事なのだろうか。

    x ok: 次に、precmd の直前で flush する様にしても座標位置がずれてしまう。特
      にコマンドを実行した直後の状態が怪しい。これは別の dock にいたりする事が
      原因なのだろうか。。と思ったが、うーん→これは分かった。info を表示してい
      る為に内部座標原点にいないのが原因であった。内部座標原点に移動してから
      flush したら、表示位置がずれる問題は解決した。

    x 然し依然として precmd の中から出力した事自体によってずれが生じる問題につ
      いてはそのままである。うーん。info を表示するよりも前に precmd は実行する
      べきという事なのだろうか。

    ? ok: そもそも precmd と prompt_command は分けて考えるべきなのかもしれない。

      コマンド実行ではなくて別の理由で (SIGWINCH などで) プロンプトの再計算が走
      る場合に本当に precmd や PROMPT_COMMAND も一緒に呼び出してしまって良いの
      かというのも疑問である。端末サイズに応じてプロンプトを更新したいという事
      を考えれば PROMPT_COMMAND は WINCH に対して改めて実行したほうが良い気もす
      る。然し、PRECMD の意味を考えたら本当にコマンド入力を開始した時にだけ呼び
      出したい様な気もする。然し、コマンド入力を開始したい時はやはり
      PROMPT_COMMAND なのではという気もする。

      その様に色々考えると PROMPT_COMMAND と一緒に実行する現在の設計で問題ない
      気もする。そして SIGWINCH でも呼び出して良い。前のプロンプトを捨てて新し
      いプロンプトを構築すると考えれば良い。

    * ble/prompt/update の呼び出しはより外側に移動しても良いのではないか。

      うーん。然し leave in opts のテストがある。これは textarea#render に渡さ
      れる引数である。呼び出し元は以下の二箇所。何れも
      ble/widget/.insert-newline からの呼び出しである。

      ./src/edit.sh:5713:    ble/textarea#render leave
      ./src/edit.sh:5724:    ble/textarea#render leave

      うーん。leave の時には改めてその場で ble/prompt/update を呼び出す。少し書
      き換えてみる。

    実装してみたは良いがよく考えたら現在の実装だとプロンプトの更新が滞る。

  * main: /dev/tty が割り当てられていない時にも ble.sh は初期化しない [#D1749]
    https://github.com/oilshell/oil/issues/1069#issuecomment-1017189089

    Docker でロードしようとしている時に失敗する。

    後、--test や --update 等の時には通常コマンドとして動作するので様々のチェッ
    クを無視して良い。更に言うとそもそも /dev/tty から端末を取得しようとする事
    自体が不要である。取り敢えずその様に実装した。

  * canvas: wezterm で DECSTBM のクリアに失敗している [#D1748]
    https://github.com/akinomyoga/ble.sh/issues/96#issuecomment-1019570983

    kitty もそうだったが \e[;r では DECSTBM をクリアできない模様。
    DECSTBM と同様にその場で端末をテストする事にした。修正した。
    この問題については解決した。

2022-01-23

  * main: IN_NIX_SHELL をチェックする (reported by SuperSandro2000) [#D1747]
    https://github.com/akinomyoga/ble.sh/issues/169#issuecomment-1019405936
    https://github.com/akinomyoga/ble.sh/issues/169#issuecomment-1019555462

    取り敢えず IN_NIX_SHELL をチェックする事にした。

    またチェックは rshell やその他のチェックよりも先に行うべきである。特に最初
    にエラーメッセージなしで抜けるのであれば、それは他の条件でエラーメッセージ
    が表示される前に一番最初にチェックするべきなのである。

  * util: _ble_term_TERM が空になっている問題 [#D1746]

    mintty で _ble_term_TERM が空になっている。何故か。unknown が設定されるので
    はないか。ちゃんと DA2R は受信できている。そして passthrough seq がちゃんと
    動いていない in screen. これは修正する必要がある→確認したら物凄く単純なミ
    スをしていた。これは恐らく置換か何かをした時の残りであろう。

  * 折返しがある時に実際に端末に改行が挿入される (reported by banoris) [#D1745]
    https://github.com/akinomyoga/ble.sh/issues/170

    これは元々は途中の列で折り返しをする為 (例えば prompt_rps1 の為) に導入した
    振る舞いだが、確かに報告にある様にコピー・ペーストしたいという場合もある。
    端末の全幅を使っている時には折返しの改行は明示的に挿入しない様にするべきな
    のではないか。

    全角文字が収まり切らない時に端末がどの様に振る舞うかについても何か仮定を置
    かなければならない。折返しの位置で改行は挿入しない。

    * うーん。全角文字が入り切らない時に挿入する空白は其処に元々存在した文字を
      消去して空白で上書きするという意味合いもあった。という事を考えると、実は
      ECH で代替できるのではないか。実は ECH を実行したとしても空白になってしま
      う端末も存在するだろうし、末尾の空白は空白とみなさない端末もあるだろうし
      実装は色々だろう。

    * 改行が挿入されるのが駄目という事であれば一旦 CR で先頭に移動してから LF
      を実行すれば良いのではないか? と考えたが多分そういうことじゃない。状況は
      逆で、既定では別の独立した行になっていて、然し折返しがあった時に限り２つ
      の行を接続するという振る舞いになっているのだと思われる。

      という事を考えるとやはり末尾で折返しを発生させる必要があるのである。

    ? rps が存在する時は relative になっているだろうか。うーん。xenl のない端末
      では改行を挿入していないという事を見ると、改行は挿入しなくてもちゃんとそ
      の場で折返しが発生するという事は想定している。

      →確認したら実際に rps1 が存在している時には relative になっていた。

      [[ $rps1_enabled ]] && render_opts=relative

      という事は relative でなければ常に全幅になっているという事を想定して良い
      様に思われる。

    ? slice してから出力した後のカーソル位置が予測不可能になるのではないか。全
      体を一気に出力する場合には次に文字があるかどうかで自動折返しが発生するか
      どうか分かる。自動折返しが発生しない時に限り改行を挿入すれば良い。然し部
      分更新をしている時には自動折返しが発生しない可能性が常に存在する。その時
      に座標が不定になってしまう。直後に行う操作 (CUU) 等によって端末に依って異
      なる結果になってしまう。うーん。

      というか此処まで来ると bash だってちゃんと動作しているかどうか怪しい物で
      ある。然し、readline の場合には基本的に着色はないので、文字の内容は変わら
      ないのに色だけ部分的に更新するという事もないのだろうと予想する。なので問
      題が発生するケースは存在しない。

    ? うーん。何と説明するか。全角折返しの空白や改行の挿入は端末の違いを吸収す
      る為に必要だという事を説明する? でも既存の readline は問題を起こしていな
      い。しかしそれは着色をしていないので部分更新でも必ず折り返しは発生するか
      ら。

      うーん。折返しを起こしてかつ後続の文字に干渉しない様な方法というのは存在
      するのだろうか。。うーん。存在しない気がする。だとすると、新しく slice 終
      端禁止点の様な物を導入して slice をする時には範囲を拡張するという具合にす
      る必要がある気がする。うーん。そういう方法しか存在しないだろうか。。。

    a 後続の文字によって自動折返しが期待できる時には改行は挿入しない。

      slice 禁止点の情報を記録する (実は既に grapheme cluster によって類似の仕
      組みが備わっていないのか)。

      xenl の端末とそうでない端末でちょうど行末に改行があった場合の振る舞いが変
      化するのではないか。それは大丈夫なのだろうか。或いは丁度行末にいる時に改
      行を実行する時には二重改行を挿入する? うーん。

      →色々考えたが b の方針に比べると考えなければならない事が多すぎる。これは
      やはり棄却する。

    b 一括出力時に自動折返しの改行文字は削除する。その為には自動折返しの改行文
      字として特別な文字を使う。例えば \r は ^M と encode されるので本来は
      textmap の中に含まれる事はないと思って良い。

      slice する際にまた \r を元に戻す処理をするのが良い気がする。うーん。この
      方針で行くのが一番安心の気がする。

      ? 丁度行末で改行がある場合の動作?

        この方針の際に丁度行末に改行がある場合はちゃんと動作するのだろうか。つ
        まり一番最後の文字の末尾に \r があって、それから次の文字の改行が \n と
        して来る。この時に slice 後の置換によって内部の \r は削除されてしまうの
        で単一の \n になってしまう。うーん。これは駄目だ。一方で \n\n にしたら
        良いのかと聞かれるとそれも何だか違う気がする。つまり改行が二重に複製さ
        れてしまう。うーん。然し、これは表示される時の表示と実際の内容のずれと
        して仕方がないのではないかという気がする。\n\n にするしかない。

        一応自動折返し位置に改行がある時に readline がどう表示するのかについて
        は確認する事にする。内容は一個の改行だけれども、コピーすると二個の改行
        に増えている。やはりこれは仕方がないのだという気がする。

      後は _ble_textmap_glyph を触っている所を全て確認すれば良い。うーん。この
      配列自体は ble/textarea#update-text-buffer からしか参照されていない様に見
      える。うーん。然しそれは変だ。と思ったが、やはりそれで良いのだ。というの
      も、通常の文字の端末上の表示は常に同じだからわざわざ textmap を参照する必
      要もないのである。最終的に "変更文字" である物だけ置き換えれば良いのであ
      る。そして実際自動折返しが発生している物については changed がマークされて
      いる。よってこの時点で _ble_textarea_buffer に反映されるのである。

      _ble_textarea_buffer を参照している箇所は以下しかない。

      ./src/edit.sh:2559:    IFS= builtin eval "ret=\"\$ret\${$_ble_textarea_bufferName[*]:i1:i2-i1}\""

    → b の方針で実装した。動いている気がする。

    x 2022-01-23 動いていると思ったら勘違いだった。丁度行末に改行がある時に座標
      がずれてしまう。何かと思ったら \r\n を \n\n に置換しようという所で、間に
      SGR がある為に置換しきれていないのが原因の様である。

      うーん。これはどうしたら良いのか。単純な置換だと無理の気がする。或いは間
      に来る SGR が既知であれば固定文字列として置換する事もできる。。と思ったが、
      そもそも不特定の \r\n の組を対象にして一括置換しようとしているのだから、
      固定文字列になっている筈がない。うーん。間に入るのは単一 SGR なのだろうか
      →実装を確認した所 sgr 決め打ちである。という事であれば extglob さえ使え
      ば置換はできる…と思ったが置換後が固定文字列になってしまうので駄目である。

      うーん。という事を考えるとやはり正規表現で \r を一つずつ一致させて処理す
      るしか無いのだろうか→うーん。その様にして実装した。CSI seq, ESC seq, 及
      び SI SO を跨いで改行を検出する様にした。

2022-01-21

  * bash-preexec に本格的に介入する事を考える事にする (motivated by SuperSandro2000) [#D1744]
    https://github.com/akinomyoga/ble.sh/issues/96#issuecomment-1016401487

    1. bash-preexec の機能を on/off する方法を探す。
      特に off にしている時には DEBUG trap は削除する様になっていて欲しい。

      そもそも __bp_install で一体何をしているのか等についてもちゃんと確認する
      必要がある。以前調べた感じだと PROMPT_COMMAND が他の枠組みに上書きされて
      も大丈夫な様に DEBUG を使って実際の登録を行う仕組みになっていた筈である。

    2. bash-preexec の機能を PRECMD / PREEXEC で再現できる様にする。

      PIPESTATUS を保存する → BLE_PIPESTATUS に記録する事にした。各 hook の中
      からはこれを参照すれば最後のコマンドの PIPESTATUS を取得できるという事を
      wiki にも書く。該当する hook は PRECMD, PREEXEC, POSTEXEC, ERR である。何
      故か CHPWD は該当しない。

    * そもそも現状の ble.sh に於いて、最初に bash-preexec をロードして置いて、
      後から source ble.sh を実行すると preexec 用の DEBUG trap が削除されてし
      まっている。

      この振る舞いについてちゃんと調べて解決する必要があるのではないだろうか。

    * done: 取り敢えず ble.sh の側で対策を実装する事にする。もし bash-preexec
      に適切な API があったとしてもなかったとしてもちゃんと動く様にする。

      ble.sh の側で実装するとなると何処かのタイミングで bash-preexec を検出しな
      ければならない。元から bash-preexec が存在している場合にはそのまま検出で
      きる。後から bash-preexec が読み込まれた時にどの様に対処したら良いのかは
      非自明である。

      a 一つの方法は precmd_functions 辺りに何か仕掛けておくという事。然し、
        bash-preexec が実際に読み込まれるかどうかも分からないのに汚染はしたくな
        い気がする。

      b だとすると POSTEXEC 辺りで bash-preexec 特有の関数が定義されていないか
        どうかチェックするという事になる気がする。これは overhead であるが、ま
        あ特に重い処理でもない気がするので気にしなくて良い。

      どの様に実装するのかというのも気になる。外部プラグインとして実装するのか
      ble.sh 本体に埋め込んでしまうのか。取り敢えず外部プラグインとして実装して
      置いて、後で本体に組み込むかどうか決定するのが良い気がする。

      →contrib/bash-preexec に実装した。更に読み込み用のコードを ble.sh に埋め
      込む事にした。

    [テスト]

    * テストの方法

      ロードの順序や attach の方法など色々考えられる。それらについて全部動作確
      認するべきの気がする。以下の場合を確かめる。

      % - bash-preexec  bashrc / interactive
      % - ble.sh        (bashrc / interactive) x (prompt / attach)
      % - どちらを先に source するか。
      % - 両方 interactive の時には同じコマンドの中で source するかどうか。
      % - bash-it       bashrc / interactive

      まとめると以下のロードの組み合わせが存在する。

      - done: bp blesh.prompt $
      - done: bp blesh.attach $
      - done: bp $ blesh.prompt
      - done: bp $ blesh.attach
      - done: $ bp $ blesh.prompt
      - done: $ bp $ blesh.attach
      - done: $ bp blesh.prompt
      - done: $ bp blesh.attach
      - done: blesh.prompt bp $
      - done: blesh.attach bp $
      - done: blesh.prompt $ bp
      - done: blesh.attach $ bp
      - done: $ blesh.prompt $ bp
      - done: $ blesh.attach $ bp
      - done: $ blesh.prompt bp
      - done: $ blesh.attach bp
      - done: bash-it $
      - done: $ bash-it
      - done: 更に detach した後もちゃんと動くかも確認する

    x done: 初回の実行時に trap DEBUG が残っている場合が存在する。特に bp が後
      にロードされた時にこれが起こる。後に bp がロードされた時には POSTEXEC で
      処理をしているのだから仕方がない。それよりも前の時点で検出する方法はない
      のだろうか→というか全パターンで trap DEBUG が初回実行で残ってしまってい
      る。これは何が悪いのだろうか。恐らく最初の PROMPT_COMMAND でから install
      string を削除できていない。

      と、ここで理由が分かった。そもそも contrib/bash-preexec が POSTEXEC から
      しか自動ロードされていない。ATTACH 及び ble.sh ソース時にもチェックするべ
      きである。

    x ok: "bp blesh.attach" 及び "$ bp blesh.attach" に於いて初回のコマンド実行
      では未だ contrib/bash-preexec による調整が有効になっていない。但し、動作
      に関しては問題ない。これはまあ仕方がないのだろうという気がする。

    DEBUG 周りを色々と修正し直す事にした。幾らか弄ったら色々動かなくなった。

    x resolved: C-c した時に変なエラーメッセージ (return に空の引数が渡されて
      いる) が発生している。これは一体何だろうか。うーん。bash --norc, source
      out/ble.sh --norc でも発生する。一旦発生するとその後もずっとコマンドを
      実行する度に発生している気がする。

    x resolved: C-c で実行をキャンセルできていない→これは正規表現の編集をミ
      スして正規表現が不正になっていた。修正した。直った。

    * done: ble/builtin/trap/invoke と ble/builtin/trap/invoke+ を統合する。
      ble/builtin/trap/invoke+ はもっと単純な戻り値に外で実行するべきコマンド
      を出力する。

    x resolved: detach した後に TRAPDEBUG が設定されていない。うーん。trap -
      DEBUG を実行した時点で builtin trap DEBUG が設定されるべきなのにされない
      という問題である。

      これは実際に builtin trap DEBUG がされていないのか、或いは実際している
      けれどもそれが関数呼び出しの為に途中で消えてしまっているのかどちらなの
      だろうか。動作を確認する事にする。

      →どうやら _ble_edit_exec_TRAPDEBUG_enabled によって明示的に無効化され
      ている様に見える。これは元々何の為の判定だろうか。gexec の中か外かで振
      る舞いを変えている様子である→分かった。ble.sh の内部にいる時に即座に
      DEBUG trap を有効にすると ble.sh の中で DEBUG が大量に走って不都合とい
      う事。

      % そういう事であれば _ble_edit_exec_TRAPDEBUG_enabled=1 にする瞬間に
      % trapdebug を実行するのが妥当なのではないだろうか。。→と思ったら既に
      % ble-edit/exec:gexec/.TRAPDEBUG/enter に於いて TRAPDEBUG をちゃんと実
      % 行していた。

      そもそも ble-detach した時に _ble_edit_exec_TRAPDEBUG_enabled=1 に最終
      的になるのかもよく分からない → 調べてみると空のままの気がする。detach
      の際に直接 trapdebug を設定すれば良いのではないだろうか。。と思ったがそ
      ういう訳でも無い様な。

      % →これは単なる変数名の変更漏れだった。修正した。

      うーん。detach の際に ble-edit/exec:gexec/.TRAPDEBUG/enter を実行すれば良
      い気がする。

      →これはちゃんと動く様になった。また detach した後でも INT が残っていて悪
      さをする問題に関しては、TRAPINT で return || break を実行して抜けられる様
      にする事にする。

    * [保留] "for ((i=0;i<10;i++)); do sleep 1; done" で C-c すると変な事になる。
      これは元から動いていなかった物なので今新しく動かなくなったという訳ではな
      い。

      →うーん。どうもこれは sleep が sigint で終了した時には、bash は trap
      handler は起動せずに完全に実行全体を終了してしまうみたいである。

        $ trap 'echo TRAPINT' INT
        $ for ((i=0;i<10;i++)); do sleep 1; done
        ^C
        $

      この様に trap が発動する事無く即座に終了してしまう。特に ble.sh の中から
      実行する際には実行が完全に終了した後も端末ハンドラーの設定がそのままになっ
      ているので、新しいユーザーの入力も RET が来るまでは受け取れないという状態
      になってしまっている。これは仕方がない。

    * done: wiki trap debug 更新

    * done: SIGINT message をもっと見やすく。これはこんな物だろう。

    * done: wiki に BLE_PIPESTATUS を記述する。

    取り敢えずコミットを作ってしまって良い気がする。

    * done: 後は contrib を修正する。

    * done: PRECMD は PROMPT_COMMAND よりも前に実行するべき。元々どちらでも良かっ
      たが、bash-preexec が最初に実行する様になっているのでそれに倣う。

  * global: protect overridden builtins against "set -eu" (reported by SuperSandro2000) [#D1743]
    https://github.com/akinomyoga/ble.sh/issues/169

    またもや set -uex でロードできなくなっているのでその修正を行う。同時に$- 及
    び $BASHOPTS (bash-4.0 以下では自前で再構築) を持ちて状態保存のコードを単純
    化した。これで以前よりは効率はよくなったのではないかと思う (nocasematch の
    検索は多少時間がかかるかもしれない)。

    次に各 builtin に対して対策コードを導入する事にする。

    - done: trap  (util.sh)
    - done: sleep (util.sh)
    - done: bind  (decode.sh)
    - done: read  (edit.sh)
    - done: exit  (edit.sh)
    - done: history (history.sh)

    そもそも set -eu をありがたがって使っている時点で余り分かっていない人が書い
    ているという気がする。何れにしてもその時点で一般には防御が難しいが、NixOS
    の用意したスクリプトでだけ set -eu を有効にするというのであれば、仕方がない
    のかもしれない。勝手に builtin を上書きしてそれで問題を起こすのは ble.sh が
    悪い。これによって状態保存・復元の overhead が生じるが仕方がない。

  * prompt: C-c で history_share が有効でない (reported by SuperSandro2000) [#D1742]
    https://github.com/akinomyoga/ble.sh/issues/96#issuecomment-1018101640

    うーん。確かにそうだ。確か以前もっと高頻度で更新する事についても考察したが、
    編集中に何か変な事が起こると大変だと思ってそれは棄却したのだった。然し、C-c
    で discard-line する場合には安全に履歴をロードする事ができる。対応する。

2022-01-20

  * prompt: cygwin で root prompt mark が正しく表示されなくなっている [#D1741]

    よく考えたら ${PS1@P} を使う様にしているからではないか。振る舞いを修正して
    いる物が含まれている場合にも ${PS1@P} の仕様は無効化する必要がある。

    つまり、cygwin, msys, etc において PS1 に \$ が含まれていたら駄目。
    これは簡単な修正だった。

  * prompt: bash-it や oh-my-bash で最初のプロンプトの座標計算がずれる [#D1740]

    ble.sh を読み込むと最初のプロンプトの表示がずれてしまう。これは ble.sh をロー
    ドして最初にプロンプトを表示した時には未だ char_width_{mode,version} が解決
    されていないので、既定の設定が使われて座標計算にずれが生じるのが原因である。

    本来は bleopt_char_width_{mode,version} が変化していれば再描画される筈なの
    であるが何故再描画が走らないのだろうか。取り敢えず
    ble/prompt/unit:_ble_prompt_ps1/update の時点で char_width_@ が解説された後
    に呼び出されていない。ble/prompt/unit#update _ble_prompt_ps1 は実行されてい
    る。という事を考えると、の間で更新が棄却されているという事になる。

    ohashref='$_ble_prompt_version::$prompt_ps1,$PWD' である。うーん。本来は
    $_ble_prompt_version と同じ所で char_width_@ も参照するべきの気がする。→結
    局 prompt_hashref_base に '$_ble_prompt_version' だけが入っていた所
    に'$bleopt_char_width_mode,$bleopt_char_width_version' も追加する事で解決し
    た。他にも LC_CTYPE が変わった時にも問題になるのではないか、と思ったが
    LC_CTYPE がコマンド実行以外で勝手に切り替わる事もないと思われるの
    で、_ble_prompt_version でカバーできていると考えるべきである。つまり、
    bleopt_char_width_{mode,version} は非同期で変化する可能性があるのでそれに応
    じて更新する必要があるという事。

    と思ったが、bleopt_char_width_{mode,version} が変化するのは検出できるのだか
    ら、其処で、_ble_prompt_version を更新すれば良いだけなのでは→その様に変更
    する事にした。実は bleopt_char_width_{mode,version} の他にも
    emoji_{opts,version} が存在した。これらも変化があればちゃんとプロンプトを更
    新する必要がある可能性がある。全て対応した。ちゃんと動いている。

  * bash-5.2 shopt patsub_replacement 対策 [#D1739]

    これは #D1738 の一環として発見されたバグであるが bash-0.3 も修正しなければ
    ならないので、独立した項目にする事にする。

    - util (ble/builtin/trap): $Q から $q へ逆方向で変換されていた。
    - util (ble/util/print-global-definitions): ${v//$q//$Q} の様になっていた為
      に置換後に余分な / が混入していた。

  * 2022-01-13 bash-5.2 shopt patsub_replacement 対策 [#D1738]

    % 取り敢えず危なそうな箇所を抽出しておく。うーん。やはり可也面倒である。
    % ble/string#replace 等の関数を作るべきなのかもしれない。
    %
    % $ grc '\$\{[[:alnum:]_]+(\[[^][]*\])?/' --exclude={memo,test,wiki}
    % $ grc '\$\{[[:alnum:]_]+(\[[^][]*\])?//?[^{}]*/[^{}]*[$&]'
    % $ grc '\$\{[[:alnum:]_]+(\[[^][]*\])?//?([^{}]|\{[^{}]*\})+/[^{}]*([$&]|\\)'
    %
    % done: ./keymap/vi.sh:6974:    ins=${ins//[!$'\n']/"$s"} ★
    % done: ./lib/core-syntax.sh:976:      a=${a//@h/$histc1}
    % done: ./lib/core-syntax.sh:977:      a=${a//@q/$histc2}
    % done: ./lib/core-syntax.sh:982:    a=${a//@h/$histc1}
    % done: ./lib/core-syntax.sh:983:    a=${a//@q/$histc2}
    % done: ./lib/core-syntax.sh:2255:    rex_event=${rex_event//@A/$A}
    % done: ./lib/core-syntax.sh:2266:    rex_quicksub=${rex_quicksub//@A/[$histc2]}
    % done: ./lib/core-syntax.sh:2267:    rex_quicksub=${rex_quicksub//@C/$histc2}
    % done: ./lib/core-syntax.sh:4453:    a=\\   ; b="\\$a"; ret="${ret//"$a"/$b}" ★
    % done: ./src/edit.sh:604:    a='\' b='\\' text=${text//"$a"/$b} ★
    % done: ./src/util.sh:118:          ble/array#push specs "${var[@]/%/=$value}" # #D1570 WA checked
    % done: ./src/util.sh:777:    ARR=("${ARR[@]::$2}" "${sARR[@]/#/$4}" "${ARR[@]:$3}")' # WA #D1570 checked
    % done: ./src/util.sh:806:  ret="${ret// /$1}"
    % done: ./src/util.sh:1083:      a=${chars1:i:1} b=\\${chars2:i:1} ret=${ret//"$a"/$b}
    % done: ./src/util.sh:5305:  ble/util/put "${_ble_term_visible_bell_show//'%message%'/$sgr$message}" >&2
    % done: ./src/util.sh:5622:  local ret=${_ble_term_Ss//@1/$state}
    %
    % ????: ./src/util.sh:1379:  builtin eval -- "${_ble_local_script//opts/$1}" # Note: 配列要素に変な文字が入っていると駄目
    % ????: ./src/util.sh:1383:  builtin eval -- "${_ble_local_script//opts/$1}" # Note: 配列要素に変な文字が入っていると駄目
    % ????: ./src/util.sh:1391:  builtin eval -- "${_ble_local_script//opts/$1}" # Note: 配列要素に変な文字が入っていると駄目
    % ????: ./src/util.sh:1399:  builtin eval -- "${_ble_local_script//opts/$1}" # Note: 配列要素に変な文字が入っていると駄目
    %   →うーん。これらについては元々配列要素を想定していない実装になっているのでここで改めて気にするのも変である。
    %   それに配列要素を想定している場合には添字は先に1回だけ評価するべきの気がする。なので、そんなに単純ではない。
    %   これは今回は見送り。
    %
    % ok: ./src/util.sh:1516:    builtin eval -- "${_ble_local_script//NAME/$1}"
    % ok: ./src/util.sh:1899:builtin eval -- "${_ble_util_gdict_declare//NAME/_ble_builtin_trap_n2i}"
    % ok: ./src/util.sh:2515:  builtin eval -- "${_ble_local_script//ARR/$_ble_local_array}"

    外部プロジェクトも気になる。うーん。これは悲惨な結果である。
    bashdb, bash-completion, etc. が大抵影響を受ける様に見える。
    -> bug-report bash/report31/affected.txt に移した。

    bug-bash に再度報告した。結局、当初の提案で実装し直して貰った。

    改めて新しい実装に合わせて ble.sh を調整する事にした。改めて丁寧にチェック
    を行って行ったところ、先の修正で見過ごしていた所も幾らか見つかった。自動検
    出しやすい様にスタイルを統一し、その上で自動検出を記述した。

2022-01-18

  * ble-measure の base がやはりずれる。より良い更新式を取得したい [#D1737]

    うーん。というより此処まで大きくずれるのであれば nest レベル毎に計測を実施
    するべきなのではないか。但し、ble-measure を自信から呼び出して使うと nest
    レベルが1だけずれてしまう。然し、それでも nest レベル毎に計測し直した方が遥
    かに良い値が出ている。

    一応 nest レベルの 1 のずれを補正する事にする。${#FUNCNAME[*]} 1..11 まで計
    測してそれを線形フィットする。

    | gnuplot> plot 'a.txt'
    | gnuplot> f(x) = a * x + b
    | gnuplot> b=4500;a=100
    | gnuplot> fit f(x) 'a.txt' via a,b
    | iter      chisq       delta/lim  lambda   a             b
    |    0 1.5114300000e+05   0.00e+00  3.22e+03    1.000000e+02   4.500000e+03
    |    1 3.2658557879e+04  -3.63e+05  3.22e+02    9.857978e+01   4.410413e+03
    |    2 1.9568027480e+04  -6.69e+04  3.22e+01    8.865848e+01   4.465751e+03
    |    3 1.9468872818e+04  -5.09e+02  3.22e+00    8.771000e+01   4.471467e+03
    |    4 1.9468872727e+04  -4.67e-04  3.22e-01    8.770909e+01   4.471473e+03
    | iter      chisq       delta/lim  lambda   a             b
    |
    | After 4 iterations the fit converged.
    | final sum of squares of residuals : 19468.9
    | rel. change during last iteration : -4.66698e-09
    |
    | degrees of freedom    (FIT_NDF)                        : 9
    | rms of residuals      (FIT_STDFIT) = sqrt(WSSR/ndf)    : 46.5103
    | variance of residuals (reduced chisquare) = WSSR/ndf   : 2163.21
    |
    | Final set of parameters            Asymptotic Standard Error
    | =======================            ==========================
    | a               = 87.7091          +/- 4.435        (5.056%)
    | b               = 4471.47          +/- 30.08        (0.6726%)
    |
    | correlation matrix of the fit parameters:
    |                 a      b
    | a               1.000
    | b              -0.885  1.000

    4471.47 + 87.71 * ${FUNCNAME[*]}

    現在のレベルが x の時、x+1 の計測結果は b+a(x+1) になっていると考えられるので、
    [b+ax]/[b+a(x+1)] 倍すれば補正できる。

    * うーん。最小時間を記録したらそれで更新する様にしたい。

      線形フィットを実測値から実施する。然しそうしたとしてどのタイミングでその
      値を使用するのだろうか? もし未知の場合には必ずその場で試行するのだとした
      ら線形フィットを用意しておく意味はあるのだろうか。

    * うーん。a=0 自体にも本来は実行コストが存在する筈である。それを計る事はで
      きないのか。例えば a=0;a=0 とやると 670ns ぐらいはかかる。という事は、
      600ns ぐらいは a=0 で消費している事になるが、一方でこれをどうやって自動的
      に補正するかが問題になる。関数を空にする事ができないのが問題である。

      計測する関数定義に return 0 を追加する事にした。これによって実際に計測時
      間が 1us 程度増加してしまう様だが仕方がない。3nest 分の遅延と同じなので余
      り気にしない事にする。→これで測ってみた所、a=0 の実行時間は最短で 666ns
      になった。事前の見積もりと一貫した結果である。

2022-01-11

  * def.sh にある設定更新メッセージが make install で削除されるのでは? [#D1736]

    # で始まる行は全て一律に削除している。

    色々考えたが init-msys2 にある様な変な回避方法はやはり不自然なのでやめたい。
    インストールスクリプトでコメント・空白行を削除している箇所を確認した所、意
    外と簡単に heredocument だけ出力する様にできそうなので、その様に修正した。
    それに伴って init-msys2 にある回避も削除した。ちゃんと正しくインストールさ
    れている。

2022-01-09

  * test: テストログをファイルに出力する [#D1735]

    osh で動くか見る上で出力の形式などが気になったので。

    * done: test-decode のテスト項目数がずれているのを直す。
    * done: ログをファイルに出力する機能もほしい。
    * done: テストの成功率を表示したい。

  * global: 算術式 10# が bash-5.1 以降エラーになる [#D1734]

    一度対策として書き換えを行ったが不十分だった。全ての箇所を個別にチェックす
    るのは大変だし、今後算術式を書く時にまた問題になっても困るので全て
    10#0$... と記述する事にした。この様にしておけば正規表現で 10#$ を検出して書
    き換える様に促す事ができる。

  * mandb: rsync の抽出 正しく抽出できていない [#D1733]

    % と思ったが今試したらちゃんと動いている?
    % →と思ったらやっぱり動いていない。

    ? うーん。gawk regex #D1729 の問題によって失敗していたというだけの事なのか
      もしれない。と思って今 gawk で試してみたら問題が再現した。うーん。gawk と
      nawk の振る舞いの違いという事か。と思って色々試したが nawk や mawk でも結
      局再現した。結局の所 gawk は多分関係ない。

    * done: " or " によるオプションの行内列挙
    * done: rsync の man の形式の解析 (.IP "--OPTION" \n desc .IP etc)
    * done: "--no-OPTION" の説明の自動生成 (for progcomp)
    * done: _parse_help における解析

  * prompt-git: source .bashrc で reload すると git-prompt のチェックが起動しなくなる [#D1732]

    何故だろうか。

    ble/contrib/prompt-defer/submit は実行しているが、
    ble/contrib/prompt-defer:_ble_contrib_prompt_git_dirty/worker が呼び出され
    ていない様だ。うーん。分かった。行番号や時計がクリアされてしまう為に、情報
    再取得の条件が満たされなくなってしまっている。

    また、ディレクトリのチェック自体は git にいる時にしか実行されないので、単に
    他のディレクトリに行くだけでは駄目で別の git repository に入ってから戻って
    こないと再計算が発生しない。

  * syntax: bash-3.2 で syntax-highlighting の初期化が起こらない [#D1731]

    [初期化されない問題]

    bash-3.2 で syntax-highlighting のロードが起こらなくなっている。元々どの様
    にロードしていたのだったか。ble-0.3 で確認するのが良い。

    ble-0.3 では core-syntax-def.sh に以下の様に記述されている。

    ble/function#try ble/util/idle.push ble/syntax/import ||
      ble/syntax/import

    それが現在は以下の様になってしまっている。

      ble/is-function ble/util/idle.push &&
        ble-import -d "$_ble_base/lib/core-syntax.sh"

    問題の変更は 321371fa #D1593 で行われている。その時の議論を再確認したが特に
    bash-3.2 について意識はしていない様に見える。というかこのコミットの変更は以
    下の様な物になっている。ble-import -d は idle.push が存在しなければその場で
    読み込む。恐らく余り意識せずに書き換えてしまったという事の気がする。

    -ble-import -d lib/core-syntax
    +ble/is-function ble/util/idle.push && ble-import -d "$_ble_base/lib/core-syntax.sh"

    →これは前の様に直すべき様に思われる。

    [初期化順序の問題]

    或いは bash-3.2 ではその場で ble-import lib/core-syntax を実行してしまうと
    問題が生じるのだろうか? 分からないので取り敢えずその場で import するとどう
    なるか確認する。うーん。bash-5.1 では特に問題は生じていないみたいだ。然し
    bash-3.2 で実行してみると着色が全くされなくなってしまった。後で ble-import
    を実行しても解決しない。文法エラーの着色は有効である。syntax_debug を入れて
    みると属性に依る着色が全くされていない様である。

    →これは独立した問題であるという事が判明した。

    ? ble/syntax/attr2iface/color_defface.onload が実行されていないという事なの
      だろうか → うーん。これを実行したらちゃんと動く様になった。

      つまり color_defface_load が発火されていないか、或いは eval-after-load の
      バグだろうか。うーん。実は上記の core-syntax.sh のードは関係なくて、単に
      eval-after-load の問題の気もしてきた。うーん。eval-after-load を見るとちゃ
      んと登録はされている。然し一方で発火されていない状態の様である。然し、
      blehook を改めて確認すると登録した hook は消去されている。何故?

      hook の呼び出し元で確認した所ちゃんと登録されている。どうも確認してみたら
      ble/syntax/attr2iface/color_defface.onload はちゃんと呼び出されている様だ。

      % 一方で ble/color/defface.onload が二回呼び出されている。特に
      % color_defface.onload の後に呼び出されている。もしかしてこれによって設定
      % がクリアされてしまっている可能性?
      %
      % と思ったら違った。 ble/{color,syntax}/defface.onload で二種類あるのだった。

    * 何れにしても初期化の順序による問題の様である。

      % と思って ble/syntax/attr2iface/color_defface.onload の実装を見ていて気づ
      % いたが、どうやらその瞬間の face の値を読み取っている? これだと駄目の筈。
      % 起動した後に着色を変えられない事になる。
      %
      % コマンド名はちゃんと変更される。然しこれはよく考えたら後付で取得している
      % から? 然し、それも変だ。結局属性から face に変換している筈 → よく考えた
      % らこれは iface に対する初期化なのだから、その場で整数値に解決してしまう事
      % 自体に問題はない。

      何れにしても問題は attr2iface/color_defface.onload は attr -> iface の対
      応付を記録しているが、iface が未だ初期化されていない為に全て iface=0 になっ
      てしまっているという事の様に思われる。

      結局 ble/syntax/defface.onload よりも後に attr2iface/color_defface.onload
      を実行しなければならないのにそれが逆転してしまっているのが原因だった。
      syntax-color-def.sh において ble/syntax/defface.onload の登録よりも後に
      ble-import -d lib/core-syntax を呼び出すべきだったのである。

  * util: bash-3.2 で alias 云々のエラーメッセージが出る様になっている [#D1730]
    これは単純に alias チェックの際に 2>/dev/null を忘れているのが原因。

  * complete: gawk regex warning (reported by telometto) [#D1729]
    https://github.com/akinomyoga/ble.sh/issues/167

    これは最近追加した ble/complete/action/quote-insert.batch/awk から出ていた。
    awk の bracket expression の中のエスケープシーケンスは解釈されるのだった。
    なので孤立した \ から警告が発生していた。普段 nawk を使っていたので気づかな
    かった。取り敢えず修正した。

    ? 他にも類似の問題が別の箇所にあったりはしないだろうか。念の為、全ての
      ble/bin/awk のスクリプトを gawk に食わせて見た方が良いのかもしれない。然
      しチェックするとしてもどうやってチェックするのか。個別にスクリプトを実行
      するのは面倒だし、スクリプトを実行する事によってファイルが作られたりして
      しまうかもしれない。また関連する変数などをちゃんと初期化しなければスクリ
      プトを正しく再現できないかもしれないし、実行時に正規表現が構築されている
      場合にも影響を与える (実行時に正規表現が構築される事はなかった様な気もす
      るが)。

      一応 bracket expression を含む正規表現を他から取得している箇所だけは再確
      認する。特に parse_help の辺り。

      * _ble_complete_option_chars は既にちゃんと対策されていて注記まであった。
      * 他にもう一箇所 [] の中に \ がある物があったが其処もちゃんと \\ になって
        いた。

      \ を全体に渡って検索してみたが core-complete の中には他には怪しい物はなかっ
      た。

      * benchmark.sh にはない。
      * history.sh にも沢山 [\\] や [^...\\] があったが、これらもちゃんとエスケー
        プされている。
      * decode.sh にも幾らかあった。綺麗に awk の中と外でちゃんと \\ と \ が使
        い分けられている。
      * util.sh もちゃんと使い分けられている。
      * edit.sh にはない。ble.pp もない。contrib/prompt-git.bash も大丈夫。

2022-01-08

  * complete: WA terminal glitch on xenl (reported by telometto) [#D1728]
    https://github.com/akinomyoga/ble.sh/issues/166

    再現できた。desc が一列表示でかつ一番最後の項目が丁度ぎりぎり収まるか、或い
    はおさまり切らない時に問題が生じるということの様だ。また、一列表示の時に
    ellipsis の位置がおかしい問題も見られる。これらは実の所同根ではないかと思わ
    れる。

    うーん。一つバグは見つけた。しかしこれは関係ない → #D1727

    ellipsis の位置と行の終端位置が一致していないが、調べてみると wcolumn は実
    際の端末の幅と同じにして trace が呼び出されている。結果を見ると、行の終端位
    置が誤っているのではなくて ellipsis を出力する位置が誤っているという事に見
    える。

    ble/util/c2w 8230; echo $ret としても実際に表示している通りの 1 になっている。

    →うーん。これは分かった。これは端末による振る舞いの違いだ。xenl 状態にある
    時に CUB をした時に、一番最後の列に移動するか或いは一番最後から二番目の列に
    移動するかである。vte は 2 番目になる。screen と contra は一番最後の列にな
    る。

    * これは一度まとめた事が contra にある筈。と思ったがこれは ech などの振る舞
      いについてだった。contra のモードに xenl_ech が存在する。

      # 行末にカーソルがある時に ECH, ICH, DCH は行の最後の文字に作用します。
      f---  mode_xenl_ech                 private     true

      CUB CUF についても調べた事がある筈だが、それは contra にはまとめられてい
      ない。

      $ printf '%*s\e[10DX\n' $COLUMNS 0123456789

      * CUD 前に最後の列に移動する
        - xterm, terminology, urxvt, alacritty
        - vte (GNOME, xfce4, terminator, lxterminal)
        - mlterm, RLogin

      * xenl の時は右端の境界にいるかの様に動作する
        - kitty, screen, tmux, termit, konsole
        - contra, Poderosa

    この振る舞いを吸収する様にシーケンスを構築する事はできるだろうか?

    % * この振る舞いの対処を過去にした事はあるだろうか。eol mark の場合には直後に
    %   \r をしているので関係ない。
    %
    % a CUU CUD などを使って強制的に一番最後の列に移動してから移動を開始する? 然
    %   し、高さが一行しか無い場合には信用できない。本当に端末の高さが一行しか無
    %   い場合には使えるが、実際にはどちらか一方にだけ移動できる様な状態になって
    %   いたとすると元の位置に戻ってくる事ができない。
    %
    % b BS を使ったら元の位置に戻る事ができるだろうか。試して見た所 screen は BS
    %   を使うと一番最後から 1 番目のセルに移動する。contra や vte は2番目のセル
    %   に移動する。うーん。なので BS を使った場合端末によって位置が異なるという
    %   事。一応この振る舞いは vttest にあるので、screen 等の一部の例外を除いて動
    %   くべきという事にしてしまっても良いのかもしれない。と思ったが tmux も
    %   screen の仲間だ。うーん。やはりこれは端末によって振る舞いが異なる。
    %
    % c 本来、本当の COLUMNS と現在の cols を区別するべきなのではないかという気が
    %   する。本当の COLUMNS と一致している時に限り特別な動作を行う。と思ったが、
    %   そうしたとしても現在の端末がどちらの振る舞いをするのか分からなければ、結
    %   局どちらの端末でも動く様に書かなければならない。或いは端末の振る舞いを事
    %   前にテストしておく必要がある。
    %
    % d 或いは CUB CUF を一回実行したら意外とどの端末でも同じになるのかもしれない。
    %   試してみる事にする。
    %
    %   - ok: wt, vscode (xterm.js), tmux, screen, xterm
    %
    %   と思ったが、これは本当に端末の一番右端にいる時には使えるけれども、それ以
    %   外の時には異なる結果になるから使えない。CUF CUB CUB CUF をするとどうなる?
    %   Class A -> 0 (-2), Class B -> 0 (-1). これだと全然駄目である。
    %
    % やはり以前も同じ考察をして無理と判断した様な気もする。しかしそれは canvas
    % の bottom dock の話だった様な気がしないでもない。

    うーん。そもそもそういう理由があるからこそ相対移動は右端に接しない様に設計
    していたという事の様な気もする。menu-style:desc も右端に接しない様に修正す
    る事にする。

  * complete (menu-style:desc): fix not working "bleopt menu_desc_multicolumn_width=" [#D1727]

    menu_desc_multicolumn_width= として multicolumn を無効化しようとするとゼロ
    除算のエラーになる。定義していない変数を誤って参照して ncolumn=0 になってい
    た。修正した。

  * decode: bind の古い形式が使えなくなっている (reported by returntrip) [#D1726]
    https://github.com/akinomyoga/ble.sh/issues/165

    これは #D1698 (b6fc4f0) の regression だろう。確認した。確かにこの時点で導
    入したバグである。テストもちゃんと追加する事にする。以前実験したケースも全
    てテストに追加する事にする。

    % どうも \C も解釈しなければならない様だ。と思ったが C で終わっていればどう
    % でも良いらしい。これは control で終わっていても良い。

    修正した。テストを追加した。テストも通っている。

    うーん。テストを作って安心したらまた regression 通常の大文字も全て小文字に
    して解釈されてしまう。追加修正する。

2022-01-01

  * util (ble/function): work around "shopt -u extglob" [#D1725]

    #D1723 で extglob が解除された状態で extglob を使って定義された関数を
    ble/function#advice した時に失敗するという問題が発生した。そもそも extglob
    が解除されてしまっている状態も問題だが、それとは別に extglob を使った関数も
    安全に待避して置き換える事ができなければならない。

    なので、更に advice 等で関数を再定義する時には extglob を一時的に有効化する
    べき → その様に修正した。


2021-12-30

  * 2021-12-20 README: oh-my-bash は流石に削除するべきだろう [#D1724]

    → oh-my-bash を引き継いだので流石にこれ以上は問題は起こらせない。追々実装
    もちゃんとした物に差し替えていく事にする。なので現状では変更しなくても良い
    という気がする。と、思ったがたかが 100 commits 程度しかない oh-my-bash を本
    当に推して良いのかというのも謎である。

    取り敢えずリンクは貼る事にした。

  * util (vbell): 外部コマンドを実行する前に vbell 消去はキャンセルするべきでは [#D1723]

    ble/term/visible-bell/.erase-previous-visible-bell で set -f が設定されてい
    る時にはどうするのか。うーん。ble/util/eval-pathname-expansion を拡張する事
    にする。canonical という opts を追加する事にした。

    キャンセルするというよりもその場で消去するというので良い気がする。単に
    ble/term/visible-bell/.erase-previous-visible-bell さえ呼び出して置けば良い
    様に思われる。ble/term/visible-bell/erase という関数を用意した。

    後は、これを何処で呼び出すのかという事。ble/term/leave の辺りで呼び出せば良
    いのではないかという気がする。

    実際に ble/term/leave の呼び出し元を見たが他に適切そうな介入点もない。また、
    ble/term/leave で erase するとしたら util.sh の中で閉じていて都合が良い。
    ble/term/leave の中で呼び出している個々の設定はどうだろうか。中を見ると
    stty, rl-convert-meta を呼び出している。更に leave-for-widget 経由で
    bracketed paste, modifyOtherKeys, cursor shape 等の端末の設定を復元している。
    うーん。leave-for-widget は fzf の呼び出しの時に使っている。うーん bind -x
    経由で何かプログラムを起動する事もあるだろうから、leave-for-widget の中で設
    定はするべき気がする →その様にしたら良い感じになった。

    ? 所で leave-for-widget,enter-for-widget を呼び出しているのが fzf だけなの
      は良いのだろうか。他の人が fzf 的な設定を用意した時に問題になるのではない
      か。bind -x の前後で毎回 leave/enter するべきだろうか?

      o 処理としては単にシーケンスを投げるだけなのでそんなに重くはないが、

      x bind -x した widget を呼び出す度に visible-bell の erase も含めて設定を
        変更するのもやりすぎな気がする。

      x それに同じ事が標準の ble/widget/* でも言える。ble/widget/* で毎回それを
        実行する訳には行かないので、結局は widget を書く人に注意点として提示す
        る必要があるのである。という事を考えれば bind -x の時にだけ注意しなくて
        良いという具合にわざわざする必要もない気がする。

      x もしこれが既存の bash 設定で頻繁に起こる問題であれば、何も考えずに移行
        できる様にするべきだったかもしれないが、実際の所余り問題も起こっていな
        い様なので現段階では少なくとも様子見というのが正しい気がする。

      →現時点では必要がある時にユーザーの側で正しく leave/widget を呼び出して
      貰う様にする。もし問題が発生するようであれば bind -x の時にだけは
      leave/enter を勝手に呼び出す事にする。

    x 2022-01-01 util (eval-pathname-expansion): extglob が勝手に解除される問題

      補完しようとした時に構文エラーが表示される問題。bash-completion をロードし
      なければ問題は発生しない。エラーが表示された後に ble/funtction#advice が
      original:_longopt が見つからないというエラーを出力している。
      original:_longopt の定義で失敗しているという事。

      実際に定義している部分で定義に使っている文字列を出力させてみたがちゃんと関
      数定義が抽出できている。とここで extglob が設定されていない事によるエラーで
      はないかと思ったらそうだった。extglob が解除されている。これは直前の変更
      #D1724 で設定を復元するのに失敗しているのが原因だろう。該当部分で shopt を
      出力して見たら空文字列になっている。ちゃんと canon=1 にはなっている。と、
      shopt=$BASH_OPTS ではなくて shopt=$BASHOPTS であるべきだという事に気づいた。
      これは修正する必要がある。

      然し、実はこの問題は未だ push していない commit の問題だったので実はそん
      なに急ぐ事はなかったのだと気づいた。

      (本当は関数のテストに際して shopt の設定が変更されていない事などもチェッ
      クするべきなのだろうという気がする。そしてそのチェックは実は BASHOPTS と
      $- を保存すれば良いだけなので簡単である。)

  * complete: echo $abc 迄入力すると progcomp から complete -p の内容が出力される [#D1722]

    調べると complete -p -- コマンド名 によって補完設定を読み込む時にコマンド名
    が空になっている。comp_words=('$abc') になっている。

    | ? そもそも何故 comp_words=('$abc') によって補完が呼び出されているのだろうか。
    |   コマンド抽出に失敗している気がする。
    |
    |   →これは ble/complete/progcomp/.compline-rewrite-command の問題であって
    |   extract-command の問題ではなかった。なので個別に気にする必要はない。
    |
    | ? 次に '$abc' が何故空の文字列に置き換わってしまうのだろうかという事。
    |
    |   →これは分かった。展開自体は complete -p -- $abc によって行われているが
    |   quote されていない所為で単語無しで設定が読み込まれているという事なのだろ
    |   う。コメントによると呼び出し元によって quote されている筈という事になって
    |   いるが何故 quote されていないのだろうか。
    |
    |   stackdump:
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:1 (ble/complete/progcomp/.compgen)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:50 (ble/complete/progcomp/.compgen)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:93 (ble/complete/progcomp)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:55 (ble/complete/source:argument/.generate-user-defined-completion)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:18 (ble/complete/source:argument)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:21 (ble/complete/candidates/generate-with-filter)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:18 (ble/complete/candidates/generate)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:15 (ble/complete/auto-complete/.check-context)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:23 (ble/complete/auto-complete.impl)
    |     @ /home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh:20 (ble/complete/auto-complete.idle)
    |     @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble/util/idle.do/.call-task)
    |     @ /home/murase/.mwg/src/ble.sh/out/ble.sh:38 (ble/util/idle.do)
    |     @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble-edit/bind/.tail)
    |     @ /home/murase/.mwg/src/ble.sh/out/ble.sh:22 (ble-decode/EPILOGUE)
    |     @ /home/murase/.mwg/src/ble.sh/out/ble.sh:81 (ble-decode/.hook)
    |
    |   うーん。行番号が全然当てにならない。
    |
    |   どうやら complete -p -D で呼び出されてその後に再実行によって変な状態になっ
    |   ている様だ。comp_words の状態は直前の呼び出しでは以下の様な形になっている。
    |
    |     orig_comp_words=('echo' '$abc') comp_words=('$abc') ucmd='echo' qcmds=('echo')
    |
    |   結局.compgen が参照するのは comp_words だけであるからこの際 ucmd や qcmds
    |   は関係ない。

    [原因]

    うーん。分かった。ble/complete/progcomp に於いて、

    1 最初のコマンド名の単語評価の際に複数単語に展開されたかまたは単語が変化し
      た時に、orig_qcmds にコマンド名の展開結果を再クォートした物を格納する。そ
      れ以外の時には orig_qcmds は空である。

    2 さて、最後に既定の補完 (complete -D) を実行する為に comp_words を書き換え
      る際に orig_qcmds に何か値が設定されていれば、コマンド名が変化していたと
      判定して、.complien-rewrite-command を用いて orig_qcmds を適用する様になっ
      ている。所が、その判定部分を間違えていて orig_qcmds が空の時であっても
      .compline-rewrite-command が呼び出されて、結果としてコマンド名が削除され
      るという状態になっていた。

    判定を修正したら echo $abc に対しては問題は発生しなくなった。

    然し此処で改めて疑問が生まれる。最初の単語の展開結果が空になる時には何が起
    こるのだろうか。例えば "$abc [TAB]" に対して何が起こるのか。orig_qcmds は空
    なので書き換えは起こらない。すると、$abc がそのまま補完対象になるのではある
    まいか。

    x fixed: コマンド名の展開結果が空の時には何が起こるのだろうか → 特に変な事
      は起こらない様子である。

      試してみると一見して問題は起こらない様に見えたが、それは空文字列に対して
      は complete -F _minimal '' という設定が存在している為に、そちらが呼び出さ
      れて complete -D が試行されないからだった。実際に complete -r -- '' をし
      て見たら問題が再現した。

    x fixed: うーん。改めて観察する。complete -D の時以外でも quote されずに
      complete -p に渡ってしまうケースが存在する様な気がする。.compgen は
      is-simple の時には必ず quote されている事を要求する。現在の実装だと
      is-simple であっても eval に失敗する等した時にはコマンド名が quote されず
      に.compgen に渡されてしまう。結果として .compgen 側で展開されて変な事が起
      こる可能性は否定できない (そもそも eval に失敗したりした時点で .compgen
      の中でも同様に失敗する様な気もするが)。

      →is-simple であれば必ず quote は最終的に実行する様に書き換える事にした。
      結果として orig_qcmds は is-simple の時には必ず設定される様になった筈なの
      で、complete -D の .compgen に際しては orig_qcmds が設定されているかどう
      かを確認するだけで良い筈。

  * 2021-12-22 highlight: 0 番目の要素の入っていない配列名の着色 [#D1721]

    直した。複数の属性がある時にどの着色にするのかというのは悩ましい所だが、そ
    れは今迄の実装でも同様であったので今迄の実装を踏襲する。

    ? 着色を合成するという可能性

      x 本当は着色を合成するという手もあるのかもしれないが、合成規則や優先順位
        を考えるのは面倒だし、結局どれかの属性は他の属性に上書きされるので意味
        がない気がする。

      o とは言えど、配列 (既定で太字) に関しては他と組み合わせても問題ない筈で
        ある様にも思う。

      x と思って対応しようとしたがどうも変数の着色は部分的に構文解析レベルで着
        色しているのでその場で生成した描画属性で着色する訳には行かない。

      x 更に太字は他にも x や luc にも付与している。array/dict の区別に色を使っ
        ている。などという事を考えると (太字かどうか) + (色) を使って配列かどう
        かと値の性質の両方を表そうというのは無理がある様に思われる。

  * readlink 対策: NixOS で皆が readlink 周りに修正を入れている [#D1720]
    https://github.com/peterzky/peterzky-overlay/commit/7b98f05e9b8f84f2d43d84db6b2d76c8e93a38df#diff-34e5f3d20be258f6630e6113d3e1409be74cae463b58eb52b5ebe493e9ee2309R20

    今迄は /usr/bin:/bin にある readlink しか信用しない事にしていたが、取り敢え
    ず readlink が存在さえしていれば単一のパスの読み取りには使えると想定する事
    にする。-f が使えるかどうかの判定に /usr/bin/readlink または/bin/readlink
    を使う事にする。

    readlink が存在しない場合にどうするかについて。

    https://qiita.com/ko1nksm/items/873cfb9c6ceb6ef32ec9

    このページを見ると ls -l を用いて link を読み取り、cd -P を用いてパスの解決
    を行っている。うーん。cd -P を実行した時にディレクトリが戻らなくなるのが心
    配だが、まあその様な事は基本的に起こらないと想定して良いだろうか。

    元々の実装では別に途中のディレクトリ名の解決はしなくても良いという態度だっ
    たが使い方によっては問題になるかもしれないと心配になって来たので、やはり cd
    -P を用いて解決する事にした。

    * readlink -f を使わない実装について簡単なテストを書いてみたが取り敢えずは
      動いている様子である。

      というか寧ろ readlink -f を用いて失敗した時にどう振る舞うのかというのが心
      配な気もする。

    x done: 解決対象のファイル名が - で始まる時に変な事が起こるのではないか? →
      これについては修正した。

2021-12-21

  * complete (action:mandb): brace の後は space ではなくて , にするべき [#D1719]

    ブレース展開の中にいるかどうかは simple_ibrace に非自明な物が設定されている
    かどうかで判定できる様に見える。然しこの simple_ibrace は公開されている変数
    ではないし途中で書き換わっているかもしれない。それよりは comps_flags 等に情
    報が反映されていないか確認する必要がある。実装を見ると x を comps_flags に
    追加している様に見えるが、この x はどういう意味だろうか。brace 展開以外の場
    合にも追加される可能性があるのだろうか。

    comps_flags の説明には含まれていない→と思ったらちゃんと含まれていた。

    既存の addtail の実装を見ると brace の中にいるかどうかは comps_flags x で判
    定している。なのでそれをそのまま真似すれば良いだろう。

  * contrib/git: index に全て登録しただけで非 dirty という事になっているがそれは変だ [#D1718]

    ? もっと詳細な情報を取得する為のコマンドは何か。

    ? プロンプトの更新を遅延させる一般の枠組みがあると良い気がする。ble.sh 本体
      がどんどん肥大化するのは良くないのでprompt-defer.bash 的なファイルに新し
      く定義するのが良い。単に現在の git の呼び出しの部分を差し替える事ができる
      様にしたら良い気がする。

      一つのプロンプト要素の中に複数の更新項目が含まれる場合にはどうするのか。
      依存を複数登録するのか、或いは、まとめて更新する事にするのか。

      うーん。現在の待ちはどの様に行われているのか確認する→idle経由で状態を更
      新している。 ble/prompt/unit/add-hash '$_ble_contrib_prompt_git_dirty' を
      通して変更を検出して更新をかけている。

      情報を格納する変数も指定するべきなのだろうという気がする。或いは version
      変数を作ってそれを参照させるか。或いは id か何かを指定させるというのでも
      良い。うーん。何が良いか。

    - より詳細な情報を得る為には git status --porcelain を読み出して使うのが良
      い。然し、それで本当に足りるのかどうかも分からない。実際にどういった情報
      を人々が求めているのかに依存する様な気がする。自分の為という意味であれば、
      取り敢えずは index に変更があるかどうかが分かれば良い。

    遅延に関係するコードを prompt-defer に分離した。意外とすっきりとできた。

    取り敢えずは staged な変更がある場合に色を変えて表示する事にした。実はもっ
    と詳しく表示する事を考えても良いが面倒なのでそのままにする。将来的には
    git-status だとか git-prompt のエミュレーションを作っても良いのではないかと
    いう気がするが、別に自分が使う訳でもないので今は実装しない事にする。

2021-12-19

  * menu (align): bleopt menu_align_{min,max} (motivated by banoris) [#D1717]

    これは別項目で議論する。というか幅に上限を作っても良いのかもしれないとも思
    う。

    - done: complete_menu_align -> menu_align_max : 並べる時の align の max
    - done: menu_align_min : 並べる時の align の min

    - reject: menu_align_item_maxwidth : 項目の幅の最大 → 対応しようかと思った
      が、現在の実装では項目の幅の計算には trace-text を使っていて、この
      trace-text は高速な代わりに truncate 等の機能がない。trace-text に
      truncate を実装するのも trace-text が高速である意義がなくなるし、或いは、
      trace にすると遅くなってしまうし、色々と面倒である。この項目についてはそ
      れ程積極的に実装する意義がある訳でもない気がするので取り敢えずは実装しな
      い事にする。

    * done: wiki
    * done: blerc

2021-12-18

  * complete: コマンド名に一致しない globchar が含まれるとエラーメッセージ [#D1716]

    '*' を含む alias を定義すると failglob のメッセージが編集中に現れる。という
    か、これは alias に関係なく今迄にも発生していた問題だった様だ。これは別項目
    で処理するべき問題の様に思われる。

    | bash-completion が有効になっている時に起きる問題の様である。然し、一方で、
    | ble.sh が有効でない時には特に問題は生じない。という事は bash が
    | bash-completion を呼び出す時にはその問題を自然に回避しているという事だろう
    | か。調べる。
    |
    | ? 何処からエラーが生じているのか?
    |
    |   うーん。そもそも bash-completion が呼び出されているのか怪しい気がしてき
    |   た。__load_completion を調べてみる事にする。
    |
    |   ble/complete/progcomp/.compgen の stderr を潰したら問題が発生しなくなった
    |   ので、bash-completion が悪かった訳ではなかった。
    |
    | ? bash から呼び出された時との違いは何か?

    これは分かった。progcomp/.compgen は最初の単語 (コマンド名) が quote 済みで
    ある事を想定していた。bash-completion などの関数を通して補完が実行される時
    には確かに compline-rewrite-command によって quote された単語に置き換えられ
    ていたが、何も補完設定が見つからなかった時の規定の progcomp/.compgen 呼び出
    しに対しては、qcmds への書き換えが実行されていなかった。その書き換えを実行
    する様に修正した (既定の補完は alias 展開する前の物に対してなので、初回の
    qcmds を別に保存しておく事にした)。

  * complete (source:command): quote していても alias が候補として生成されている [#D1715]
    その為に、menu の中でエラー着色されている。

    うーん。特に自分で alias を生成している訳ではなくて compgen -c -- s 等の時
    点で alias が生成される様だ。一方で、 compgen -c -- "'s'" 等とすると、何も
    生成されなくなってしまうので alias を除外した生成にする事は難しそうである。

    更に compgen -c は expand_aliases が off になっていても alias を列挙する様だ。

    一方で、for 等の keyword はどの様に判定しているのだったか。うーん。
    source:command で filter している様だ。同じ箇所で alias のチェックもする事
    にした。

    x fixed: 実装してみたら全て赤くなっている→ これは今回の編集ではなくて前回
      の commit の時点で既に駄目になっている。#D1714 で修正した。

    x fixed: alias は noquote を付加する必要があるのでは? → 修正した。その他に
      も ! や [[ 等は quote しない様にする必要がある。

    x fixed: alias が *? 等の文字を含んでいる場合コマンド着色でエラーになってし
      まう。修正した。

      と思ったが、考えてみれば、そもそも alias 名に一致している場合には展開を試
      みる前に alias に確定させるべきなのではないか。

  * menu-complete で 30s かかるという話 (2/2) yield quote-insert 高速化の試み [#D1714]
    https://github.com/banoris/dotfiles/issues/11

    #D1710 に於いて、設定を調整すれば以前より大分高速になるようにはしたが、それ
   でも yield の速度が気になる。別項目で yield の高速化ができないか考察する事に
   した。

    * 先ず計測してみる事にする。

      | * quote-insert をコメントアウトすると 0.63s かかっている。quote-insert
      |   があると 2.24s かかっている。うーん。3/4 ぐらいが quote にかかっている
      |   という事。一方で、quote 作業を gawk 等に任せたとして高速化の程度は限
      |   られるし、また、gawk が出力した結果を読み出す為に追加の処理が必要にな
      |   る事に注意する。その様に考えると gawk で quote 処理を実施する事に積極
      |   的な意味は見いだせないかもしれない。
      |
      | * 更に yield 関数の中身まで考えたらより高速化できる可能性もある。→然し
      |   文字数を数えたり等の操作が入っているので solaris などの駄目な awk 実
      |   装で対応するのが難しい様な気がする。更に filter 等、より様々の事を実
      |   装する必要が生じる気がする。
      |
      |   念の為 filter を抜いてみると 2.02s なので、filter のチェックに 0.22s
      |   かかっている。quote-insert にかかっているのが 1.61s だった。残りは
      |   0.4s である。成程、両方ともくっつけたら大分短くできるのではないかとい
      |   う気がする。
      |
      | * というか progcomp ばかり高速化しても仕方がない。全ての yield ループで
      |   共通している項目は高速化できるのではないかという気がする。何れにしても

      yield loop の処理時間の内訳
      ------------ --------------------
      filter       0.22s (fignore, etc)
      quote-insert 1.61s
      残り         0.40s

    * awk で実装してみて速度を比較する。

      % うーん。試しに実装してみて比べるのはありかもしれないという程度。そうだ
      % としても gawk を呼び出すのにかかる時間を計測して、ある程度以上の項目数
      % の時に呼び出す様に変更するのが望ましい。gawk を使ってすら重いという状況
      % については余り考えていない。というかそもそも '' 等で補完を開始しようと
      % する事が間違っている様な気もする。

      done: 先ずは各種の escape を awk で実装する必要がある。

      →最終的に awk で色々 quote-insert する所まで実装できた。然し、awk の内部
      で test -f file 及び test -e file を判定する事ができないので、必要になる
      場合 (progcomp) の場合には予めテストを実行してからそれを awk に渡す事にす
      る。

      外側でファイル判定する必要がない場合には 28ms であり、ファイル判定する必
      要がある場合には 129ms である。更に読み出しの速度も考える必要がある。然し
      そうだとしても速度的には十分速い。将来的には沢山の項目数の場合には awk に
      移行する事について考えて良いのではないかという気がする。

    * 現在の quote-insert の実装も、外側でできるだけ準備をしてから、中では最低
      限の判定だけで行ける様に修正する事ができる筈。

      その様にした方が現在の awk による実装とも近くなり、両者の一貫性を保ちやす
      くなる筈である。

      →実装した。然し大して高速化していない。元々 2260ms 程度だったのが 2090ms
      程度に減少しただけである。つまり bottleneck はやはり其処ではないという事
      だろうか。

      うーん。escape-for-bash-specialchars が遅いという事の気がしてきた。という
      のも ' を入力した状態で補完するだけで 1600ms にまで減少する為。

    * done: refact ble/complete/action/util/ ble/complete/action/? と思ったが色々
      の関数が既にある様だから、取り敢えずは現状を維持する事にする。と思ったが、
      やはり現在の action/inherit-from は action#inherit-from に改名して、代わ
      りに action/util/ を action/ に書き換えた。

    * done: 候補の数で awk を使うか使わないかを切り替える様にしたい

      ファイル数    従来   nawk    mawk    gawk
      100           24ms   10ms    10ms    12ms
      200           43ms   16ms    17ms    19ms
      500          106ms   35ms    39ms    41ms
      1k           212ms   67ms    76ms    78ms
      2k           424ms  128ms   147ms   150ms
      5k          1092ms  319ms   360ms   364ms
      10k         2094ms  626ms   720ms   723ms

      適当に 500 項目以上の時に awk に切り替える事にした。
      但し、cygwin/msys の場合には閾値は 2k にまで引き上げる事にする。

    * 一般の場合に適用しようとすると改行の取り扱いに気をつけなければならない。

      というか progcomp の場合だって \ を使って候補を繋ぐ事ができたという可能性?
      と思ったが試しに compgen -f を実行してみたが、改行が含まれるファイル名を
      そのまま出力してしまっていて、別々のファイル名の時との区別がつかない実装
      になっているので、progcomp に限っては余り気にしなくて良い様に思われる。

      一方で一般の場合には awk が \0 区切りに対応しているかどうかで実装方法が変
      わってくるのではないかという気がする。更に bash の version に依存して効率
      的に読み取る事のできる形式も変わってくるだろう。

      取り敢えずは progcomp の場合だけ意識して実装して、改行に関しては注釈を加
      えるべきだろうと思われる。

      * 改行が含まれている可能性があるかどうかの情報を渡してそれに応じて判定す
        る様に変更した。今、quote-insert.batch は終了ステータス 1 を返した時に
        何もしない事に注意する。

      * 更に quote-insert.batch が使える所ではできるだけ使える様にする→取り敢
        えず沢山の候補が生成されそうな場所は全て yield.batch に切り替える様にし
        た。

    * done: user-input で途中キャンセルできる様にする必要がある。
      →conditional-sync 経由で呼び出す様に変更した。動作確認した。

    * done: xpg4 の sed でちゃんと "\\\\\\\\&" 置換が期待通りに動くかどうか確認
      する必要がある → "\\\\&" としなければならない様だ。その様にした。

    x fixed: コマンド候補が全て赤く着色されている

      → conditional-sync にした時点で駄目になっている様だ。うーん。
      出力結果を確認してみたがファイルは空である。何も出力していない。
      A & で起動したコマンドは、どうも外側でリダイレクトした fd から読み出せていない様だ。
      A の内部でリダイレクトする様に変更したら動く様になった。

    2021-12-22 追加修正。"continue 0" という文が混入していた。

  * ble/string#escape-for-bash-specialchars で HT を SP HT に置換しているのは何故? [#D1713]
    manu-complete 最適化中に気づいた事。

    e344a156 ble-core.sh (Koichi Murase     2018-08-06 13:43:50 +0900 1135)     a=$'\t' b=$' \t'   ret=${ret//"$a"/$b}
    9629b9dd lib/core-complete.sh (Koichi Murase 2018-08-05 15:28:25 +0900   75)     a=$'\t' b="\\$a"   ret=${ret//"$a"/$b}

    うーん。これを見ると e344a156 のリファクタリング時のミスの様な気がする。該
    当する項目は #D0719 であるが、たった一行で済ませているという事を考えるとこ
    れは本当にミスであると判定して良い。というかそもそも元々の実装自体が間違っ
    ている。

    改行と同様に $'\t' に置き換えるという手と、恐らく現在・以前の実装で意図して
    いたと思われる \[TAB] という形に置き換えるという二つの方針が考えられる。本
    来意図していた筈の後者にする事にする。

  * main: root ユーザーで入ると the owner of '' is not correct と表示される (reported by zim0369) [#D1712]
    https://github.com/akinomyoga/ble.sh/issues/163

    _ble_base_run か _ble_base_cache のどちらかの初期化の途中で、ディレクトリ所
    有権の問題が起こっている。それからエラーメッセージにも問題がある。うーん。

    * 再現の試み

      取り敢えず手元で再現できないかどうかは試してからより詳細を求める事にする。

      うーん。root と user の両方にインストールしたとしているがどのように入れた
      のだろうか。取り敢えず root の home ディレクトリをチェックするべきなのだ
      ろうか。うーん。色々やってみたが特に問題は生じていない様だ。

      或いはインストールの方法に問題があるのかもしれない。ユーザーから root の
      .local/share/blesh にインストールした等。と思ったが、これだとインストール
      できない筈である。一方で、root からユーザーのディレクトリにインストールし
      た可能性? 然しそれだと root user に switch した時にエラーメッセージが出る
      という現象にはならない。

    分からないので取り敢えずエラーメッセージを修正して何が表示されるか問い合わ
    せる事にする。

    2021-12-19 分かった。'/run/user/1000/blesh' である。つまり、XDG_RUNTIME_DIR
    が su する前のユーザーのディレクトリのままになっているのが問題である。

  * complete: FIGNORE で全てが棄却されるバグ (reported by seanfarley) [#D1711]
    https://github.com/akinomyoga/ble.sh/issues/162

    これは極めて単純なバグだった。そもそも実は FIGNORE は今まで全く動いていなかっ
    たと思われる。

2021-12-16

  * menu-complete で 30s かかるという話 (1/2) construct-page のバグ (reported by banoris) [#D1710]
    https://github.com/banoris/dotfiles/issues/11

    確かに ble.sh は bash で書かれているし遅いが其処まで遅いかっただろうか。自
    分の手許でやってみた所、確かに bash-completion を有効にしていると 10k files
    に対して 15s かかっている。調べてみると良いだろうという気がする。

    ble/complete/progcomp/.filter-and-split-compgen は 0.1s

    うーん。_minimal 自体の呼び出しが 4 秒かかっている。ble.sh の外では 0.2s な
    のでこの違いは大きい。一体何処から違いが出てくるのだろうか。

    % →実際に _minimal の時間を計測しようとしたら _minimal 自体はそんなに遅く
    % なかった。実は、それよりは ble/util/assign の読み取りが遅いのではないかと
    % いう疑惑。と思ったらそうでもなかった。_filedir が実際に遅くなっている。

    * 何やら _filedir が勝手に置き換わっていると思っていたら
      /etc/bash_completion/redefine_filedir とかいう変なファイルによって実装が
      置き換わっていた。うーん。おかしな事をする物である。

      古い実装では while read -r line; do done で一つずつ行を読み出しているので
      遅かった。これを置き換えたら _minimal の呼び出しにかかる時間はほぼ 0 になっ
      た。然しそれでもやはり 13s ぐらいは待たされる様である。

    * その他の bottleneck は、2) yield ループが遅い、3) 一時ページに沢山表示し
      ようとしている為に menu 配置の計算が遅いという事がある。

      yield ループに関してはどうしようもない。絞り込みをする為には結局事前に実
      行しなければならないので、スキップする事はできない。とすると、awk 等を使っ
      て加速するという事も考えられるが、処理を重複して実装するのも面倒である。
      それでも場合によってはそれを考えても良いのかもしれないとは思う。

    * menu 配置で初期化遅延が効いていなかったバグ

      | menu 配置に関してもなかなか難しい所がある。C言語で書ければそれで終わりな
      | のかもしれないがそれも難しい。或いはより高速な Bash スクリプトのインター
      | プリタについても考えてみるが、そもそも制限された Bash の機能を使って実装
      | しているので不自然な実装になっている。劇的に早くなるとは思えないのが現状
      | である。
      |
      | 実際に測定する。
      |
      | [1639646039.075008]compgen:1
      | [1639646039.076485]compgen-helper:2 <_minimal echo  echo>
      | [1639646039.101227]compgen-helper:3
      | [1639646039.111599]compgen:2
      | [1639646039.111884]compgen:3
      | [1639646039.139718]compgen:4
      | [1639646039.139801]compgen:5
      | [1639646041.294533]compgen:6
      | [1639646041.464829]menu#construct:1
      | [1639646049.977139]menu#construct:2
      |
      | 1. compgen 呼び出しは現在は 0.04s
      | 2. filter-and-split は 0.028s
      | 3. yield に 2.15s かかっている
      | 4. construct-page には 8.5s かかっている。
      |
      | やはり一番重いのは construct-page である。
      |
      | complete_menu_style や complete_menu_maxlines を設定して1ページに表示する
      | 項目の数を制限するしかない気がする。念の為、1ページに表示する項目の数を制
      | 限した時に改善するかどうか確認はしておく
      |
      | →うーん。全然改善していない。8.3s である。もしかすると全項目スキャンして
      | いる可能性がある?
      |
      | 調べてみた所、何と全項目を処理している。しかも
      | .measure-candidates-in-page の時点で全て処理していて、これが最も時間を消
      | 費している。

      結局 menu 配置に関して頁毎に必要なだけ trace を実行しているつもりだったのが、
      実は毎回全項目に対して配置計算を実行していたという事が判明した (しかしそう
      だとしても、耐えられる速度の範囲だったというのは驚きではある)。

      以下の ncell_eol の式を間違えている。

      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  119)     if [[ $menu_style == align-nowrap ]]; then
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  120)       # Note: nowrap が起こるのはすでに wcell == max_wcell の時なので、
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  121)       # 改行処理が終わった後に wcell が変化するという事はない。
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  122)       local x1=$((ncell%line_ncell*wcell))
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  123)       local ncell_eol=$(((ncell+line_ncell-1)/line_ncell*line_ncell))
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  124)       if ((x1>0&&x1+w>=cols)); then
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  125)         # 行送り
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  126)         ((ncell=ncell_eol+cand_ncell))
      | 43bb0749 lib/core-complete.sh (Koichi Murase 2019-03-23 21:41:19 +0900  127)       elif ((x1+w<cols)); then

      元を辿ると以下の様に一番最初に頁を実装した時から間違っていたという事の様だ。

      | commit a488e0193927b78ea2066c5d3118ff5a38c6872c
      | Author: Koichi Murase <myoga.murase@gmail.com>
      | Date:   Thu Mar 7 18:29:51 2019 +0900
      |
      |     complete: support pages of menu/style:{align,dense}
      |
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2117)     if [[ $menu_style == align-nowrap ]]; then
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2118)       # Note: nowrap が起こるのはすでに wcell == max_wcell の時なので、
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2119)       # 改行処理が終わった後に wcell が変化するという事はない。
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2120)       local x1=$((ncell%line_ncell*wcell))
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2121)       local ncell_eol=$(((ncell+line_ncell-1)/line_ncell*line_ncell))
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2122)       if ((x1>0&&x1+w>=cols)); then
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2123)         # 行送り
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2124)         ((ncell=ncell_eol+cand_ncell))
      | a488e019 lib/core-complete.sh (Koichi Murase 2019-03-07 18:29:51 +0900 2125)       elif ((x1+w<cols)); then

      取り敢えずこれについては修正した。

    * complete_menu_maxlines を設定したらもっと高速になるか?
      →恐らく高速になる。

      * 4.0s _filedir       -> 0.04s
      * 2.2s yield          -> -----
      * 8.5s construct-page → 2.50s (これは maxlines を設定する事でもっと減らせる)

      うーん。_filedir は外部の問題である。また construct-page は修正したが、全
      画面表示にしている場合には効果は限定される。yield に関してはまあ、仕方が
      ないのかもしれない。何れにしても construct-page の修正だけでも適用しても
      らって、それで様子見する。それでも改善しなかったら yield の高速化について
      も真面目に考える事にする。

      complete_menu_align
      complete_menu_maxlines
      complete_limit

  * complete: gawk-4.0.2 workaround (reported by Knusper) [#D1709]
    https://github.com/akinomyoga/ble.sh/issues/161

    これは gawk のバグだった。特定のパターンの正規表現に対して false warning を
    出す。影響範囲が大きいと思って一つ一つ対策するのは困難かとも思われたが、正
    規表現で問題の正規表現を検出できる気がするので、やはり個別に対策する事にし
    た。

2021-12-15

  * mandb: オプション候補生成で変な動作が幾つかある [#D1708]

    * ...] という謎の項目が生成されている at man.d/man

      どうやら以下の項目から生成されている様子だ。

      | -m system[,...], --systems=system[,...]
      |
      |        man を含めます。このオプションは $SYSTEM 環境変数を上書きします。

      うーん。オプションを分割する時に /,\s*/ ではなくて /,\s+/ で分割する事に
      した。スペース無しで記述するという事は考えにくいだろう。或いは
      --arg=(hello, world) みたいになっている可能性もなくはないが面倒なので考え
      ない。OK

    * fixed: declare で空の completion が生成されている。

      空の候補については集約の際に混入している様だ → これは修正した。
      nodesc のオプションを集める時に name[count++] としていたのを name[count];
      count++に分けた所、count を初期化していなかったので空文字列の添字に格納さ
      れる様になってしまっていたのが原因だった。

    * fixed: wget の man page 抽出で short option の desc が空になっている。
      これは man.d/man 由来である → 修正した。

  * progcolor: mandb_opts をキャッシュする様にする [#D1707]

    progcolor_optctx と同様に。これは declare のより詳細な実装で mandb_opts を
    参照したいから。

  * refactor: mandb_opts はコマンド一般用に転化しても良いのではないか [#D1706]

    その時には cmdspec に移動して、更にそれを core-complete から読み込む様にす
    れば良い。と思ったが help, help-usage 等は名前的には mandb_opts 専用の物で
    ある。名前を変更する必要があるかもしれない。

    或いは、help:help-usage 等 mandb 専用のオプションはそれ専用の配列に格納する?

    取り敢えず現在使われているオプションについて整理する。また、将来的に使い
    そうなオプションについても考える。

      mandb-disable-man
      mandb-help
      mandb-help-usage
      mandb-usage

      plus-options=xxxxx
      no-options
      stop-options-at=IWORD
      stop-options-on=REX_STOP
      stop-options-unless=REX_CONT
      stop-options-postarg
      disable-double-hyphen

      加えて no-options も追加するべきかも

    →cmdspec に移動して cmdspec_opts に名前を変更した。mandb 特有の項目には
    mandb- の接頭辞を付ける事にした。

    * done: 説明を書く

2021-12-12

  * highlight: declare のオプション名…変数名よりも後にあるのはエラー着色にするべき [#D1705]
    これは #D1704 で一緒に対応した。

  * complete: declare a -[TAB] でも候補が生成されてしまっている [#D1704]

    →調べてみた所、これは declare の引数 (変数形式) が extract-commands で抽出
    されていないのが原因であった。引数の種類を調べると ATTR_VAR である。然し色々
    と振る舞いを調べると ATTR_VAR はコマンドの前につく a=b の形の変数代入に使わ
    れている単語の種類である。

    もっと調べると declare a=b の場合には a=b の単語の種類はちゃんと ARGI になっ
    ている。また、a=b declare hello の時にも hello の単語の種類はちゃんと ARGI
    になっている。つまり、特定の条件で declare hello の変数名が変数代入であるか
    の様に単語登録されてしまっているのが原因である。

    wtype の決定経緯を調べる。ctx-command/check-word-end に入った時点で既に
    wtype == ATTR_VAR になっている。従って、word-begin の段階で ATTR_VAR になっ
    ているのが問題である気がする。然し、check-word-begin の段階では wtype =
    CTX_ARGVX の様である。つまり、何処かで wtype が書き換わってしまっているのが
    原因という事になるのだろうか。

    うーん。分かった。ble/syntax:bash/check-variable-assignment の中で ARGVI 及
    び ARGEI の時には = の有無に関係なく ATTR_VAR にしてしまっている。これは何
    故だったろうか。経緯を調べる必要がある。

    | 2f2f0eb6
    | @@ -2401,7 +2406,7 @@ function ble-syntax:bash/check-variable-assignment {
    |    # パターン一致 (var= var+= arr[ のどれか)
    |    local suffix='=|\+=?'
    |    ((_ble_bash<30100)) && suffix='='
    | -  if ((ctx==CTX_ARGVI)); then
    | +  if ((ctx==CTX_ARGVI||ctx==CTX_ARGEI)); then
    |      suffix="$suffix|\[?"
    |    else
    |      suffix="$suffix|\["
    |----------------------------------------------------------------------
    | commit 1823c540cfe25c952fc96d8e50ae7dab712aacaf
    | Author: Koichi Murase <myoga.murase@gmail.com>
    | Date:   Mon Nov 27 23:46:09 2017 +0900
    |
    |     syntax (tilde expansion): support ordinary words with variable assignment form
    |
    | @@ -2054,6 +2112,109 @@ function ble-syntax:bash/check-tilde-expansion {
    |      ((_ble_syntax_attr[i]=ctx,i+=${#BASH_REMATCH}))
    |    fi
    | [中略]
    | +
    | +## 関数 ble-syntax:bash/check-variable-assignment
    | +## @var[in] tail
    | +function ble-syntax:bash/check-variable-assignment {
    | +  ((wbegin==i)) || return 1
    | +
    | [中略]
    | +
    | +  # パターン一致 (var= var+= arr[ のどれか)
    | +  local suffix='=|\+=?'
    | +  ((_ble_bash<30100)) && suffix='='
    | +  if ((ctx==CTX_ARGVI)); then
    | +    suffix="$suffix|\[?"
    | +  else
    | +    suffix="$suffix|\["
    | +  fi
    | @@ -2577,51 +2760,6 @@ function ble-syntax:bash/ctx-command/.check-word-begin {
    |    return 0
    |  }
    |
    | -## 関数 ble-syntax:bash/ctx-command/.check-assign
    | -## @var[in] tail
    | -function ble-syntax:bash/ctx-command/.check-assign {
    | -  ((wbegin==i)) || return 1
    | -  ((ctx==CTX_CMDI||ctx==CTX_ARGVI)) || return 1
    | -
    | -  # パターン一致 (var= var+= arr[ のどれか)
    | -  local suffix='=|\+=?'
    | -  ((_ble_bash<30100)) && suffix='='
    | -  if ((ctx==CTX_CMDI)); then
    | -    suffix="$suffix|\["
    | -  elif ((ctx==CTX_ARGVI)); then
    | -    suffix="$suffix|"
    | -  fi
    |----------------------------------------------------------------------
    | 7d862418 (Koichi Murase 2017-03-01 06:29:55 +0900 2580) ## 関数 ble-syntax:bash/ctx-command/.check-assign
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2581) ## @var[in] tail
    | 7d862418 (Koichi Murase 2017-03-01 06:29:55 +0900 2582) function ble-syntax:bash/ctx-command/.check-assign {
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2583)   ((wbegin==i)) || return 1
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2584)   ((ctx==CTX_CMDI||ctx==CTX_ARGVI)) || return 1
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2585)
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2586)   # パターン一致 (var= var+= arr[ のどれか)
    | 69bac74a (Koichi Murase 2015-12-24 21:47:15 +0900 2587)   local suffix='=|\+=?'
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2588)   ((_ble_bash<30100)) && suffix='='
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2589)   if ((ctx==CTX_CMDI)); then
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2590)     suffix="$suffix|\["
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2591)   elif ((ctx==CTX_ARGVI)); then
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2592)     suffix="$suffix|"
    | be5c4616 (Koichi Murase 2015-12-23 22:09:39 +0900 2593)   fi
    |
    | commit be5c461693ddacd2acf581011c3decd1390641d5
    | Author: Koichi Murase <myoga.murase@gmail.com>
    | Date:   Wed Dec 23 22:09:39 2015 +0900
    |
    |     (ble-syntax:bash): special treatment of arguments of `declare'.
    |
    |     * (ble-syntax:bash): declare, typeset, local, export, alias コマンドの引数を文法的に特別に扱う。特に配列構文 =() を許容する。
    |       その為に新しい文脈値 CTX_ARGVX, CTX_ARGVI を追加する。
    |     * (ble-syntax:bash): CTX_ARGVI に対する補完候補は変数名。等号 '=' 以降の部分についてはファイル名の補完候補を列挙する。
    |     * (ble-syntax:bash): 通常の代入構文における配列構文の動作を変更。
    |     [以下略]
    |
    | +2015-12-23
    | +
    | +  * ble-syntax:bash declare 配列初期化構文対応
    | +
    | +    > * [2015-02-16] ble-syntax.sh: local a=(arr) a+=
    | +    >   これは declare や local typeset readonly 等を文法的に特別扱いしなければ対応できない
    | +
    | +    色々試してみた所、以下のコマンドの引数で =() を特別扱いする様である。
    | +      declare readonly typeset local export alias
    | +    alias に関しては他のコマンドと全然性質が違う様な気がするし、
    | +    export に関しては配列の初めの要素しか export されない気がするが、
    | +    文法的には両者とも =() の形式を許容する様である。
    | +    或いは、他にも同様の形式の引数を許容する組コマンドが存在するかもしれない。
    | +
    | +    (少なくとも echo などの組み込みコマンドや、外部コマンドに関しては
    | +    引数に =() 等という物が含まれていると失敗する。)

    これを見る限りは特別扱いは ARGVX, ARGVI を導入した最初の瞬間からあった様で
    ある。特に後付で ARGVI に対して特別扱いを実装したという訳ではなく、最初から。
    実装の経緯を観察する限りはどうも補完で変数名を生成させる為に特別な単語の種
    類を割り当てている様な気がする。一方で現在の実装に於いては、補完は特に
    wtype を参照している訳ではないのでこの様に特別に取り扱う理由もない気がする。

    * ARGVI, ARGEI の際の変数代入で = を要求しない振る舞いは修正する方向で考え
      る。

      x 然し、そうしたら単語着色が消えてしまった。うーん。ARGVI 及び ARGEI の時に
        は単語着色はするべきだろうか。

        先ず文法レベルで。それから引数レベルで。

        | うーん。先ず初めに、文法レベルでの着色については ARGVI だけで良い。
        | ARGEI の時には = 無しで単語が現れたとしたらそれは単語ではないので着色し
        | なくて良い。
        |
        | そもそも文法レベルの着色をするべきなのかという疑問も実は存在する。bash
        | の文法的には実は declare hello= は変数代入になっているが、declare hello
        | は変数代入になっていないと思われる。という事を考えると文法レベルの着色
        | はするべきでない。

        引数レベルの着色については declare 系列専用の着色を定義する必要がある。

        うーん。ble/cmdinfo/color: という名前も何だか微妙な気がするが、これは後
        でいくらでも変更できるので取り敢えずは実装する。既存の実装は存在してい
        ない様だ。ble/cmdinfo/chroma: に変更する。

        うーん。ファイルを分離しようと思ったが名前はどうしたら良いだろうか
        ... やはり cmdinfo は何だか名前として不自然な気がする。core-cmdinfo,

        | * core-help, core-man, core-mandb, core-info, core-whatis, core-which,
        |   これらは既存のマニュアル系のコマンドの名称を取ってきた物。
        |
        | * core-catalogue, core-manual, core-dictionary, core-book,
        |   corer-guidebook, core-map, core-cmdmap, core-reference,
        |   core-commandreference, core-cmdref (reference 系は別の意味になるので
        |   駄目), core-library, core-cmdlib, core-spelllib (library 系も別の意味),
        |   core-spellbook ... 或いはより現実的な物に例えてみる等の方針。
        |
        | * core-getopt これは、実際に cmdinfo を定義する主要な形態として getopt
        |   的な方法を考えている事から。然し、これだけが唯一の定義方法という訳で
        |   もないし、getopt は更にその上の階層の枠組みに名付けたい気がする。実際
        |   には、cmdinfo の中に定義する形になるのではないかと考えている。
        |
        | * core-cmddb, core-database (一般的過ぎる), core-commanddatabase,
        |   core-cmdspec, core-commandspec, core-cmdspec

        うーん。cmdspec の方が幾らかましの気がするので取り敢えず cmdspec という
        事にする。

        然し本当に cmdspec に定義するべきなのだろうかという疑問も残る。実は
        bash-completion でやっている様に contrib/cmdspec/* の下に個別のファイル
        として定義した方が良いのではないかという疑惑。うーん。然しそうだとして
        も取り敢えずの実験的な実装として cmdspec の中に色々記述して API が落ち
        着いてからファイルに分割するというので良い気がする。そう。それがしたかっ
        た事の気がする。

      o ちゃんと引数レベルでの着色で変数名着色ができている。

      o declare の通常引数の後のオプションをエラー着色する機能もOK

    * done: コマンドレベルで declare, etc. + alias の着色を行う。
      うーん。alias については今回は対応しなくて良い。

    * done: 変数代入も extract-command で列挙する。但し、extract command に影響
      がない様にしなければならない。

    x fixed: もう一つの謎は a=b declare a= の形式の時には変数代入が検出されない
      という事。そもそも、変数名着色だって無効化されている。これは一体どういう
      事だろう

      調べてみると "a=b declare@ " の時には @ の位置に stat ARGX が置かれている
      様である。一方で、 "declare@ " の場合には @ の位置には stat は置かれてい
      なくて、代わりにその次の位置に ARGVX が置かれている。この振る舞いは他の通
      常コマンド (echo など) でも同様であった。CMDXV の特別な振る舞いという事な
      のだろうか。

      →うーん。正にそれを実行するコードが check-word-end にある。これはどうい
      う事だろうか。→分かった。どうもこれは変数代入の直後にはキーワードは来な
      いという事を養成する為のコードの様だ。昔は単に ctx=ARGX を設定して抜けれ
      ば良かったが、その後の複雑化で只単に ARGX を設定すれば良いという訳ではな
      くなった。各文脈に応じた複雑な処理を CMDXV の時にも実行する必要がある。

    o ok: declare a -[TAB] での候補生成の抑制は動いている。

    幾つか残っているのを修正する必要がある。

    * ok: global -- が着色されていない。これは今確認したらちゃんと動いている。
      勘違いだったか或いは別の物を修正した時に一緒に直ったか。

    * done: blerc, wiki, 移動: argument_error

    * done: ble/syntax/progcolor は最早 ble/progcolor で良いのではないか。そも
      そも純粋な文法解釈から離れてきていて、bash 特有の実装になっている。

2021-12-11

  * [External] bash-completion: printf -v ... [#D1703]
    https://github.com/akinomyoga/ble.sh/issues/155#issuecomment-984619516

    これは bash-completion 側で対応するべき事の気がする。

    取り敢えず --help 対応が終われば、変数名の補完はできないにしても、オプショ
    ンの表示ぐらいはできる様になる。printf の場合には最初の引数には '' を指定す
    るのが良い気がする → 取り敢えずオプションは表示される様になった。

  * [External] bash-completion: better support for "test", "[" [#D1702]
    https://github.com/akinomyoga/ble.sh/issues/158

    これも bash-completion の側で対応するべき事の気がする。
    但しオプションの説明についてはちゃんと生成しなければならない。
    progcomp の枠組みで説明も一緒に生成できる仕組みがあっても良いのではないか。

    うーん。生成し切れていない物は別枠で指定する? うーん。getoptions 的仕様を確
    定する必要がある気がする。

  * complete: [[ 及び declare の補完 (requested by EmilySeville7cfg) [#D1701]
    https://github.com/akinomyoga/ble.sh/issues/155
    https://github.com/akinomyoga/ble.sh/issues/157

    | user-customization を許可? 或いは自前で実装しても良い
    |
    | うーん。declare に関しては a=(....) 等が含まれる場合の取り扱いが謎だし、
    | 自前で実装する方が良いのではないかという気もする。
    |
    | 一方で [[ についてはユーザーが指定できる様にする? と思ったが、それでも今度
    | は [[ (a == b && c== d)||x == y ]] 等の様な入れ子構造があった時に、ユーザー
    | に渡すコマンドラインを構築するのが大変である (実は現状の実装だとそんなに難
    | しくないかもしれないが、此処は将来的に改修する予定なので現段階で下手にユー
    | ザーインターフェイスを提供すると、将来弄る時に面倒な事になる)。また'[[' '('
    | 'a' '==' 'b' '&&' ... という具合に分割するのが自然だと思われるが、一方で勝
    | 手に空白を挿入しても良いのかだとか色々よく分からない (まあこれは実装を詳し
    | く観察して調整すれば済む話ではある)。
    |
    | うーん。結局、どちらも自前で実装した方が良い様に思われる。これは仕方がない
    | ので、取り敢えず自前の実装を提供する事にして customization については諦めて
    | 貰う事にする。

    将来的に自前で実装する事にする。

    取り敢えず declare 系統は簡単な気がするので先に実装することにする。

    * done: 現在 source:option に於いて ["--" 以降のオプションを解釈しない] や
      [非オプションよりも後のオプションを解釈しない] などの各コマンドの性質はほぼ
      ハードコードされている。これを外部から指定できる様にする。

    * ok: ble/complete/mandb/get-opts ... alias 展開もする? → refactor して、
      alias 展開なども全て処理して mandb が見つかった時点で初めて get-opts を呼
      び出す様に変更した。

    * done: 更に $_ble_complete_option_chars もちゃんと様々の箇所で使う様にする。
      →これは元々より緩いのを部分的に厳しくしているだけなのでそんなに気にしな
      くて良い様に思われる。

    x fixed: "declare [TAB]" で補完が開始されない。

    * done: +o に関しては一番最後の集計時に説明を適用に生成する。

    * done: mandb: 現在 + で始まるオプションは積極的に抽出していない。これにも対応したい。

      * ble/complete/mandb:help/generate-cache (--help|--usage 抽出用) については対応した。

      * generate-from-man は未だ → 対応した。微妙な修正しかしていないが多分これ
        で大丈夫。

    x "top -[TAB]" が正しく動作しない。

    取り敢えず declare については大体完了した。

    [[ に関しては文法も考慮したより正しい補完をすぐに実装するのは難しいが、取り
    敢えずオプションだけは生成できる様にするのが良い。

    * 文脈だけでも確認する → 部分的には対応していたみたいである。ファイル名を
      補完していた。其処に source:option を追加する。
    * それから空文字列からの補完の設定が欠けていたのでそれも追加する。
    * mandb_opts に複数の help=... を記述できる様にする。
    * オプション抽出で -a, --file=<...> や -b (this is test) 等の形式の物にも対
      応した。

  * complete: 沢山 quote が発生する場合には '' で囲むべきなのではないか [#D1700]

    然しこれだと、例えば 'a b c' と 'alpha' というファイルがあった時に前者は 'a
    b c' を生成して、校舎は alpha を生成する事になり、共通一致部分がなくなって
    しまう。共通一致部分をちゃんと求める為には、候補によらない quote の方法に頼
    らざるを得ない。そうすると、 a' b c' 等の様な不格好な物になってしまうという
    気がする。

    或いは最後の挿入時に、COMPS= の時に挿入文字列を修正するという事も可能かもし
    れない。

    うーん。今までの実装を見ると ACTION/complete で suffix を修正はしているが、
    挿入文字列本体 insert を変更している例は見当たらない。然し、呼び出し側の実
    装を見る限りは insert を自由に取り替えても問題は無いように見える。というの
    も insert 自体が、determine-common-prefix によって動的に生成されているから
    である。特に COMPS= だった時によりコンパクトな表現に変更するというのは十分
    に考えられる処置である。

    実装してみた。良い。置き換える時に違和感があるかもしれないと思ったが、実際
    やってみると "絞り込み用の表現" が最終的なコンパクトな表現に切り替わる瞬間
    というのは気持ちの良い物である、という感じである。

    * done: もう少し積極的になっても良いのではないか。例えば / や = の直後から
      補完を開始した場合等にも適用して良いのではないか → 対応した。

    x fixed: requote を実装したら頭の悪い auto-complete が表示されている

      cd tmp/filename_contains_symbols/'() () [] directory'/ [tmp/filename_contains_symbols/\(\)\ \(\)\ \[\]\ directory]

      これは bash-completion がなくても再現する現象である。うーん。
      auto_complete の候補表示に於いて ACTION/complete で insert が変更されない
      という事を仮定しているのかもしれない。

      うーん。ACTION/complete 前の状態を見ると以下の様になっている。
      COMPS="tmp/filename_contains_symbols/'() () [] directory'/"
      insert="tmp/filename_contains_symbols/\\(\\)\\ \\(\\)\\ \\[\\]\\
      directory" ACTION=file

      分かった。insert が COMPS を prefix として保持していないのが原因である。
      然し、何故その様な事になっているのだろうか。どうしたらこの様な候補が生成
      されるのだろうか。本来は COMPV が共通している筈だから除外されるのではない
      のか。

      →何故この様な事になっているか分かった。その実、この補完候補は単語を短く
      する (末尾の / を除去する) 事を提案しているのである。なので、遡った書き換
      えとなって quote が保持されないという形になっているのである。

      うーん。遡った書き換えの時にはどうせ全体が置き換わるのだと思えば、やはり
      全体を requote してしまっても良いのではないか?

    x fixed: そもそもスラッシュが除去される時点で変なのでは? どうやって候補が生
      成されているのだろうか → construct-ambiguous-pattern が誤っていた。今ま
      でに予期せず遡って置き換えが起こったりしていたが、それの原因の一端は此処
      にあるのかもしれない。

  * README: 一つのキーで複数の widget を呼び出す方法? (motivated by michaelmob) [#D1699]
    https://github.com/michaelmob/portable-config/commit/49f9566afd8b62d47a090328104ad803962e6d3f

    説明を書いた。設定例の動作確認もした。

  * bind: "" で囲まれていない keyseq \C-l を解釈できない (motivated by cmplstofB) [#D1698]
    https://github.com/cmplstofB/dotfiles/blob/master/_dffiles/.config/bash/bashrc#L170-L172

    うーん。bash の振る舞いを色々調べてみた所、"" で囲まれていない時にはやはり
    完全には解釈しないが、\C-x 等の形の時は解釈できる様だ。

    * \C-x\C-y の時には \C-y と解釈される。
    * xyz の時には x と解釈される。
    * \a も \ と解釈される。
    * \C-nop は \C-n となる。
    * \C-xC-y は C-y となる。
    * \C-axC-b は C-b となる。
    * helloC-b も C-b となる。
    * helloC-x,TAB も C-x となる。
    * C-xTAB も C-x となる。
    * TABC-x も C-x となる。
    * BC- は C-@ となる。

    つまり…最後の "C-文字" が採用される?

    * C-M-a および M-C-a は \201 となる。
    * C-aalpha-beta は C-b となる。
    * \C-a\M-c は \203 である。
    * panic-trim-c は \204 である。

    つまり、最初に - で split してそれから評価している。

    * C-- は C-@ になる。
    * C--x は C-x になる。
    * - は抑々指定できない (bind に対するオプションと解釈されてしまう)。
      inputrc に入れたら恐らく C-@ になるのだろうという気がする。

    取り敢えず bash と同様の振る舞いになる事を確認した。

  * util (cursor-state): tmux や screen の中では pass through シーケンスを用いる? (motivated by cmplstofB) [#D1697]
    https://github.com/cmplstofB/dotfiles/blob/3e41ac47f47cc7788215409a5c3f26635f02d6a0/_dffiles/.config/blesh/blerc#L193

    tmux: \ePtmux;%s\e\\ (中に含まれる \e は二重にする)
      また tmux; の部分は存在しなくても良い様である (https://gist.github.com/saitoha/4723390)
    screen: \eP%s\e\\

    対応した。

    * done: 本来は外側の端末の対応状況に応じて _ble_term_Ss を送るべきの気がする。

      | 然しそうするとユーザー設定または terminfo の _ble_term_Ss とどちらを優
      | 先するべきなのかという問題が生じる。うーん。実質的に _ble_term_Ss は対
      | 応しているとしたら一意なので、有限文字列かそうでないかだけが問題である。
      | だとすれば、ble.sh の側で外側の端末が Ss に対応していると判定したならば、
      | それに対応するシーケンスを送りつけてしまって問題ない気がする。

      _ble_term_Ss が空で端末multiplexerの外側の端末が対応していると判断できる時、
      独自の判断で外側の端末の対応する DECSCUSR を pass through で送信して良い。

      Note: _ble_term_Ss が空でない時には既に外側に pass through で送りつける様に
      なっている。但し、_ble_term_Ss に設定された値を尊重する。ユーザーが好みで設
      定しているかもしれないので。

      →外側の端末情報の取得も実装した。任意の階層だけ入れ子になった端末マルチ
      プレクサでもちゃんとカーソル形状の変更が伝播する様になった。

  * edit: self-insert の振る舞い [#D1696]

    * 一番最後のキーを挿入するべき。現在は一番最初のキーを挿入している。
    * C-l 等、対応する制御文字が存在する物については単に ctrl を外すのではなくて、その元々の文字に復元するべきである。

    或いは CHARS を直接挿入するべき? → CHARS を確認したが此処には escape
    sequence の文字列が入っているという事の気がする。うーん。何れにしても
    fallback なので気にしなくて良い様な気がする。

    * 類似の物が実は幾つかある。isearch や auto_complete で読み出す部分。
      他にも _ble_decode_MaskChar や KEYS[0] を参照している箇所は確認するべきである。

    o bind '"\C-t\C-l":self-insert'
    o ble-bind -f 'C-t right' self-insert

  * wiki: C-BS に対する binding について記述した (found by banoris) [#D1695]
    https://github.com/banoris/dotfiles/commit/f36b396c8de18159e9b5cf23974f789e3766d8ba

2021-12-08

  * complete: bind -[TAB] で bash-completion がオプションを生成してくれない [#D1694]
    ble.sh の外側ではちゃんと生成してくれている。

    これは分かった。上書きしている builtin が --usage オプションに対応していな
    いのが原因。というか unrecognized option と表示する時に、エラーメッセージと
    して usage を出力していて、それに従って usage が出力されているのであった。

    うーん。これに対してはどの様に対処するべきだろうか。つまり、bash-completion
    は敢えて誤った用法でコマンドを呼び出してその結果を解析している。上書きする
    builtin は誤った用法に対するエラー時の振る舞いに対しても同様に振る舞う必要
    があるのだろうか?

  * mandb: --help から読み出し? [#D1693]
    https://github.com/akinomyoga/ble.sh/issues/158

    少なくとも builtin に関しては (一部を除き) --help を使っても良いのでは?

    bash-completion で --help を呼び出している物に関しては --help を参考にして
    も良いのではないかと思われる。_parse_help 辺りに hook してしまえばこちらの
    物である。

    * というか、--help を使っても良いコマンドのリストを contrib に保持しても良
      いのではないかという気がする。

    * うーん。bash-completion の _parse_help に hook して、_parse_help が呼び出
      されたらそれに対応するオプションを使って db を構築しようとも思ったが、こ
      れだと bash-completion が呼び出される迄は更新されない。

      それよりは自前で --help が使えるコマンドの一覧を保持していた方が良いので
      は? と思ったが、それだと --help を呼び出すのに -h を使うコマンドや '/?'
      を使うコマンドなど、コマンド毎の変化を管理するのが面倒である。

      それよりは bash-completion 経由で必要な時に情報を読み取る方が良い?

      と思ったが、bash-completion で複数の異なるオプションで _parse_help を呼び
      出した時に、どの様にキャッシュを統合するのかというのが問題である。そもそ
      も man との統合でも問題になる。bash-completion を呼び出す前の時点で man
      から呼び出してキャッシュを作ってしまうと以後それを使う様になってしまう。
      なので、bash-completion で _parse_help を呼び出した時に man & --help で再
      生成しなければならないのではないだろうか。或いは、man から生成されたデー
      タと --help から生成したデータは別々に管理する事にして、後でそれを統合す
      るという形にするのかもしれない。その時には、_parse_help の他に
      _parse_usage だとか或いは _parse_help の異なるオプションの場合についても
      全て統合する必要がある。

    * man と --help のどちらを優先させるべきか?

      | かなり面倒である。後、man による説明と --help による説明のどちらを優先さ
      | せるべきなのかという問題も生じる。
      |
      | o man の方が詳しい説明がある?
      |
      | x 或いは --help の方が簡潔な説明になっているから menu の desc に表示する
      |   のに適している?
      |
      | x man 日本語は古い事があるのでコマンドの --help の方が良い?
      |
      | o 逆にコマンドには直接日本語の説明が対応されていなくても man では対応され
      |   ているという事があるのではないか? と思ったが逆のパターンもあるだろうし
      |   一概には言えない。
      |
      |   man の方は単にファイルを用意すれば良いだけなので対応は簡単である。一方
      |   で、翻訳量が多いという観点で --help よりは対応が遅れているのではないか
      |   という考え方もできる。
      |
      |   一方で --help の方の日本語対応については、そのコマンドが locale に依存
      |   して振る舞いを変えなければならないので、そういう意味で対応が遅れている
      |   可能性はある。特に python や go や rust 等、新しい言語で書かれた物につ
      |   いては i17n の標準的な方法が確立しているのか怪しい。とすると対応が遅れ
      |   ているという可能性があるのではないか。然し、そもそもそう言ったツールに
      |   至っては man ですら対応していないかもしれない。結局分からない。
      |
      | o man から抽出した物については太字や下線等の装飾がついている。--help で
      |   は装飾をしている事は滅多にない。あったとしても抽出の過程で削除しなけ
      |   ればならない気がする。

      --help を優先させるべきの気がする。つまり、同じオプションに関する説明があっ
        たら --help から抽出した物を優先させる。太字等の装飾については諦めるし
        かない。

    * コマンドによっては man を無効化する選択肢があっても良いのでは?

      然し、余分に man から生成したとしても余分な選択肢が表示されるだけで、ある
      べき物が欠けるといった形での不都合は生じない。また、man が有用な情報を含
      んでいなかったとしても man から何も抜き出せないという形になるだけの気がす
      るので気にしなくて良い気がする。

      うーん。と思ったが… declare や bind 等は bash のマニュアルからオプション
      を拾ってしまうかもしれないのでやはり抑制する機能があっても良いのではない
      か。

    * bash-completion でオプションを生成したとしても、内部的には _parse_help を
      呼ばない可能性はある。そう考えると --help を用いるコマンドのリストを管理
      して良い気がする。

    * todo: 存在しないコマンドについて mandb cache を生成するのは無駄なのではな
      いか。一応存在チェックをしてから mandb 生成を試みるのが良い気がする。

      然し、何処かのディレクトリに入っているコマンドの場合にはどうするのか?
      abc/def/hello.exe に対して mandb を呼び出す場合には結局 hello.exe が呼び
      出されるのではないか。

      然し、そもそも abc/def/hello.exe としなければ呼び出せないコマンドで普通に
      hello.exe では呼び出せない物が、man の中に説明があるとも考えにくい。とい
      う事を考えると、mandb はやはり存在するコマンドに対してだけ生成すれば良い
      気がする。

    [方針]

    * done: 存在しないコマンドに対しては mandb キャッシュは生成しない。

    * <del>man は常に有効。</del>

    * done: それとは別に --help を使えるコマンドのリストを保持する。printf 等は
      その最たる例。man を抑制するリストも用意する。うーん。リストよりは
      ble/set# の方が良いのかもしれない。うーん。ble/gset は実装していない。寧
      ろ ble/gdict の方が良い気がする。其処に opts 方式で色々格納できる。

    * done: _parse_help 及び _parse_usage に trap する。呼び出し方に応じて異な
      るファイルに保存する。その後で、既存の個々のキャッシュ (man, help, usage,
      ...)  を纏めて統合キャッシュを再生成する。

      Note: _parse_help は必ずしも補完したいコマンド名に対して呼び出される訳で
      はない。例えば gcc については prefix/share/libexec/cc1 的な物に対して
      --help が呼び出される。

      → _parse_usage をしてもオプションの一覧が取得できるだけで説明を生成でき
      る訳でもない。という事を考えれば、_parse_usage には対応しなくて良い気がする。

    * done: desc が一つもない場合には desc にする必要はないのではないか。

    * done: と思ったが _parse_usage からオプション引数を取るか取らないか程度の
      情報は抜き出せるような気もする。実装した。取り敢えずは動いている様な気が
      する。

    * fixed: hash-pjw の実装が怪しい

    * done: help 解析で -a, --aaaa=X は -a X, --aaaa=X に翻訳する必要がある。

2021-12-06

  * highlight: for の第一引数のファイル名着色はしない。変数名着色はする [#D1692]

    for - の word highlighting で option を除外。というか for の highlighting
    を普通のコマンドとして処理しているのはおかしい。

    for - in のエラー着色は - だからしていると考えていたがそうではなかった。唯
    単に for 文が不完全であることによるエラー着色だった。というか for の第一引
    数は変数名に合致しない物を指定した時にはエラー着色になる様にするべきである。

    うーん。どうやら for の変数名の部分は here-document の word と同じで、切り
    出しは文法的に行われる物の、実際にはコマンド置換もクォート除去も何も解釈さ
    れずに直接変数名かどうかの判定対象となる様である。

    取り敢えず arr[xxx] 等に対してはエラー着色が出る様にしたが、その他の入れ子
    構造 (例えば "for $(echo var)" など) に対してはエラー着色になっていない。

  * 2021-09-08 complete: 'fo で補完すると 'for' になってしまうが for はキーワードなので駄目 [#D1691]

    元々の compgen では対応しているのに ble.sh が勝手に quote を変更するから
    駄目なのだろうかと思ったが、元の compgen -c ではそもそも "'f" や "'f'" を
    渡しても何も候補生成されなかった。

    更に plain Bash の補完でも 'fo で補完すると 'for' が補完されてしまう。と
    いう事を考えると ble.sh だけの問題ではないのでそんなに気にしなくても良い
    のかもしれない。

  * ble.sh: complete check-here を制限 (reported by EmilySeville7cfg) [#D1690]
    https://github.com/akinomyoga/ble.sh/issues/156

    check-here を完全に消すと恐らくコマンド名を生成できない。

    実装を確認した。ARGX 系統は直前に必ず空白の類が存在して check-prefix で生成
    される。なので、ARGX 系統に関しては check-here から削除してしまって問題がな
    い様に思われる。

    元々、check-here に残していたのは、候補が全く生成できない時にその場で前の単
    語に続けて生成したい事があるかもしれないという事だったが、よく考えてみれば
    その様な使い方が有用な場合は意図的にその様に設計された限られた状況だし、そ
    の様な状況の場合には、前の単語の補完の一部としてその様な候補を生成するべき
    である。従って、check-here による ARGX 系統の補完文脈は寧ろ削除するべきであ
    る。

    x fixed: 2021-12-11 complete: 何故か空の引数から補完を開始する事ができない

      | と思ったが、これはもしかするとつい先日修正した物が原因なのかもしれない。
      | →うーん。そうだった。これは困る。どう判定するのが良いのだろうか。もう面
      | 倒なので空白で判定する。依然として "for \ " の直後で問題になりそうだが仕
      | 方がない。
      |
      | うーん。然し類似のケースとして "echo hello[TAB]" の時には何故問題にならな
      | かったのか? 或いは一つでも補完文脈が生成されていれば、check-here は有効化
      | されないという事? → と思ったらそうだった。.check-here 関数の一番初めで、
      | 既に source が存在していた時には何もせずに戻る様になっている。
      |
      | つまり、今回の問題点は何だったかというと…FARGI1 及び FARGX1 に対して正し
      | く補完を生成しなかった事? うーん。然し実装を見る限りはちゃんと生成しそう
      | な物である。

      "echo hello[TAB]" で問題にならないのは何れにしても check-prefix で引っか
      かって補完文脈が生成されるので、check-here が抑制されるからである。然し、
      "for -[TAB]" の時には - から始まる補完文脈を生成できないので、check-here
      が始まってしまう。本来、"-" が文法的に正しくないとしたら、その位置からの
      補完は存在しないという事で、何も生成しない補完文脈を此処に設置するべきな
      のである → 新しく source:none を作成してそれを使う事にした。

    x fixed: { echo; } 'f[TAB] を実行すると fi' の様に補完されてしまう。"fi と
      すると fi" になるし、$"fi とすると fi" になる。つまり、遡って書き換えが起
      こっているのにも拘らず、終端の quote が付加されてしまっている。

      これは action:literal-word のバグだった。修正した。

  * mandb: 空文字列の時にも mandb に基づくオプション生成を実行するべき [#D1689]

  * 2021-08-30 complete: オプションの説明と progcomp の integration を考える (motivated by Shahabaz-Bagwan, bbyfacekiller and EmilySeville7cfg) [#D1688]
    https://www.youtube.com/watch?v=YS1vxEhd2Pc
    https://github.com/akinomyoga/ble.sh/issues/132#issuecomment-908266634
    https://github.com/akinomyoga/ble.sh/issues/152
    https://github.com/akinomyoga/ble.sh/issues/155#issuecomment-984596470

    complete: 折角 option の説明を抽出する機能を実装しても
    bash-completion を使っていると説明が表示されない。
    だからと言って bash-completion を無効にするのも惜しい。

    やはり bash-completion のオプション生成に介入するべきだろうか。
    或いは bash-completion に限らず progcomp を使っている場合には、
    最後にオプション名の抽出を試みるというのも手である。

  * mandb: awk, sed の man ページからの抽出に失敗している (reported by bbyfacekiller) [#D1687]
    https://github.com/akinomyoga/ble.sh/issues/152

    当初は bash-completion との integration の問題かとも思ったが、それ以前に
    mandb での抽出に於いて awk, sed でそれぞれ異なる形で失敗していた。両方につ
    いて対応した。

    更に、awk の man page の中にある ".ig ... .." はコメントセクションの様だ。
    古いオプションや文章が含まれているらしい。

    2021-12-07 更に "wget" も補完されないという事が報告されていた。他にもあるか
    もしれないと思って色々動作を確認する。"bc", "mv", "fish" 等に対して追加で抽
    出コードの修正を行った。man のオプションの説明の形式には一貫性が全然ないの
    でコマンド毎に表現の仕方が異なるというのは問題である。それでも、典型的なパ
    ターンというのは有限である筈なので、それで大体カバーできると思うしかない。

    2021-12-08 更に "ping" もちゃんと man から抽出できていなかった。

    2021-12-09 man から抜き出す時に -c, --cookies=<cookies.txt> の引数が -c の
    側に適用されていなかった。help の方の実装を参考にして対応した。

    2021-12-12 "top" の抽出に失敗していると思ったら fmt4 の desc が終
    端できていなかった。空行がある場合には強制的に中断する事にした。

  * 2021-09-06 menu: fish の様に twocolumn 形式で表示する desc を作っても良いのではないか (motivated by Shahabaz-Bagwan) [#D1686]
    https://www.youtube.com/watch?v=YS1vxEhd2Pc
    https://github.com/akinomyoga/ble.sh/issues/132

    或いは任意の column の数に設定できる様にする。或いは、望ましい幅的な物 (最
    小幅でも良いかもしれない) を設定して column 数を自動で決定する。

    実装してみた。

    x fixed: 再表示の際に truncate した内容が表示されてしまう。今までの実装では
      候補は truncate されないという前提だったがそれが崩れているという事。

    x done: desc/guess についても実装を更新する必要がある。というよりそもそも
      guess とは何だったか。

    x fixed: カーソルキーによる navigation を再設計する必要がある。今までは Z
      型に走査する場合しか考えていなかった。

      a N 型に走査する選択肢と Z 型に走査する選択肢の二種類に場合分けして実装す
        るか、

      b 或いは一般的なアルゴリズムを考えるか (これは効率の良いアルゴリズムは困
        難の気がする。)

      c 或いは menu-style 側で振る舞いを変更できる様にするか。

      N型かZ型かに関してはページを構築した時に何処かの変数に補助情報として記録
      すれば良い。N型だとしても desc の場合には上下左右の操作は自明であるのでN
      型一般のアルゴリズムを用いるよりも、それ専用の処理を実装した方が良い気が
      する。

      menu-style 側でカスタムに実装できる様にする事にする。

    x fixed: 座標計算がずれる。_ble_b[TAB] において。

    x fixed: trace が無限ループになっている気がする。 _ble_[TAB] において。

      これは単に各列の行数の計算を間違えて全ての項目を一つのページに含めようと
      して巨大なページが出来上がっていたのが原因だった。

    * done: desc-raw -> desc に改名する?

      古い設定名は desc に移動する。

      新しく desc-text を用意する。desc-text はもっと良い名前はないか。
      desc-less, desc-esc, ... info が text, esc と言った名前を使っているのでや
      はり text で良い気がする。

      取り敢えず今は desc-raw は desc の synonym という事にしておく。ble-update
      等した時に不整合が起きると問題だし、そもそもそれぐらいなら別に対応してい
      ても大した問題にはならない。

    * 新しい bleopt の名称を固定する。ドキュメントに記述する
    * 新しい widget menu/{forward,backward}-column をドキュメントに記述する

  * 2021-08-30 complete: alias desc に alias の内容を表示するべきだろうか (motivated by Shahabaz-Bagwan) [#D1685]
    https://www.youtube.com/watch?v=YS1vxEhd2Pc
    https://github.com/akinomyoga/ble.sh/issues/132

    * reject: 或いはその場で展開してしまう様なオプションを提供しても良いのかも
      しれない。その場合には遡った書き換えが起こるので不可逆であるという事。そ
      して他の候補が表示されている場合には候補が表示されなくなるなどの問題があ
      る。

      取り敢えずその場での展開は考えない事にする。後で要望があれば実装するかも
      しれない。何れにしてもユーザーがそういう設定を書けば実現できるのだから
      ble.sh 側で一々設定しないという態度も考えられる。とは言いつつユーザー側で
      ちゃんと実装するには色々と細かい事があるような気もする。

    * done: そもそも job 名が補完候補に現れていない気がする。
      コマンド名の補完でジョブ名も列挙する事にした。

    * done: 変数 (action:variable) についても説明をちゃんと生成する。変数の中身
      でも展開すれば良い気がする。

    * done: 説明を着色する。現在は単に黒で表示しているが着色した方が分かりやす
      いのではないか。或いは種別の方を着色して、展開結果などの値については黒で
      表示した方が分かりやすいかもしれない。

      実行可能ファイルの着色に関してはパスをシンボリックリンクかどうかで各セグ
      メントを着色すると良い気もする。そう考えるとやはり値の方を着色する事も考
      えるべきの気がする。

  * 2021-09-06 trace: ellipsis の位置が relative の時にずれる [#D1684]

    menu_style=desc で説明が表示しきれない時に発生する問題。但し既存の処理にず
    れがないか後で確認するべき。これは relative の時の xlimit と実際に表示する
    範囲の制御のずれが原因だった。

    折返しも全て xlimit で行う事にする。

    然しそうすると relative の時の振る舞いが変わってしまう。改めてテストで振る
    舞いを確認する必要がある。うーん。やはりテストに失敗が発生している。
    relative の時には呼び出し元が気をつけていると想定して xlimit を減少させない
    様にするべきなのではないかという気がする。

    然しそうすると安易に relative を付けている箇所ではちゃんと COLUMNS を 1 減
    少させるという対策が必要になる。

    2021-12-05 改めてこれについてどう処理するのが良いか考察する事にする。当初の
    問題は ellipsis を relative で置く時に xlimit を元にして位置を決定している
    事。然し、relative の時であっても文字を置ける一番右の位置は xenl に依存して
    いる。

    % * というかそもそも xlimit はどう決定されているのだったか。 xenl または
    %   relative がある場合には cols でそれ以外の時には cols-1 になっている。

    * 改めて修正箇所について確認する。

      * 先ず HT の振る舞いについて。移動先が cols よりも先に行ったら cols-1 に
        戻すという処理だったのが、今回の修正で xlimit よりも先に行ったら
        xlimit-1 に戻すという処理に変更されている。然し、そもそも cols-1 が限界
        になっているのは xenl のある端末でもない端末でも同じ振る舞いの筈である。
        cols-1 までしか行かないのであれば xenl だろうと xenl でなかろうと、
        relative であろうとそうでなかろうと同じである。

        これについては元の実装に戻す事にした。

      * ASCII 文字列の連続に対する対策も見た感じは的外れの物に見える。というか
        これまでの実装でちゃんと xenl (_ble_term_xenl || opt_relative) の時の対
        策も行われている様に見える。

      うーん。前に行った修正点はやはり色々考えると変である。元々ちゃんと考慮に
      入れて作ってある様に見える。

    * そもそもの問題点は何だったか。ellipsis を出力するに当たって xenl のない端
      末だと、ellipsis を最後に出力しただけで行が変わってしまうという問題がある。
      その為、ellipsis の位置を1文字後退した位置に出力する様になっているが、そ
      れによってはみ出た文字が表示されてしまっているという事?

      然しそれも何だか変である。改めて menu の出力がどうなっているか確認する。
      relative:ellipsis で呼び出している。

      うーん。ellipsis が出力される状況を見てみたが変な事はない気がする。寧ろ、
      何故か xlimit を超えて文字が出力されているのかという事の方が問題である様
      に思われる。

      | -p file : True, if file exists and is a fifo special file or a p…e
      | 0123456789012345678901234567890123456789012345678901234567890123456

      xlimit=66, cols=67 になっているのに 67 まで文字が埋められてしまっている。

    * 改めて xlimit の決定部分を見て何が問題なのか分かった気がする。

      - xenl は _ble_term_xenl で初期化される。
      - opt_relative もしくは justify の時には 幅を縮めて xenl=1 に上書きする。
        この時の "幅" は xlimit=cols-1 である。

      因みに xenl が最初から 1 だった時には xlimit=cols のままである。

      うーん。そもそも xlimit は何のための変数だったのか。使用箇所を確認してみ
      ると overflow の判定と implicit-move で参照しているに過ぎない。

      前者に関しては最終行での幅が xlimit でそれ以外が cols という事になってい
      る気がする。

    ? done: ellipsis を出力する時にそもそも幅が足りない時にどうするか?
      → . の連続に置き換えるのが良い。

    ? done: process-overflow で最終行以外での処理は?
      →取り敢えず最終行かそれ以外かで xlimit or cols を切り替える事にした。
      →改めて考えたがそもそも行末以外での overflow で ellipsis を出力するのは変だ。
        という訳で ellipsis は最終行にいる時にだけ出力する事にする。

    ? fixed: そもそも xlimit の設定方法は正しいのだろうか。
      xenl が元々ある場合には xlimit=cols-1 にする必要性もないのではないか。
      →これは改めて考え直して修正した。

    ? ok: print+ における overflow 判定は正しいか?
      →xenl||wmax-- でちゃんと処理できている。現在の新しい実装では xlimit の減
      少は xenl だけで決定されているので。

    ? implicit-move で行われている以下の処理は一体何なのか

      L1164: ((y++,x=w<xlimit?w:xlimit))

      うーん。これは一応OK? xenl がない場合は一番右の列に移動すると考え、xenl
      がある場合には端末の右端に行くと考える。実は xenl がない場合には更に次の
      行に行くという考え方もあるかもしれない。何れにしてもコメントにある様に端
      末によって振る舞いが変わるのではないかと思われる。

2021-11-28

  * 2021-11-05 vim の :term 内部で backspace が効かない (reported by laoshaw) [#D1683]

    C-q に続けて backspace を入力しても何も反応はない。auto-complete が表示さ
    れている状態で backspace を入力すると auto-complete がキャンセルされる事
    から何かしらは受信している。

    modifyOtherKeys を off にしても問題は発生する。

    ble/debug/keylog#start で確かめてみた所、何と backspace に対して NUL が受
    信されている。bash 本体はちゃんと受信できているという事を見ると bind の問
    題だろうか。

    | * うーん。然し端末 (host to terminal) では DEL と NUL が同じ効果というの
    |   もある。それに関連して vim terminal が何か勝手に変化させている可能性?
    |   でもそうだとしたら他の application でもっと問題になる筈である。何より
    |   readline がちゃんと動いている。
    |
    | * 最新版の bash でも同様に問題が発生する。なので version 依存のバグという
    |   訳でもない様に思われる。
    |
    | * 単に以下を bind しただけでは問題は再現しない。
    |
    |   $ bind -x '"\C-@": echo NUL'
    |   $ bind -x '"\C-?": echo DEL'
    |   $ bind -x '"\C-h": echo BS'
    |
    | * vim :term の中の ble.sh で builtin bind -Xs の結果を見てもちゃんと \C-?
    |   に対して 127 が割り当てられている。逆に 0 が割り当てられている hook も
    |   \C-@ しかない。不思議だ。
    |
    | * 実際に本当に .hook 経由で NUL が混入しているのか確認した。確かに .hook
    |   が 0 を引数として受け取っている。これはどういう事なのだろうか。FUNCNAME
    |   配列を出力してみたが問題の .hook は top level から呼び出されている。こ
    |   れも異常はない。だとすると、bind の組み合わせによって変な振る舞いになる
    |   可能性があるという事だろうか。
    |
    | * stty を潰してみたがそうすると端末ハンドラの行エディタらしき物が有効になっ
    |   てしまってテストできない。
    |
    | * stty の設定を確認してみた。vim の中では brkint ignpar imaxbel が欠けて
    |   いる。然し、それらの設定を一致させてみてもやはり問題は振る舞いは治らな
    |   い。stty の設定によって引き起こされているという訳でもない様だ。
    |
    | 不思議なのは :term の中では発生して他の端末では発生しないという事である。
    | bash の振る舞いがおかしいという事なのだろうか。取り敢えず bash の
    | bash_execute_unix_command がどう実行されているかについて確認したほうが良
    | い様に思われる。
    |
    | * bash_execute_unix_command の時点で \C-@ になっているという事を確認した。
    |   また vim の外側では \C-? である。然し不思議なのは自分で手動で bind した
    |   時には特に問題も起こっていないという事なのである。
    |
    | うーん。この bind -s の設定によって問題が起こっている気がする。それ以外に
    | は考えにくいのである。然しそうだとしても :term だけで発生するのは不思議で
    | ある。
    |
    | うーん。bash が受信しているバイト列について追跡する事にする。うーん。何と
    | rl_getc の中の read(fd) の段階で 00 を受信している。ble.sh を有効にしてい
    | ない時には問題は生じない。ble-detach している時には問題は生じない。うーん。
    | 此処まで来ると bind -s の問題ではなくてやはり vim の :term の側の問題の様
    | な気がする。
    |
    | stty 関連の設定を変更して試してみるとどうなるだろうか。と思ったがそれは既
    | に試している。端末ハンドラの行エディタが有効になってしまってちゃんと処理
    | できない。
    |
    | うーん。bash の内部状態における端末状態と ble.sh の内部状態における端末状
    | 態が異なるというのが原因だろうか。通常の readline における rl_getc の瞬間
    | の端末状態を出力する事は可能だろうか。stty を実行すれば良い?
    |
    | これによる結果はどうも各種 key を undef している事だけが違いである。うー
    | ん。undef になっていると勝手に 0x7F が 0x80 になってしまうという事なのだ
    | ろうか。
    |
    | -intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
    |  eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt
    |  = ^R; werase = ^W; lnext = <undef>; discard = <undef>; min = 1; time =
    |  0;
    | +intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof =
    |  ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop =
    |  ^S; susp = <undef>; rprnt = ^R; werase = <undef>; lnext = <undef>;
    |  discard = <undef>; min = 1; time = 0;
    |
    | ここで erase undef をしない様にしたらちゃんと vim :term の中でも動く様に
    | なった。他に ^C ^U ^\ ^Z (+ あれば ^W ^V ^R) について stty で変更している
    | 様だが、
    |
    | - ^C, ^U, ^Z, ^V, ^R については普通に受信できている。
    | - ^W については vim で使われている。
    | - ^\ については寧ろ ble.sh の内部ではちゃんと受信できているが、外では受信
    |   できていない。というか vim :term の外側にいる時でも受信できていない?

    [原因] stty erase undef としていたのが原因になっている様である。

    一方で、この設定がなくてもちゃんと動作する様に思われる。そもそもこの設定は
    何故あるのだろうか。どの様な場合に必要になるのだろうか。

    | 然しもし erase undef しなくても受信できるのだとしたらそもそも何の為にそう
    | していたのか。昔は icanon 等をしていなかった為に受信できなかったという事
    | だろうか。
    |
    | ? 何処かにコードコメントは残っていないか? → 残っていない。
    |
    | icanon がない時の対策なのだとしたら、実際に icanon に対する対策を落として振
    | る舞いを確認すれば本当にそうか確認できる。うーん。icanon に対する対策を外し
    | たとしても ^? は有効である様に見える。逆に icanon があったとしても ^Z は効
    | かなくなる。
    |
    | それぞれの key について改めてちゃんと振る舞うかどうかを確認する事にする。
    |
    | - ^Z, ^\, ^C ... icanon があっても対策が必要。
    |
    | - ^U, ^? ... 別に問題は起こらない様に見える。icanon は恐らく関係ない。
    | - ^V, ^W, ^R ... これらも問題は起こらない様に見える。icanon を対策していな
    |   くても振る舞いは変わらない。うーん。これらは単に
    |
    | うーん。分かった。adjust-uvw で ^U^V^W^? が対策の対象になっている。つまり、
    | 初期の実装に於いて ^U^V^W^? が bash の内部的な rebinding によって無効になっ
    | ているのを、stty の設定の問題であると誤認して追加した対策コードなのではない
    | かという事。そして、実際の所、これらの対策コードは役割を果たしていなかった
    | という事なのではないか。

    [まとめ] ^U^V^W^? について stty で undef にしていたのは、これらのキーに
    bind できない事に対する誤った対策だったと考えられる。これに対する対策は
    ble/decode/bind/adjust-uvw で行われている。昔は原因が不明だった為に、念の為
    で stty でも undef する様にしていたのだと考えられる。

    * 一応古い bash version でもちゃんと動くか確認する。→ bash-3.0, 3.1, 3.2,
      4.0, 4.1, 4.2, 4.3, 5.1 でも試した特に問題は起こっていない様である。

2021-11-23

  * progcomp: libvirt virsh completion に対する防御 (reported by telometto) [#D1682]
    https://github.com/akinomyoga/ble.sh/issues/147

    virsh completion を実行した直後にエラーメッセージが出るという事。これは
    virsh の補完が IFS=$'\n' と書き換えを行ってそのまま放置するのが原因である。

    libvirt に対して patch を送った。accept された。然しこれが実際に
    distributions に反映されるのには時間がかかるだろう。workaround として IFS
    及び word を tmpenv にする事にした。

  * util (modifyOtherKeys): kitty は modifyOtherKeys を廃止する (reported by kovidgoyal) [#D1681]
    https://github.com/akinomyoga/ble.sh/issues/110#issuecomment-975732850

    * ok: kitty のインストーラのリンクからダウンロードできない。証明書がおかし
      い。と思ったら単に vm の時刻がずれていただけだった。

    * Ubuntu 20 の VM に残っていた kitty 0.20.3 では既に CSI > 1 u には対応して
      いる様子である。DA2R は 1;4000;20 である。然し何だか C-S-? に対する振る舞
      いが分からなかったので kitty 0.23.1 に上げてしまった。DA2R は 1;4000;23
      である。

    * 然し、ctrl+shift+a などが全く効かない。と思って気づいたのだが、どうやら
      kitty がそれを解釈している様である。C-S-up, C-S-down はスクロールで C-S-h
      は clear-screen か何かだろうか。C-S-a は無反応で C-S-g はちゃんと制御シー
      ケンスが送られる。つまり、kitty に割り当てられていない C-S-? に関してはちゃ
      んと送信する事ができる。然し、試した感じだと殆どの C-S-? は kitty によっ
      て上書きされている様である。

    * kitty の ctrl+shift+a を無効にする方法はないのだろうか? うーん。結局一つ
      ずつ解除していくしかない様だ。取り敢えず全部解除したらそれっぽい感じになっ
      た。

    * どの version から CSI > u と CSI < u が存在するのだろうか。というかそもそ
      も現在の version でも CSI >4;2m は効くという事なのだろうか。

    https://github.com/kovidgoyal/kitty/issues/4075
    https://github.com/kovidgoyal/kitty/commit/d6a43a7729d50b6f452ccdb93c746b0e115ebd38

    どうやら kitty から modifyOtherKeys が完全に削除される運びとなった様だ。発
    端は vim から kitty の modifyOtherKeys の振る舞いが変だという指摘を受けて、
    逆上して全削除という事に相成った様だ。

2021-11-12

  * main: "alias set=export" としている人がいる (reported by eadmaster) [#D1680]
    これは単に退避リストに set を追加するだけで良い。

2021-10-30

  * edit: WINCH の際の再描画 (reported by Johann-Goncalves-Pereira, guptapriyanshu7) [#D1679]
    https://github.com/akinomyoga/ble.sh/issues/142

    * 前回よりも幅が小さい時には行数は同じか増える筈なので遡って削除する。

    それ以外で問題が起こるのは幅が増える時という事になる。

    * 幅が増えた時、前回 rprompt が表示されている時、またはプロンプトが改行され
      ていない時(右端まで到達していない時) には、恐らく右端を通り越して出力した
      事による折り返しは起こっていないので、配置に変化はないと仮定する。

      と思って実装を確認したが WINCH に対する処理は ble/application/render によっ
      て実行しているので、このレベルだと実際の描画内容に基づいて text reflow が起
      こったかどうかを判定する術はない。うーん。panel::hasLineWrap の様な関数を追
      加する必要がある気がする。

      その様に考えると現在の描画内容に応じて遡るかどうかを決定するのは余り綺麗
      でない様な気がする。やはり下手に予測しようとするよりもオプションなどで振
      る舞いを一括で変更した方が良いのだろうか。

    ----

    うーん。然し端末によっては折り返しが起こったかどうかに関わらず、一番右端に
    文字があるかどうかで折り返しを判断するという実装も可能かもしれない。そう言っ
    た場合にもちゃんと動く様な信頼できる方法があってそれが単純であればその方が
    良い。その実装が複雑に成るのであれば、実際その様な端末が確認された訳でもな
    いので、其処まで気にしなくても良い。

    * info の折返し判定について。うーん。menu は別の描画機構を用いているので、
      また別に処理する必要がある。試してみた感じだと menu_style=dense の時には
      折り返しになっている様である。

      というかこれを考えるとそもそも menu の再配置を先に実行するべきの気もする。

    ---

    * 取り敢えず暫定的にオプション

      段々と大掛かりになって来た気がする。折返しが発生しているかどうかの判定を
      用いて遡るかどうか判定するのは今後対応する事にして、現在は暫定処置として
      オプションで一括で対応するという方向も考えられる。

      bleopt prompt_erase_previous_on_winch=xxx
      bleopt textarea_winch_reposition=xxx
      bleopt canvas_winch_reposition=xxx
      bleopt canvas_winch_position=here|prev|
      bleopt canvas_winch_redraw=here|back|clear

    うーん。時間がかかっているので取り敢えずはオプションを提供する事にする。
    選択肢として redraw-here, redraw-prev, clear を用意する事にした。

  * edit: inputrc キャッシュの読み出しでエラーが発生する (reported by laoshaw) [#D1678]

    .bashrc から単純に source ble.sh を実行すると以下のエラーが出るという事。

    -bash: /Users/user1/.cache/blesh/0.4/decode.inputrc.adict.xterm-256color.emacs: No such file or directory
    -bash: /Users/user1/.cache/blesh/0.4/decode.inputrc.adict.xterm-256color.vi_imap: No such file or directory
    -bash: /Users/user1/.cache/blesh/0.4/decode.inputrc.adict.xterm-256color.vi_nmap: No such file or directory

    直接 source ble.sh を実行した時に問題になっていて、1.3 の方法で設定した時に
    問題が発生していなかったのは、source ble.sh を実行した瞬間に既にユーザー設
    定がされていたかされていなかったかの違いだろう。なので、この問題は
    attach=prompt に特有の問題ではない。

    不思議なのは $cache_prefix.settings が存在して中身が一致している事まで確認
    しているのにも関わらず $cache_prefix.$keymap が存在しないという事態になって
    いるという事。不思議な事である。

    うーん。変だそんな事起こらない筈なのに。

    * done: 調べてみると copyfile でファイルを読み出すのに失敗すると、ファイル
      が正しくコピーされていないのにも関わらず settings が作成される様である。
      取り敢えず、copyfile に失敗したら settings は作成しない事にする。

    * done: どうやら bash-3.? の時には readfile が実際に読み取れていたとしても
      失敗する様になってしまっている。read -d '' で読み取っているので、ファイル
      に NUL が含まれない限りは終了ステータスが 1 になってしまうのである。これ
      はちゃんと対策をした。読み取れるか読み取れないかの判定は事前にしておく。

    | 然し依然として何故報告された事が起こったのかは不明である。
    |
    | * 或いは書き込み時に問題が発生した可能性もある? 然し、どうやってそれが起こ
    |   るのか。settings はちゃんと書き込まれている (と思われる) 事から考えると、
    |   ディレクトリが存在しないだとか書き込み権限が存在しないだとかそういう話で
    |   はない気がする。copyfile の中でも clobber しているので上書き拒否されたと
    |   いう訳でもないだろう (というか上書き拒否されたのだとしたら既存のファイル
    |   が存在した筈なので上記の様なエラーは発生しない筈である。)
    |
    |   また、上記の read の問題かとも思ったがこれは bash-3.? での実装である。エ
    |   ラーメッセージを見ると 0.4 になっている。と思ったが分かった。0.4 はそもそ
    |   も bash の version じゃなくて ble.sh の version である。つまり、報告者は
    |   bash-3.2 を使っている。

    報告者は bash-3.2 を使っている為に問題が発生している。

    更に suggestion が出ないという問題についてもこれで説明がつく。

  * make: macOS make-3.81 で contrib/contrib.mk の依存関係が正しく解決されない (reported by laoshaw) [#D1677]
    https://github.com/akinomyoga/ble.sh/issues/145

    当初はどういうエラーかと思ったが 3.81 から 4.3 に update したら直ったという
    のでやはり make が悪いのだろう。実際に手元に 3.81 をインストールして試して
    みた所問題を再現できた。色々試して workaround できる事が分かったのでその様
    に対処する事にする。

    [make インストールログ]

    * make-3.81

      そのままだと古い version の make はコンパイルできない。

      | /usr/bin/ld: glob/libglob.a(glob.o): in function `glob_in_dir':
      | /home/murase/.opt/build/make/make-3.81/glob/glob.c:1361: undefined reference to `__alloca'
      | /usr/bin/ld: /home/murase/.opt/build/make/make-3.81/glob/glob.c:1336: undefined reference to `__alloca'
      | /usr/bin/ld: /home/murase/.opt/build/make/make-3.81/glob/glob.c:1250: undefined reference to `__alloca'
      | /usr/bin/ld: /home/murase/.opt/build/make/make-3.81/glob/glob.c:1277: undefined reference to `__alloca'
      | /usr/bin/ld: glob/libglob.a(glob.o): in function `glob':
      | /home/murase/.opt/build/make/make-3.81/glob/glob.c:575: undefined reference to `__alloca'
      | /usr/bin/ld: glob/libglob.a(glob.o):/home/murase/.opt/build/make/make-3.81/glob/glob.c:726: more undefined references to `__alloca' follow

      以下のページによると glob.c の #ifdef を書き換えたら良い。

      https://stackoverflow.com/questions/51675200/install-older-version-of-gnu-make-in-ubuntu-18-04

    * make-3.82

      ble.sh に対して make-3.82 しようとすると segfault する。3.81 で問題になっ
      ていた物を削除しても問題は解決しない。検索してみると上記のコンパイルエラー
      と同じく glob 関係のバグの様である。

      https://stackoverflow.com/questions/52618055/gnu-make-3-82-on-ubuntu-18-04-segfault-in-glob-call
      https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/XCYUF5BQLICUAAI3OM7EORCNOKEYP2MF/

      3.82 は 3.81 で行った修正をしてもしなくてもコンパイルできるが、どちらでコ
      ンパイルしたとしても segfault する。make-4.0 でやった様に
      GLOB_INTERFACE_VERSION を 2 に書き換えても、やはりコンパイルはできるが
      segfault する。

      https://git.savannah.gnu.org/cgit/make.git/commit/?id=193f1e81edd6b1b56b0eb0ff8aa4b41c7b4257b4

      で紹介されている修正を適用したらちゃんと動く様になった。ble.sh の
      contrib.mk はちゃんと動作する事が確認できた。

    * make-4.0

      4.0 についても同じ箇所でコンパイルエラーになる。== を >= に書き換えるとい
      う作戦は通用しなかった。GLOB_INTERFACE_VERSION を 2 に書き換えてみたらコ
      ンパイルできた。ble.sh の contrib.mk もちゃんと動く。

    * make-3.80 も 3.81 と同じ様にしてコンパイルできた。然し、make-3.80 は
      $(.FEATURES) を持たないので ble.sh GNUmakefile はもっと新しい version を
      使ってくれと文句を出力する様になっている。3.80 は 2002 の version で 19年
      も前の version なので切っても仕方がないだろう。

2021-10-21

  * main: "ble.sh: This is not an interactive session." (reported by andreclerigo) [#D1676]

    恐らく non-interactive session に於いて bash_profile から bashrc が読み込まれている。
    bash_profile なので bashrc であると検出できなくてメッセージが表示されている。
    何れにしても non-interactive session で読み込もうとしているのがいけないといえば行けない。

    →推測で修正してみたが直っていないそうだ。画面を見ると原因が分かった。GDM
    が Xsession を source して、 Xsession が /etc/profile 経由で .bashrc を呼び
    出しているという事の様だ。つまり、non-interactive script が source .bashrc
    をしている可能性を考慮に入れなければならない。この場合には、どう対処するべ
    きか。

    a warning を表示するというのは違う気がする。ユーザーは [[ $- == *i* ]] を考
      慮に入れて bashrc を記述する事を要求されているのである。なので、ble.sh を
      source する時にユーザー側で [[ $- == *i* ]] をチェックするか、或いは
      ble.sh 自身でも *i* をチェックして silent に return するというのは妥当で
      ある。

    b 或いは warning は全く表示しないという可能性? しかし、直接 bash ble.sh を
      実行された場合や、まるでライブラリであるかの様にプログラムから直接 source
      ble.sh を実行した場合などは、明らかに使い方を間違えているのだから warning
      を表示しても良い気がする。

    c profile, bashrc など経由で ble.sh が source した時には、それが
      non-interactive であっても警告は表示しない様にする。何しろ、profile,
      bashrc は interactive でも non-interactive でも source され得るのだから、
      non-interactive であったとしても使い方を間違えているとまでは言い難い。

      Bash が source する可能性があるのは以下である。

      - /etc/profile
      - ~/.bashrc
      - ~/.bash_profile
      - ~/.profile

      /etc/bashrc などはその他のファイルから呼び出されるので、これらはチェック
      しなくても良い? と思ったが、もしかすると何らかのスクリプトが直接 source
      /etc/bashrc みたいな事をしている可能性も考えられる。という事を考えると
      bashrc も除外リストに入れて置いた方が良いのではないかという気もする。うー
      ん。やはり除外リストに入れる事にする。

      - /etc/bashrc

2021-10-04

  * blerc: 含まれていない face が存在する (reported by Prikalel) [#D1675]
    https://github.com/akinomyoga/ble.sh/issues/140

    blerc も wiki も共に以下の2つが抜けている。

      argument_option
      cmdinfo_cd_cdpath

    * core-complete-def.sh で ble-color-defface を使っている。
      →直した。他に ble-color-defface を使っている箇所はない。

  * cmap: find/select が TERM によって定義されていたりいなかったりする [#D1674]

    今思ったのだが TERM によって find/select が存在したりしなかったりする事によって、
    keymap.emacs や keymap.vi のキャッシュに不整合が生じるのではないか。うーん。

    これによって keycode が不整合を起こすのではないか。
    $_ble_base_cache/keymap.{emacs,vi} は特に TERM に依存せずに共通の物を用いて
    いるので問題が発生する筈である。

  * prompt: prompt_ruler で空文字列に展開される文字列を指定すると無限ループになる? [#D1673]

    これは直ぐに直った。

    x fixed: 但し、属性だけ設定して何も出力しないプロンプトの場合、背景色等も適
      用されない。これは trace が実際に文字を出力する迄着色を遅延する為である。
      trace に最終的な属性を反映させるオプションを用意しても良いのではないだろ
      うか?  或いは既にその様なオプションはあっただろうか。

      うーん。trace の実装を確認してみたが、sgr が遅延されるのは clip の時のみ
      であって、今回は clip は指定していない。

      と、思ったら実際に出力するものを間違えていた。trace で解析した物ではなく
      て解析前の物を直接出力する様になっていた。これは修正した。

  * canvas (c2w.*.sh): テーブルの初期化に於いて *_ranges は ${!table[@]} に実は置き換えられる? [#D1672]

    但し、table に飛び地も記録している場合にはこの方法は使えない。
    canvas.c2w.musl.sh を見ていて思ったのだが、他には短縮できそうな物はなかった。

  * canvas.emoji: version 毎のテーブルを統合 [#D1671]

    c2w.emoji.sh: version 毎にテーブルを作るのではなくて、合成したテーブルを使っ
    た方がスペースを節約できるのではないか。

    実装し直した。

    x fixed: 出力結果を比較してみたが全然違う値になってしまっている。何故だろう
      か。うーん。実際に出力されているテーブル自体が何だか違う結果になっている
      気がする。何かデータがスキップされてしまっている可能性?

      念の為元のデータを確認しておく。U+1F7E5 (128997) が以前は 1
      (fully-qualified) だったのが現在は 0 になってしまっている。元のデータには
      ちゃんとこれは含まれている。最新のテーブルを確認すると値が消滅している。

      →と思ったらミスが見つかった。修正する。

    x fixed: emoji_version=13.1 で比較した所、以下の code point の EmojiStatus
      が変わってしまっている。

      -U+0270F 3
      +U+0270F 1

      元のデータを参照するとこれは unqualified でなければならない。何故値が変化
      してしまっているのだろうか? 新しいテーブルの実装を確認する。270F = 9999
      である。

      % うーん。最新のテーブルを見るとそもそも 0 になるべきの気がする。何故 1
      % になっているのだろうか。と思ったが、分かった。範囲としては 9994-10000
      % に含まれていて、9994 は 1 という事になっている。

      つまりテーブル生成の時点で何故か 9999 (unqualified) が 9994 (270A) に属す
      る形になってしまっているのが原因である。

      →これは gawk の中で < による比較が文字列比較になっていたのが原因だった。
      int() で整数に変換してから処理する様にした。

    o 13.1, 14.0 で比較した。ちゃんと一致している。
    o 11.0, 5.0, 2.0, 1.0 でもちゃんと一致する事を確認した。
    o 0.6, 0.7 は以前は対応していなかったが対応する事にした。
    o 14.0 も新しく対応した。

2021-09-27

  * 2021-09-24 decode: 起動中に入力した文字が遅延する問題 [#D1670]
    https://github.com/akinomyoga/ble.sh/issues/135#issuecomment-919088879

    起動後に最初に文字が入力された時に初めて処理される。

    | 但し、これはちゃんと対策できるのかどうか怪しい。うーん。何れにしても現在ど
    | の様にしてこの遅延が発生しているのかを調べる必要はある。
    |
    | * 先ずは単純な bashrc で再現するのだろうか。という事。単純な bashrc だとちゃ
    |   んと bashrc が終わった段階でバイトを受信する事ができている。
    |
    |   # bashrc
    |   sleep 1
    |   bind -x '"A":echo A'
    |
    | * 次の実験は ble/.hook は受信できているのかという事。実際に次の内容を受信し
    |   ている:
    |
    |   [recv: 101] [recv: 99] [recv: 104] [recv: 111] # echo
    |
    |   [recv: 192] [recv: 155] [recv: 91] [recv: 50] [recv: 59] [recv: 49]
    |   [recv: 82] # \e[2;1R
    |
    |   [recv: 192] [recv: 155] [recv: 91] [recv: 62] [recv: 56]
    |   [recv: 51] [recv: 59] [recv: 52] [recv: 57] [recv: 57] [recv: 48] [recv:
    |   48] [recv: 59] [recv: 48] [recv: 99] # \e[>83;49900;0c
    |
    |   うーん。
    |
    | * ble-decode-char: うーん。同じものをちゃんと受信できている。
    |
    |   [char: 101] [char: 99] [char: 104] [char: 111]
    |
    |   [char: 27] [char: 91] [char: 50] [char: 59] [char: 49] [char: 82]
    |
    |   [char: 27] [char: 91] [char: 62] [char: 56] [char: 51] [char: 59] [char:
    |   52] [char: 57] [char: 57] [char: 48] [char: 48] [char: 59] [char: 48]
    |   [char: 99]
    |
    | * ble-decode-key: 到達している。
    |
    |   [key: 101] [key: 99] [key: 104] [key: 111]
    |
    | * call-keyseq: 何も到達しない。
    |
    |   何が起こっているか分かった…。ble-decode-key に "echo" が届いた時点では、後
    |   に CPR や DA2R が控えている為にその場では処理されない。然し、CPR や DA2R は
    |   ble-decode-key を呼び出さないので、そのまま処理が止まったままになる…。と思っ
    |   たが何だか変だ。改めて調べる。
    |
    |   うーん。やはり既に _ble_edit_str はちゃんと echo という文字列を含んでいる
    |   様に見える。という事は call-keyseq とは別の経路でちゃんと文字列が挿入され
    |   ているという事か。

    うーん。分かった。ble-decode-key/.invoke-partial-match の中で文字入力がある
    時に _ble_decode_key_batch に文字入力をキャッシュしている。なので次に何らか
    の widget が呼び出される迄、キャッシュされたままになってしまう。

    なので、何処かでユーザー入力がないと確かめられたら
    ble-decode-key/batch/flush を呼び出す必要がある。ble-decode/.hook で呼び出
    すのが最も確実だろう。

    →直った。syntax highlighting の遅延もちゃんと見える様になった。というより
    今迄見えていなかったのはやはりこれによる問題だったのだろう。

  * util: CPR に timeout を入れる可能性 [#D1669]

    偶々何らかの都合で端末が返答を無視した時などの為に、SECONDS 等を参照して古
    い CPR handler は削除してしまうというのが必要になる気がする。handler 毎に設
    定しなくても、最後に request を出してから一定以上時間が経過していればその時
    点で flush してしまうというのでも良い気がする。

    一方で現実的な疑問としてその様に途中で CPR が消えたり、或いは端末が贈り忘れ
    たりという事がありうるのか、というのはある。例えば ssh を用いている限りはちゃ
    んと stream が hash で繋がっているし、途中で内容が抜けるという事はありえな
    い。TCP でそのまま繋がっているとしてもちゃんと途中で抜けがないかチェックは
    入っている筈である。udp で接続しているという事はありえない。まして、ローカ
    ルの端末・パイプで繋がっている時にはやはり途中で抜けるという事は考えがたい。

    これは安全策の為に一応実装しておくという程度の物である。

    * もしかすると現実的に ssh 切断→再接続→debugger API で tty を再構築みたい
      な事をすると、CPR が抜けるという事が発生するかもしれない。

  * canvas (c2w): akinomyoga-emacs / musl-wcwidth の自動判定にも対応する? [#D1668]

    voidlinux にそういえば変な標準ライブラリを使っている version があった。改め
    て確認すると musl というそうだ。musl wcwidth で検索したらソースコードが出て
    きた。この musl-wcwidth について wcwidth の結果を出力してみた所、何だか滅茶
    苦茶な結果が返ってくる。musl-wcwidth は 2012 で更新が止まっているので頻繁に
    変わる物という訳でもないだろう。

    追加で 25b6 をチェックすれば emacs は判定できる。

    musl の判定は Unicode versions の判定用の幅も使えば判定できるのではないかと
    いう疑惑。どうせどの Unicode version にも合わない様な変な振る舞いの文字があ
    るのではないかという気がする。

    * その前に musl-wcwidth の実装をしなければならない。musl は元のコードと同じ
      様にすればコンパクトにできるが、ライセンス的に面倒なので振る舞いから再構
      築するのが良い気がする。やはり2分法で実装するか、或いは…

      musl が使っているのはどういう実装だろう。

      例えば 256x256 に分けて考えると、256のパターンを 8 整数 (64x8 = 512 =
      256x2bits) で表して、更にそれに対して同じ物を潰して higher 8bit から、パ
      ターンへの参照を作る。と思ったが、musl の実装を見る限りは曖昧な部分などを
      積極的に潰す事によってテーブルを小さくしている様な気がするので、一般のア
      ルゴリズムとしては可逆でそんなに簡単に圧縮できるとは思えない。musl がその
      様に圧縮されているという前提知識があるので同じ方法を取る事もできるかもし
      れないが、そうすると結局ソースコードをそのまま真似た形になってしまい、ま
      たライセンスの問題になる。

      やはり変な事を考えるよりも愚直に二分法なり何なりで実装するのが最もコンパ
      クトな気がする。一方で、効率を考えたら二分法よりも良い方法はあるだろうか。
      結局 trie の様な構造を考えることになるのだろうか。

      うーん。何れにしても二分法を使う事にする。U+XXXX width を出力した表からテー
      ブルを作成するコードがあれば今後も便利であろう。改めて make_command.sh の
      内容を確認する。

    * musl の判定に既存の文字が使えるかどうかの確認

      25bd 25b6 に対しては両方とも幅 1 になる。

      Unicode version 判定に用いているコードに関しては 2 2 2 2 0 2 1 1 1 1 1 1 2 という数列を返す。

              | -----Unicode EAW+GeneralCategory---------------|musl
      U+9FBC  | -1  2  2  2  2  2  2  2  2  2  2  2  2  2  2 2 | 2
      U+9FC4  | -1 -1  2  2  2  2  2  2  2  2  2  2  2  2  2 2 | 2
      U+31B8  | -1 -1 -1  2  2  2  2  2  2  2  2  2  2  2  2 2 | 2
      U+D7B0  | -1 -1  2  2  2  1  1  1  1  1  1  1  1  1  1 ? | 2 何故か動いていない?
      U+3099  |  2  2  2  2  2  2  2  0  0  0  0  0  0  0  0 0 | 0
      U+9FCD  | -1 -1  2  2  2  2  2 -2  2  2  2  2  2  2  2 2 | 2
      U+1F93B | -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2  1 1 | 1
      U+312E  | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2  2 2 | 1
      U+312F  | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2  2 2 | 1
      U+16FE2 | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2  2 2 | 1
      U+32FF  | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2  2 2 | 1
      U+31BB  | -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1  2 2 | 1
      U+9FFD  | -1 -1  2  2  2  2  2 -2 -2 -2 -2 -2 -2 -2 -2 2 | 2

    * 何故 D7B0 が動かなくなっているのだろう。現在これを出力しようとすると常に
      0 が表示される。

      と思ったら _ble_unicode_c2w_custom で上書きされてい
      た。_ble_unicode_c2w_custom を一旦削除して判定して、終わったら復元して
      _ble_unicode_c2w_custom に含まれるコードだった時に警告を出力する様に変更
      した。

  * 2021-08-31 wiki, blerc: import_path [#D1667]

    done: bleopt import_path の記述が抜けている。blerc にもない。

    他にも抜けている物がないか確認するべきなのでは。

    done: grapheme_cluster
    done: emoji_opts
    ok: menu_desc_multicolumn_width これは現在対応中で後で載せる。

    取り敢えず一つずつ説明を追加していくのが良い。

    * 一方で blerc で抜けている物はもっと沢山ある。

      done: keymap_vi_imap_undo
      done: keymap_vi_keymodel
      done: keymap_vi_operatorfunc
      done: keymap_vi_search_match_current
      done: term_vi_smap
      done: decode_macro_limit
      done: idle_interval
      done: syntax_debug

      これらについては wiki から説明を拾ってくれば良い。

    * done: vim_airline_* は全く説明書にない

      vim_airline_theme だけは blerc にある。

  * edit: powerlevel10k の prompt_add_newline を実装する (motivated by Barbarossa93) [#D1666]
    https://github.com/akinomyoga/ble.sh/issues/135#issuecomment-927284636

      prompt_ruler='empty-line'
      prompt_ruler='-'
      prompt_ruler=$'\e[38;5;242m-'
      prompt_ruler='---='

    等に対応する。これは実はそんなに難しくないかもしれない。対応した。

    対応する powerlevel10k に於ける設定名は以下の通り

      POWERLEVEL9K_PROMPT_ADD_NEWLINE=true/false
      POWERLEVEL9K_SHOW_RULER=true/false
      POWERLEVEL9K_RULER_CHAR=-
      POWERLEVEL9K_RULER_FOREGROUND=242

    ble.sh では prompt_ruler に ANSI seq を指定できる様にしたので色も一つの変数
    で済む。

  * [外部 bashrc] Void Linux で文字幅計算がずれる (reported by Barbarossa93) [#D1665]
    https://github.com/akinomyoga/ble.sh/issues/135

    と思ったがそもそもキャッシュしていない様に見える。という事は何を意味するの
    か。うーん。prompt 計算のキャッシュが残っているという事だろうか。そんな気が
    する。試してみる事にする。→プロンプトの trace_hash に char_width_mode も入
    れて置く事にした。char_width_mode=west にしても前の設定が残っている問題は解
    決した。

    * 2021-09-26 これは結局 Barbarossa93 の設定に含まれる getCPos で printf
      DSR(6) & read CPR していたのが原因だった。この為に ble.sh の遅延処理して
      いる CPR の処理と getCPos の CPR の処理が入れ替わって双方で誤った結果を生
      み出しているというのが原因であった。

      更に、もう一つの報告された問題である入力した文字列が失われるという問題に
      ついても、この getCPos が CPR 待ちで読み取っているが為に起こっている問題
      であった。この問題は ble.sh をロードしなくても、単に bashrc で時間がかか
      るだけで再現するという事が分かった。

    * 2021-09-26 PROMPT_COMMAND の中でこの様な事をしても大丈夫な様に対策する?

      そもそも技術的に可能なのか分からない。

      a PROMPT_COMMAND の呼び出し前の段階でユーザー入力があるかどうかを確認して、
        もしユーザー入力があるのであれば一旦その時点で抜けるという事が必要にな
        る気がする。然し、現時点で既にその様な実装になっている様な気もする。こ
        れは全然対策になっていない。

        つまり、textarea#render に入る直前までに返答が返ってくれば処理もできる
        が、そうでなければ PROMPT_COMMAND の中で stdin を読み取ろうとした時に、
        返答が来るまで待って其処で CPR が読み取られてしまうという事になる。

      うーん。やはりこれに対する対策は原理的に困難である様な気がする。

      b 或いは、terminal-test.buff を sync (timeout 付き) で処理する可能性もある。

        然し、端末が CPR に対応していない時に固まってしまう。

        timeout を入れたとしてもその分遅延が生じる事になる。ble.sh では初期化の
        遅延を可能な限り減らそうとしているので 50ms でも待つ等という事はしたく
        ない。それに timeout した時に、それよりもずっと後になって返答が返って来
        た時にまた問題が生じるかもしれないので、timeout はもっと長く設定しなけ
        ればならない気がする。もしくは、timeout してしまったら何らかのエラーと
        して処理を中断するというのが普通のシェルプログラムの動作として望ましい
        が、対話セッションの時にはセッションを抜けるという訳にも行かない。

        もし本当に位置を特定したいのであれば、やはり ble.sh の様に非同期で処理
        する事が必要で、その為には line editor の event loop に登録するしかない。
        ble.sh ではその為の枠組を用意しているので、本当にそういった処理を実施し
        たいのであれば、ble.sh の枠組みを経由でカーソル位置を取得してもらうしか
        ない。readline に至っては robust な方法はない様な気がする。一応、
        readline の動作は高速なので変な遅延が生じる可能性は少ないし、そもそも
        readline が返答を必要とする様な要求を出さないので問題が起こる事は余りな
        いのだろう。

      結局技術的に考えても困難であるし、これの対策はしない事にする。

      対策しないとするとどれだけの範囲で問題が生じるか調べておく必要がある。

        https://github.com/search?q=filename%3Abashrc+getcpos
        https://github.com/Barbarossa93/Muspelheim/blob/c9ea8ffd83ab5c85da47b5c36f39b3ec97b96230/.config/bash/bashrc

      検索すると以上の様に報告者の bashrc しか見つからないので、この getCPos を
      bashrc の中で使うという手法は報告者独自のものであると推察される。なので、
      そんなに多くの設定で使われている物という訳でもないのだろうという気がする。
      うーん。以下で検索すると PROOMPT_COMMAND で CPR を取得するのは実は沢山存
      在している様だ。

        https://github.com/search?q=filename%3Abashrc+PROMPT_COMMAND+%22%5B6n%22
        https://github.com/ScoreUnder/scripts-and-dotfiles/blob/f69f2f11739342a7c46fb38a9be2f5a5c803a438/dotfiles/.bashrc.m4
        https://github.com/safocl/safocl_profiles/blob/31ce40e9ff4619d1099c4f95c1f717e8a9b389fb/.bashrc

    * [再現不可] urxvt: C-l をした直後に何故か反応が遅くなる

      C-l の直後以外では問題はない様に見える。うーん。もしかすると C-l の直後以外
      ではプロンプトの更新がされていない? 単にプロンプトの計算に時間がかかってい
      るという事?

      以下の PS1 で再現する

      PS1=$'\[\e[38;5;1m\]┏━[\e[38;5;7m\]\w\[\e[38;5;1m\]]\n\[\e[38;5;1m\]┗━━ \[\e[38;5;8m\]■ \[\e[38;5;7m\]'

      というか更に以下の PS1 でも再現する

      PS1=$'\e[31mA '

      うーん。これは結局再現する事はできなかった。改めて urxvt で提供された
      bashrc を実行してみたがそれでも駄目だった。何か urxvt か或いは別の設定が
      壊れていたのかもしれない。

    * 2021-09-26 workaround を提示したら思っている動作と異なるとの報告が来た。
      改めて見てみると、元のコードでしたのは「一番左にいなかったら改行を追加す
      る」ではなくて「一番上にいなかったら改行を追加する」という物だった。

      少し考えてみたがよく分からない。困難の気がする。powerlevel10k にその機能
      があるというので p10k を 6n で検索してみたが、特にその様な文字列は含まれ
      ていない様だ。或いは、powerlevel10k はまた異なる手法を用いているのかもし
      れない。どうやら

        POWERLEVEL9K_PROMPT_ADD_NEWLINE

      というのが該当する設定の様である。うーん。これを使っている所を調べると

        [[ $P9K_TTY == old ]] && { unset _p9k__empty_line_i; _p9k__display_v[2]=print }

      というのを設定している。P9K_TTY は preexec で old に設定されている。

        if [[ $_p9k__preexec_cmd == [[:space:]]#(clear([[:space:]]##-(|x)(|T[a-zA-Z0-9-_\'\"]#))#|reset)[[:space:]]# &&
              $_p9k__status == 0 ]]; then
          P9K_TTY=new
        elif [[ $P9K_TTY == new && $_p9k__fully_initialized == 1 ]] && ! zle; then
          P9K_TTY=old
        fi

        if [[ $1 == (clear-screen|z4h-clear-screen-*-top) ]]; then
          P9K_TTY=new
          _p9k__expanded=0
          _p9k_reset_prompt
        fi

      うーん。これを見ると powerlevel10k は単に直前のコマンドを見ている様だ。具
      体的に座標を抽出している訳ではない様だ。これなら実装できなくもないが…。

  * canvas: 文字幅判定の為の CPR は internal 状態で実行したい [#D1664]

    CPR が画面に出力されてしまうのは stty echo の時に DSR(6) が出力されるから。
    ちゃんと internal state の時に CPR が出力される様にすれば防げるのではないか。
    後で何処から出力されているかを確認する。

    と思ったが、CPR の遅延があるのでそれによって表示されているだけかもしれない。
    その場合には対策できないかもしれないができるだけ早い段階で DSR を送信してお
    く事はできる。

    うーん。或いは、コマンド実行が終了した時点で char_width_mode=auto もしくは
    char_width_version=auto になっている時に初めて要求を出すというのは一つの手
    である。

    * done: refactor: 関数名を変更する c2w+ -> c2w:

2021-09-26

  * edit (command-help): use ble/util/assign/.mktmp to determine the temporary filename [#D1663]

    これは ble/util/readfile の用例を確認している時に気づいた事。
    修正した。ちゃんと動いている様な気がする。

2021-09-23

  * decode: [openSUSE] bash-it 側の検証に際して色々問題が生じている (reported by cornfeedhobo) [#D1662]
    https://github.com/Bash-it/bash-it/pull/1884

    https://web.libera.chat/?channel=#bash-it ここの議論はすぐ消滅する
    | [8:27:38] → akinomyoga has joined
    | [8:31:20] <akinomyoga> Hmm, it seems everything I wrote has been lost after I
    | restarted the web browser. I don't get used to IRC, so I didn't know this
    | behavior. So there is no log of the channel?
    | [9:55:21] <akinomyoga> I summarized the current situation at
    | https://github.com/Bash-it/bash-it/pull/1884#issuecomment-923489130
    | [12:07:33] ← akinomyoga27 has left (Quit: Client closed)
    | [12:08:01] → akinomyoga27 has joined
    | [12:08:07] ← akinomyoga27 has left (Client Quit)
    | [13:45:22] <cornfeedhobo> akinomyoga: hello again
    | [13:45:45] <cornfeedhobo> akinomyoga: yeah, irc doesn't keep history. but i
    | have a record of it
    | [13:46:02] <akinomyoga> Hello
    | [13:46:06] <akinomyoga> Ah, OK
    | [13:47:29] <cornfeedhobo> ah, okay, so maybe i can explain the PROMPT_COMMAND
    | situation at least
    | [13:48:30] <akinomyoga> I have summarized my situation in the GitHub issue
    | page. Maybe you can first take a glance at the comment and just explain the
    | difference of the setups.
    | [13:50:28] <akinomyoga> Unfortunately I will have a meeting 10 minutes
    | later. So I think I cannot respond for one or two hours after that.
    | [13:50:28] <cornfeedhobo> your comment from an hour ago sums up what I was
    | assuming was happening
    | [13:50:47] <cornfeedhobo> okay, no worries. sorry i couldn't reply
    | sooner. today was filled with meetings.
    | [13:52:09] <akinomyoga> OK! Nice! Then I will look for a workaround
    | [13:52:51] <cornfeedhobo> awesome! thanks for working through this. your
    | attention to detail is impressive.
    | [13:53:04] <akinomyoga> thank you!

    * done: home/end が効かない。これは結局 find/select を認識する事にした。本
      当に openSUSE の workaround の為だけの変更である。Ref #D1648

    * done: "preexec が壊れる" という文句について。Ref #D1650

    * done: set-mark 及び history-search-{for,back}ward が nmap で対応されてい
      ないというエラーメッセージに対する苦情 Ref #D1651

    * done: /etc/inputrc{,.keys} が大量に設定を行っている為に初期化が遅い問題
      Ref #D1652

    * done: error messages on openSUSE ... これは openSUSE における既
      知の問題である。これに関する対応は既に openSUSE の最新版には反映
      されているので気にしなくて良い。もし今後も openSUSE 15.2, 15.3
      のユーザーから報告があるのであれば、ble.sh の側で何らかの
      workaround を追加する必要があるかもしれない。

      うーん。結局これは openSUSE の問題だし、Tumbleweed では問題は発生しないの
      だからわざわざ対応しなくて良い気がする。これは無視する。

      うーん。或いは openSUSE 15.2, 15.4 を検出して inputrc を off にしても良い
      かもしれない。然し、これは他の WA がちゃんと動く事を確認してから対応する
      方が良い。そうしないと WA がちゃんと動くかどうかの feedback を得られない。
      これは最後に処理する。

    最終的に openSUSE /etc/inputrc.keys が存在して変な keyseq を含んでいる場合
    には bind の出力は参照せずに .inputrc を解析する様に変更した。

  * edit (widget history-search): support empty=emulate-readline (motivated by jainpratik163) [#D1661]
    https://github.com/akinomyoga/ble.sh/issues/139

    history-search-{for,back}ward は検索なので一致場所にカーソルを置くという仕
    様に今までしてきた。また、空文字列検索の時には空文字列による検索を継続する
    為に、敢えてカーソルを先頭に置く様にしていた。しかし、readline の振る舞いを
    改めて確認した所、空文字列の時には恰も通常の history-prev を使用して移動し
    たかの様に振る舞っていながら、空文字検索を継続しているのだという事が判明し
    た。仕方がないので ble.sh でもやはり空文字列検索であっても内部的には
    nsearch 状態に突入して、但しカーソル位置は末尾にするという具合に変更する事
    にした。

    改めて思うに Ref #D1517 https://github.com/akinomyoga/ble.sh/issues/101 で
    要望にあった"2. I would like the cursor to move to the end of line while
    searching with Up/Down." というのはこの振る舞いに関連しての事だったのではな
    いかという気がする。まあ、今となっては考えても仕方のない事なのかもしれない。

    [追加]

    * 対応したと思ったら動かない。と思ったが、prior に history-search-backward
      を束縛しても、nsearch keymap の中で prior が束縛されていないので、続けて
      prior が押されると一旦 nsearch を抜けて改めて nsearch が開始される為に、
      空文字列検索を続ける事ができないという状態になっていた。nsearch keymap に
      も prior/next を束縛する事にした。

    ところで、ble.sh は複数行編集に対応しているので、その意味での prior/next を
    解釈する方が本当は理に適っているのでは? と思ったが、複数行編集している時に
    はその複数行で履歴検索したいという事はないだろうし、代わりに現在カーソルが
    ある行の文字列を履歴から検索するとしても、折角複数行のコマンドを編集してい
    るのに別のコマンドに移動してしまう事になるので変な感じがする。という事を考
    えれば、実は「複数行の時にはページ移動で、単一行の時は履歴検索」という
    widget として実装すれば良い気がする。これはまた別項目として残す事にする。

2021-09-22

  * README: roadmap [#D1660]

    発音の部分が取ってつけた様なので紹介文を書いてみた。

    然し何だかふざけた感じになってしまった。特に日本語に関してはどのような言葉
    遣いで書いたら良いのか分からない。日本語では説明書にそういう話は書かない気
    がする。お菓子の説明にはそのお菓子がどのように成立したかなどの説明があった
    りする気がするのでそんな感じで書くのだろうか。真心込めて作りました的な説明
    になってしまってそれも何だか変な感じである。とにかく説明書に書くような内容
    ではない気がする。

    % 縁起: 端緒は二〇一三年三月の末、とある `zsh-syntax-highlighting` の記事に触
    % 発され `.bashrc` の片隅で始まった実験でありました。数百行の設定で不完全でも
    % 何か着色ができようという当初の安易な期待は即座に裏切られ、行エディタを全て
    % 再実装するより他にないことが露見したのであります。一個の独立したスクリプト
    % として開発することに改め、名を ZLE (Zsh Line Editor) から借り、シェルで書か
    % れたことを示す `.sh` を付して `ble.sh` としました。二週間の実験は、実用に堪
    % える完全な行エディタをスクリプトで実装することが可能との結論に終わりました。
    % 本格的な実装が始まったのは二〇一五年二月のことです。同年十二月には行エディ
    % タとしての機能は大方出揃い、これを以て最初のバージョンとしました。

    結局、新しく history and roadmap という section を README に加える事にした。
    発音に関する説明は結局 README の上部にそのまま残っている。

  * README: sabbrev の例で \word を薦めるのが良い気がする [#D1659]

  * README: zsh-abbreviations なる物は存在しない [#D1658]

    https://unix.stackexchange.com/questions/6152/zsh-alias-expansion
    https://qiita.com/matsu_chara/items/8372616f52934c657214
    https://github.com/olets/zsh-abbr

  * repo: ディレクトリ構造の整理。docs, make ディレクトリの作成 [#D1657]

    * done: make ディレクトリに Unicode 関係のテーブルの生成コードを移動する?

      現在は memo/ 以下にファイルを持っているが何だか違う気がする。他に leakvar
      の whitelist のファイルなども make 以下に移動した方が良い様な気がする。

      make ディレクトリという名前で良いだろうか。tool というディレクトリを一時
      作りかけた。うーん。或いは memo の下にサブディレクトリを作る? うーんやは
      り make で良い気がする。

    * done: ext/mwg_pp.awk も make に移動してしまって良い気がする。此処で問題になるか
      もしれないのは GNUmakefile の更新に失敗するかもしれないという事? 然し
      make の最中に checkout したりする事はないし、mwg_pp.awk が移動していれば
      既に GNUmakefile の方もそれに応じて書き換わっているし、GNUmakefile の方が
      書き換わっているのであれば mwg_pp.awk も移動している筈なので問題は起こら
      ない筈。

    * reject: docs ディレクトリに雑多のファイルを移動する?

      x GitHub のシンボリックリンクの問題

        色々のファイルを docs ディレクトリに押し込めようと思ったが、git clone
        した時に分かりにくいので LICENSE と README に関してはせめて symbolic
        link を置こうと思ったが…GitHubのインターフェイスだと symbolic link を
        開いても中身の文字列が表示されるだけで、その指し示している先にジャンプ
        する事ができない。これはかなり不便である。検索したが余りそういう要望は
        ない様である。以下に何やら要望があるが、そもそもこの repository を
        GitHub が見ているのかどうかも謎である。

        https://github.com/dear-github/dear-github/issues/156

      x GitLab など他のサービスだと docs 以下にファイルを置いても認識してくれな
        いかもしれない。

      これは一先ずは棄却する。後にもっとファイルが増えた時に気になれば対処する。

    * done: ChangeLog.md, Release.md ぐらいは docs に移動しても良いのかもしれない。

      多くのファイルは現在の場所に取り敢えず残すとしても memo/ChangeLog.md や
      memo/Relases.md に関してはまた docs/ 等の下にある方が分かりやすい筈である。
      此処での問題は ChangeLog.md を移動すると rebase がしにくくなるという事。
      まあ、これは一気にやってしまえば問題はない。

    * keymap の下にある物も何処かのタイミングで lib/* に移動したい。0.5 に変更
      する時に移動しようとも思っていたが、0.4 がいつ完成するか分からないし、コー
      ドの移動を一度に実行すると code frequency にまた大きな spike が立ってしま
      うので、release 等とは関係なく思い立った時に実行した方が良いのかもしれな
      いとも思う。

    何れにしても既存の物についてのディレクトリ構造の変更は、他の変更が pending
    になっていない綺麗な状態で実行するべきである気がする。現在は Unicode 関係の
    テーブル生成についても、中途半端である。少なくとも c2w 関連の実装が一区切り
    してから考えるべきことである様に思われる。

  * [棄却] util (readfile): bash-5.2 に $(< xxxx) without fork が実装された [#D1656]
    ble/util/readfile にはこれを使うのが良いのではないか。後で速度についても確認する。

    | bash-5.1
    |
    |    201.567 usec/eval: ble/util/readfile var sig.h (x500)
    |   1070.529 usec/eval: var=$(< sig.h) (x100)
    |   1078.159 usec/eval: var=$(< sig.h) (x100)
    |   1067.909 usec/eval: var=$(< sig.h) (x100)
    |   1078.159 usec/eval: var=$(< sig.h) (x100)
    |
    |   process-count ... 200位増えている
    |   $ echo $(echo $BASHPID)
    |   29617
    |   $ ble-measure 'var=$(< sig.h)'
    |   $ echo $(echo $BASHPID)
    |   29810
    |
    | bash-5.2
    |
    |    205.423 usec/eval: ble/util/readfile var sig.h (x500)
    |    205.131 usec/eval: ble/util/readfile var sig.h (x500)
    |    204.201 usec/eval: ble/util/readfile var sig.h (x500)
    |     29.551 usec/eval: var=$(< sig.h) (x5000)
    |     29.339 usec/eval: var=$(< sig.h) (x5000)
    |     29.491 usec/eval: var=$(< sig.h) (x5000)
    |     29.623 usec/eval: var=$(< sig.h) (x5000)
    |     29.535 usec/eval: var=$(< sig.h) (x5000)
    |
    |   $ echo $(echo $BASHPID)
    |   29985
    |   $ ble-measure 'var=$(< sig.h)'
    |   $ echo $(echo $BASHPID)
    |   30010

    現在の実装よりも圧倒的に高速である。但し、現在の実装と比べて問題があるとす
    れば改行を保持する事ができないという事である。

    うーん。readfile の仕様として自動的に末尾の連続改行は一つにまとめ、改行がな
    い時は改行を加えるという事にしても良いのかもしれない。と思ったが、
    test-util.sh に末尾改行を保持する事を要請するコードが存在している。

    後、互換性を考えると末尾の連続改行については未規定という様にしないと、古い
    version で逆に末尾改行を除去するのに逆に処理を追加しなければならなくなる。

    色々試してはみた物の速度的にも mapfile と比べてそれほど違うという訳でもない
    様な気がしてきた。そもそも readfile の時点でそんなに遅い訳でもない。という
    事を考えると、わざわざ改行が消えてしまう $(<) を使う必要はない様な気がする。

  * Makefile: 単なる git clone & make install でちゃんとインストールできる様にしたい [#D1655]
    https://github.com/Bash-it/bash-it/pull/1884#issuecomment-922615431

    特に --recursive をユーザーが指定しなかった時。
    現在の実装だと contrib が存在しなかった場合には一回の make だけだと
    contrib 以下のインストールするべきファイルが認識されずにインストールされない。
    contrib を checkout した時には改めてそれを読み直す様にさせる必要がある。

    うーん。これは GNUmakefile を contrib/.git に依存させれば良いのでは?
    という気がする。但し、何か変な事が起こるかもしれないので、
    何回か手元で実行して確認する必要がある。

    うーん。駄目だ最初からやり直してはくれない。実際に Makefile が書き換えられ
    る事がないと駄目という事だろうか。contrib の方に .mk を作成してそれを読み込
    む様にしなければならないのだろうか。取り敢えずその様に実験してみる事にする。

  * prompt: do not evaluate PROMPT_COMMAND for subprompts [#D1654]

    #D1654 で観察していて気づいたが現在のコードだと subprompt に対しても
    PROMPT_COMMAND を実行している。それは何だか変なので subprompt に対しては
    PROMPT_COMMAND は実行しない様に修正する。

    これは後で ble-0.3 にも適用したいので commit を分ける事にする。

  * vi: ? や / が動かなくなっている [#D1653]

    * 表示が滅茶苦茶になってしまう。
    * そもそもプロンプトも表示されていない

    一方で nsearch で入力させる機能はちゃんと動いている。両者で何かが違うという
    事だろうか。→と思ったら nsearch は read -ep を使っていたのだった。

    昔は確かに動いていた筈なので先ずは bisect する所から始めるべきの気がする。
    手動 bisect の方法について調べながら実行する事にする。
    手動 bisect の結果以下が問題の commit であると判明した。

    | commit cf8d94930af5a57e7ae9309a16eca7fc3e3479ad (refs/bisect/bad)
    | Author: Koichi Murase <myoga.murase@gmail.com>
    | Date:   Mon Jun 7 12:13:56 2021 +0900
    |
    |     prompt: track dependencies and detect changes

    プロンプト計算に失敗しているという事だろう。

    うーん。大きな変更すぎて原因はコードを見ても分からない。
    恐らく補助プロンプト関係で何か不整合が起きているという事。
    例えば prompt update ではスキップしているのに描画の際には考慮に入っている等。

    うーん。rps1, status を無効にしてみたがそれでも問題が発生する。

    * そもそも ps1 自体表示されていない。
      _ble_edit_PS1 は値としてはちゃんと ble/prompt/update の中から見えている。

      うーん。_ble_prompt_ps1 の更新は prompt_ps1 を参照している筈。それなのに
      subprompt の時と prompt の時で解析結果が異なる。subprompt の時には空の結
      果になってしまっている。何故?

      そもそも ble/prompt/unit:_ble_prompt_ps1/update が呼び出されていない。
      うーん。ohashref が literal 0 になってしまっている。

    * そもそもプロンプトを一切表示しない場合でも表示が乱れてしまっている。
      panel の高さ計算でミスしている可能性? 例えば復元した時に不整合が生じている等。
      というか subprompt に入る段階でも既に何だか変な事になっている。

    分かった。_ble_prompt_ps1_data の形式が変わったのに vi.sh の中での
    _ble_prompt_ps1_data の初期値をそれに合わせて変更するのを忘れていた。
    古い _ble_prompt_ps1_data の初期値が更新済みのデータとして解釈されて
    prompt の再計算が行われないまま誤ったデータとして座標計算などが行われていた。
    →この初期値の形式を修正するだけで全て動く様になった。

  * decode: 巨大 inputrc の翻訳内容をキャッシュする [#D1652]
    https://github.com/Bash-it/bash-it/pull/1884#issuecomment-923489130

    /etc/inputrc{,.keys} が大量に設定を行っている為に初期化が物凄く遅い問題に
    ついて。これは bash の既定の binding に対する cmap cache だけではなくて、
    前回の ble.sh 実行時の cmap cache も保持する事で解決する様な気もする。と
    いうか寧ろ前回の ble.sh 実行時の状態を使って cmap cache を保持するべきの
    気もする。

    [現状]

    現在どの様にキャッシュしているか確認する。

    例えば decode.readline.50108.vi-insert.txt 等に対して保存されている。これ
    に対してユーザーが保存した物も付け加えるのはどうだろうか。と思ったが
    emacs, vi-insert, vi-command で分けて保存しているのはどういう事だろうか。
    うーん。emacs/vi-insert/vi-command の三組で ble.sh の keybinding の状態が
    定まる。という事を思うと、ユーザーの inputrc の状態を保存するとしてもやは
    り三組を記録する必要がある。そして、それらの保存されたファイルと現在の状
    態に相違がない時に限り保存された keybinding の状態を復元するという振る舞
    いにする。

    --noinputrc で分岐している部分を確認する。noinputrc が指定されている時に
    は以下の変数に値を設定している。これらの変数に値が設定されていない時に限
    り現在の状態が読み取られる。

      _ble_builtin_bind_inputrc_done=noinputrc

        これは ble/builtin/bind/initialize-inputrc で参照される。ユーザーの
        inputrc を読み取る関数。

      _ble_builtin_bind_user_settings_loaded=noinputrc

        これは現在の bind -vetc の出力を元に keybinding を設定する関数
        ble/builtin/bind/read-user-settings 及び
        ble/builtin/bind/.reconstruct-user-settings で処理される。

    うーん。この .reconstruct-user-settings の中で呼び出している各ステップで
    どれだけ時間がかかっているのかを計測するのが先ずはする事の気がする。もし
    かすると bottleneck を見誤っているかもしれない。

    実際に時間を計測してみると、比較対象と現在の状態の両方を gawk に入力する
    為に集めるので 0.04s かかっている。gawk は 0.016s で終わっている。その後
    の ble-bind で 0.77s 消費している。

    [修正]

    * ok: 入力情報を集める部分については恐らく設定の量に依存しないし、入力情報
      が前回と一致しているかどうかというのを判定するのにまた時間がかかるだろう
      から、キャッシュの同一性の判定は gawk で処理した後に行うべきの気がする。

    * done: 後段の最も時間がかかっている部分について内容を確認する。bind -m xxx
      'xxx' というのが約200行続いている。これについてキャッシュできないか考える
      べきなのだろう。この時点での内容を何処かに保存しておいて…

      % うーん。そもそも初期化の順序がどうなっているのか分からない。この関数の
      % 呼び出しが初期化時の物であれば、この時点での keymap の状態は標準の状態
      % になっていると考えられるので、"$settings" の内容だけでこれを eval した
      % 後の状態が確定するのでキャッシュを読み込んで終わりにする事ができる。一
      % 方で、別の場所から呼び出された時には、更に別の設定が keymap に加えられ
      % ている可能性もあるので、不用意にキャッシュする事はできない。
      %
      % →という事を考えると初期化時の呼び出しの時だけキャッシュする様に、呼び
      %   出し元から特別な opts を指定する等して区別しなければならない。
      %
      % もう一つの事はユーザー設定をキャッシュする為には emacs.sh 及び vi.sh を
      % 読み込まなければならないという事である。そうすると keymap の遅延読み込
      % みが全く為されなくなり意味がない。
      %
      % * うーん。bind の遅延には対応していたのだったか。もし bind の遅延に対応
      %   していたとすると更に話はややこしくなる。遅延した物を最後にひとつにま
      %   とめてその上でキャッシュするという様な仕組みにする必要が出てくる。然
      %   し、それは複雑すぎる様に思われる。
      %
      %   →うーん。遅延されている。という事を考えると 0.7s かかっているのは実
      %   際の ble-bind ではなくて、それをキャッシュする段階でかかっている時間
      %   という事になる。
      %
      %   というかその前にそもそも遅延がどの段階で実装されているのかを確認する
      %   必要がある→うーん。内部関数の ble-decode-key/bind の呼び出しがキャッ
      %   シュされている。この関数は decode 済みの keys 値と実際のコマンド名
      %   (ble/widget/xxxx など) を受け取っている。という事を考えると、時間がか
      %   かっているのは decode の部分なのだろう。
      %
      % * 元の標準設定が切り替わった時にはどうするのか。その時にもキャッシュを
      %   更新しなければならない。

      どうも時間がかかっているのは bind -m xxx yyy の yyy に含まれる keyseq
      -> keys への翻訳の様に思われる。keymap は最初は初期化されていないと思わ
      れるので、翻訳結果は全て ble-decode-key/bind の中でキャッシュされる。そ
      のキャッシュ結果を何処かに保存しておけば良いという事になるのではないか。

      翻訳過程をキャッシュしているので cmap 及び rlfunc 表の更新だけを気にし
      ていればキャッシュの一貫性は保てる。

      確認: 本当に初回呼び出しでは全ての keymap が未登録状態か? →実際にそうなっ
      ている事を確認した。その条件が満たされている時にのみキャッシュを利用する
      事にする。

      取り敢えず実装した。動作確認した。inputrc を編集した時にちゃんと更新され
      る事も確認した。

    * done: 情報を集める箇所で ble/util/cat を3回実行している。これは readfile
      か何かに置き換えるべきなのではないか。
      →readfile に置き換えた。

    * done: というか reconstruct のパイプを assign で分解したら 0.12s から
      0.06s に短くなった。パイプは分解した方が良いのか…。

      →分解した。

2021-09-21

  * edit: set-mark 及び history-search-{for,back}ward を nmap で bind しようとしている [#D1651]
    https://github.com/Bash-it/bash-it/pull/1884

    これも結局は openSUSE の /etc/inputrc.keys が設定しようとしている設定である。
    或いはもしかすると bash-it のどれかの plugin が同様に何か設定しようとしてい
    る可能性もある。

    うーん。set-mark については単純に v と同一視してしまうのが良い気がする。

    一方で、history-search-{for,back}ward に関しては微妙である。

    a motion 的に実装するというのが一つの案だったが、history-search は opts に
      応じて現在の文字列を置き換える様に動作したり或いは実際に履歴を遡ったり振
      る舞いが変わる。前者の時には編集コマンドとして動作するし、後者の場合には
      移動コマンドとして動作する。どの様に実装するべきかは一定しない。

      x 各場合に対して適切に振る舞いを変更するのも面倒だし、

      x 更に、nsearch map の修正はしなくて良いのかという問題まで出てくる。つま
        り、nmap から呼び出しているのだとすれば jk で移動できる様にするべきなの
        ではないかという事になる。現状の設定では普通の文字列を入力したら普通に
        抜けて通常の文字入力をする設定になっている。

      よく考えたら opts については bind 経由だと何も指定できないので特定の opts
      である事を想定して history-search を nmap 上で動かしても良いのではないか??

    b うーん。vi_imap に一旦抜けてから実行してしまうというのが一つの手である。
      この場合の懸念は勝手に imap に移行した事によってユーザーに混乱を来さない
      のかという事である。

      然し nmap 専用に実装するとすると、実装の複雑さを考えると実装する価値が本
      当にあるのか怪しいし、更に振る舞いの複雑さを考えるとそもそもユーザーがちゃ
      んと使えるのかというのも怪しい。特に、bind で変な設定をした時にだけ利用で
      きる物なのでユーザーが使い方に慣れてくるという事は期待し難い。そう考える
      と、nmap 上で motion/edit として実装する方が余程混乱を来す様に思われる。

      そう考えると、imap に移行して通常の history-search として振る舞わせる方が
      良い様に思われる。

    うーん。実は history-isearch については直接束縛する様になっている。
    history-isearch は唯単に履歴項目を移動するだけなので問題ないという事なのだ
    ろう。

    うーん。振る舞いを固定してしまえば普通に edit として振る舞わせて良い気がす
    る。と思ったが、vi_imap, emacs の方で動作を履歴移動に変更しているので、やは
    り履歴移動として実装する。うーん。そうなると実は history-isearch と同様に修
    正無しで nsearch を実装してしまっても良いのではという気がしてくる。

    と思ったが、確認してみると nsearch を完了する時に eolfix が必要だし、また検
    索開始時もカーソルを一文字ずらす必要がある様な気がする。然し抜ける時にカー
    ソルが移動するとなると直感と異なる動作になる可能性もある。

    a うーん。一つの案は history-search の opts として新しく nmap を追加して、
      更に、history-search の選択範囲の抽出も nmap に依存する様に書き換える。

      →opts に設定する事にするとユーザーが自分で ble-bind した時に指定し忘れる
      事になる気がするので、直接 _ble_decode_keymap を参照して動作を決定する事
      にした。

      vi_nmap 及びその他の vi コマンドモードの中にいる時には、検索文字列を決定
      する時と一致時のカーソル位置を設定する時にカーソル位置の補正を行う事にし
      た。

    実装した。見た感じちゃんと動いている。

  * main: work around self-modifying PROMPT_COMMAND by bash-preexec (reported by cornfeedhobo) [#D1650]
    https://github.com/Bash-it/bash-it/pull/1884

    % preexec が動かないと言っている。うーん。そもそも PROMPT_COMMAND の内容が向
    % こうとこちらで異なる。こちらで色々試したが再現しない。ちゃんと
    % PROMPT_COMMAND には __bp_* が含まれているし、実際に preexec(), precmd() を
    % 定義すると期待通りに呼び出されている。
    %
    % preexec で lambda 経由の呼び出しになる様に無理やり設定した所、どうやら問
    % 題を発見した。コマンドを実行する度に preexec, precmd の処理がどんどん追加
    % されていく。調べてみると、bash-preexec は PROMPT_COMMAND に自身が含まれて
    % いない時、自身を其処に無理やり追加する様である。通常であれば
    % PROMPT_COMMAND がそれで修正されて問題は起こらなくなるが、ble.sh が
    % PROMPT_COMMAND を復元してしまう為に毎回処理が追加されるという事になってい
    % る。

    結局 cornfeedhobo は

      source bash_it.sh
      source ble.sh

    と bashrc に書いていた様だ。ble.sh の推奨する使い方からは外れているし、また
    blesh.plugin.bash を使って読み込む場合とも異なる。なかなか再現できなかった
    理由はこれだった。"minimal setup" としか言わなくて具体的な説明を一切しない
    のだから駄目である。minimal setup と言っても色々あるだろうに。

    [修正]

    これに関してはどうやら PROMPT_COMMAND の変更がちゃんと反映されればループ
    が停止する様であるから、PROMPT_COMMAND の変更をちゃんと記録するようにする。
    現在の実装だと lambda の関数本体に直接 PROMPT_COMMAND を記録しているが、
    やはり変数に記録する事にする。重複して記録されて上書きされて無限ループに
    なるのを防ぐ為に、配列にして lambda には配列添字を記録する事にする。

    取り敢えず実装して動作確認もした。

  * contra oldbug: どうも新しい c2w が問題を起こしている [#D1649]

    一番怪しいのは幅の自動判定である → 取り敢えず char_width_version を別の値
    に設定すればずれは生じない事を確認した。最悪の場合には既定値を適当に設定す
    る事にすれば良い。

    % contra では問題は発生しない。という事は受信時の処理で何かがずれているという
    % 事だろうか。というより contra も DSR(6) に対応した筈なのに反応していないの
    % は何かと思ったら、実はそもそも最新版の contra に入れ替えていなかった。
    % 2020-10 の contra を使っていた。contra を差し替えたら問題が消えてしまった。
    %
    % つまり screen と contra の不整合によって行がずれていただけという事だろうか。
    % 取り敢えずこれは無視する事にする。

    どうも Linux 上で動かしている時には問題は起こらないが、Cygwin 上で動かして
    いると問題が生じる様である。screen / contra で発生する。contra, mintty,
    screen / mintty では発生しない。うーん。tmux / contra でも発生しない。

    screen で C-a C-a C-a C-a で一旦別の window に行って戻ってくると内容が変わっ
    ている。つまり、これは screen の中の端末状態と contra の端末状態がずれてい
    るという問題である。特に、screen に於いて変な濁点のような物が行末で出力され
    ていて、contra は改行していると思っていて、screen は改行していないと思って
    いる気がする。改めて座標計算を弄って調整する必要がある気がする。

    どうやら問題の文字を出力すると発生するという事は確かだが不思議な現象が発生
    している。問題の文字を出力しない様に ble.sh を修正すると、次の一回は未だ問
    題が再現するが、それ以降は再現しなくなる。どういう事だろうか。。うーん。こ
    れは単に画面上に問題の文字が残っていて既存の文字の振る舞いを見出していると
    いう事の気がする。

    また CPR を要求しなくても問題が発生しているので、これは DSR や CPR の問題で
    はなくて純粋に文字列を出力した時の振る舞いが問題になっている。

    うーん。0x3099 が問題の文字である。もしかすると行頭で 0x3099 を実行するとカー
    ソルが前の位置に移動してしまうという事なのかもしれない。[] で囲んで出力する
    様に修正したら問題なく動く様になった。

    * char_width_{mode=auto,version=auto} とすると重複して要求が走ってしまう。
      要求を省略する事はできないか。一つの方法は test-terminal.buff (旧
      update.buff) を呼び出す前に未だ処理中であれば test-terminal.buff を呼び出
      さないという物。というか、test-terminal.buff の側で処理中かどうかを検出す
      れば良い気がする。

      取り敢えず DSR を送った回数を記録しておいて、同じ数だけ CPR を受信した時
      点で処理完了という事にする様に修正した。

      動作確認もしておきたい。先ずは VoidLinux の各端末で version 判定できてい
      るか確認する。OK. urxvt, st は version=13.0 で gnome-terminal は
      version=14.0 になった。Fedora の上で実行した urxvt は 11.0 になった。ちゃ
      んと区別できている様だ。

    x 2021-09-26 と思ったら auto が1度処理されると二度と処理されない。

      そもそも request が送信されていない気がする。
      →これは簡単なミスだった。修正した。

  * cmap: home/end が openSUSE で効かない (reported by cornfeedhobo) [#D1648]
    https://web.libera.chat/?channel=#bash-it

    home/end が効かない。これもまた openSUSE の問題の可能性はある。
    これは /etc/inputrc.keys の以下の行が原因であった。

    https://github.com/openSUSE/aaa_base/blob/master/files/etc/inputrc.keys#L233-L234

    そもそも find/select は terminfo にも存在しないし、terminfo を参照している
    だけでは判定する事は不可能である。つまり TERM を直接見て判断しないと
    find/select を検出するのは不可能である。一方で openSUSE inputrc.keys は直接
    term を参照している。

    また openSUSE に対して問題を報告しようと思ったが、xterm 決め打ちならば 1~,
    4~ は find/select とする事に明確な問題がある訳でもない様な気がする。問題が
    発生するとすれば screen の xterm-256color emulation であるが、どうも確認し
    た感じだと手元の screen.xterm-256color と向こうの screen.xterm-256color で
    khome, kend の内容が異なる様である。openSUSE の screen は khome, kend は
    \e[H, \e[F になっているが、手元の screen.xterm-256color だと khome=\e[1~,
    kend=\e[4~ になっている。

    もう面倒なので find/select に対応する事にする。結局誰も使わないキーの様な気
    もするが、単にトラブルを避ける為に無視するキーの名前という事になる。
    →実際に openSUSE で試してみて動作する事を確認した。

2021-09-16

  * decode: failglob で cmap 初期化時にエラーになる問題 [#D1647]

    Solaris で試している時に気づいた。bashrc の中で ble-bind を実行して、cmap
    initialization が其処で走ると failglob の時に cmap cache の読み取りに失敗す
    る。

    原因は _ble_decode_csimap_kitty_u に直接 keyname が格納されていて、中でも
    '*' が悪さをしているという事だった。cache は declare -p による dump で生成
    しているので本来は quote されている筈だが、容量を節約する為に quote を外し
    ていたのが原因だった (kitty_u 以外は整数なので quote の必要はなかった)。

  * edit: stdout.off で stderr だけ suppress という案について (motivated by rashil2000) [#D1646]
    https://github.com/akinomyoga/ble.sh/issues/133#issuecomment-910543950

    試してみたら普通に動く様である。つまり bash は stderr にしか物を出力しない。
    他の環境でも同様に動くか確かめてから適用する事にする。

    * Cygwin: OK
    * Void Linux: OK
    * Ubuntu: OK
    * Solaris: OK
    * Haiku: OK
    * Minux: OK
    * BSD: OK

    うーん。置き換えてしまって問題ない気がする。

2021-09-15

  * canvas: c2w の再設計 [#D1645]

    幅の計算は端末によって全然異なる。

    更に UAX 11 は可也適当で実際にこれに完全に準拠するという訳には行かない。
    多くの端末は wcwidth を参照している。一部の端末は wcswidth を参照するとし
    ている。これらの関数が内部で一体どの様なアルゴリズムを用いているか不明で
    ある。そもそも locale によっても異なるし、システムによっても異なるかもし
    れない。wcwidth のデータベースが一体何処で管理されているのかも分からない。
    もし特定の文字の幅について変更の必要があるという判断に至ったら何処に要求
    を出せば良いのかすら不明瞭であるし、例えだしたとしてもそれが末端まで波及
    するのかどうかも不明である。それらを管理している人たちがちゃんと端末の専
    門家であるのかというのも怪しい。wcwidth が整数値を返す事からこれは主に端
    末の為の関数の様に思われるから wcwidth のデータベースは TWG が少なくとも
    端末に詳しい人が管理するべきなのである。

    [これまでに分かった事のまとめ] Ref #D1619

    * UAX 11 によればこれが指定するのは実際の幅ではなくて、その文字が属する言
      語の典型的な幅なのであって、例えば制御文字について幅2 や A が与えられて
      いたとしてもその文字自体が本当に幅2 や A に割り当てられた幅を持つという
      訳ではないという事。

      結局 UAX 11 は well-defined ではないのである。

    * Fedora 31 の wcwidth を参照すると、これは Unicode 11.0 を元にしている様に
      見える。また A の文字は幅 1 としている。Cn (未使用) については -1 を返す。
      Cc, Cs, Zl, Zp についても -1 を返す。但し例外として NUL は 0 になる。Mn,
      Me, Cf は基本的に 0 を返す。以下に掲げる通り Cf の一部は例外として 1 を返
      す。

      00ad       wcwidth=1 width(eaw=3,gencat=Cf)=0 SHY(soft-hyphen)
      0600..0605 wcwidth=1 width(eaw=1,gencat=Cf)=0 アラブの数字らしい。何故Cfなのかは謎
      06dd       wcwidth=1 width(eaw=1,gencat=Cf)=0 ARABIC END OF AYAH (アラビア語?)
      070f       wcwidth=1 width(eaw=1,gencat=Cf)=0 SYRIAC ABBREVIATION MARK (シリア短縮記号?)
      08e2       wcwidth=1 width(eaw=1,gencat=Cf)=0 ARABIC DISPUTED END OF AYAH (アラビア語)
      110bd      wcwidth=1 width(eaw=1,gencat=Cf)=0 KAITHI NUMBER SIGN
      110cd      wcwidth=1 width(eaw=1,gencat=Cf)=0 KAITHI NUMBER SIGN ABOVE

      他の文字については基本的に UAX 11 に従った幅になっているが、以下の3つの範
      囲に関しては例外として UAX 11 とは異なる幅になっている。

      1160..11ff wcwidth=0 width(eaw=1,gencat=Lo)=1 ハングル字母 (160字)
      3248..324f wcwidth=2 width(eaw=3,gencat=No)=1 囲み文字10-80 (8字)
      4dc0..4dff wcwidth=2 width(eaw=1,gencat=So)=1 易経記号 (6字)

    [実装]

    大体様相が分かったので c2w の新しい実装を構築する事にする。現在の実装と
    形式を変更する必要があるかもしれない。現在は条件式を使って簡単に判定で
    きる所までは絞り込んでその後で二分法に持ち込んでいる。

    1 そうではなくて最初に孤立している文字は先に判定する。ASCIIもテーブルで
      直接判定する。
    2 code >> 8 を使ってすぐに判定できる物はその場で返すそれ以外の物につい
      ては次のステップで使う二分探索テーブルの範囲を指定する。
    3 二分探索で絞り込み。

    という具合にするのが良い気がする。

    * done: 問題点は、code>>8 を実行したとしてもUnicode の範囲を考えると 4352
      の区間が存在するという事。だからと言って2分木や patricia を実装するのも大
      袈裟な気がする。何より2分木や patricia は遅い。code>>16, code>>8 の2段構
      成にするという手も考えられるが、0,1,2,3,E,F,10 が使われているので、結局
      1792要素は存在するという事。もう一つの手は code>>8 で加速するのは BMP だ
      けにして、それ以外のものは初めから2分探索を実行するという事。うーん。見て
      みたが SMP も結構細かいので SMP も最初の判定に含めて良い気がする。

      →これについては最終的には BMP, SMP に関しては c>>8 にして、それ以降の物
      については c>>12 で振り分ける事にした。

    * done: wcwidth が -1 を返す様な物に対してはどの様に対応するべきだろうか。
      例えば、一つの方法は他の端末がやっている様に幅 1 を適当に割り当てるという
      物。また別の方法は EastAsianWidth に従って割り当てるという物。或いはまた
      別の方法としては -1 は保持した儘でテーブルを参照する時に補正する方法。然
      し補正する為には EastAsianWidth 特性の値もちゃんと覚えて置かなければなら
      ない…等と考えていくとやはり EastAsianWidth と GeneralCategory を別々に管
      理する必要があるのではないかという疑惑も出てくる。

      % うーん。取り敢えずは EastAsianWidth だけでもスクリプトから参照できる様
      % にするべきではないか。GeneralCategory のテーブルサイズも巨大になりそう
      % ではあるがそれは仕方がないと思って諦めるか。。

      →これに関しては -1 を返す代わりに -1 -2 -3 で、幅1, 幅2, 幅A を区別でき
      る様にする事にした。

    * reject: もう一つ気になるのは、EastAsianWidth, GeneralCategory から幅に対
      応付ける方法には他の可能性はないのかという事である。Unicode は中途半端に
      しか指定していないので何らかの方法を決める必要があるが、その方法は固定で
      良いのだろうか。そうではなくて、スクリプトの側でより柔軟に設定できる様に
      した方が良いという事はないのだろうか。

      やはりただでさえ EastAsianWidth だけで巨大なのに GeneralCategory まで入れ
      ると大変な事になるので、これは却下する事にする。ライブラリとしてユーザー
      が使える様に GeneralCategory のテーブルを作成するという可能性は未だ残って
      はいる。

    * done: もう一つの問題は Unicode version 依存性をどの様に取り扱うかという事。
      全ての Unicode version について情報を纏めて一つのテーブルにするという手と、
      Unicode の version 毎にテーブルを用意するという手がある。

      ? wcwidth 用の例外措置が必要になる文字の集合も version によって異なるかも
        しれず色々面倒である。例外処置について Unicode version 毎に管理するか、
        或いは、一括で管理するか。或いは端末ごとに管理する必要があるか。うーん。
        wcwidth はシステム等に依存するだろうと思われるので Unicode 由来のデータ
        に統合するのは始末が悪い様に思われる。やはり例外は別枠で管理するべきで、
        その折には Unicode version 等と紐付けて管理するのは悪手である。それより
        は locale/system 毎に管理するべきである。

        →wcwidth が Unicode とずれている分については別枠で管理するのが良い。少
        なくとも Unicode の version と紐付けて管理するのは悪手である。

      version 毎のテーブルにするか或いは一つのテーブルに統合するかは実際に両方
      の方式でテーブルを作成してサイズについて比較しかない様な気がする。実の所、
      サイズとしてどちらの方が小さくなるのか予想が付かない。

      取り敢えずテーブルを作成するコードを書くことにする。どうせなのでもう C++
      で書いてしまう事にしようか? →うーん。formatting などが色々面倒なのでやは
      り gawk で実装したのを適当に加工するのが良い気がしてきた。

      - 全てを統合したファイルのサイズは 426行 45KB である。単一だと 283行 36KB
        である。こうなって来るとやはり統合した物を埋め込むべきの様に思われる。

    * ok: 以下は例外処理をしていた物だが新しい c2w でもちゃんと半角になっている
      だろうか?

      [0x303F]=1 # 半角スペース

      →実際に ble/unicode/c2w で確認した所、周辺は2になっているのに関わらず
      0x303F は 1 になっているという事が確認できた。なのでこの例外処理はもはや
      不要である。

    [追加実装]

    * done: char_width_version 自動判定

      そもそも現在の設定インターフェイスで良いのかという疑問もある。他に、
      wcwidth=-1 になるが UAX 11 では幅を指定している物の取り扱いをどうするか
      (_ble_unicode_c2w_invalid) の振る舞いの制御等も設定対象の可能性の一つである。

      自動判定に関しては実は UnicodeMapping を参照すれば良いという気がする。
      target の version で切り替わる文字を使って判定する。然し、端末が微妙に変な
      振る舞いをしていたりする場合にはこの方法だと一番近い version を判定できなかっ
      たりする可能性もある。例えば、undefined な文字であっても元から幅 2 である事
      を予想できた場合には古い Unicode version であったとしても初めから 2 を返し
      ていた等という事が考えられる。色々考えると robust に判定する方法は無い様な
      気がする。更に絵文字の可能性がある文字については判定に使う事ができない。

      何れにしても取り敢えず UnicodeMapping を拾ってみる事にする。

      * 4
      * 9
      * 10
      * 12

      よく考えたら 負→正 になった等だと wcwidth < 0 に対して 1 を割り当てている
      端末での判定ができなくなる。という事を考えると、幅2の文字を使って判定するべ
      きなのではないか。

      * 42 ... ver1 以降で 2
      * 30 ... ver2 以降で 2
      * 45 ... ver3 以降で 2
      * 63* ... ver4 以降で 1, ver9 以降で 2
      * 33 ... ver5 以降で 1
      * 15 ... ver6 で 1, ver7 以降で 0 (元々-1)
      * 41 ... ver7 以降で 0 (元々2)
      * 24 ... ver8 以降で 0 (元々-1)
      * 63* ... ver9 以降で 2 (他に56も同様)
      * 43 ... ver10 以降で 2
      * 44 ... ver11 以降で 2
      * 57 ... ver12 以降で 2
      * 47 ... ver13 以降で 2
      * 46 ... ver14 以降で 2

      63 は emoji　だった。63 になっている全ての範囲の先頭文字について確認して、
      何れも emoji であるという事を確認した。うーん。プログラム的に確認するべきの
      気がしてきた。

      ver1 U+9FBC(40892) 龼 1->2 (-1 2 2 2 2 2 2 2 2 2 2 2 2 2 2)
      ver2 U+9FC4(40900) 鿄 1->2 (-1 -1 2 2 2 2 2 2 2 2 2 2 2 2 2)
      ver3 U+31B8(12728) NA 1->2 (-1 -1 -1 2 2 2 2 2 2 2 2 2 2 2 2)
      ver4 判別不能
      ver5 U+D7B0(55216) ힰ 2->1 (-1 -1 2 2 2 1 1 1 1 1 1 1 1 1 1)
      ver6 判別不能
      ver7 U+3099(12441) NA 2->1 (2 2 2 2 2 2 2 0 0 0 0 0 0 0 0)
      ver8 U+9FCD(40909) 鿍 1->2 (-1 -1 2 2 2 2 2 -2 2 2 2 2 2 2 2) うーん。古い ver でも幅1に注意
      ver9 U+1F93B(129339) NA 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2 1)
      ver10 U+312E(12590) ㄮ 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2 2)
      ver11 U+312F(12591) ㄯ 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2 2)
      ver12 U+16FE2(94178) 翢 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2 2)
      ver13 U+32FF(13055) ㋿ 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2 2)
      ver14 U+31BB(12731) ㆻ 1->2 (-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 2  2)
      ver15 U+9FFD(40957) 鿽 1->2 (-1 -1 2  2  2  2  2  -2 -2 -2 -2 -2 -2 -2 -2 2)

      実装した。設定を直接上書きする方式に変更する事にした。例えば
      char_width_mode=auto にしていると、幅の判定を終えた時には
      char_width_mode=west か char_width_mode=east に書き換える。同様にして
      char_width_version についても決定した値で上書きする事にする。

    * done: blerc, wiki: bleopt char_width_version

      対応した。

2021-09-14

  * prompt: $? is not properly set in ${PS1@P} (reported by nihilismus) [#D1644]
    https://github.com/akinomyoga/ble.sh/issues/136

    setexit をしていなかった。

    他にも何か影響があったりするだろうか。例えば、その他のシェル設定は復元しな
    くても良いのだろうか。PROMPT_COMMAND の前後では何か調整していた気がする…
    と思って改めて確認した所 PROMPT_COMMAND は単に PS1 を復元していただけだった。
    その他の設定は待避した儘になっている。なので気にしなくて良い。

2021-09-11

  * global: resolve leak variables [#D1643]

    - fixed: CHARS=([0]="13")
    - fixed: git_base=/home/murase/.mwg/src/ble.sh
    - fixed: git_base_dir=/home/murase/.mwg/src/ble.sh/.git
    - fixed: nhash=$'10:10,10,10,337,10,10,10:justify=\r,\\q{lib/vim-airline}'
    - fixed: wattr_buff=([0]="5:72057594037930244")
    - fixed: wattr_g=d
    - fixed: wattr_pos=101
    - fixed: _data=([2]="")

    - BASH_REMATCH: これは bleopt 等をユーザーから実行すると書き換わってしまう。
      然し、local BASH_REMATCH を実行しようにも readonly でエラーになってしまう。
      書き換わるのは問題ないと諦めるしかない。

      read, bind, history, etc. 等では保存復元した方が良いかもしれない。
      →read, exit, bind, history, trap で保存復元する様にした。

      他に初期化時にも問題になるかもしれない…が、そもそも soruce xxx としたら
      中で BASH_REMATCH を使っている可能性は排除できないので、これは気にしなく
      て良い気がする。

2021-09-08

  * width: char_width_mode を変えた時にキャッシュがクリアされていない気がする (reported by Barbarossa93) [#D1642]
    https://github.com/akinomyoga/ble.sh/issues/135

  * syntax: "\"" が正しくエスケープ着色されない [#D1641]
    対応した。

2021-09-01

  * util (bleopt, bind): fix interfaces [#D1640]

    * bleopt の unknown option のエラーメッセージでオプション名が '-c' 固定になっている。

    * 2021-07-20 bind --help の exit status が 1 になっている。2 であるべき。

  * complete: 古い bash における -D, -I の対応 [#D1639]

    どうやら -D, -I はそれぞれ内部的には _DefaultCmD_, _InitialWorD_ という名
    前のコマンドに対する補完として実装されている様である。だとすれば、古い bash
    の version で -D, -I に対応するとしたらこれらの単語に対して検査すれば良いの
    ではないか。

    というか現在の実装で古い bash ではどの様に振る舞うのだったか。
    確認した。 -I に関しては version を確認して処理している。
    -D に関しては complete -p -D が成功するかどうかで動作を変更している。

  * 2021-05-03 edit: support bash-5.2 READLINE_ARGUMENT [#D1638]

    5.2 新機能: READLINE_ARGUMENT: 調べてみると引数が存在している時にのみ定義さ
    れる様である。また今気づいた事だが -x 属性が入っている。他の READLINE_* も
    全て同様である。よく考えてみれば、bind -x で外部コマンドを呼び出す事もある
    のだから -x 属性が入っていないと困る。

  * 2021-08-23 mandb: manpath コマンドを使っても MANPATH は得られる [#D1637]

    また、MANPATH に空パスが含まれている場合にはそれは標準の manpath と解釈される様だ。

    manpath の emulation についてちゃんと考える。

    MANPATH が設定されていない時または空パスが含まれている時は/etc/man_db.conf
    及び ~/.manpath を読み取る必要がある。MANDATORY_MANPATH 及び MANPATH_MAP を
    解釈すれば良いだろう。更に PATH 中の bin を share/man に置き換えてディレク
    トリが存在するかどうか確認する。

    →その様に実装した。

    * MANDB_MAP についても実装するべきなのではないか。というか MANDB_MAP とは何
      か。説明を見ると MANPATH から CATPATH への対応表の様だが、CATPATH とは何
      か。検索してみると整形済みの物をキャッシュしておく場所の様だ。つまり、cat
      するだけで説明が読める様な状態でファイルを保存しておく場所という事なのだ
      ろう。

      実際に指定されている /var/cache/man の下を見ると index.db という 500kB の
      ファイルが一個あるだけで、cat するだけという状態ではない様な気がするが、
      然しデータベースとして記録しているのだろうと思う。

      何れにしてもこれは ble.sh の関知する所ではない。気にしない。

  * auto-complete: idle.sleep で異なる時計を参照していた事による無限ループ (reported by rashil2000) [#D1636]
    https://github.com/akinomyoga/ble.sh/issues/133

    msys2 で auto-complete が特定の状況で実行されないという報告だったが、自分の
    手元で complete_timeout_auto= にしてみたらどうやら無限ループになっている気
    がする。調べてみると idle.sleep しているのに sleep していない。と思ったら、
    どうやら異なる時計を参照していた為に msleep が skip されて、無限に msleep
    の要求をし続けている状態になっていた。

    これを直したらちゃんと補完候補が表示される様になった。

    然しこれについては過去に修正した様な気がする。過去に修正した時の修正漏れか
    或いは逆方向に間違えて修正したか。再度確認する必要がある。

    * ble/complete/auto-menu.idle の #D1597 での修正

      53dd018e で他の箇所を類似の問題により isleep から sleep に切り替えている。
      #D1597 である。一方で今回問題になっている箇所は最初から sleep だった様だ。
      #D1597 に詳しく説明が書かれている。

      改めて実装を確認する。auto-menu.idle は _idle_clock_start を元にしてい
      る。_idle_clock_start は ble/util/idle.clock を元にしている。
      ble/util/idle.clock は色々実装を切り替えているので環境によって異なる。ま
      た、idle.sleep もまた ble/util/idle.clock を元にしている。

    * 今回の ble/complete/auto-complete.idle に関しては、唯単に idle.sleep を要
      求しているだけの様に見える。但し、最後にユーザー入力があって以降の経過時
      間を考慮に入れる為に ble_util_idle_elapsed を用いている。この
      ble_util_idle_elapsed は _ble_util_idle_sclock-_idle_sclock_start を元に
      していて、更にこれらは ble/util/idle/.sleep で積算される。

      うーん。つまり、ble_util_idle_elapsed を参照する限りは isleep を使う必要
      があるという事。一方で auto-complete の delay を処理するのは isleep に基
      づくべきか sleep に基づくべきかという疑問もある。

    * また macOS の 100% も関係しているかもしれない。報告によると履歴のロードに
      関係しているという事だが、nawk が走っている間ずっと CPU が動いているとい
      う状態になっている可能性もある。と思ったがそうでもなかった。そもそも履歴
      の初期化では sleep は行っていない。

2021-08-30

  * edit: command-help が効かなくなっている [#D1635]

    どうやら以下の commit で external-command を書き換えた時に、内部で使用して
    いる変数名 command と command-help で使用している変数名が被ってしまって問題
    が起こっている様だ。

    7b63c60d src/edit.sh (Koichi Murase     2021-05-06 16:04:39 +0900 8755)   local command=$1

    一旦は command-help の側でコマンド名を他の変数に待避する様に書き換えてみた
    が、うーん。そもそも external-command は呼び出し元の変数名に影響が無い様に
    特別な変数名を使うべきである。

  * README: やはり ble.sh の読み方を与えるべきかもしれない [#D1634]
    https://www.youtube.com/watch?v=YS1vxEhd2Pc

    動画の最初で読み方に戸惑いが見られる。やはり発音しやすい発音として blesh を
    呈示しておいた方が良い様な気がしてきた。別に正しい読み方がある訳でもないし、
    寧ろ個人的には bee-elle-yee-dot-ess-eightch と読んでいるが、やはり膾炙する
    のは発音しやすい読み方だろう。

    或いは両方提示する。

      /blɛʃ/ or /biːɛliː dɑt ɛseɪtʃ/

    うーん。後者は態々 IPA で書く迄の事もなく、くどい感じがする。

    少しずつ push した方が GitHub の suggestion に現れる様なので、
    試みに今日から一日に 1 commit ずつ push する事にする。check の意味も兼ねて。

    他の README に関連する編集も纏めて一つの commit にする事にする。

    * README: @oc1024 がリンク切れになっている。やはり質問しているとは言え他の
      人をどんどん README に追加していくのは出過ぎた真似だろうか。huesche の件
      が偲ばれる。然し一方でこちらが正体を当てた事から oc1024 ではなくてちゃん
      と capezotte という名前にアカウントを変更したのかもしれない。何れにしても
      capezotte に変えるべきだろうと思われる。

    * README: Wiki -> wiki?

      Wiki ではなくて wiki なのではないか。README の他にも文頭でないのに Wiki と
      書いている箇所があるかもしれない。

      改めて検索してみると日本語の記事だと wiki を Wiki と書いている様である。つ
      まり、Wiki と capitalize するのは日本語の習慣という事なのだろう。

    * README: 各機能の無効化について記述する
      https://github.com/akinomyoga/ble.sh/issues/134

  * 2021-08-19 st: insert で CSI 4h を送るなど色々変な key sequence を送ってくる [#D1633]

    他に以下の物が見られる。

      CSI L (C-insert)
      CSI J (C-end)

    他にも色々ありそうなので一つ一つ既に実装されている物と見比べて調べる必要が
    ある。幾つか追加した。ESC[M は他とかちあっている。

2021-08-19

  * st: unknown csi error message (reported by Shahabaz-Bagwan) [#D1632]
    https://github.com/akinomyoga/ble.sh/issues/132

    * 先ず st は DA2 に応答しない。DA1 に対して CSI ?6c を返答する。

      何れにしても古い st が一掃されるまでは CSI ?6c を st と解釈するなどの処置
      で良い気がする。

      と思ったら何と st は TERM に st-256color を設定する様だ。なので先にこれを
      見て st と判明したならば DA2 は送信しなくて良い。modifyOtherKeys に関して
      も現在の st の構造を見る限りは将来的に実装すると思われない。完全に無効化
      するという事で良い気がする。

    * ok: 然し報告によると stderr が slave の stdrr に書き込まれると言う…。不
      思議な事である。と思って改めて報告を見たら違った。エラーメッセージは起動
      元の terminal に表示されているのだった。つまりこれはそもそも期待通りの振
      る舞いであり問題はない様に思われる。その旨説明する。

    * ok: st で prompt_status_line を有効にしていると座標計算がずれるどうやらこ
      れは雷絵文字の幅計算がずれているのが原因の様である。これはまあ仕方の無い
      ことである。もしちゃんと対応するのだとしたらまずは st をちゃんと検出でき
      る様にしなければならない。

    2021-08-26 minux になっている箇所がある。
    2021-08-30 #D1633 で一緒に直した。

2021-07-19

  * edit: support TMOUT for session timeout [#D1631]

    またそれと並行して session TMOUT についても実装したい。うーん。振る舞いにつ
    いて確認する。恐らく最後にコマンドを実行してからどれだけ時間が経ったのかで
    timeout を実行するという仕組みになっている。これはどの様に実装すれば良いの
    だろうか。

    動作確認をして見た所、新しいコマンドを実行したタイミングというよりはやはり
    accept をしたタイミング、或いは newline を挿入したタイミングでリセットされ
    るという事の気がする。

    例えば insert-newline に於いてログアウト時刻をセットするという仕組みにする
    のが良い気がする。ログアウト時刻が設定されていたらそれまで sleep するという
    事にする? 然し、それだと十分に長い timeout にしてたくさんコマンドを実行する
    と、実行したコマンドの数だけ待ちタスクが増えて大変な事になってしまう。ユー
    ザー入力または sleep で時間を測るというタスクが必要になる気がする。または、
    後で外部からタスクの待ち時間を書き換える仕組みが必要になる気がする。

    うーん。外部から既存のタスクの待ち時間を書き換える仕組みにするのが良い。

    タスク番号を指定して書き換えられる様にする。その為にはタスク登録時に登録し
    たタスクの番号が分かる様にするべきである。

    ? それから bash-4.0 未満で idle.push が使えない場合にはどうするのか…? これ
      は諦めるしかない様な気がする。bash-3.2 以下では TMOUT は動かない。

      # 或いは bash-3.2 以下でも read -t 0 もしくは select に対応する様な物を
      # loadable builtin 等で用意できればそれはそれで良いのかもしれないが、実の
      # ところライセンスなどの問題から loadable builtin で実装するかどうかは悩
      # ましい所である。代わりに外部コマンドとして実装するという手もあるが。何
      # れにしてもこれは散々別の場所で議論してきた所であるから今ここでは議論し
      # ない。

    ? どのタイミングでタイマーをリセットするのが良いのか? insert-newline で実行
      しようかと考えていたが、insert-newline はコマンド実行前に実施される。本来
      はコマンド実行後にプロンプトが最初に表示された時点から実行するべきの様に
      思われる。

      うーん。という事を考えると POSTEXEC で実行するべきだろうか。また、この場
      合には一番最初のプロンプトに対して timeout が設定されないので、ble-attach
      に際しても同様に設定をするべきの気がする。

      POSTEXEC だと複数回のコマンドが実行される時に余分に timeout が再計算され
      る事になる。それよりは /.end 辺りで設定した方が良いのではないかという気も
      する。うーん。

      或いは、insert-newline で何か行番号等を更新して、PS1 の表示時にその行番号
      が変化していたら更新するという具合にするのが良い気がする。

    取り敢えず実装した。動いている。表示を多少調整した。

  * global: "TMOUT: readonly variable" というエラーメッセージが表示される (reported by farmerbobathan) [#D1630]
    https://github.com/akinomyoga/ble.sh/issues/129

    問題のエラーメッセージは ble-edit/io/check-stderr から出てきている。

    これは /etc/profile.d/ 辺りに readonly TMOUT=xxxx 等という設定が書き込まれ
    ているサーバーが存在する事があってその時に発生する。うーん。正直な所そうい
    う設定を行うサーバーの方が悪いとしか言いようがない。然し勝手に読み込まれる
    のはユーザーとしては仕方がない。


    a TMOUT に変な値が設定されている時には -t 巨大な数 というのを指定して誤魔化
      すしかない。一方で、毎回 TMOUT の値をチェックするのは効率が悪い。

    b 或いは常に -t 巨大な数 を指定するという手もあるのかもしれないが、それだと
      read を実行する度に alart/select が設定される事になって効率が悪い。

    c 或いは TMOUT に有限の値を設定されている時に限り -t 巨大な数 を設定すると
      いう手もあるのかもしれない。

    d 或いはユーザー空間に入る時に TMOUT が readonly になっていないか確認して、
      TMOUT が readonly になっていたら workaround の必要性を示す変数を設定する
      という手がある。取り敢えず TMOUT が readonly の時にだけ振る舞いを変えるの
      だとすればこの方針を貫くのが良い。

    e 或いは enter する時に TMOUT を未設定にするという手もあるのだろうか? と思っ
      たが、それだと session timeout としての TMOUT が動かなくなってしまうので
      駄目→と思ったが、確認してみた所、そもそも session timeout としての TMOUT
      は ble.sh ではちゃんと動作していなかった。となると、TMOUT は自前で実装す
      る必要がある。自前で実装するのだとすれば ble.sh 内部では TMOUT= になる様にして、
      read を実行する箇所で TMOUT= を実行する事はない様にすれば良いのである。

      _ble_builtin_read_tmout_wa=(-t 巨大な数) 等でも適当に設定してこれを read
      の引数に指定する事にする。

    [修正] e の方針で実装した。取り敢えず動いている。

  * history: ble-attach に使ったコマンド履歴が欠けている。履歴番号にもずれが生じている [#D1629]
    Ref #D1120

    bashrc から attach した時には欠けているコマンドは存在しない様だ。

    % source ble.sh で新しく読み込んだ時にも欠けているコマンドは発生しない。と
    % 思ったらこれは気の所為だった。

    うーん。然し ble-attach を実行した時点ではちゃんと履歴が登録されている筈だ
    から後になって履歴が変化していると考えるべきだろうか→やはり確認してみた所、
    一旦履歴項目が追加されているのにも関わらずその後で削除されている様に見える。

    履歴を初期化する時点での最後の項目はどうなっているのかについて確認する必要がある気がする。

    分かった。これは ble/builtin/history/is-empty で history -p を使っている為
    に履歴項目の数が減少している。この関数では BASH_SUBSHELL を参照して
    subshell の中にいる時には対策をしない様にしているが、実は subshell の中であっ
    ても履歴項目が減る時には減るし、後で履歴データを参照する場合にはちゃんと
    subshell の中で history -p を実行しなければならない。

2021-07-13

  * 2021-06-28 main: set -Bk 等の場合に対しても対策する [#D1628]

    set -B に対してはブレース展開を使っているコードが影響を受ける。ブレース展開を使っているコードは以下で抽出する事ができる。

    $ grc '[^$]\{[^[:space:]]*,[^[:space:]]*\}' --exclude={wiki,memo,test,ext} --exclude={lib/test-\*.sh,make_command.sh}
    ./keymap/emacs.sh:21:  copy{,-forward,-backward}-{c,f,s,u}word
    ./keymap/emacs.sh:22:  copy-region{,-or}
    ./keymap/vi.sh:220:  delete-backward-{c,f,s,u}word
    ./keymap/vi.sh:221:  copy{,-forward,-backward}-{c,f,s,u}word
    ./keymap/vi.sh:222:  copy-region{,-or}
    ./keymap/vi.sh:2799:  local _ble_keymap_vi_single_command{,_overwrite}= # single-command-mode は持続させる。
    ./keymap/vi.sh:2813:  ble/util/unlocal _ble_keymap_vi_single_command{,_overwrite}
    ./lib/core-complete-def.sh:78:                  ble/complete/menu-style:{align,dense}{,-nowrap}/construct-page \
    ./lib/core-complete-def.sh:80:                  ble/complete/menu-style:desc{,-raw}/construct-page
    ./lib/vim-airline.sh:114:  for name in {a,b,c,x,y,z,error,term,warning}{,_normal,_insert,_replace,_visual,_commandline,_inactive}; do
    ./lib/vim-airline.sh:343:  for unit in _ble_lib_vim_airline_section_{a,c,z,b,y,x}; do
    ./src/benchmark.sh:231:  for n in {1,10,100,1000,10000}\*{1,2,5}; do
    ./src/decode.sh:3944:  'M&&E,A[i++]=_ble_decode_Erro|'{254,255}
    ./src/edit.sh:7793:                  ble-decode/keymap:vi_{i,n,o,x,s,c}map/define
    ./src/util.sh:2667:    builtin unset -f ble/function#advice/{before,after,around,original}:"$name" 2>/dev/null
    ./src/util.sh:4218:    ble/array#push dirs "$_ble_base"{,/contrib,/lib}
    $ grc '[^$]\{[0-9.]+\}' --exclude={wiki,memo,test,ext} --exclude={lib/test-\*.sh,make_command.sh}
    ./lib/init-bind.sh:153:  for i in {128..255} {0..127}; do
    ./src/decode.sh:3937:  'M&&E,A[i++]='{0..127}
    ./src/decode.sh:3938:  'C=C<<6|'{0..63}',--M==0&&(A[i++]=C)'
    ./src/decode.sh:3939:  'M&&E,C='{0..31}',M=1'
    ./src/decode.sh:3940:  'M&&E,C='{0..15}',M=2'
    ./src/decode.sh:3941:  'M&&E,C='{0..7}',M=3'
    ./src/decode.sh:3942:  'M&&E,C='{0..3}',M=4'
    ./src/decode.sh:3943:  'M&&E,C='{0..1}',M=5'
    ./src/decode.sh:3985:  for i in {0..255}; do

    それほど多い訳でもないが代替手段がある訳でもない様な物が多く含まれる。
    うーん。これも ble.sh の内部では解除するオプションとするべきの気がする。

    set -k に対しては bleopt a=b 等が影響を受ける。他にも影響を受ける物は多く存
    在するかもしれない。何れにしてもこのオプションは非現実的である様に思われる
    のでやはり ble.sh 内部では解除する事としたい。

  * kitty, fzf: modifyOtherKeys で問題が生じている (reported by Nudin) [#D1627]
    https://github.com/akinomyoga/ble.sh/issues/126

    うーん。fzf が modifyOtherKeys で動かなくなっている。
    というか補完全般で問題が生じるのだろうという気がする。

    x 何故か知らないがまた kitty で動かなくなっている。うーん試して見た所、いつ
      の間にかに \e[>4;0m ですら効かなくなっている様だ。\e[>4m としなければなら
      ない。もう面倒なので kitty の時だけ異なる sequence を出力する様に修正する。

      以前は確かに修正したと思ったのだが…。確認すると以下で動作する事を確認している。
      ということはまた kitty の振る舞いが変わったという事である。
      https://github.com/akinomyoga/ble.sh/issues/110#issuecomment-841839605

      取り敢えず修正した。動作確認した。OK と思う。

  * kitty: keypad enter が変なシーケンスで送られてくる (reported by Nudin) [#D1626]
    https://github.com/akinomyoga/ble.sh/issues/127

    取り敢えず以下に挙げられているキーの番号を kitty 専用に判定する事にした。
    https://sw.kovidgoyal.net/kitty/keyboard-protocol.html#functional-key-definitions

  * compat: terminal dnkl/foot は DA2 で 010801 などの文字列を返すようだ (reported by GorrillaRibs) [#D1625]
    https://github.com/akinomyoga/ble.sh/issues/128

    これが DA2 の判定で8進数と解釈されてしまって問題が発生している。
    escape sequence に含まれる数字は全て明示的に10進数で解釈するべきである。

    因みに dnkl/foot は DA3 で FOOT という文字列を返すそうだ。

    * dnkl/foot を認識する様にした。
    * CSI の解釈で 0 が前置されていても良い様に書き直した。
      一部の CSI については既に対策されていたが今回全てに対して処理する事にした。
    * DA2 の解析はまた別の箇所で行われていた。これも対処する事にした。
    * ble/canvas/trace の諸々の制御機能についても対策した。
    * SGR の解析部分 (ble/color/read-sgrspec) は既に対処済みだった

    https://github.com/akinomyoga/ble.sh/issues/128#issuecomment-878670622

    追加修正。10# で後ろに何も数字が続いていないと 5.1 ではエラーになる。
    これは修正した。多分大丈夫。

2021-07-12

  * emacs モードで vi-bword 使う (requested by SolarAquarion) [#D1624]
    https://github.com/akinomyoga/ble.sh/issues/125

    調べると vi-bword vi-Bword があって、内部的にはそれぞれ vword uword として
    いる。それなら edit.sh に既に定義されている vword, uword を代わりに呼び出し
    たら良いのではないか、と考えたが、vword は定義されていない。実装を具体的に
    観察すると単純に単語決定に使う文字集合を edit.sh に引き込めば良いという訳で
    もない。

    観察する限りでは別に emacs mode でこの vi-bword 等を呼び出しても特に問題は
    生じない様にも見える。念の為どの変数を参照していてどの変数が emacs mode で
    期待している値になっているのかについて確認する。

    単語単位の移動は ble/widget/vi-command/forward-word.impl 等で実行されている。
    特別な動作をするかどうかは渡された引数 flag で判定している。取り敢えず flag
    が空だと仮定するとそのまま ble/widget/vi-command/exclusive-goto.impl
    "$index" "$flag" "$reg" が呼び出される。そしてそのまま exclusive-range.impl
    に渡される。ble/keymap:vi/needs-eol-fix "$dst" && ((dst--)) が呼び出されて、
    移動して、 ble/keymap:vi/adjust-command-mode が呼び出さる。

    * 最初の flag に関しては ble/keymap:vi/get-arg 経由で _ble_keymap_vi_reg の
      値を読み取っている。これは get-arg を呼び出していれば clear されている筈。
      一方で、set -o emacs 等を実行した時にちゃんとクリアされるだろうか。少なく
      とも vi-command/accept-line の中では clear-arg が呼び出されている。

      vi_imap の中にいる時にちゃんと clear されているのかというのは気になる。一
      応 ble/widget/vi_nmap/.insert-mode を呼び出す時にはちゃんと
      ble/keymap:vi/clear-arg が事前に呼び出される様に書いてある様である (見落
      としはあるかもしれないが)。

      emacs-editing-mode 経由で切り替えた時にちゃんと arg が clear されるのかど
      うか。見た所は全く考慮に入れていない様に見える。

      a reject: keymap に attach する時に clear する? 然し emacs 側で始末するの
        も変である。本来独立に実装されているべきである。

      b という事を考えると detach 時に処理できる様にするべき? 然しその場合には
        新しく __detach__ という特別キーも定義する必要が出てくる。もし定義した
        とすると、それを処理するのは何処で行うべきだろうか。
        ble/decode/reset-default-keymap を弄れば良い様な気もするが、初回呼び出
        しの際には既定で 'emacs' が代入されている為、detach が無意味に呼び出さ
        れてしまう気がする。それは変だ。

        a 或いは初期値を emacs 以外 (例えば safe) などにするという手もあるだろ
          うか。

        b 或いは初期値は空でも良いのかもしれない。例え emacs であっても初期化な
          しに使える訳ではない筈だから、現状の実装で必ず初期化は実行されている
          と見做すべきである様に思われる。

        c 或いは safe を代入しておくのでも良いのかもしれない。然し確認してみた
          所、safe であっても初期化なしには使えない様である。なので結局
          _ble_decode_keymap の初期値は空文字列で良いのではないかという気がする。

      もっと全然別の方法で clear される事を保証する事はできないのか。

      c 例えば、emacs-editing-mode widget 自体に clear-arg を呼び出すコードを付
        加しておくなど。

      d それよりは change-editing-mode hook でも定義しておくのが良い様な気もす
        る。然し、それだと結局 __detach__ の劣化版にしかならないので、それぐら
        いならば b の __detach__ に対応するべきの気がする。

      今の所 b が最有力の対処方法である。

    ble/keymap:vi/needs-eol-fix については現在の keymap が vi[on]map でなければ
    false になるので記にしなくて良い。

    ble/keymap:vi/adjust-command-mode については

    * _ble_keymap_vi_search_activate が非空の時に何か処理している。

      これは様々の検索で使われている気がする。例えば単語検索等の一致で使われて
      いる? この状態で vi_imap に入ったりすると値が残る気がする。と思ったが別に
      値は代入されていなかった。改めてどの状況でクリアされるか確認する。

    * _ble_edit_mark_active == vi_search の時にも何か処理している。

      これはどうやら $_ble_keymap_vi_search_activate 経由で代入される様だ。

    * _ble_keymap_vi_search_matched が何か有限の整数値を持っている時にも処理がある。

      その他は特に何も無いように見える。これらの変数についてそれぞれどう設定さ
      れてどう clear されるのか確認する。

    うーん。上記に関しては .insert-mode の中で
    ble/keymap:vi/search/clear-matched を呼び出す事にした。また、emacs mode に
    対しては clear-arg の処理に際して同時に clear-matched も呼び出す事にした。

    [動作確認]

    o 取り敢えず __detach__ は実装して思い通りに動く事を確認した。

    o また vi-bword が動作する事も確認した。テストが面倒なのでこれ以上の細かい
      動作確認は省略する。

2021-07-08

  * nullglob が勝手に on になってしまう現象 (reported by Lun4m) [#D1623]
    https://github.com/akinomyoga/ble.sh/issues/123

    nullglob を保存復元している ble/complete/util/eval-pathname-expansion が怪
    しいと考えたが実際に動作を確認してみるとどうやらこの関数の外側で状態が書き
    換わっている様である。また、補完の最中に設定が書き換わる事に違いない。と思っ
    たが分かった…。148 で抜ける時に dtor を実行せずに eval-pathname-expansion
    を抜けていた。修正した。

2021-07-04

  * bash-completion (_find): error message (reported by oc1024) [#D1622]
    https://github.com/akinomyoga/ble.sh/issues/121
    https://github.com/scop/bash-completion/issues/509
    https://github.com/scop/bash-completion/commit/f1ddf810e4ee6693acb9fab1be1794586aa111a0

    これはどうしようもない。bash-completion が悪い。

  * ble-0.3: bashrc で bind '"\e[D": backward-char' を実行した時にエラーメッセージ [#D1621]
    https://github.com/akinomyoga/ble.sh/issues/122#issuecomment-872690396

2021-06-19

  * term: どうも GNOME terminal が terminal identification を変更した様だ [#D1620]

    65;600x;1 になっている。

    | 6cd4713c5 src/vteseq.cc (2018-03-27) int const version = (VTE_MAJOR_VERSION * 100 + VTE_MINOR_VERSION) * 100 + VTE_MICRO_VERSION;
    | 6cd4713c5 src/vteseq.cc (2018-03-27) reply(seq, VTE_REPLY_DECDA2R, {65, version, 1});
    |
    | fde88ef7f src/vteseq.cc (2018-03-27) if (version != NULL) {
    | fde88ef7f src/vteseq.cc (2018-03-27)         for (i = 0; version[i] != NULL; i++) {
    | fde88ef7f src/vteseq.cc (2018-03-27)                 ver = ver * 100;
    | fde88ef7f src/vteseq.cc (2018-03-27)                 ver += atol(version[i]);
    | fde88ef7f src/vteseq.cc (2018-03-27)         }
    | fde88ef7f src/vteseq.cc (2018-03-27)         g_strfreev(version);
    | fde88ef7f src/vteseq.cc (2018-03-27) }
    | fde88ef7f src/vteseq.cc (2018-03-27) g_snprintf(buf, sizeof (buf), _VTE_CAP_ESC "[>65;%ld;0c", ver);
    |
    | Behdad Esfahbod
    | 3b22bcc86 src/vteseq.c (2009-01-06) g_snprintf(buf, sizeof (buf), _VTE_CAP_ESC "[>1;%ld;0c", ver);
    |
    | f3d79059c src/vteseq.c (2006-02-10) version = g_strsplit(VERSION, ".", 0);
    | f3d79059c src/vteseq.c (2006-02-10) if (version != NULL) {
    | f3d79059c src/vteseq.c (2006-02-10)         for (i = 0; version[i] != NULL; i++) {
    | f3d79059c src/vteseq.c (2006-02-10)                 ver = ver * 100;
    | f3d79059c src/vteseq.c (2006-02-10)                 ver += atol(version[i]);
    | f3d79059c src/vteseq.c (2006-02-10)         }
    | f3d79059c src/vteseq.c (2006-02-10)         g_strfreev(version);
    | f3d79059c src/vteseq.c (2006-02-10) }
    | f3d79059c src/vteseq.c (2006-02-10)   ret = g_strdup_printf(_VTE_CAP_ESC "[>1;%ld;0c", ver);
    |
    | Nalin Dahyabhai
    | ddad9e00e src/vte.c (2003-06-27) ret = g_strdup_printf(_VTE_CAP_ESC "[>1;%ld;0c", ver);
    |
    | 3c6d81bf0 src/vte.c (2002-08-22) version = g_strsplit(VERSION, ".", 0);
    | 3c6d81bf0 src/vte.c (2002-08-22) if (version != NULL) {
    | 3c6d81bf0 src/vte.c (2002-08-22)         for (i = 0; version[i] != NULL; i++) {
    | 3c6d81bf0 src/vte.c (2002-08-22)                 ver = ver * 100;
    | 3c6d81bf0 src/vte.c (2002-08-22)                 ver += atol(version[i]);
    | 3c6d81bf0 src/vte.c (2002-08-22)         }
    | 3c6d81bf0 src/vte.c (2002-08-22)         g_strfreev(version);
    | 3c6d81bf0 src/vte.c (2002-08-22) }
    | 3c6d81bf0 src/vte.c (2002-08-22) ret = g_strdup_printf("1;%ld;0c", ver);
    |
    | commit 3c6d81bf06becda3f9ab005c7310b2343588115e
    | Author: Nalin Dahyabhai <nalin@src.gnome.org>
    | Date:   Thu Aug 22 23:27:31 2002 +0000
    |
    |     * src/vte.c: Implement send-primary/secondary-device-attributes.  Bind
    |             shift+insert to "paste PRIMARY".  Guard against NULL window/icon title
    |             when telling the child app what they are.

    この歴史を観察すると一番最初に vte に実装された時 2002-08 から 1;version;0 であったが、
    2018-03 に 65;version;0 に変更された様である。VERSION は何処で定義されているのだろうか。

    | 現在の version は meson.build の中に定義されている。
    |
    |   project(
    |     'vte',
    |     ['c', 'cpp'],
    |     version: '0.65.0',
    |
    | meson に移行したのは 7566ad673 (2019-04-14) である。この時は 0.57.0
    |
    |   7566ad673 (Christian Persch 2019-04-14 21:11:43 +0200  20)   version: '0.57.0',
    |
    | それより前は configure.ac に定義されていた様だ。
    |
    |   m4_define([version_major],0)
    |   m4_define([version_minor],57)
    |   m4_define([version_micro],0)
    |
    | fde88ef7f の時点での version は 0.53.0 の様だ
    |
    |   137e16630 configure.in (Behdad Esfahbod      2010-06-30 15:27:30 -0400   1) m4_define([version_major],0)
    |   6f330cc1a configure.ac (Christian Persch     2018-03-12 21:44:43 +0100   2) m4_define([version_minor],53)
    |   b4b2eb2ce configure.ac (Christian Persch     2018-03-05 21:58:12 +0100   3) m4_define([version_micro],0)

    従って 1;5300;0 から 65;5300;1 に移行したという事。

    * 他の端末についても確認してみると konsole は 0;115;0 に固定である。
      (src/Vt102Emulation.cpp Vt102Emulation::reportSecondaryAttributes)

2021-06-18

  * 2021-02-05 canvas: 絵文字シーケンスや grapheme cluster (motivated by huresche) [#D1619]

    今まで対応は不可能と思って割り切って考えてきたが実は可能なのではないかとい
    う気がしてきた。ゼロ幅の文字が存在しても特に変な事は発生しない気がする。注
    意しなければならない事としては dirty 範囲を広げなければならないという事と、
    文字の途中で SGR 等を挿入したりする事はできないという事。

    一方で端末の側でもこれに対応している必要があるのでテストという観点からは微
    妙。contra は対応していないし screen も恐らく対応していない。tmux はどうな
    のだろうか。

    tmux はこれに対応しているターミナルがないから未だ対応しないという事を言って
    いる。一番最近では 2020-05 https://github.com/tmux/tmux/issues/1605

    2021-05-30 書記素で動かないという話が来た。
    https://github.com/akinomyoga/ble.sh/issues/117

    というか逆に動くアプリケーションは一体どれ程あるというのだろうか。振る舞い
    を調べてみると、bash は ハート+VS に関してはそれぞれ一文字と解釈している事
    によってたまたま良い感じに振る舞っている。

    a 対応方法の一つは grapheme cluster を一つの私用文字に置き換えて取り扱う方法。
      この方法を取ればカーソル移動や文字の削除等は自然にできる様になる。

      後は入力時と出力時に変換を実行すれば良い。入力時に関しては文字挿入時に変
      換を実行すれば良い。出力時 (コマンド実行時) には逆方向に変換すれば良い。
      入力時に関しては ble-edit/content/reset で変換を行えば良いのではないかと
      いう気がする。

      問題は履歴検索である様な気がする。検索する時には文字列を変換してから検索
      する必要がある。その時にカーソル位置なども変換しなければならない。更に、
      検索して一致が見つかった時にまたカーソル位置を復元する必要がある。

      ? 此処で問題になるのが検索に於いて書記素の部分的な一致を許すのかという事。
        本来の文字列に復元して検索するとすると中途半端な位置で一致する事になる
        気がする。

      * 或いは逆に履歴の方を変換して保持するという手もあるだろうか。然し、その
        時に問題になるのは履歴の全項目について変換を実行しなければならないので
        重いという事。更に awk で処理するにしても私用文字と書記素クラスタとの対
        応表をどうやって bash と共有するのかという問題が生じる。

        a 既に登録されている物に関してはその codepoint を利用したいし、まだ登録
          されていない物がある場合には新しい項目を bash に反映させる必要がある。
          この方法を採用すると可也面倒な処理が必要になる。

        b 或いは、予め対応表を固定しておくというのも手であるが ZWJ sequence 等
          も考えると無限にある。ZWJ sequence は対応しないというのも手である。然
          し将来的な事を考えると中途半端な手法で無駄に複雑にはしたくない。

      * vim のバイト数による移動に関しては注意が必要になる。私用領域の代替文字
        のバイト数で換算される事になる。この方法を採用した場合にはその程度の不
        都合については我慢する必要がある。

    b また別の対応方法は emoji sequence をそのまま文字列として保持して、textmap
      やカーソル移動、一文字削除 etc の側で正しく処理するという事。然し、エラー
      着色なども考えると中途半端な箇所で SGR を挟む訳にも行かないので着色や構文
      解析のレベルでも grapheme cluster を意識する必要が出てくる。

      * 全ての widget について注意深く grapheme clusters に対応する必要がある。
        カーソル移動、一文字削除、etc. 然し、これらに関しては実は codepoint 単
        位の操作になってもまあ許せるのではないだろうか。

        ? readline について: 然し、readline は上手にその辺りを処理できている様
          にも見える。ただ、これは OS の mb 実装が上手に面倒を見てくれているの
          だという見方もできる。恐らく "一文字進む" とかそう言った処理を行う時
          に grapheme cluster 単位で処理してくれているという事なのではあるまい
          か。

          然し、そうすると "一文字を表現するのに要するバイト数" の過程に狂いが
          生じるのではないかという気もする。その辺りがどうなっているのかは気に
          なる所である。

        Readline が Unicode の要求通りの動作を実行できているという事を考えると
        codepoint 単位の操作というのは余り良くないかもしれない。一方で zsh はそ
        の辺りを適当に処理する事ができている様な気もする。

      * 再描画に際しては dirty range の端点が書記素クラスタの内部の中途半端な位
        置に発生すると厄介な事になるので拡張する必要がある。

      * コマンド実行や履歴検索に関しては特に細かい事を気にする必要はない。然し、
        カーソル位置の設定に関しては依然として注意が必要である。

      * カーソル移動について。

        a 移動する度に位置を cluster boundary に調整する必要があるのではないか。

          x よく考えたら、調整するにしてもどちらの端に調整するのかという問題が
          ある。例えば、左から右に一文字進んでそれが cluter の内部にある時に、
          また左端に調整してしまうとカーソルを移動する事ができなくなってしまう。

        b 或いはカーソル移動をする時には (例えば文字数で)、一文字ずつ進んでいか
          ないと cluster を認識した移動にはならない。

        c 調整する方向を前にいた位置を参考にして決めるという実装も可能かもしれ
          ないがその様な ad hoc な方法で自然な動作になるのかは不明である。

        d そもそも調整する必要があるのかという話。カーソル移動は文字単位で良い
          のではないか。しかしそうすると書記素の真ん中に文字を新しく挿入した時
          の処理が非自明になる。取り敢えず textmap の配置再計算に際しては前後の
          cluster 境界まで dirty range を拡張して処理する必要がある。その他の構
          文解析などの dirty range も同様である。という事を考えれば dirty range
          拡張は別に textmap で行う必要はなくて、reset の段階で実行しておけば良
          い。

        うーん。この手法で行くとしたら d の方針が現実的である。カーソル移動の文
        字を書記素単位に変更するのはあらゆる所に影響が出るので大変である。

      * textmap に於いて grapheme cluster をどの様に取り扱うのかというのは非自
        明である。先ず dirty range を grapheme cluster boundary にまで拡張する。
        その上で grapheme cluster の2文字目以降には0幅を割り当てる。といった具
        合になるのだろうか。座標から文字を特定しようとした時にどのような振る舞
        いになるのかも非自明である。

        着色に関しても textmap に於いて土台の文字の方に全て記録する様にして、0
        幅になった物には空文字列を設定する事にすれば問題は発生しなくなる。其処
        まで考えていくと実は構文解析ですら中途半端になっても大丈夫なのではない
        だろうか。つまり textmap に対する修正だけで全部行ける?

        残る問題はゼロ幅の文字があっても座標決定等で無限ループなどにならないか
        という事。

    [実装]

    grapheme clusters について真面目に考える前に UAX を改めてまとめるのが先の気
    がする。UAX は最初から順に読んでいったが実のところ重要なのは 3.1.1 だけだっ
    た。他は全て御託である。

    * done: Grapheme_Cluster_Break 表の作成

      さて、実装するに当たって一番最初にする必要があるのは、
      Grapheme_Cluster_Break プロパティの表を入手するという事。
      http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
      にあるそうだ。これを加工して使える様にする。加工するスクリプトは何処に置
      くのが良いだろうか。emoji_version の時にはどうしたろうかと思って 3f6c9b9
      を確認したがテーブルの生成に使ったスクリプトは見当たらない。
      git@github.com:akinomyoga/unidata にも何もなかった。と思ったが
      emoji_version の開発 commit は d1f8c27 だった。そして生成スクリプトは
      make_command.sh の update-emoji-database にあった。./make_command.sh のリ
      ストの一番下にあった所為か見逃していた。

      どの様な表現にするのが最も良いだろうか。単一のコードポイントで或る
      Grapheme_Cluster_Break を持っている時には単に配列に格納するのが良い気がす
      る。それ以外の範囲で値を持っている物に関してはどの様にするのが良いだろう
      か。何しろ様々な値を取る可能性があるので、単に境界を並べた配列から検索す
      るだけでは済まない。一つの方法は、範囲の先頭については直接配列に値を入れ
      る事にする。二分探索で範囲の先頭を求めて、その後で配列を参照して値を取り
      出す。というのが良い気がする。取り敢えずどの様な分布になっているのかを確
      認する必要がある気がする。

      * 孤立 Property は 664 個存在した。更に範囲先頭も含める。範囲は 487 である。
        配列項目の数は 664+487*2 = 1618 になる。

        因みに二個連続迄を孤立と見做す事にすると 980 個の孤立があり、範囲は 304
        にまで減少する。配列項目の数は 980 + 304*2 = 1588 になる。

        3個連続迄直接登録にすると 1157 個の直接登録と、239 の範囲登録がある。配
        列項目の数は 1157+239*2 = 1635 になり大きさが多少増える。4個の時は
        1321/191 になり、配列の大きさは 1703 になり益々増える。5個の時は、
        1426/173/1772。10個にすると 2067/80/2217 という具合に増えていく。例えば
        配列項目を最小の2倍まで許すとすると、実は可也の物を直接登録しても良いの
        ではないかという気がしてくる。50にしたら15818/18なので駄目。30でも
        14291/33なので駄目。20にしたら2676/45 なので丁度よいぐらい。

        然しまあ速度をそんなに重視しても仕方がない気がする。取り敢えず最小であ
        る 2 個連続までを直接登録する事にする。

      * \p{Extended_Pictographic} に対する判定も追加しなければならない。という
        か\p{Extended_Pictographic} は Grapheme_Cluster_Break の細分になってい
        るのだろうか。つまり、全て Other だと良い。Extended_Pictographic が変な
        性質を持っているとは思い難い。何か持っているとしても Regional_Indicator
        程度であると期待したい。

        うーん。Extended_Pictographic 属性は emoji-data.txt に含まれている様だ。
        これも emoji version 毎に管理するべきなのだろうか。取り敢えずの実装とし
        ては最新版を使う事にする。

        調べた限りに於いては Extended_Pictographic は全て Other の様である。な
        ので何も気にしなくて良い。取り敢えず最初の boundary を特定するコードに
        ついては書いた。

    * done: find-previous-boundary のテストも追加したい。

      →テストを追加してみたところ見事にミスが見つかった。やはりテストをつけて
      よかった。然し、まあ結局はテストを追加したような気もする。更に
      find-previous に関してもテストを追加するべき気がする。テストを追加した。
      やはり色々ミスが見つかった。そもそもデータの生成にも誤りが見つかった。

    * done: Unicode のページにテストケースが見つかった。沢山ある。これらを
      import する。行数が沢山あるので圧縮したい。→OKテストケースが 2000 行あっ
      たのを 100 行程度にまで小さくした。

      またこれらのテストケースにより間違いも発見されたのでそれを後で修正する必
      要がある。

      x 2件は CRLF の規則を変更した事による物。

      x Pictographic Extend* ZWJ Pictographic で位置の決定に失敗している気がす
        る。ZWJ:Pictographic の処理に於いて local ret を宣言してしまっていた所
        為で戻り値が反映されなくなっていたのを修正した。

      x 未だ問題が発生している。Extend を Extended と間違えていた。

      x 他はハングルに対する規則が欠けていた。

      OK これでテストも全て通る様になった。

    * ok: 次の問題は如何にして効率的に文字幅を実装するかという事である。
      うーん。効率はさておいて取り敢えず実装する事にする?

      Prepend さえ無ければ前の文字に付加していくだけで十分の筈である。絵文字で
      ない文字に Emoji_Modifier がついた時に文字の幅を変更するのかというのは謎
      である。更に Variation Selector によって幅が変化する場合についても考える
      必要がある。うーん。然し…Variation Selector で絵文字かそうかを切り替える
      という話ならば Variation Selector の値を見て幅を変更すれば良い。然しこれ
      は幅が遡って修正されるという事を意味する。やはり Grapheme_Cluster を特定
      して処理する必要があるのだろうか。然し、全ての文字について
      Grapheme_Cluster を特定して処理していたら面倒な事この上ない。ASCII だけに
      ついて処理をスキップすれば良いだろうか。日本語の文章についてはどうする?
      実は Other だけスキップする様にする事が可能だったりしないか? と思ったが、
      やはり Encoding に依存しない実装になっている限りは難しい様にも思われる。
      UTF-8 の時にだけ特別扱いするのも変な気がする。

      やはり Grapheme cluster を特定して実装する必要があるだろうか。

      * 最初の文字が非ASCIIの場合には Grapheme_cluster を特定して処理する。最初
        の要素に全ての文字を投入するというので良い気がするが、実は core の部分
        に指定しても良いのかもしれない。然し、カーソルを移動した後の操作などを
        考えるとやはり最初の要素に全ての文字を入れる様に実装しないと処理として
        一貫しない感じになる。因みにこの実装の時にはカーソル上下移動した直後に
        は、零幅文字の"後"に index を配置するべきである。

      * ASCII文字の場合には最後の文字について Grapheme extension を計算すれば十
        分である。

      処理を開始する境界の特定ができた暁にはこの手法が最も良い気がする。
      Grapheme cluster とその幅を計算する関数を実装してそれを呼び出す様にする。
      また、対応する文字列と codepoint の数も計算する様にする。xenl のない端末
      の場合に行末で Grapheme cluster を構築した時にどうなるかは謎。受信時に
      Grapheme cluster を構築してから挿入するタイプの端末ならちゃんとくっつく
      (然し timeout などで離れる)。前の行に何があるか見てくっつける実装でもくっ
      つく (その時行末が Folding とマークされている時に限りくっつく実装と関係な
      くくっつく実装とが存在しそうである)。何も考えていない端末だと離れてしまう。
      うーん。取り敢えずくっつくと思って実装しておくのが良い気がする。Grapheme
      cluster の対応まで考えたら端末は xenl にせざるを得ない気がする。

    * reject: 使わないかもしれないが実装の確認の為に next boundary を実装するの
      が良い気がする→結局より高機能な match を定義したので next boundary を個
      別に実装する必要は全くなくなった。

    * done: GraphemeClusterBreak/match という関数を実装

    * done: textmap を最初に修正する。

      * done: 取り敢えず非ASCII printable については実装した。

      * done: 次は ASCII の末尾で extend する事について考える。

      * done: variation selector について考慮に入れる。調べると U+FE0E が TPVS
        で FE0F が EPVS である。それぞれ非Emoji/Emojiの切り替えを行う。

      取り敢えずはこれで良い気がする。動作確認を先ずは行う。

    * 余談: Unicode は 11x64k の文字が原理的に存在する。bit で表現するとすれば
      88kB のデータサイズになる。50 の Property を考えるとすると 4.4MB のデータ
      サイズになる。小さいとは言えないがそれほど大きいとも言えない。然し、考え
      るに漢字などの領域は自明な値になっている筈なので容量は削減できる筈である。
      例えば、256文字ずつ組みにして考えるとすれば、最初のインデックスで選別すれ
      ば最低でも 1/10 程度には圧縮できるのではないだろうかという気がする。まあ、
      余り考えても仕方のない事かもしれないが。

    * ok: 位置から文字を特定する関数をちゃんと修正する。特にその位置の最後の文
      字に移動する様に修正したい。

      現在の ble/textmap#get-index-at の実装について確認する。基本的に f(l) <=
      x < f(u) を保つように範囲を狭めていっている。最終的に l と u の間隔が 1
      になる迄続ける。この時に l==u になる事はない。l と u は実の所境界に対応し
      ていて、f(u) は対応する文字開始位置を返す。

      例えば今 A E E E B (A, B は幅 1 で E は幅 0) という具合になっていて位置 1
      に対応する index を見つけようとすると… u=4 l=5 しか条件を満たす位置は存
      在しない。つまり、期待通りに Extend の後の位置が求められる筈。

      これについてはテストでも作成して確認するのが良い気がする。
      →OK ちゃんと動いている。

    * ok: Emoji sequence を grapheme cluster とは別に処理する必要があるか

      Emoji sequences に関してはまた別に表を保持して合成する等しなければならな
      い。Emoji sequence は incremental だろうか。つまり ABC が Emoji sequence
      であれば AB も Emoji sequence だろうか。まあ、それらの差異については気に
      しなくて良いというか、一般にはそうではないとした実装にしておくのが安全な
      気がする。何れにしても Emoji sequence の表の形式を考えておく必要がある気
      がする。

      Emoji_modifier については Grapheme cluster の考慮に入っているのだろうか。
      →確認した所、ちゃんと考慮に入っていた。うーん。然し…普通の半角文字に対
      して Emoji_Modifier が適用されていたりする場合には一体どういう事になるの
      だろうか。気になる。

      実は定義済みの Emoji seuquences は全部 Emoji_Modifer による実装で、既に
      Grapheme cluster に組み込まれているのではないかという気がしてきた。これに
      ついてはまた後で確認する事にする。

      定義済みの Emoji sequence について2文字目以降の文字種について確認する。

      $ for code in $(awk 'sub(/;.*/,"") {$1="";print}' out/data/unicode-emoji-14.0.txt |
          grep -Eo '\b[[:xdigit:]]+\b' | sort -u); do
          ble/unicode/GraphemeCluster/c2break $((16#$code)); echo $ret
        done | sort -u
      12 .. Emoji
      2 .. ZWJ
      4 .. Extend
      6 .. RI

      うーん。これだけだと Emoji が ZWJ で接続されているのかそうでないのかが分
      からない。やはりちゃんとスクリプトを書いて変換して確認する必要がある気が
      する。どう言った属性値のシーケンスが存在するのか確認する。以下の種類のシー
      ケンスが存在する。4 は単に無視して良い。1 1 1 1 というのは気になる…。他
      は全て Grapheme Cluster の形式をしている→これは単に凡例を拾っているだけ
      だった。

      seq: 0 4
      seq: 0 4 4
      seq: 12
      seq: 12 2 12
      seq: 12 2 12 2 12
      seq: 12 2 12 2 12 2 12
      seq: 12 2 12 4
      seq: 12 2 12 4 2 12
      seq: 12 2 12 4 2 12 2 12
      seq: 12 4
      seq: 12 4 2 12
      seq: 12 4 2 12 2 12 2 12 4
      seq: 12 4 2 12 2 12 4
      seq: 12 4 2 12 4
      seq: 12 4 2 12 4 2 12 2 12 4
      seq: 12 4 2 12 4 2 12 4
      seq: 12 4 4 4 4 4 4
      seq: 4
      seq: 6 6

      という訳で孤立した Extend を除き全て grapheme cluster である。なので
      emoji sequence については grapheme cluster に加えて気にする必要はない。

    * done: unqualified は既定では Emoji presentation ではなく Text presentation にする

      kitty で動作確認した所、文字によって既定で text presentation か emoji
      presentation かがまちまちの様である。うーん。どの様にするのが良いか。。
      EPVS で初めて絵文字になる物に関しては実は単に "絵文字ではない" という事に
      して良い気がする。現在の設定ではユーザーが個別に絵文字か絵文字でないか指
      定できるような設計になっていただろうか。

      というよりそもそも問題の U+2660 が既定で text か emoji かというのが規格化
      されていたりはしないのだろうか。emoji のデータベースを確認すると
      fully-qualified, unqualified 等というのがある様だ。

      うーん。端末を確認してみた所、絵文字にまともに対応しているのは kitty/vte
      系列の様であるからこれの動作に倣う事にした。他の端末の動作に関しては追々
      対応していく事にする。そして kitty/vte では unqualified は絵文字ではない
      様なのでそれに倣う事にする。

    * done: trace-text の実装。

    * done: trace の実装。

      うーん。lc は困る。基底文字だけを指定すると lc によって装飾が全て消えてし
      まう。一方で、一番最後の文字を指定したとしても、端末によっては連続してい
      ない出力に関しては前の基底文字を削除してしまうかもしれないし、またそうで
      なかったとしても Extend が余分に追加されてしまう事になる。なので、書記素
      クラスター全体を出力し直さなければならない筈だが lc (整数値) では表現でき
      ない。

      これに本当に対応しようと思ったら lc lg の組ではなくて lcs lw lg の組に拡
      張するしかない。然し、そもそも lc lg は現在ではデバグ用としてしか意味を為
      さないので其処までちゃんと対応する労力を割く必要があるかというと、ない。
      一応項目として残しておく事にする。

    * done: 制御文字を ^X 等の形に変換するのは GraphemeClusterBreak/match の側
      でやった方が良い気がする。然し本当にそうだろうか。これから match を
      trace, trace-text でも共有しようと考えている。trace, trace-text での実装
      をしてから制御文字を変換するかどうか判断するという方が良い。

    * done: 零幅文字: 完全に零幅の単一文字 (Control Character) に関してはやはり
      ASCII rep で置き換えるべきの様に思われる。これについてはまた別項目で取り
      扱うべきなのだろう。core の欠けている Extend chars に関しては台字として
      space か或いは専用の○が存在した気がする。

      trace に於いては直接出力したい。なので取り敢えず Unicode 制御文字について
      はゼロ幅で出力する事にする。

    * ok: 関数名を再考。GraphemeClusterBreak はプロパティ名である。それよりは
      ble/unicode/GraphemeCluster/* の形で様々の機能を提供するべきではないか。
      もしくは ble/unicode/grapheme-cluster/*. うーん。変数名等を考えると
      ble/unicode/GraphemeCluster/* の方が良い気がする。変数名も一緒に考え直す
      と良い。

      ある程度置き換えたがまた後で改めて考える。特に変数名を
      GraphemeClusterBreak のままにするか GraphemeCluster_Break と分けるか。うー
      ん。分けずに今のままで良い気がする。

    [修正]

    * done: kitty は fully-qualified, minimally-qualified, component については
      肌の色は幅0で髪については幅2にしている様だ。実際の Unicode の例を見ても髪
      は単一の文字で肌の色は Extend の様に見える。

    * done: screen, mlterm, terminology 辺りは unqualified も参照している気がす
      る。unqualified のテーブルも作るか、或いは、現在のテーブルを拡張して
      qualified, unqualified の区別もできる様にするか。うーん。下手にメモリ使用
      量が増えるのも否なので一つの配列で qualified/unqualified の両方に対応でき
      る様にするのが良い気がする。序に skin/hair の区別もできる様にする?

      もし unqualified も判定できる様にしようと思ったら現在の実装を変更する必要
      がある。現在は境界に +1 をして行って、奇数の値を持つ境界のみを抜き出す事
      によって emoji の範囲を取得している。然し、複数の種類の要素を区別する為に
      は、同じ方法は使えない。うーん。種類毎に bit を用意して xor して行けば、
      境界はちゃんと抜き出す事ができる。然し問題はそれが始まりの境界なのかそれ
      とも終わりの境界なのかを判定する事ができないという事にある。という事を考
      えると、始まりである事を表す marker も作った方が良いのでは。うーん。その
      様な事をするぐらいであれば、普通に始まりと終わりの bit を用意しておけば良
      いだけの気がする。

      うーん。始まりを設定する時にその属性値を別の配列に記録する事にするという
      事。また、境界を検知する為には xor で記録するという事。より良い方法はある
      だろうか。単に前回の属性値を覚えておいてそれと同じかどうかを確認するだけ
      で良いのではないか。終端に関しては何も記録しない。

      unqualified にも対応して取り敢えず試した全ての端末で絵文字の幅計算が一致
      する様になった。

    * 0x1F3FB..0x1F3FF や 0x1F202, 0x1F237 は振る舞いが異なる実装が多い。実は古
      い Unicode では属性が違ったという事だろうか。確認する必要がある気がする。
      と思って unicode.org からファイルを持って来ようとしたがどうも unicode.org
      が停止している。

      Internet Archive から GraphemeCluster について各 version をダウンロードし
      て diff して見ると破壊的変更がない訳ではない様だ。

      Unicode 6.0.0 で以下の属性が削除されている (別の属性が割り当てられた可能性もあるが確かめていない)
      -06DE          ; Extend # Me       ARABIC START OF RUB EL HIZB
      -0E30          ; Extend # Lo       THAI CHARACTER SARA A
      -0E32..0E33    ; Extend # Lo   [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM
      -0E45          ; Extend # Lo       THAI CHARACTER LAKKHANGYAO
      -0EB0          ; Extend # Lo       LAO VOWEL SIGN A
      -0EB2..0EB3    ; Extend # Lo   [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM

      うーん。見た感じ結構書き換わっている。やはり各 version について対応するべ
      きか。取り敢えず問題の 1F3FB が各 version でどうなっているか確認する。ど
      うやら 1F3FB は 9.0 で E_Modifier として導入されて 11.0 で Extend に変更
      になった様である。うーん。これは当時の規則を参照する必要があるのだろうか。

      1F202,1F237 に関しては GraphemeCluster 的には特に何もないようである。これ
      は Emoji の規格の側の取り扱いの変化だろうか。うーん。規格の各 version の
      記述を観察してみたが、1F202 は最初から一貫して unqualified である。もっと
      ちゃんと書くと 4.0 ではそもそもリストに載っていない。5.0 では
      non-fully-qualified という名前。12.0 から unqualified という名前に変更さ
      れた。という事は単に OS の locale の wcwidth が変な値を返しているという事
      なのだろうという気がする。

      実の所、1F3FB の振る舞いに関しても OS の wcwidth が怪しいのではないかとい
      う気もしてくる。

      wcwidth (C.UTF-8) の振る舞いを確認すると 1F202,1F237 は 2 を返している。
      1F3FB..1F3FF も 2 を返している。これらが変な風に振る舞う原因なのだろうか。

    * done: urxvt についても確認する
    * done: mintty についても確認する

    * fixed: 2021-06-21 複数行編集でプロンプトの末尾が消去される? rprompt 関連の可能性

      →これは grapheme cluster の対応によって発生する様になった問題の様だ。つま
      り何らかの文字列の幅計算に失敗しているという事になる。然し、プロンプト自体
      は ASCII だけで構成されている筈で幅計算に問題が発生するというのも不思議であ
      る。或いは、一緒に変更した別の部分が問題の原因になっているのかもしれない。

      もしかして改行が ^J の幅である 2 で計算されている可能性? だとすると rps1 や
      status_line は関係なくどの行でも2文字ずつ内容が削られてしまう筈である。実際
      に試してみた所、確かに rps1 や status_line がなくても問題が発生する。更にど
      の行も次の行に行く瞬間に2文字右にずれて表示されて、更に次の行の内容を入力し
      ようとすると左に2文字ずれて再描画される。何れにしても2文字のずれが生じてい
      るのは確かである。

      textmap の問題である事を確認した。開業直後の x の位置が 2 になっている。

    * UAX 11 を再確認した所、何と combining marks や nonspacing characters に関
      しては実は実際の幅に関係なく言語に応じて N, Na, W 等が割り当てられるとい
      う。なので、素直に UAX11 の表だけで文字幅を決定するのは危険という事である。

      取り敢えず grapheme clusters の中に於いて combining や nonspacing につい
      てもちゃんと文字幅を計算できる様にしたい。その為に c2w は
      combining/nonspacing に対して 0 を返す様に変更したい。基本の文字幅テーブ
      ルも他の物と同様に実装したい。と思ったが最初に下8bitを落としたテーブルで
      判定するのが妥当の気がする。SMP に関しては全体に対して適用するという事に
      する。

      | うーん。取り敢えず wcwidth が返す結果を再現するのが一つの方法の気がする。
      | General Category と UAX11 の組み合わせで再現できるだろうか。取り敢えず
      | GeneralCategory のテーブルを作成してみたが、可也サイズが大きい。然し、個
      | 別に属性を切り出すよりは良い気がするので取り敢えずこれで色々調べてみるの
      | が良い気がする。というか、実際には c2w のテーブルさえ持っていれば良いので、
      | 最終的にはこの GeneralCategory のテーブルは ble.sh には含めなくても良いの
      | かもしれない。
      |
      | さて、それぞれの category について見ていく。Mn は nonspacing mark, Mc は
      | spacing combining mark (??), Me は mark enclosing である。Cc は制御文字で
      | Cf は hyphen, ZWJ, ZWNJ 等色々。Cs は surrogate で Co は私用領域。Cn は未
      | 使用・予約文字。この中で特別な値を割り当てる必要があるのは Mn, Cc 及び一
      | 部の Cf だろうと思われる。Me は一体何だろうか。うーん。grep で見てみると
      | これらも combining の様である。Mc も combining の様な気がする。
      |
      | 0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;
      | 0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
      | 1ABE;COMBINING PARENTHESES OVERLAY;Me;0;NSM;;;;;N;;;;;
      | 20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;
      | 20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;
      | 20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;
      | 20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;
      | 20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;
      | 20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;
      | 20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;;
      | A670;COMBINING CYRILLIC TEN MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
      | A671;COMBINING CYRILLIC HUNDRED MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
      | A672;COMBINING CYRILLIC THOUSAND MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
      |
      | そうすると Mn/Mc/Me は全て combining として幅0にする? うーん。SpacingMark
      | を確認してみるとどうも Mc になっている。うーん。という事は Mc については
      | EAW による幅をそのまま与えるべきだろうか。分からないので wcwidth の結果に
      | 従うというので良い様な気もする。という事は何れにしても wcwidth を自前で再
      | 現するという試みが必要である。
      |
      | うーん。EastAsianWidth を確認してみた所、実は既に此処に General Category
      | も附記されている。単にこれを元にして幅を決定すれば良いだけなのでは?
      | EastAsianWidth 及び General Category を元にして求めた比較を実装した。
      | Mn|Me|Cf を幅 1 にして Unicode 11.0 を使うと最も差分が小さくなる。然しそ
      | れでも Cf に関しては wcwidth は 0 だったり 1 だったりまちまちの結果を返す
      | 様である。
      |
      | 2021-09-14 取り敢えず文字幅に関してはちゃんと決着を付けなければならない。
      | 改めて現状について確認する。GenCat 及び EAW を元にした幅は
      | out/data/c2w.eaw-*.txt に出力してある。このデータは range で出力している
      | ので、それぞれどの文字についてずれが発生しているのかは確認しにくい事に注
      | 意する。
      |
      | 先ずは違いを分かりやすく取り出す様に修正しなければならない。うーん。ずれ
      | のある各文字について GenCat や文字の名前について確認したいという事を考え
      | ると、C++ から EAW のデータを読んで処理する方が良いのだろうか。
      |
      | 取り敢えず時間を区切って実装することにするのが良い。先ずは形式を確認する。
      |
      | % * Co については -1 の時と 1 の時がある。
      | %
      | %   調べてみると wcwidth が 1 を返すのは以下の領域のみである。
      | %   これらに文字が割り当てられているとは思えないが…
      | %
      | %   e000..f8ff wcwidth=1 width(eaw=3 gencat=Co)=-1
      | %   f0000..ffffd wcwidth=1 width(eaw=3 gencat=Co)=-1
      | %   100000..10fffd wcwidth=1 width(eaw=3 gencat=Co)=-1
      | %
      | %   →と思ったが unassigned に誤って Co を割り当てていたのが駄目だった。
      | %   unassigned に対して Cn を指定して Cn に対して -1 を返す様にしたら、
      | %   残る Co は上の領域だけでしかも全て A であり、これは cjkwidth west と
      | %   一貫している。
      | %
      | % * wcwidth は EAW=W の領域の Co に対しても -1 を返す。なので、-1 を単純に
      | %   1 にすれば良いという訳でもない。
      |
      | * Cc に関しては NUL 以外は wcwidth で -1 になる。
      |   ble.sh では NUL は取り扱えないのでこのずれは無視して良い気がする。
      |
      |   0000 wcwidth=0 width(eaw=1,gencat=Cc)=-1
      |
      | * Cf については wcwidth は殆ど 0 を返すが一部の物について 1 を返す。
      |
      |   00ad wcwidth=1 width(eaw=3,gencat=Cf)=0       SHY(soft-hyphen)
      |   0600..0605 wcwidth=1 width(eaw=1,gencat=Cf)=0 アラブの数字らしい。何故Cfなのかは謎
      |   06dd wcwidth=1 width(eaw=1,gencat=Cf)=0       ARABIC END OF AYAH (アラビア語?)
      |   070f wcwidth=1 width(eaw=1,gencat=Cf)=0       SYRIAC ABBREVIATION MARK (シリア短縮記号?)
      |   08e2 wcwidth=1 width(eaw=1,gencat=Cf)=0       ARABIC DISPUTED END OF AYAH (アラビア語)
      |   110bd wcwidth=1 width(eaw=1,gencat=Cf)=0      KAITHI NUMBER SIGN
      |   110cd wcwidth=1 width(eaw=1,gencat=Cf)=0      KAITHI NUMBER SIGN ABOVE
      |
      |   うーん。これらは emoji とは関係ない気がする。ので、emoji 関係の
      |   property を参照しても仕方がない気がする。個別に設定するしかないのだろうか。
      |
      | * Lo は以下の範囲のみ wcwidth が予測と異なる物になっている。
      |
      |   1160..11ff wcwidth=0 width(eaw=1,gencat=Lo)=1 ハングル字母
      |   3248..324f wcwidth=2 width(eaw=3,gencat=No)=1 囲み文字10-80
      |   4dc0..4dff wcwidth=2 width(eaw=1,gencat=So)=1 易経記号
      |
      |   うーん。一体誰が wcwidth のデータベースを作っているのかは謎だが…。
      |
      | 取り敢えず Fedora の wcwidth に合わせる形で実装することにして将来的に不都
      | 合があればその時に改めて環境依存性について考える事にする。また、将来的に
      | 別の環境の locale でも wcwidth の振る舞いを調べる必要が生じた時の為に、
      | これに使ったコードも残しておく事にする。

      → #D1645 にまとめ直した。

    段々と大掛かりになって来たので一旦現状で commit を作っておくべきな気がした。
    現在の状態は幾つか未だ課題があるものの中途半端な状態という訳でもない。課題
    についてまとめて別の項目で議論するべき気がする。

    [残っている課題] 別項目で議論

    * #T0008 SpacingMark, Prepend は grapheme cluster の修飾でありながらそれ自
      体が幅を持つ。つまり、grapheme cluster の幅を拡張する。従って、grapheme
      cluster の Extend についても width を grapheme cluster の幅の計算に加算す
      る必要がある。その為には c2w をちゃんと設計する必要がある。具体的には幅 0
      の Extend に対してはちゃんと 0 を返す様にする必要がある。

    * #D1645 上の為に c2w をちゃんと再設計する必要がある

2021-06-13

  * 2021-06-06 complete: auto-menu の振る舞いの調整 [#D1618]

    * ok: auto_menu に於いては empty_completion の抑制もするべき。というか一般
      に auto に対して抑制するべきの気がする。と思ったが、実際に実装を確認する
      と既にその様な実装になっていた。no-empty opts を指定していた。

    * reject: うーん。auto-menu を既定で on にする事も考えたがこれは流石にうる
      さい様な気がする。やはり好き嫌いが出るだろうから既定で on にするのは避け
      た方が良い様に思われる。然し、on にした時にはできるだけ自然な動作になる様
      に努めたい。

    * complete_limit_auto_menu?

      導入した。然し、complete_limit_auto_menu を導入すると複数の source から候
      補を生成した時に一部の source からの結果だけ抽出してしまう。その時点では
      それで良いかもしれないが menu-filter が走ると直ぐに候補の数が少なくなって
      候補がなくなってしまう。此処で改めて候補を生成したい所だが、

      a complete_limit に引っかかったら全体をキャンセルして中途半端な候補による
        menu は表示しない。

      b (no items) になったら改めて候補を再生成する。然し、これは何処に実装する
        べきだろうか。実装するとしたら menu-filter.idle の気がする。然し、その
        menu がどの様に start したかによって振る舞いを変えるべきではないか。例
        えばユーザーが明示的に source を指定して候補を生成した場合には勝手に再
        生成すると元々のユーザーの与えた絞り込みが消えてしまう。

        或いは候補の生成に要した設定を何処かに記録しておいて同じ設定で補完を開
        始するという事。入力内容が増えた事によって絞り込み候補が少なくなったり
        して曖昧補完に移行するなどの事が考えられる。

      同様に menu-filter.idle の開始点よりも前に移動した場合も候補を再生成する
      べきなのではないだろうか。

  * 2021-06-10 prompt: [最適化] 単純なプロンプト内容は ${PS1@P} で展開? [#D1617]

    プロンプトが単純な内容しか含んでいない時には ${PS@P} で計算を省略できるので
    はないか。つまり、\X で特別な物を含んでいない限りは bashに任せる事ができる。
    (一方で \w の追跡などについては個別に判定する必要がある気もする。)

    然しそんなに速度向上には寄与しないのではないかという気もする。結局 trace は
    しなければならないからである。

    取り敢えず PS1 が単純化どうかの判定をどうするか。\ の後に "安全" でない文字
    が続いている物は全て除外するのが良い様に思われる。"安全" な文字を列挙する。

    - 0-7aenrdtAT@DhHjlsuvV[]!$\
    - wW ... これらには add-hash を付加したい様に思われる。
    - # ... これは駄目。ble.sh 的には内部の bash の番号をちゃんと更新できていない。

    意外と簡単に実装できた。動いている。\# も大丈夫。\w の更新も大丈夫。

  * 2021-06-06 prompt: エラーはまとめて出力するべき? [#D1616]

    現在の実装だとエラーを直接その場に出力する仕組みになっている。然しそうでは
    なくて、例えば新しい行を表示する直前等にエラーメッセージを出力するべきの気
    がする。その場合にはプロンプトの類を一旦仕舞うなどの工夫が必要である。或い
    は、trace 等で計測して出力する事になる。trace で計測したとしても画面の範囲
    よりも大きい場合には表示しきれないという事等色々考えるとプロンプトの類を一
    旦仕舞うのが妥当な気がする。

    特にプロンプトに関連するエラーはプロンプトの表示直前にまとめて表示するのが
    良いのではないか。と思ったが、プロンプトの部分更新でもエラーは発生する。と
    いう事など考えていくと微妙。というかプロンプトの処理に関しては、
    visible-bell で良いのではないかという気がする。

    というかそもそもエラーメッセージを表示する意味はあるのだろうか。認識してい
    なかったら単純に \q{...} のまま出力すれば良いのではないか。うーん。取り敢え
    ずは \q{...} の形でそのまま出力すると共に、visible-bell でも表示する事にし
    た。

2021-06-12

  * benchmark: ble-measure が bash-4.4 未満で結果を返さなくなっている [#D1615]

    これは local TIMEFORMAT= を指定したのが原因だった。
    TIMEFORMAT が unset の時には既定の結果になるが、
    TIMEFORMAT が空文字列の場合には既定の結果にはならないのだった。
    この際なので TIMEFORMAT に単純な文字列を指定して計測する事にした。

    この問題は割合最近に埋め込んだ物の気がする。確かめてみる。bbc2a904
    src/benchmark.sh 2021-05-19 11:25:18 +0900 である。うーん。この commit は雑
    多の物をまとめた commit である。特に ble.pp のロード時間計測コードを
    TIMEFORMAT を使って見やすくした時にその序として benchmark.sh で TIMEFORMAT
    が書き換えられていた時の対策のコードをちゃんとテストせずに書き加えたのが原
    因であった。

  * 2021-05-15 util: ^A, ^? を含む排列に関連するテストが失敗している [#D1614]

    % ^A 及び ^? に対する declare -p 補正が動かなくなっている @ bash-3.2
    %
    % #D1522 に於いて bash-3.2 以下では配列表記で ^A が ^A^A^A^A になる事を発見
    % したと思ったが、何故か今手許で試してみると ^A^A にしかなっていなくて以前
    % のコードでも良かったという事になる。再現するための条件が何かあるのだろう
    % か。例えばスクリプト内部では declare -p の結果は ^A^A^A^A になるなど。
    %
    % うーん。ble/util/assign を介すと確かに ^A^A^A^A になるがそれは scalar も
    % array も同様になっている。然し、#D1522 で対処した問題は配列の時にのみ起こっ
    % ていた問題の筈なのでこれは関係ない。
    %
    % 関数内のみで起こる問題の可能性? と思ったがそれも変である。実際に ^A^A^A^A
    % にならず ^A^A になっているのは関数内で実行している時である。対話でも ^A^A
    % にしかならない。
    %
    % 元々は memo/D1522.large-array-passing.sh に於いて発生していた問題だった。
    % 今となっては writearray の実装を使う様に変更した為に再現していない。うー
    % ん。分からないので、取り敢えず改めて各 version での振る舞いを整理してそれ
    % で OK とする事にする。
    %
    % 以下が実際にスクリプトを書いて実行してみた結果。
    %
    % * bash-3.0, 3.2, 3.2
    %   declare -- s="x^A^Ay^A^?z"
    %   declare -a a='([0]="x^A^A^A^Ay" [1]="z^A^A^A^?w")'
    % * bash-4.0, 4.1, 4.2, 4.3
    %   declare -- s="x^A^Ay^A^?z"
    %   declare -a a='([0]="x^A^Ay" [1]="z^A^?w")'
    % * bash-4.4, 5.0, 5.1
    %   declare -- s="x^Ay^?z"
    %   declare -a a=([0]=$'x\001y' [1]=$'z\177w')
    % * bash-dev
    %   declare -- s=$'x\001y\177z'
    %   declare -a a=([0]=$'x\001y' [1]=$'z\177w')
    %
    % うーん。やっぱり二重にエスケープされている気がする。
    % 発生する条件があるのだろうか。
    %
    % a 関数の中で実行すると発生しなくなる? そういう訳でもない様だ。
    % b interactive session で実行すると発生しなくなる? →そうでもない
    % c ble.sh をろーどしていると発生しなくなる? →そうでもない
    % d サブシェルで実行すると発生しない? →そうでもない
    %
    % うーん。これは寧ろチェックコードの方の問題だろうか?
    %
    % a コピーに関しては問題ない
    % b 出力に関しては
    % c 比較対象の "正解" を生成する時に "正解" が化けている。
    %   あー。これだった。修正した。というか正解はハードコードする事にした。


    結局問題は arr=(...) の形式でテスト用の配列を用意した時点で ^A や ^? が
    ^A^A や ^A^? に化けてしまっていた事にあった。それなのに、配列の中には ^A や
    ^? が正しく格納されているという前提で declare -p arr の結果だけに着目してい
    たのが混乱の原因だった。

    * 何と $'\c?' は Bash-4.4 と 4.3 以下で振る舞いが違う様だ。最近書いた関連
      するコードを fixup した。

    * 他にも類似の問題が生じている。これもテストの問題なのだろうか。

      L1482 で発生している問題。うーん。これもやはりテストの側の問題だった。
      というかどうやったら正確にテストする事ができるのか?

      色々試したが何だか変だ。これは出力する時の問題ではなくて、変数に代入する
      時の問題だろうか。特に配列に代入する時に発生する問題?

      →うわー。やっぱりそうだった。という事は今 writearray でやっている処理は
      正しくない。writearray でやっている処理は arr=() で代入した事によって壊れ
      ている内容を正しい物に修正するという様な処理を行っている事になる。


      * done: writearray 修正 (^A^A^A^A 対策コード除去)
      * done: print-definitions 修正 (^A^A^A^A 対策コード除去)
      * done: print-definitions の出力で arr=() の形式を避ける。
        print-definitions はどの様に修正したら良いのか非自明である。というのも
        ^A 及び ^? を含む時にどの様な内容を出力しても arr=() の形式を使っている
        限りは正しい値を代入することができないからである。

      取り敢えずこれについては修正した。OK

  * 2021-05-15 test: BUG 失敗する様になっている [#D1613]

    * quote-command の test に失敗している @ bash-4.3 直した

    * ^A, ^? を含む排列に関連するテストが動かなくなっている → #D1614
    * ble-measure が bash-4.4 未満で結果を返さなくなっている → #D1615

      これらについては別項目で処理する事にする。

  * main: DEBUG version の bash で警告を表示する [#D1612]

    relstatus が alp*|bet*|dev*|rc*|releng*|maint* の時にはロード時に "遅い" と
    いう事を警告するべきではないか。同時に wiki か README にも注意書きを書く必
    要はあるだろうか。

  * complete: "complete -p" 解析の修正 + 細かい修正 [#D1611]

    complete に対する細かい修正が溜まっているのでいい加減に push する。

    * 一つは quote された progcomp　が正しく unquote されずに続く complete -p
      の関数名抽出に渡っている問題の修正。

    他は m scan に関連する軽微なミスである。

    * local "${_ble_complete_cand_varnames[@]}" の localvar_inherit に対する対
      策が間違っている問題。

    * 文字数を数えるのに ${#ret[0]} の形式を使ってしまっている問題 (bash-3.0
      bug)

  * util: bleopt の unknown option の表示が空になる [#D1610]

    bleopt で誤ったオプション名を指定した時のエラーメッセージでオプション名が空
    文字列になっている。

  * prompt: \g{...} [#D1609]

    将来的に Bash が \g に対応するとしても \g{...} の形になるとは限らないし、ま
    た、\g 単体であれば \g と \g{...} を区別する事によって処理を分ければ良い。
    偶々 \g の次に {...} を書きたいという事もそうあるまい。

  * reject: idle: 時々自動的に表示更新をかけるべきではないか [#D1608]

    裏で処理が走っている間に状態が変化してそれを表示に反映させたい時にはどうす
    るのか。現在の実装だとその様な仕組みにはなっていない筈。例えば
    textarea#invalidate を実行した時にその場で反映されるだろうか。

    処理が一巡したら、もしくはn巡したら更新するのも良い気がする。否、時間を決め
    て置いてある程度時間が経ったら更新するというのでも良い。しかしそれならば、
    普通の task として n 秒置きに更新をかけるというので良い気がする。その様にし
    ておけば idle の他の処理が終わった後でも更新を確認し続ける様になるし自然な
    実装であるように思われる。

    それとは別に idle 内部の動作によって表示を更新する必要があるのであれば、そ
    の動作を起こした側でその場で更新をかけるか或いは新しく task を投入するかす
    るべきなのである。

  * util (bleopt): 遅延定義された設定項目の check [#D1607]

    airline: ble-reload する時に状態が書き換わってしまっているのに bleopt
    vim_airline_theme=light の儘なので初期化が正しく為されない。うーん。既定値
    から再設定される筈なのだがそれも正しく処理されていない? と思ったがそれは
    ble.sh のロード時に処理される事なので遅延ロードされるモジュールの設定には当
    て嵌まらないという事。遅延ロードされる時にはその場で "設定" を再現する必要
    があるのではないか? 然し、そうすると関連する関数が既に定義済みでないと正し
    く動作しない事になる。或いは bleopt -I vim_airline_@ 的な関数を最後に呼び出
    して最初期化を強制するという可能性もある。

    現在遅延定義される設定項目は恐らく vim_airline 及び vim_surround に限られる。
    complete, syntax は ble.sh に設定項目を定義しているので問題にならない。

    * done: vim-airline で bleopt -I vim_airline_@ を実行する

    * done: 他にも影響のある場所がないか確認する。特に bleopt/check:
      を定義しているオプションで、ble.pp の "bleopt -I" よりも後に実行
      される可能性のある物が対象である。

      確認した所 core-syntax.sh で定義されている check:filename_ls_colors が怪
      しい。と思って実際に確認してみた所ちゃんと対策は為されていた。今回のこの
      対策を bleopt -I を使う物に置き換える事にする。

    * ok: update wiki と思ったが、元々 bleopt はそんなに詳しく説明していなかっ
      た。bleopt -u　も bleopt -r も wiki には説明が書かれていないので、bleopt
      -I について今すぐに追加しなければならないという事はない気がする。一方で、
      bleopt のもっと詳しい説明についてはいつか書かなければならない。

  * prompt-git: bash 3 では async にできない→修正した [#D1606]

  * history: cygwin に於いて arg_offset を処理していない気がするが大丈夫なのか [#D1605]

    ble/builtin/history/.load-recent-entries から append:count=$delta という形
    で呼び出されている。Cygwin の時でも同様である。count により追加分だけが
    background で dump される様子である。arg_offset が使えない時には arg_count
    をクリアする等の工夫もされていない。つまり、Cygwin 上では正しく動かないとい
    う事? これを実装した時にどう考えていたのか後でログを確認する必要がある気が
    する。或いはもしかして何か ToDo に項目が残っていたりするだろうか。

    * 現在の実装について記録を確認

      うーん。何か ToDo に残っていないか探してみたが cygwin/Cygwin　では引っかか
      らない。次に arg_offset を導入した時のログを確認してみる。

      a 1bfc8ebe 2019-07-09 16:42:26 +0900 が怪しい。うーん。当時の記録を確認して
        みたが offset 等の実装の詳細に関する議論は全く残っていない。これは
        history.sh を導入した時の議論であって、恐らくこの時に現在の実装の様に
        history コマンドの模倣も実装してその過程で offset を導入した。

      b と思ったが、その前の f204bc73 src/edit.sh 2019-06-27 20:38:34 +0900 の段
        階で既に arg_offset は導入されていた様である。一応 offset がどうのこうの
        という議論はあるみたいだが、これはまた別の機能の offset の話の様である。
        この時の実装の arg_offset に関係する議論ではない様に見える。更に明示的に
        arg_offset で検索をかけてみたが done.txt の中には何も残っていない様である。

      c 更にその前の commit に行ってみたらもう arg_offset は残っていない。履歴の
        読み取りも直接 mapfile を呼び出しているに留まっている。

      うーん。或いは cygwin　では offset は使わない様になっていたという可能性はあ
      るだろうか。何故 Cygwin の事を考えずに変更を行ったのかかなり理解に苦しむ。
      うーん。それとも += を使う事にしていた可能性? うーん。然し再度確認してみて
      もその様な雰囲気は見られない。

    或いは実はちゃんと実装されていて Cygwin の時には arg_offset があっても問題
    ない様になっている可能性? うーん。そんな風になっている雰囲気は見られないが。。
    取り敢えず、Cygwin でもちゃんと途中からの追記になる様に修正する必要はあるだ
    ろう。

    * history: mapfile -O offset で読み取り始めると既存の項目がクリアされない様
      だが良いのか? これは Cygwin での実装をどの様にするのかという事にも関連し
      ている。

      現在の実装を見ている感じだと offset は任意に指定できる訳ではなくて常に末
      尾を指定する様になっている気がする。もしそれが正しいのだとしたら既存の項
      目の truncate 等について悩む必要はないという事になる。

      * ok: 一方で、_ble_history_edit に関しては一番最後に要素が追加されている
        可能性があるという事を考えると、やはり truncate しておくべきの気がする。
        と思ったが、_ble_history_edit に関しては Cygwin では単に _ble_history
        からコピーしているだけなので気にしなくて良い。

      * done: 末尾以外の offset を指定できる機能は削除するべきだろうか

        別の問題として特に末尾以外の offset が指定された時に後ろに続いているデー
        タを削除するべきか或いは保持するべきかという事。やはり offset を指定し
        ている箇所がないか確認が必要な気がする。という訳で '\boffset=' で検索し
        てみると。

        > $ grc '\boffset=[^=]' --exclude=ext | grep -v 'local offset='
        > ./keymap/vi.sh:2973:  local ind=${1:-$_ble_edit_ind} offset=$2
        > ./lib/core-complete.sh:2221:  local word1 index=0 offset=0 sep=
        > ./lib/core-complete.sh:4411:##     offset=NUMBER
        > ./lib/test-edit.sh:11:  local _ble_edit_str=$1 index=$2 offset=$3
        > ./lib/test-edit.sh:16:  local _ble_edit_str=$1 index=$2 offset=$3
        > ./src/edit.sh:1880:  local index=${1:-$_ble_edit_ind} offset=${2:-0}
        > ./src/edit.sh:1914:  local index=${1:-$_ble_edit_ind} offset=${2:-0}
        > ./src/history.sh:283:  ##     offset=NUMBER
        > ./src/history.sh:301:    elif local rex=':offset=([0-9]+):'; [[ :$opts: =~ $rex ]]; then
        > ./src/util.sh:617:  # Note: Bash 4.3 以下では ${arr[@]:${2:-1}} が offset='${2'

        やはり誰も　offset は指定していない。この機能は削除する。

      結局 truncate はしなくて良いと判断する。何故なら offset が指定されるとし
      ても常に末尾に対する追加だからである。

    * 次の問題は Cygwin に於いてどの様に追記を実装するのかという事である。

      % += を使うと 3.0 で使えない。然し ble/array#push は遅そうである。うーん。
      % 複雑になるが opt_source と arg_offset に応じて分岐する事にする。という
      % 訳で offset==0 の時には今まで通りにして、それ以外で bash-3.1 以上の場合
      % は += に置き換える。bash-3.0 の場合には _ble_history[10000]='str' とい
      % う具合に直接 index を指定して出力する事にする。
      %
      % →結局 arr=() arr+=() は遅いという事が分かったので、arr[ind]=str 一本で
      % 実装する事にする。

      ? 然し改めて思ったのだが、そもそも array=() や array+=() は arra[]='...'
        よりも高速なのだろうか。実験してみる価値はある。

        $ for a in {0..3}; do history; done | sed 's/'\''//g;s/^[[:space:]]*[0-9]\{1,\}[[:space:]]*//' > h.txt
        $ < h.txt awk 'BEGIN{apos="'\''"}{print "_dbg_history[" NR - 1 "]=" apos $0 apos}' > a.txt
        $ < h.txt awk 'BEGIN{apos="'\''";print "_dbg_history+=(";}{print apos $0 apos}END{print ")";}' > b.txt
        $ time source a.txt
        0.222
        $ _dbg_history=(); time source b.txt
        0.211

        うーん。Cygwin で試してみた限りでは大して変わらない様に見える。若干
        arr+=() の方が速いぐらいである。でも bash-3.0 では試していない。Cygwin
        には bash 3.0..3.2 は入れていない。然し、一応 Linux で bash 3 でどちら
        かが致命的に遅かったりという事がないかを確認する事にする。

        $ bash -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.454s
        $ bash -c 'TIMEFORMAT="%Rs"; time source b.txt'
        0.483s
        $ bash-3.0 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.886s
        $ bash-3.0 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        b.txt: line 1: syntax error near unexpected token `newline'
        b.txt: line 1: `_dbg_history+=('
        0.002s
        [ble: exit 1]
        $ bash-3.1 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.770s
        $ bash-3.1 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        物凄く時間がかかるので中止した
        $ bash-3.2 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.757s
        $ bash-3.2 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        ^C
        [ble: exit 130]
        $ bash-4.0 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.782s
        $ bash-4.0 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        ^C
        [ble: exit 130]
        $ bash-4.2 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.613s
        $ bash-4.2 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        0.929s
        $ bash-4.4 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.474s
        $ bash-4.4 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        0.911s
        $ bash-5.0 -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.457s
        $ bash-5.0 -c 'TIMEFORMAT="%Rs"; time source b.txt'
        0.494s
        $ bash-dev -c 'TIMEFORMAT="%Rs"; time source a.txt'
        0.322s
        $ bash-dev -c 'TIMEFORMAT="%Rs"; time source b.txt'
        0.383s

        この結果を見ると arr+=() は古い bash では致命的に遅い。arr=() について
        も確認して置いた方が良いのではないか?

        $ < h.txt awk 'BEGIN{apos="'\''";print "_dbg_history=(";}{print apos $0 apos}END{print ")";}' > c.txt
        $ bash-dev -c 'TIMEFORMAT="%Rs"; time source c.txt'
        0.385s
        $ bash-4.4 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        0.901s
        $ bash-4.2 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        0.915s
        $ bash-4.1 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        1.098s
        $ bash-4.0 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        1.099s
        $ bash-3.2 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        1.091s
        $ bash-3.1 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        1.111s
        $ bash-3.0 -c 'TIMEFORMAT="%Rs"; time source c.txt'
        1.155s

        うーん。この結果を見る限りは arr=() に関しては問題は存在しなかった様で
        ある。但しそうだとしても、arr[]=() の方式の方が安定して高速な結果を出し
        ている。これは完全に arr[]='...' に切り替えた方が実装もすっきりするので
        はないか。

      * ok: 一応 #D0701 に議論がある様なので確認しておく。確認した。この時の記
        録を見る限りは "_ble_history[index]='...'" 的な方法については速度を計測
        していないのだという気がする。なので、この方法自体に何か問題があったと
        いう訳ではなく、当時は一顧だにしなかったという事なのだろう。

      arr[index]=str を使うように切り替えた。awk 内部での hindex の取り扱いも変
      更した。これに伴って nlfix の時の修正インデックスの解釈も変更。nlfix につ
      いてはちゃんと変更後も動いている事を確認した。

      x fixed: 後は Cygwin で問題なく動くかを確認する。と思ったら動かない。フリー
        ズしてしまう。何故だろう。

        * うーん。どうも動かない様に見えたのは _ble_history_edit の方をロードし
          ていなかったからの様だ。

        * C-r でフリーズするのも _ble_history_edit に有限の内容が含まれる様に変
          更したら直った。然し、だからと言ってそれだけでフリーズするというのも
          解せない。

          それだと履歴が全く無い時にはどうなるのだろうか。試してみたが特に問題
          は生じなかった。どうも履歴項目で引数が多い物があってそれで遅くなって
          しまっているという事の気がする。これはまた再現したら対処するという事
          で良い事にする。

    これで offset 問題は解決だろうか。trunate に関しては arg_offset が有限の時
    は常に末尾に対する追記という事にした。arg_offset=0 の時には配列をクリアする
    事にした。その上で offset については Cygwin　の場合には直接 arr[index]=str
    の形式で初期化する事にしたので問題ない。他の環境では mapfile -O を今まで通
    り使う。大丈夫な気がする。

  * 2021-05-04 折を見て simple-word/eval のデータ授受にも mapfile -d '' を使う [#D1604]
    Ref #D1522

    mapfile -d "" が buffered になったら
    ble/syntax:bash/simple-word/eval/.print-result (lib/core-syntax.sh) を修正する。

    2021-05-08 もう bash の側では修正されている。然し、Cygwin に対しても動作を
    変更できないかどうか尋ねてその上で改めて一緒に修正するのが良い気がする。

    2021-06-12 未だ Cygwin についても修正できないかの問い合わせはしていないが、
    代わりに history のロードの側でも mapfile -d "" を使う様に変更したので、こ
    の際一緒に変更を適用する事にする。先に修正のある simple-word/eval を差し置
    いて history の方で利用するのは変だし、だからと言って history の方に対する
    変更も pending にするのには変更が大きすぎる。

    * reject: read -t ... についても同様に bash-5.2 以降で実装を切り替えて良い気がする。

      2021-06-12 今改めて考えると read -t の何の振る舞いを切り替えるのか分から
      ない。今まで unbuffered になっていた事によって read -d "" を使いたくても
      使えなかったのを控えていた箇所はあっただろうか。後、read -t というのは
      timeout の指定の事だが、今回の buffered/unbuffered の変化が timeout の振
      る舞いにどう影響を与えるのかは不明である。"read -t" の "-t" は唯単に手の
      癖で入力した物の様な気がする。

      これに関しては取り敢えず棄却で良い気がする。

  * history: [最適化] 初期化に新しい mapfile -d '' を使えないか [#D1603]
    Ref #D0681

    これは ble/util/readarray -d '' で実装されている。と思ったが…そもそも
    builtin mapfile を直接使えば良いのではという疑惑もある。一応、他の version
    の bash でも使える様にしてあるという利点はあるが。

    | というよりそもそも現在の実装になっているのは mapfile -d '' が遅かったからと
    | いう解釈は正しいのだろうか。ログを調べてみる必要がある。うーん。適当に検索
    | してみたが難しい。git blame で観察してみると
    |
    | 1bfc8ebe src/history.sh に移動
    |
    |   現在の実装は 2019-07-09 に大きく書き換えられている。と思ったが…これは単
    |   にコードを移動しただけの話かもしれない→うーん。やはりそうだった。
    |
    | f204bc73 src/edit.sh: history -nr の対応
    |
    | 18fdaf2a Cygwin 対策
    |
    | c0c7f13e 2018-03-14 これ。この時点で mapfile & nlfix を実装している。まと
    |   まった議論があるのもこの時のログである。#D0681 である。

    うーん。当時のログを確認してみるとそもそも mapfile -d '' で NUL 区切りのデー
    タを読み込めるという事を認識していなかった様な節がある。今回改めて実験及び
    実装をして見る事にする。Bash version 毎の配列コピー時間についても確認する。

    - 取り敢えず実装した。ちゃんと読み込めている。やはり配列コピーよりも
      mapfile の方が高速の様である。

    * done: 後で printf '[[%s]]\n' "${_ble_history[@]}" > a.txt 等として出力し
      た結果を比較して正しいかどうかを検証する。

    * done: Cygwin に於ける動作も変更したので動作確認の必要がある。

      Cygwin では awk 側で unescape をする様にしたので nlfix は不要である。

      動作確認の結果 mapfile -d '' の為に書いたコードでやったのと同じミスを修正
      するのを忘れていた。それを修正したらちゃんと動く様になった。OK

  これを機に以前の mapfile の修正も適用してしまう事にする。

2021-06-11

  * 2021-05-16 edit: BUG とても長いプロンプトにした時に列計算が壊れている (reported by telometto) [#D1602]
    また右端から入力を始めた時の折返しが正しくできていない。

    2021-06-11 stackoverflow で報告されていた (by telometto)
    https://stackoverflow.com/questions/67917673/odd-long-space-in-bash-when-writing-commands

    | うーん。ble.sh のバグが stackoverflow で報告されている。これは自分でも気
    | づいていた筈の問題である。何故忘れていたのだろう。割合最近気づいた事だっ
    | た筈である。調べたら 2021-05-16 の項目を見つけたのでそれに移動する事にす
    | る。

    取り敢えず修正する。抑々 trace が怪しいという事なので計算結果について確認する。

    $ x=0 y=0; LINES=10 COLUMNS=10 ble/canvas/trace 'HelloWorld'; declare -p x y ret
    x=10 y=0
    $ x=0 y=0; LINES=10 COLUMNS=10 ble/canvas/trace 'HelloWorldH'; declare -p x y ret
    x=2 y=2

    物凄く意味不明な間違い方をしている。うーん。implicit-move が悪いという所ま
    で特定した。と思ったら分かった。折返しが発生すると分かった場合に x+=w を二
    重に実行している。2回目の x+=w を削除したら普通の振る舞いに戻った。調べてみ
    るとこれは 4fa139ad 2021-03-21 に複数行 "rps1" に対応した時に埋め込んだバグ
    であった。

2021-06-10

  * prompt: 最適化 git の現在の dirty 状態は background で取得できる様にしたい [#D1601]

    prompt-git.bash に実装したい。という事を考えると、
    prompt-git.bash は早晩に lib に移動するべきなのではないかという気がする。

    これはどの様に実装するか。先ず初めに background で git を起動する。timeout
    を指定して直ぐに制御が戻らなければ取り敢えず放置する事にする。その後で結果
    が分かったらそれを取り出す。既に git を起動していて未だ結果が分かっていない
    時には何もしない。最後に結果が分かってから X 秒経過する迄は以前の結果を参照
    する。ディレクトリを移動した場合には、起動中の git はキャンセルして新しいイ
    ンスタンスを起動する。と言った位。

    一から実装する事も可能だが既存の枠組みに沿った形で出来るだけ実装したい。git
    の結果待ちは idle プロセスとして実装する。うーん。history 初期化のコードを
    観察した。正にこれと同じことをしたいのである。

    うーん。ライブラリにしようと思ったが微妙…。実は ble/util/idle.push -F
    tmpfile を使うだけで行ける話ではないか。履歴の場合にはデータが大量だったの
    で各ステップを分割して少しずつ処理する必要があった。然し、今回の場合には
    git の実行を待つという操作が1回存在するだけである。

    実装した。動いている。と思ったが何だか遅い。うーん。ble/util/msleep 20 を入
    れるか入れないかで大分変化する。ble/util/msleep 20 なら1秒で50回捌ける様な
    気がするがそうでもないのだろうか。うーん。取り敢えず一定時間経過する迄は
    version が変化しても無視する事にする。

    - 改めて計測してみると vim-airline を有効にしている時ですら一秒間に20プロン
      プト表示する事ができている。そもそも一つのプロンプトを表示するのに 50ms
      しかかかっていない。なので其処に 20ms 追加するのは 1.5 倍の時間がかかる様
      になる事を意味していて体感としてとても遅くなるのだという事。

    - 取り敢えず前回の結果からそんなに時間が立っていない時、かつ、前回の要求か
      らプロンプト更新が10回以内の時には git の呼び出しは控える事にした。

    # 単純な PS1 の時だけの場合のプロンプトの計算速度はどの程度だろうか。試して
    # みた所、29,26回/秒 だった。平均で 36.4ms かかっている。14ms の短縮である。
    # 此処で　PS1 の処理をなくしたとしてもそんなには変わらないのだろうという気
    # がする。プロンプトの計算は実はそんなに重くないのだろうという事。

    - また Linux では可也高速に git diff --quiet の結果を得る事ができる様なので
      ble/util/msleep の時間も 5 まで減らした。これでも大きすぎるかもしれないが、
      まあ、頻繁に更新はしない事にしているし特に問題にはならないだろう。

  * [dissolved] 2021-05-28 prompt: 最下行で ble-reload すると statusline が重複してしまう [#D1600]

    ble-detach してその後に ble-attach した時には問題は発生しない。
    →これは確認した所再現しなくなっていた。恐らく #D1592 で解決した問題だろう。

  * [reject] 2021-05-24 prompt: プロンプトの変数展開の更新検出 [#D1599]

    プロンプト更新検出に於いてプロンプトに含まれて
    いる変数展開 $XXXX も自動検出する? 然しエスケープや $() 等も拘ってくると複
    雑である。適当な方法で解析できたりしないだろうか。というか、終端を処理する
    為に parse していた様な気もする。その辺りについてはまた後で確認する。

    $RANDOM や $EPOCHREALTIME 等については除外するべきである。これらの変数への
    nref の検出は困難である。という事を考えるとやはりユーザーに任せるという可能
    性も考えられるが。

    然し一方でプロンプトを計算した瞬間の値を参照したいという需要も考えられる。
    例えば $BASH_COMMAND, $LINENO 等がプロンプトに含まれていたとして、その内容
    が変わったからといってユーザーはプロンプトの表示を更新する事を想定はしてい
    ないのではないか。という事を考えるとやはりユーザーが明示的に要求しない限り
    はプロンプトに含まれている変数展開を改めて評価する必要はないのではないかと
    いう気がする。

  * [ok] 2021-05-24 prompt: 現在のモードの算出の共有化・最適化 [#D1598]

    ble/prompt/.get-keymap-for-current-mode やble/keymap:vi/script/get-mode に
    関しては一旦計算値を別の変数に格納してそれを参照して値を計算するべきの気が
    する。これは git 等の最適化と一緒に新しく枠組みを考える事にする。

    取り敢えず枠組みは整えた。そしてこれらの関数では関連する変数に対して
    add-hash を実行している。新しい unit にする程の物でもないだろう。一つにはこ
    れらの関数はそんなに思い関数でもないという事。そして幾つも何度も実行する様
    な物でもないのでキャッシュしても仕方がないのではないかという事。大抵の場合、
    依存関係を追跡するコストの方が大きそうである。なので add-hash をして、これ
    らを含むプロンプトを再更新させるぐらいで良いだろうと思われる。

  * auto-menu: ubuntu20 で auto-menu を有効にしても動いたり動かなかったりである [#D1597]

    auto-menu の起動条件 (直前の widget) に対する判定で失敗しているのだろうか。
    或いはもっと別の要因だろうか。うーん。或いは idle.sleep に失敗しているとい
    う可能性もあるのかもしれない。

    どうやら ble_util_idle_elapsed が常に 0 になってしまって時間が経過しない
    という事で無限ループになっている様子だ。調べると _ble_util_idle_sclock が
    0 の儘で全く動いていない。_ble_util_idle_sclock は ble/util/idle/.sleep
    によって増える手筈になっている。ble/util/idle/.sleep は .sleep-until-next
    から呼び出される事になっているが、この関数の振る舞いを見るとどうやら
    sleep_amount が微妙に負になっている。現在時刻と次のタスクをする時刻を比較
    しているが、次のタスクを実行する時刻が何故か現在時刻よりも前の時刻になっ
    てしまっている。

    現在時刻は ble/util/idle.clock で取得されていて内部的には ble/util/clock
    になっている。ble/util/clock は中で EPOCHREALTIME を参照している。一方で
    次の時刻 _idle_next_time は何処から来るのかというと task の SXXXX という
    エントリーから読み出される。この SXXXX というエントリーは
    ble/util/idle.sleep で設定されていて、その関数の中で ble/util/idle.clock
    が呼び出されている。整理すると

    1 最初に ble/util/idle.sleep が呼び出されてその時の時刻を元にして待ち時刻
      が設定される。何らかの処理がなされてその回のループが終了する。

    2 次のループに入る前に次の待ち時刻まで sleep する。しかし、この時迄に時刻
      が経過して次の待ち時刻を超えてしまうので、スリープ無しで次のループが始
      まる。

    3 再び auto-menu.idle が開始するが auto-menu.idle は合計 sleep 時間を使っ
      て経過時刻を確認する。然し、実際には sleep は行われていないので
      auto-menu.idle は時間が経過していないと勘違いして再び sleep を設定して
      抜ける。

    此処での問題は auto-menu.idle は絶対時刻による待ちを設定しているのにも関
    わらず、判定及び残り sleep 時間の算出に sclock つまり sleep 合計時間を使っ
    ている事である。どちらかに統一するべきである。裏で重い処理が走っていよう
    ともそれはユーザーには見えないのでできるだけ定刻通りに処理を開始するべき
    であると思うと、絶対時刻を使用する方に揃えるべきである。

2021-06-09

  * 2020-09-07 complete: メニュー絞り込みの着色が残ったままになってしまう事がある [#D1596]

    menu_filter が off にならない状況が分かった。auto-complete による単純挿入で
    継続した時、menu_filter が更新されない。更に別の機能によって menu が削除さ
    れてしまった時にも更新されない?

    | と思って実装を確認したがそうでもない様な気がする。実装を確認すると現在の
    | keymap が menu-complete でもない限りは menu-filter の処理を走らせている。
    | 領域抽出などに失敗した時にも単に menu を clear するだけでそれ以外の特別な
    | 解除処理は行っていない。だとすると、menu-filter の着色の側で処理を行って
    | いる?
    |
    | 然し ble/highlight/layer:menu_filter/update を見る限りは現在 menu が表示
    | されている場合にのみ着色を行う様になっている。うーん。或いは dirty range
    | がない限りはそもそも layer が呼び出されない可能性? と思ったがそれも変であ
    | る。何か文字列を入力してもやはり着色が残ってしまうという現象が見えていた
    | 筈である。

    - やはり振る舞いを見るとちゃんとキャンセルはされている様である。この時に
      layer が更新されないのが問題なのだと思われる。
    - 更に layer の実装の方も確認してみると、これもちゃんと動いている気がする。
      ちゃんと update-dirty-range が呼び出されている。此処で改めて表示が更新さ
      れるべきなのである。うーん。勝手に後で表示が変化しているという事なのか。

    - 或いは、上の layer が更新を無視してしまっているのか。layer の list を確認
      すると plain syntax menu_filter region overwrite_mode disabled になってい
      る。 overwrite_mode と disabled は不活性になっていて region は
      auto_complete によって設定されている。つまり region が変更を握りつぶして
      いるという事。再構築の部分を確認してみると、既存の内容は全て捨てて下層と
      現在の範囲着色で完全に再構築している。

      うーん。分かった。選択範囲の変更がない場合に、例え下層で何か変更があった
      としてもスキップしてしまう様になっている。

    ? ok: layer:menu_filter は layer:region を参考にして作られた同様の問題点は
      ないだろうか→確認したがその問題はなさそうである。PREV_BUFF を上書きして
      返す場合にはちゃんと PREV_UMIN<0 である事を確認している。layer:region が
      問題になったのは PREV_BUFF を上書きしているのにも拘らず、元の PREV_BUFF
      に起こった変更を拾わなかったのが原因である。

    ? ok: さて、今回の修正では選択範囲が存在する時に menu_filter 着色が残ってし
      まうという話だったが、実際のコマンド実行に於いても menu_filter の着色が残っ
      てしまう様な場合が存在する気がする。と思ったが、実際にコマンドを実行する
      段階まで行けば menu_filter の着色は解除されていた様な気もする。これは選択
      範囲と関係ない様な気がするが、何故問題がそのまま発声していたのであろうか。
      うーん。

      というか今回の場合も何故問題が生じていたのかよく分からない。というのも
      auto_complete による選択範囲は変わっている筈だからである。うーん。DMIN<0
      なのは良い。そして、select[*] と osel[*] が一致している時に限りスキップが
      起こっている筈なのである。それなのに、実際に発声している状況を見ると sel
      <- osel で変更が起こっている筈なのに着色がスキップされてしまっているとい
      う事。どういう事なのだろうか。

      →確認してみた所、何といきなり osel が変化している。うーん。DMIN に変更が
      あってそれでスキップされていたという事だろうか。うーん。分かったそういう
      訳ではない。

      何が起こっているかというと…

      (1) auto_complete で空白文字が入力されて、カーソル位置と region の開始点
        が一文字後ろにずれる。この時点で一旦描画が呼び出される。この時は未だ
        menu_filter.idle が走っていないので menu は表示した儘で menu_filter の
        着色も有効の儘である。そうすると e[cho ][予測内容] の前半の [] を
        menu_filter 着色にして、後半の [] を region 着色した状態になる。
      (2) その後で menu-filter.idle が走って menu を削除する。この時、内部的に
        はecho [予測内容] の様に書き換わるが選択範囲に変更がない為に、
        layer:region が下層の変更を拾わずにその儘になっていた

      という事。今まで時々見られた物もこれで説明が着くのではないか。取り敢えず

    [まとめ] layer:region が、選択範囲が存在して前回と変更がない時に、下層で変
    更があったとしてもそれを反映しない設計になっていたのが原因であった。

  * 2021-05-29 bleopt: wildcard を使った時に obsoleted な物も列挙されている [#D1595]
    複数単語に展開された時にはフィルタする様にしたら良い。

  * blehook: -a を指定しないと直接 hook を指定しても表示されない [#D1594]

    % blehook -a face_name による結果の表示も一緒に遅延されている気が
    % する。というかそもそも blehook に遅延機能があったのだろうか。。
    % そしてその理由は? うーん。見た感じは遅延機能等ない。と思ったが分
    % かった。blehook 自体が faces にアクセスしようとして、それで初期
    % 化が発生している。

  * color: initialize-faces の遅延に関する問題 (motivated by jmederosalvarado) [#D1593]
    https://github.com/akinomyoga/ble.sh/issues/96#issuecomment-813185300

    * vim-airline: theme を blerc で設定しても何故か暫くすると dark の配色が読み
      込まれている気がする。改めて設定し直すと問題は起こらない。theme を変えた瞬
      間の配色が何だか変になる。

      うーん。調べてみると initialize-faces が2回呼び出されている気がする。何故だ
      ろうか。ble/syntax/attr2g 経由である。うーん。分かった。core-syntax.sh が定
      義している関数で ble/syntax/attr2g の初期化を遅延しようとしている。然し、最
      初にプロンプトを表示した時点で既に initialize-faces が実行されるので、その
      後で ble/syntax/attr2g { initialie-faces && ble/syntax/attr2g "$@"; } 等と
      すると二重に初期化される様になるのである。eval-after-load 的な仕組みで登録
      する必要があるのではないか。

    * また、initialize-faces が実行されたら実行した hook はクリアする事にする。

    * この際なので GitHub #96 のコメントで指摘されている遅延についても対処する。

      沢山の setface 設定を仕込んでいると最初のキーストロークの反応が遅いという
      話。これに関しては initialize-faces を idle で実行すれば良い。

      idle の登録順序はどうなっているだろうか。ロードした直後の idle の順序を確
      認する。complete を絶対パスでロードするように変更して、また syntax より後
      にロードする様に変更した。変更後の様子は以下の通り。

      [0]="R\\ble/history:bash/resolve-multiline async"
      [1]="R\\ble/util/import '/home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh'"
      [2]="R\\ble/util/import '/home/murase/.mwg/src/ble.sh/out/lib/core-complete.sh'"
      [3]="R\\ble/util/import '/etc/profile.d/modules.sh'"
      [10000]="R\\ble/util/msleep/calibrate"
      [10001]="R\\ble/textarea#render-defer.idle")

      うーん。syntax よりは前に faces は initialize して良いのではないか。とい
      う事を考えると、実は一番最初に登録してしまっても問題ない。登録した。

  * vim-airline を blerc からロードする様にすると余分な行が表示される [#D1592]

    | 調べると \q{lib/vim-airline} の中で問題が発生している。更に調べると
    | ble/prompt/unit:_ble_lib_vim_airline_mode/update の中の
    | ble/history/get-entry により何かが出力されている。出力内容を調べるとエスケー
    | プシーケンスを出力している。エスケープシーケンスの出処を調べる。
    |
    | | ble-attach
    | |   ble/term/initialize
    | |     ble/term/test-DECSTBM
    | |       ESC7
    | |       ESC[1;2r
    | |       ESC[2;1H
    | |       ESC[1B
    | |       ESC[6n
    | |       ESC[;r
    | |       ESC8
    | |   ble/decode/attach
    | |     ESC[>c
    |
    | 上記の出力内容は単に buffer に残っていただけ。
    | これらは特に何も問題を起こさない。
    | 以下の内容が問題を起こしている。
    |
    | | ESC(BESC[m^MESC[2KESC[1M
    | | ESC(BESC[mESC[30C
    |
    | もっと分かり易く書くと以下の形になる。
    |
    |   SGR0 CR
    |   EL(2) DL(1) ... put-dl.draw
    |   LF SGR0 CUR(30)
    |
    | EL(2) DL(1) の組み合わせは put-dl.draw が使っている物である。put-dl.draw に
    | 仕掛けて FUNCNAME[@] を出力してみると以下の結果になった。
    |
    | | ble/canvas/put-dl.draw
    | | ble/canvas/panel#set-height.draw
    | | ble/canvas/panel/reallocate-height.draw
    | | ble/edit/info/.render-content
    | | ble/edit/info/show
    | | ble/edit/info/immediate-show
    | | ble-edit/history/history-message.hook
    | | blehook/invoke
    | | ble/history:bash/load
    | | ble/history:bash/initialize
    | | ble/history/initialize
    | | ble/history/get-entry
    | | ble/prompt/unit:_ble_lib_vim_airline_mode/update
    | | ble/prompt/unit#update
    | | ble/prompt/backslash:lib/vim-airline
    | | ble/prompt/backslash:q
    | | ble/function#try
    | | ble/prompt/.process-backslash
    | | ble/prompt/process-prompt-string
    | | ble/prompt/.instantiate
    | | ble/prompt/unit:{section}/update
    | | ble/prompt/unit:_ble_prompt_status/update
    | | ble/prompt/unit#update
    | | ble/prompt/update
    | | ble/textarea#render
    | | ble/textarea#redraw
    | | ble-attach
    | | ble/base/attach-from-PROMPT_COMMAND
    | | ble/function#lambda/0
    |
    | つまり、ble-attach から呼び出したプロンプト再描画の中で vim-airline が呼び
    | 出されて、その中での modified の判定の為に get-edited-entry が呼び出されて
    | いるという事。get-edited-entry は内部で ble/edit/info/immediate-show を呼び
    | 出して居て、結果として何らかの不都合が生じて計算がずれる。
    |
    | a reject: 一つの可能性として DRAW_BUFF に出した出力が中途半端になっている事
    |   によって問題が生じているのではないかと思ったが、DRAW_BUFF を覗いた感じだ
    |   と特に何も登録はされていない。なので出力のバッファリングが輻輳していると
    |   いう可能性は考えなくて良い。
    |
    | b reject: 或いは buffer に既に入っている内容が問題になっている? と思ったが
    |   そうでもない。その場で buffer.flush して、get-edited-entry の出力だけ潰し
    |   ても特に問題は生じない。
    |
    | c reject: 或いは端末に繋がっている時だけしか問題のある出力をしない可能性は
    |   あるだろうか。つまり e.log に出力された内容を今は観察しているが、実際には
    |   端末に繋がっている時に限りもっと色々な出力をしている。具体的には非端末の
    |   時にはble/history/initialize は info で何も表示しない可能性。一旦
    |   get-edited-entry の直後で sleep を入れて何か表示されるのか確認してみる事
    |   にする
    |
    |   →特に何も表示されない。恐らく端末に繋がっているかどうかの違いで振る舞い
    |   が変わるという訳ではないと思われる。
    |
    |   →実際に非端末の出力先として 2> >(cat) を使った場合にも問題が再現する。と
    |   いう訳なので観察している出力で確かに問題が発生しているのだという事。
    |
    | d reject: もう一つの可能性は後で遅延して履歴読み込みが完了した時に info を
    |   削除する時に問題が生じているという可能性。
    |
    |   →これは関係ない。実際に get-edited-entry の stderr を潰せば問題は生じな
    |   くなっているし、その imbalance が生じる事によって表示が偶々正しくなってい
    |   るという様には考えがたい。
    |
    | e reject: 或いは get-edited-entry を呼び出した直後に buffer に入っている内
    |   容が後になって問題を起こしている可能性? → 確認したが、get-edited-entry
    |   直後には buffer は何も入っていない。これは関係ない。
    |
    | f もう一つの可能性として全体更新が中途半端になっている事によって座標計算が
    |   ずれているのではないかという事。然し、問題が生じているのは ble-attach か
    |   ら直接 ble/textarea#redraw を呼び出した時であって、これは panel/render で
    |   はないので、textarea と info の描画は独立の筈である。
    |
    | となって来ると、info から呼び出した set-height の実装か、或いは位置計算に問
    | 題が生じているという事になる気がする。出力内容と _ble_canvas_x,y の状態につ
    | いて確認する必要がある。
    |
    | | _ble_lib_vim_airline_mode
    | | declare -- _ble_canvas_x="30"
    | | declare -- _ble_canvas_y="0"
    | | declare -- _ble_canvas_excursion=""
    | | ^[(B^[[m^M^[[2K^[[1M
    | | ^[(B^[[m^[[30Cdeclare -- _ble_canvas_x="30"
    | | declare -- _ble_canvas_y="0"
    | | declare -- _ble_canvas_excursion=""
    |
    | うーん。これを見る限りは canvas 的にはカーソル位置は動かしていないつもりな
    | のである。改めてこのシーケンスがどの様に生成されているか確認する。
    |
    | | _ble_lib_vim_airline_mode
    | | declare -- _ble_canvas_x="30"
    | | declare -- _ble_canvas_y="0"
    | | declare -- _ble_canvas_excursion=""
    | | declare -a _ble_canvas_panel_height=([0]="1" [1]="0" [2]="0")
    | | [delta=-1,opts=]
    | | ^[(B^[[m^M^[[2K^[[1M
    | | ^[(B^[[m^[[30C[delta=0,opts=]
    | | declare -- _ble_canvas_x="30"
    | | declare -- _ble_canvas_y="0"
    | | declare -- _ble_canvas_excursion=""
    | | declare -a _ble_canvas_panel_height=([0]="0" [1]="0" [2]="0")
    |
    | うーん。どうやら panel#0 の高さが潰れてしまっている様子。然し、高さが潰れて
    | しまっているからと言ってカーソルの位置が変わるのは変である。うーん。
    | set-height までは別に座標計算が変な事にはなっていない様だ。set-height を抜
    | けた後で座標位置を復元している箇所があって、其処で計算がずれているという事
    | の気がする。
    |
    | うーん。分かった。以下の様な状態になっている。x=0 y=0 content=$'\n' になっ
    | ている。content に改行が入っているのだから、本来は y=1 でなければならない筈
    | である。何故この様な内容が生成されるのか確認する必要がある。
    |
    | declare -a _ble_edit_info=([0]="0" [1]="0" [2]=$'\n')
    |
    | 更に調べると ble/edit/info/.construct-content text 'loading history...' の
    | 構築結果がその様になっている。
    |
    | % 更に辿ると ble/canvas/trace-text がまるで動かなくなっている。何故。。。
    | %
    | %   x=0 y=0; ble/canvas/trace-text 'ABC'; echo "($x,$y)[$ret]"
    | %
    | % とすると x=0 y=0 ret=$'\n\n' 二重改行になってしまっている。これは大事。
    | % いつからこの様な事態になっていたのだろう。今まで気づかなかったのも不思
    | % 議である。というより、殆どの機能で着色を使っているので trace-text は余
    | % り使われてこなかったのである。更に遡って調べてみると v0.3.0 の時点で既
    | % に trace-text は動作していなかった様だ。0.2 系列では
    | % ble-edit/info/.construct-text という関数で現在の実装とは全く異なる物凄
    | % く単純な実装だった。この時は勿論問題はなかった。
    | %
    | % まとめると ble/canvas/trace-text は可也昔から壊れていた。v0.3.0 の時点
    | % で駄目。一方で v0.2 の段階ではその前身である
    | % ble-edit/info/.construct-text だったが、これはとても単純な関数でまた問
    | % 題も存在しなかった…と思ったが微妙に関数の仕様を勘違いしていた。
    | % trace-text は領域の大きさを外部から与える必要があったのである。

    結局何が起こっていたのかというと、ble/edit/info/.construct-content に於いて、
    ble/edit/info/.initialize-size が lines=0 を返して、それに対して
    ble/canvas/trace-text が変な振る舞いをしていたという事。

    問題が3つある。

    x fixed: ble/canvas/trace-text は lines が限界に達しているのにも関わらず改
      行を末尾に付加してしまう。これは個別に対応した。

    x ok: 改行を付加したのにも関わらず y を増やしていない。これは trace-text を
      ほぼ再実装した結果発生しなくなった。何故元の実装でこれが発生していたのか
      は分からない。そもそも改行 \n ですら trace-text では ^J と表示される。

      →これは分かった。ble/canvas/trace-text/.put-nl-if-eol が put-simple の中
      と終了時の2回呼び出されている。cols=0 の時には一回実行したとしてもまだ行
      末にいると判定されるので二回実行されるのである。

    x fixed: ble/canvas/trace-text を初期化する前に、何故か
      ble/edit/info/.initialize-size が lines=0 を結果として与えている。

      中では ble/canvas/panel/layout/.get-available-height を呼び出している。

      % 中で戻り値を確認すると ret=9730ret という謎の値が生成されている。と思っ
      % たがこれは debug コードのミスだった。

      改めて調べるとこの時点で 0 が生成されている。

      declare -a mins=([0]="1" [1]="0" [2]="0" [3]="0")
      declare -a maxs=([0]="1" [1]="0" [2]="1" [3]="0")
      declare -a heights=([0]="0" [1]="0" [2]="0" [3]="0")
      declare -- index="2"
      declare -- ret="0"

      うーん。この時点で maxs に LINES が設定されて欲しいが 1 になってしまって
      いる。うーん。原因が分かった。プロンプトの処理を行っている最中は LINES
      COLUMNS を通して描画範囲の大きさを指定しているが、これだと本来のレイアウ
      ト処理に影響を与えてしまう。

      取り敢えずは ble/canvas/trace は引き続き LINES COLUMNS を参照する事にして
      おいて、その外側の instantiate 等については LINES/COLUMNS は別変数経由で
      指定する事にする。

      書き換えた。これで現在 LINES= 及び COLUMNS= を設定している箇所は全て
      ble/canvas/trace の呼び出しか、または ble/textmap#update の呼び出しに限ら
      れる事となった。

    x fixed: 何故 panel#0 の高さが潰れてしまうのか。本来は此処で高さを変更する
      必要はないのではないか。というより高さ 1 の儘であるべきなのではないのか。
      特に ble/prompt/update の段階では。

      これは LINES=1 を設定していた為に visible-bell 専用の行が引き算されて 0
      になってしまっているという事だろう。LINES=1 の時には visible-bell も表示
      しない様に修正する必要がある。もしくは visible-bell の表示方法を変更して、
      即座に行送りにする。と思ったが、visible-bell を表示した時点で現在の表示内
      容を保持する事ができないので、やはり LINES=1 の時には visible-bell は表示
      しない様に変更するのが適切だろう。

    * done: この問題とは独立に get-edited-entry に於いて最新の値を参照している
      時には履歴をロードせずに済ませる様に実装する様にした方が良い。実装した。
      取り敢えず vim-airline の modified はこれでもちゃんと動いている。

    * done: trace-text のテストを拡充

    x 2021-06-08 airline: ロード時に keymap_vi_mode_show=1 に再設定すると表示が
      ずれてモード行の位置にプロンプトの残像が残ってしまう

      →これは #D1592 を修正したら再現しなくなった。

    x 2021-06-08 airline: status 行を表示している時の空コマンド行による改行がス
      ムーズではない。

      →これも #D1592 の修正で再現しなくなった。LINES/COLUMNS によりレイアウト
      再構成が毎回走っていたという事なのだろうか。何れにしても空コマンド行によ
      る改行で status line を出した儘にしているかどうかだけ、実装について確認す
      るのが良い。

      →確認した。textarea (panel#0) の再描画しかしていないので statusline 等に
      ついてはその儘の筈。但しプロンプトの再計算が入るので結局再描画はされる様
      な気もしないでもない。うまく cache が働いていれば dirty にもならずに再描
      画もなくそのまま前の表示が使われるのではないかという気がする。

2021-06-07

  * prompt: [最適化] 依存関係追跡の整理・最適化 [#D1591]

    x .instantiate の section update で git 情報や現在の vim モードに依存してい
      るが、一方で自動的な依存解決による section update が git 情報や vim モー
      ドを初期化する前に呼び出されている。

    これに関しては本来は git の情報は ble/prompt#update _alpha '' prompt-data
    等として初期化する必要があるのではないかという気がする。というか
    ble/prompt#update を流用する必要があるのかは謎である。実はデータ専用の関数
    を用意しても良いのではないだろうか。そしてデータは好きな様に利用する。

    ? そもそも配列を共有している理由はあるのだろうか。。。

      version hashref hash に関しては依存関係の管理に関係している。
      これは一つ上の枠組みで管理される物なので切り離しても良いのではないか。
      一方で (instantiate 7つ組) 及び (tailor データ) はプロンプト情報固有の物である。

      但し、version 更新の条件として (instantiate 7つ組) または (tailor データ)
      による更新が実際にあったかどうかを使っている。然し、version は一般に外から
      その内容が変更されたかどうかを判定する為に用いているから、やはり version
      hashref hash の組で管理するべきである。

      取り敢えず veresion hashref hash の順序を変更する事にする。

    うーん。何だか分からなくなってきた。そもそも現在の構造に欠陥がある様な気が
    する。hash を見て更新する必要があるかどうかを観察する事になっているが、依存
    関係がある時には hash で参照している先を初めに更新しておかなければ反映され
    ない。なので、依存先を先に更新しようと考える訳だが更新に使用する引数が分か
    らないという問題が生じる。

    a 依存先の hashref を展開して長大な hash で更新確認をする案

      % これは version で参照しているから行けないのであって、依存先の hash 本体を
      % 依存元が取り込んでしまえば問題ないのでは? とも思われるがそれは変数の時だ
      % けである。history index や git の情報など何らかの処理によって確認を取って
      % 値を計算してから出ないと分からない物に関してはやはり変数で参照していても
      % 駄目である。

      依存の更新がグローバル変数の変化を通してのみ発生する場合にはこれで良いが、
      実際には git 等の様に現在の値をその都度更新する必要がある物もある。

      history index/count に関しても既存のコードを大きく変えたくないので、同様
      の仕組みを使って実装したいと考えている。と思ったが、history に関しては変
      数経由にした方が良い様な気もする。描画(カーソル移動も含めて)の回数と履歴
      移動の回数を数えたら断然描画の回数の方が多いだろうから。

    b そもそも各 unit に外から引数を与えられる様になっているのが変である。外か
      らプロンプト文字列を与えられなくてもそれ単体として更新をできる様にする。
      これはそんなに難しくない筈である。というより、今まで外から引数を指定でき
      る形で更新していた事自体が変なのである。

      この場合に真面目に考えなければならないのは特定の条件で on/off される様な
      プロンプトの存在である。うーん。特定の条件で表示非表示を切り替える様な物
      の場合には、消去のコードも自分で生成するか或いは消去は外に任せる事にして、
      自身は表示している時の状態を保持し続けるという事か。うーん。これについて
      は外からの支持で動作するというので良い気がする。つまり、今までの振る舞い
      で良い。特に rps1, xterm_title, etc. に関しては他から参照される事もないの
      で、外から呼び出された時にだけ更新すれば良い。更新する必要がないのに古い
      依存関係経由で呼び出されるという様な事はないので大丈夫。

      1 先ず更新は全て unit#update 経由で実行するという事。現在は class 等とし
        て {section}/update を定義しているがこれは廃止する。個別にちゃんと
        /update で実装するという事。unit#update には引数は渡さない

        prompt-expand-{gbox,bbox} は廃止する。必要ならば呼び出し元で抽出を行う。
        と思ったが、helper 関数として存在しても良いのではという気がしないでもな
        い。何れにしてもこれは後回し。先ずは大きな構造の方を整理する事にする。

    * done: ble/prompt/section#update 廃止

    * done: vim-airline-mode は unit として実装する。

    * done: ble/prompt/unit:UNIT/section::tailor 削除

      これは明らかに実装を複雑化させている。そして tailor だけを invalidate す
      るというのも元々は効率の為だったが、既に様々な無駄がある中で余り意味のあ
      る最適化である様にも思われない。従って tailor は削除する。

    * done: history index/count は変数にする

      取り敢えず _ble_history_INDEX 及び _ble_history_COUNT

      ? _ble_history_prefix が謎である。設定している箇所は見つかるが解除してい
        る所が見つからない。local で宣言している訳でもないし textarea vars に設
        定されている訳でもないから復元される事もない様な気がする。

        例えば vi.sh で _ble_history_prefix=_ble_keymap_vi_filter_ を設定してい
        る。これは ble/keymap:vi/async-commandline-mode から
        ble/textarea#save-state _ble_keymap_vi_cmap を呼び出した後に実行されて
        いる。と思ったらこれについては _ble_keymap_vi_cmap_history_prefix に手
        動で保管して、その後で手動で復元している。vi.sh の中にある物は全てこれ
        だった。

        ./src/edit.sh:7857:  _ble_history_prefix=_ble_edit_read_
        これに関しては subshell で実行しているので戻さなくて大丈夫。

        他に設定している箇所はない。

      他の ble/history/get-{count,index} に関しては明らかに history を
      initialize しなければならない所以外は現状のままで関数経由で取得する事にし
      た。直後に history を initialize する場合にはその場で
      ble/history/initialize を呼び出して直接 _ble_history_{COUNT,INDEX} を参照
      する様に書き換えた。

    x 2021-06-09 textmap が更新される前に表示しようとすると col がずれてしまう。
      これはその場で更新してしまっても問題ないのではないか。特に textmap の更新
      が必要になるという事は dirty という事なので。

      →うーん。此処で気づいてしまったが。textmap で使用する文字幅を決定する為
      には rps1 の幅が必要で、一方で rps1 の中に配置情報を表示しようとするとそ
      の前に textmap を計算しなければならない。取り敢えず rps1 の中に含まれる情
      報は 前回の rps1 の幅に基づく textmap の情報と解釈する事にする。

      後、もう一つの問題は ble/widget/.update-textmap の内部で呼び出している
      textmap が rps1 の幅を考慮できていないという事。
      ble/widget/.update-textmap の実装をちゃんと rps1 の幅を考慮に入れる物に書
      き換えて、更に backslash:position 等の中から ble/widget/.update-textmap
      を呼び出す様に修正した。

  * prompt: [最適化] 依存関係の追跡と部分更新の対応 [#D1590]

    ble/prompot/clear については各プロンプト毎に設定できる様にするべき。
    再描画部分についても dirty かどうかを保持して更新するかしないかを判定するべ
    きの気がする。

    各プロンプト毎に何に依存しているかのリストと依存している物に対する hash を
    自動で生成する様な仕組みが欲しい気がする。仕様としては各プロンプト内部で情
    報を参照した時に ble/prompt/add-dependency xxxx を呼び出す。プロンプトの実
    体化を司る側ではこれをリストにして管理する。hash を生成する時には、
    ble/prompt/data:xxxx/hash を通して関数を呼び出し hash+=:xxxx=$hash を実行す
    る。然しこれだと hash のインスタンス化自体に split, for, += が必要になって
    重そうである。それよりは、直接 eval できる形にした方が良いのかもしれない。

    % つまり
    %
    % _ble_prompt_version_ref+='$LINENO'
    % eval "_ble_prompt_version=$_ble_prompt_version_ref"
    %
    % という具合にする。invalidate する時には各変数について ((LINENO++)) する等し
    % て処理を行う。各プロンプト要素を個別に invalidate できる様に各プロンプト固
    % 有の変数も用意する。コマンド実行後には全て更新する様にしたいので共通の更新
    % 条件としてそれも含めて置くことにする。
    %
    % 実際には ble/prompt/add-dependency は重複して呼び出す可能性もあるので [[
    % :$version_ref: == *:'$LINENO':* ]] 等を用いて重複を排除する。

    vim-airline の様に複数のサブプロンプトを組み合わせる形の場合には、サブプロ
    ンプトの version_ref を集めて判断する必要がある気がする。然し、そうすると長
    大な version 文字列になってしまうがそれで良いのだろうか。或いは無条件にサブ
    プロンプトを巡回して、その後で全体更新が必要かどうかについて判断するという
    のでも良い。その場合にはサブプロンプトの version 番号だけを参照する事にすれ
    ば良い。プロンプトのリストに登録する順序に注意する必要がある。

    _psx_hashdef  ... eval をすれば _psx_hash を計算できるパラメータ展開のコロ
                      ン区切りのリスト。
    _psx_hash     ... _psx_hash を eval して得られた文字列。更新を要求する場合
                      (invalidate) にはこの変数を空にすれば良い。
    _psx_version  ... プロンプト描画内容が変更された時に増加する番号。
    _psx_gdirty   ... プロンプト描画内容が更新された時に 1 に設定。

    同様に共通 hash を保持する。これが変化した時は全てのプロンプトは強制的に更
    新する様に仕組まれる。つまり、全てのプロンプトはこの共通 "prompt" に依存性
    を持つとする。この共通 "prompt" には実体が存在しない。PROMPT_COMMAND 及び
    PRECMD はこの仮想プロンプトに対して更新する。

    _prompt_hashdef
    _prompt_hash
    _prompt_version

    for p in prompt-list; do
      local _hash=${p}_hash _hashdef=${p}_hashdef
      eval "local new_hash=${!_hashdef}"
      [[ ${!_hash} == "$new_hash" ]] && continue

      hashdef='$_prompt_version'

      update....

      内容に変更があった && ((${p}_version++))
      eval "$_hash=$hashdef $_hashdef=\$hashdef"
    done

    hashdef の定義は更新時に毎回行う。最初は依存対象として $_prompt_version か
    ら始める。

    function ble/prompt/reference-prompt { hashdef+=:\$${1}_version; }
    function ble/prompt/reference-variable { hashdef+=:\$$1; }

    ? 全てのプロンプトを巡回しているとすると使われていないのに更新される物が出
      てくるのではないか。そう思うと使う物から順番に要求して、深さ優先順序で更
      新していく様にするべきなのではないか。その為には依存先のプロンプトの一覧
      を個別に保持する必要がある様な気もする。

      hashdef=$_prompt_version:$ps1_version,$ps2_version,...:$var1:$var2:$var3

      の様な形にして : で区切った二番目の要素を , で split して其処から依存先を
      抽出する様にするというのはどうだろうか。

    ? 現在の履歴項目内部の位置など一部の物は事前に関数の実行等が必要になる気が
      する。その場合にはどの様に対応するのか。$(ble/history/get-index;echo
      $index) を埋め込むのは遅そうである。では評価の前に関数を実行するのかと問
      われるとそれもよく分からない。そもそも更新の必要性はプロンプト毎に固定と
      いう訳ではなくて、現在表示している内容に依存している。

      或いは現在の履歴項目内の位置を常に変数で参照できる様にするべきなのだろう
      か。というか何故その様になっていないのだったか。

      うーん。history コマンドの使用によって不意に履歴がロードされたり、或いは、
      初期化によって history がロードされたりという事を想定しての事の気がする。
      実の所、この手のチェックは prologue か何処かで行ってしまえば良いのだとい
      う気がする。

      うーん。というか現在の履歴項目の位置というのも、read 等によって別の履歴に
      切り替わっている時にそれを反映するべきかというのも議論の余地がある。うー
      ん。_ble_history_prefix を設定する時にその辺りの更新処理も実行する必要が
      ある気がする。

      後、共通の変数名をどうするのかというのも困る。_ble_history_ind 及び
      _ble_history_count は既にメインのコマンド履歴の為に使われてい
      る。_ble_history_count を例えば _ble_history_cnt に解明して、その上で新し
      く_ble_history_{count,index} を現在の index/count の変数とする事にすると、
      今度は cnt,ind との区別が分かりにくい。やはり名前空間を分けたい気がする。
      然し一方でコマンド履歴は特別なので _ble_history, _ble_history_edit に格納
      されているというのも妥当である様に思われる。

      - reject: _ble_hist_index, _ble_hist_count というのも変である。
      - reject: _ble_history_current_index, _ble_history_current_count
      - reject: _ble_history_cur_index, _ble_history_cur_count
      - reject: _ble_history_prefix_index, _ble_history_prefix_count
      - reject: _ble_history_i, _ble_history_c
      - reject: _ble_history_cindex, _ble_history_ccount (common)
      - reject: _ble_history_gindex, _ble_history_gcount (global)
      - reject: _ble_history_pindex, _ble_history_pcount (prefix)
      - reject: _ble_history__index, _ble_history__count
      - reject: _ble_history_Index, _ble_history_Count
      - _ble_history_lineno, _ble_history_lines
        これだと繋がりが分かりにくい。
      - BLE_HISTORY_INDEX, BLE_HISTORY_COUNT
        これは一つの手な気がするがこれをユーザーへの公開変数とする意義はあるのか。
        慎重になった方が良い気がする。
      - _ble_history_INDEX, _ble_history_COUNT
        後でまた仕様変更できるのだという事を考えるとこれぐらいで良いのかもしれない。

    ? 設定を新しく変更して別のプロンプトに依存する様になったらどうするのか。うー
      ん。そう考えるとプロンプト更新は順番に呼び出すというよりは、必要になった
      時に不定期に何度でも更新すれば良い気がする。循環参照にならない様に注意さ
      えしておけば特に問題はないだろうという気がする。

    [実装]

    * done: プロンプト周りの整理が必要になる

      先ず ble/prompt/update はプロンプト全般の情報更新に努め、PS1 の結果は呼び
      出し元で必要になった時に読み出す様に変更する。

      ble/prompt/update の結果の内 x y lc lg は後で使用されている。一方で、g 及
      び ret に関しては使われていない気がする。特に ret は直後に別の物で上書き
      されているので関係ない。

      * ok: 変数 g を削除しても問題ないだろうか。

        g に関しては本当の所はどうだろうか。昔の実装では、trace を実行する時に
        入力していた様な気もするが…うーん。やはり違うかもしれない。結局 trace
        は使っていないし専ら textmap, slice, etc. で使っているのみである。もし
        使う事があるとすれば、一番最初の文字の着色だけである。然し、着色に関し
        てはに layer に任されている。layer では最初の g を認識して着色を省略す
        る等の事はしていただろうか。と考えるとしていない気がする。そもそも
        prompt の終端で g を sgr0 以外にしておく必要も分からない。

        実際に出力する場所を確認してみると必ず textarea#slice-text-buffer を使
        用している。そしてこの関数では必ず端点の g を読み取ってそれに対して sgr
        を生成して付加している。なので、prompt 終端の g が表示に影響を与えると
        は考えにくい。それとも highlight/layer の実装で g の値を参照する可能性
        はあるだろうか。うーん。外の g がどういう値になっているかは定義されてい
        ない筈なので参照していない筈。

      * reject: PS0 の最後の g をコマンド列の既定着色として用いる可能性:

        と思ったが、ユーザーがコマンドに色をつけようとしてわざと g として変な値
        を残しておくという事も考えられるだろうか。まあ、それに関しては余り考え
        ない事にする。少なくとも現在の実装では考慮に入れていないし、考慮に入れ
        るとしても別項目で考察するべき内容である。

        それに既定着色を指定できる様にするとなると SGR を生成する段階で様々の修
        正が必要になってくる。変更として大きくなってしまうし有用性がよく分から
        ないのでこのままにする。そもそも色を設定したいのであれば、ble-face を用
        いて設定するべきであって、PS1 経由で着色をするというのは避けてもらうべ
        きである。

      lc lg の計算は現在 ble/textarea#update-text-buffer 内部で実行しているがこ
      れは別の関数にする方が自然なのではないか→別の関数にした。

      ble/prompt/.load は最早誰も使っていないので削除しても良いのでは→削除した。
      引数の詳しい説明については ble/prompt/.instantiate に移動した。

      これ以上の整理に関しては枠組みが完成してからにするべきという気がする。

    * 試験的に新しい枠組みを作成する

      プロンプトを指定する番号はどの様にしたら良いだろうか。というか番号で指定
      できる必要はあるだろうか。考えてみればどうせ色々の変数は指定した prefix
      の下で変数を複数作って管理するのだった。という事を考えると実は prefix で
      指定すれば良いだけなのではないだろうか。取り敢えず prefix で指定する様に
      する。

      一番最初は依存関係の解決等は考えずにただ単純に更新するだけの関数にしてみる。

      * done: control-string 系全てに _data を付加する

      * ok: dirty が個別に設定されていなくても全て再描画する必要が生じる場合も
        ある。というか新しいプロンプトを表示する時は常にそう。invalidate の際に
        全てに dirty を設定する必要がある?

        % 普通に hashref_base (_ble_prompt_version) を確認するだけだと、プロン
        % プトの再計算までは行われるが内容が以前と一致した場合に再描画迄は行か
        % ない可能性がある。今迄は内容を再計算した時には必ず dirty が代入されて
        % プロンプトまで再描画していたが、今回は内容を再計算して更に変化があっ
        % た時にだけ dirty が設定されているので、再描画が実施されるとは限らない。

        と思って確認したが ble/textarea#invalidate が呼び出された時には全体描画
        になって、その時には改めて全て描画される様である。dirty が参照されるの
        は一部だけ更新されている時だけである。なのでこれについては気にしなくて
        良い。

      考えるに dirty は参照される時には参照されるが、参照されない時には参照され
      ない。何れにしても全て再描画される場合には dirty は見ずに常に再描画する仕
      組みになっているので問題ない。

      * done: 変数を参照した時にそれを登録する為の関数を定義する。

        関数名は何が良いだろうか。

        - reject: ble/prompt/add-variable var
        - reject: ble/prompt/add-variable-reference var
        - reject: ble/prompt/add-varref var
        - reject: ble/prompt/reference-variable var
        - reject: ble/prompt/listen var
        - reject: ble/prompt/listen-variable var
        - reject: ble/prompt/hook-variable var
        - reject: ble/prompt/depend-on var
        - reject: ble/prompt/add-dependencies var...
        - reject: ble/prompt/cite-variable var
        - reject: ble/prompt/cite-var var
        - ble/prompt/ref var
        - ble/prompt/onchange var
        - ble/prompt/detect var
        - ble/prompt/cite var
        - ble/prompt/cite-vars var...
        - ble/prompt/reference var

        a 将来的に変数以外の物を参照する可能性があるかどうかという事で var を関
          数名に入れるかいれないかが決まる気がする。考えて見るに eval して fork
          を伴わない物と言えば変数展開以外には算術式展開しか考えられない。とい
          う事を考えるとやはり reference で良いのではないだろうか。

        b 或いは、"変数" である事を示唆する様な動詞が存在すればそれを使うのが良
          い。例えば reference と言えば変数である。

        c というか良く考えたら追加する式を直接指定すれば良いだけの話の気がして
          きた。つまり、

        - ble/prompt/reference '$var'
        - ble/prompt/hash '$var'
        - ble/prompt/add-hash '$var'
        - ble/prompt/add-hashref '$var'

        うーん。add-hash が一番無難な気がする。結局内部で何をするかがこの関数名
        だけで分かるので。もっと分かりやすくするならば、add-update-hash 等にな
        るだろうか。然し短いほうが良いので add-hash にする。

      * done: うーん。vim-airline で子プロンプトを参照する様にしたが、よく考え
        ると、チェックを行うのは子プロンプトを更新する前なので、子プロンプトの
        更新による変化を検出できない。子プロンプトの更新を実施してからチェック
        を行う必要がある。

        然しここで問題になるのは、子プロンプトに渡すオプションやプロンプト文字
        列は事前には分からないという事。子プロンプトが存在する場合には先に子プ
        ロンプトを更新してから更新判定を実行する必要がある。うーん。或いは。や
        はりプロンプト毎に更新を行う関数を事前に登録しておくべきなのだろうか。

        プロンプト section_a を更新する為の関数を登録することにした。

      * done: ble/prompt/clear は個別に invalidate または自動検出にする

        というか実は更新の必要すらないかもしれない。今となっては必ず全ての
        prompt について hashref のインスタンス化を試す様になっている。ここに ps
        も含めるべきなのではないか。

        と思ったが、現在の実装だと ble/textarea#redraw は何も変更がないと即座に
        抜けてしまう様になっている。少なくともプロンプトに関しては更新を行わな
        いと駄目なのではないか。

        * ble/prompt/clear の使用箇所を改めて確認する

          ./ext/.../fzf-marks.plugin.bash:317:    [[ $PWD != "$pwd" ]] && ble/prompt/clear
            これは \w または \W を参照している時に呼び出す事にする。
            他に埋め込まれている変数の場合の可能性もあるが気にしない。

          ./keymap/vi.sh:468:    ble/prompt/clear

            これは show-mode-in-prompt の時に呼び出す物。これは変数に変える事が
            できるのでは。

          ./src/edit.sh:169:      ble/prompt/clear

            bleopt_prompt_status_align の変更に伴って更新を行う。うーん。これに
            関しては実は prompt#update の hash に値を含めても意味がない。最終的
            に生成される esc が同じである以上は dirty と判定されないからである。
            特に left と right の切り替えに対してちゃんと処理できない。という事
            を考えると hash をクリアするしかない気がする。

            結局、ble/prompt#update の内部から ble/prompt:"$prefix"/tailor とい
            う関数を呼び出させてその中で加工処理を行う事にした。tailor だけの
            invalidate として、ble/prompt#clear _ble_prompt_status tail を呼び
            出させる事にした。

          ./src/edit.sh:1275:    ble/prompt/clear

            これは ble/prompt/notify-readline-mode-change である。更にこの関数
            の呼び出し元も調べる必要がある?

          ./src/edit.sh:7568:  ble/prompt/notify-readline-mode-change

            これは ble/widget/safe/__attach__ から

          ./keymap/vi.sh:7649:  ble/prompt/notify-readline-mode-change

            これは ble/widget/vi_imap/__attach__ から

          というか本当にちゃんと更新されるのだろうか。と思った
          が、./keymap/vi.sh:468: ble/prompt/clear は実の所
          ble/prompt/notify-readline-mode-change に変えるべきなのでは? と思った
          が、vi.sh:468 は show-mode-in-prompt だけでなくプロンプトの表示を切り
          替えるのに使う物の気がする。うーん。

      * done: ble/prompt/notify-readline-mode-change に関しては自然に変数経由で
        更新を検知できる様にする。関数自体を削除した。

    x fixed: 何か入力した場合に何も表示されなくなってしまっているこれは何だろう
      か。恐らくこれは単に更新した時に expand gbox,bbox が解釈されていないのが
      原因だろう。

      修正した。問題は発生しなくなった。

    x fixed: 2021-06-09 history: isearch 検索を中止した時に履歴の先頭に移動する
      様になってしまっている。検索を開始する前の初期化に関係するのだろうか。と
      思ったがそうでもない様だ。履歴がロードされた後でも同様に問題が再現する。

      これは最近発生する様になった問題である。明らかに prompt の改良に伴っ
      て_ble_history_INDEX の記録関係に失敗する様になっている。うーん。
      get-index ではちゃんと大きな値を取得する事ができている。逆に復元する時の
      様子を見てみると…。

      _ble_edit_isearch_arr=([0]="29801:-:0:0:" [1]="29769:-:22:23:f" [2]="29305:-:6:8:fd" [3]="29305:-:6:9:fds")
      step=([0]="29801"

      うーん。ちゃんと正しい値を読み出す事ができている気がする。という事は現在
      の履歴位置が間違っているという事になるのだろうか。うーん。何と、
      history/goto の直後に _ble_history_INDEX は空欄になってしまっている。どう
      いう事だろうか。

      これは分かった。ble/history/set-index の実装で存在しない変数 (削除した変
      数) を参照していた。修正した。

  * 2021-05-24 airline: 説明書を書く。theme の枠組みを整える [#D1589]
    https://github.com/akinomyoga/ble.sh/issues/114 (2)

    * done: themes の枠組みを整えたい気がする。現状だとユーザーがそれぞれ対応し
      なければならない。面倒である。うーん。取り敢えず contrib に適当に加えてみ
      るというのも良い気がする。

    * done: _modified には対応していない。

      履歴項目については現在の内容とずれている時に modified にできる。最新項目
      については何か文字列があれば modified にできる→これは対応した。

    * done: themes は自動的に変換する様にできたら良いが調べてみると面倒な気がする。

      自動変換は vim スクリプトを書いて行った。取り敢えず themes は現状で良い気
      がする。mode_map も抜き出そうと思ったが実は atomic.vim しか設定している物
      はなかった。

      contrib に一括で追加しようと思ったが止めて置く事にした。もっと普通のファ
      イルが増えてからにするのが良い気がする。或いは要求したら自動的に何処から
      かダウンロードするというのも手なのかもしれない。

    * reject: テーマ用の bleopt を用意する

      bleopt vim_airline_theme=xxxx

      を設定したら自動で ble-import contrib/airline/xxxx を読み込む様にしたい。
      或いはよく考えたら直接 ble-import contrib/airline/xxxx と書けば良いだけな
      のではないか。

    * 説明に関しては theme を用意してそれを見てもらえれば十分の気がする。但し、
      辞書に関しては theme は bash-4.1 以下でも動く様に gdict を使わなければな
      らずややこしい。

      何れにしても huresche に対する返答で説明するので、その内容を後で Wiki に
      転記すれば良い。

    * done: というか、考えてみたら ble-import する時に毎回 contrib まで指定する
      必要があるのは変な気がする。source path を指定したら其処から自由に source
      してもらうべきなのではないのか。

      ble-import vim-airline
      ble-import core-syntax
      ble-import keymap-vi
      ble-import prompt-git
      ble-import fzf-bingings
      ble-import fzf-completion
      ble-import airline/landscape

      別にこれで良い気がする。寧ろこちらの方が良い。

      local user=${XDG_DATA_HOME:-$HOME/.local/share/blesh}
      BLE_IMPORT_PATH=$user:$user/lib:$_ble_base:$_ble_base/contrib:$_ble_base/lib

    x emacs mode にいる時に vim-airline を呼び出すと真っ黒になって何も表示され
      ない。と思ったらこれは inactive face が使われていて、この inactive の設定
      が物凄く見にくいという事だった。微妙に色が見える。じれが dark.vim の設定
      という事なのでそのままにする事にする。

    x 2021-06-10 ble-import の search path として ~/.local/share/blesh を追加し
      たが、これだと異なる version の設定ファイルが混在する原因である。そうする
      と不整合を生んで変な事になる。特に keymap/vi や keymap/emacs は致命的な問
      題を引き起こし得る。という事を考えると、 ~/local/share/blesh は直接は追加
      せずに ~/.local/share/blesh/local 等から読み取る様にするべきである。

2021-06-05

  * locale によっては正規表現の [a-z] でも駄目 (reported by huresche) [#D1588]

    a 一つの方法は全ての文字を [abcdefghijjklmnopqrstuvwxyz] と言った具合にして
      並べるという事。これは冗長である。0-9 に関しては C 言語の要求で連続に並ん
      でいる事が保証されているので書き出す必要はない。

    b もう一つの方法は必要な箇所で LC_COLLATE=C を設定するという事。然し、必要
      になる箇所が多岐に渡る。

    c 或いは、もう ble.sh の処理を全て LC_COLLATE で囲んでしまうというのも手な
      のかもしれない。と思ったが、LC_COLLATE を解除する場所でエラーメッセージが
      出るのを抑制しなければならない。とは言え、それはそんなに難しくない。問題
      は何処で LC_COLLATE で囲めば良いのかという事。ユーザーコマンドを実行する
      前後で切り替えれば良いのだろうか。或いは、PROMPT_COMMAND や hook を呼び出
      す時にも配慮しなければならないのだろうか。

    * 取り敢えず必要な箇所がどれだけあるかについて確認する。

      $ grc -i 'a-fa-f|a-za-z' --exclude=ext

      で検索すると流石に沢山ある。さて、もし LC_COLLATE=C を設定するのあれば実
      は [:alpha:] や [:alnum:], [:xdigit:] も使えるのではないだろうか。

      然し、何れにしても全ての箇所について個別に対応するのは難しい気がする。

    * reject: 正規表現を使っている各箇所で LC_COLLATE=C を設定する方針

      少し変更してみたがどうにも限界がある様な気がする。この方針は諦める事にす
      る。修正は memo/D1588.stub-LC_COLLATE-1.patch に残す。

    * reject: bind/.{head,tail} 内部で LC_COLLATE を設定する方針

      locale の設定をする時にはユーザーのロケールが壊れている場合に備えて、
      stderr を抑制している。然し、無闇に全体を囲んでしまうとエラーメッセージが
      全て隠蔽されてしまう。局所的に stderr を抑える事はできないだろうか。試し
      に実験してみると以下の様にすれば問題ない様だ。bash-3.0..dev まで全て確認
      した。

      $ bash -c '
        { LC_COLLATE=alpha; } 2>/dev/null
        unlocal() { unset -v "$1"; }
        fun() { local LC_COLLATE=fsa 2>/dev/null; unlocal LC_COLLATE 2>/dev/null; }
        fun'

      この方針でも全てをカバーしきれる訳でもないので微妙である。

    うーん。LC_COLLATE=C にする事にするか。取り敢えず内部環境では LC_COLLATE=C
    を強制する事にする。LC_ALL の状態も調整する。

    * LC_ALL 待避の取り扱いについて

      と思ったが現在の実装では LC_ALL も含めて文字コードの振る舞いを決定してい
      る。待避した _ble_bash_LC_ALL を使って振る舞いを変更するべきだろうか。或
      いは、現在の LC_ALL を使って振る舞いを決定するべきだろうか。うーん。

      ここで問題になるのは、LC_ALL を空にしてしまうと LC_CTYPE 等他の設定に影響
      を及ぼすという事である。現在、local LC_ALL= LC_COLLATE=C という形で様々な
      箇所で待避を行っているが、これだって LC_CTYPE カテゴリの値に影響を与えて
      しまう。

      a LC_ALL= を設定すると共にその他のカテゴリについても全て LC_ALL を適用す
        る。例えば ble/util/locale/project 的な関数を用意して、LC_ALL に有限の
        値が設定されている時にはそれを各 LC_* 変数に適用する。然し毎回それを実
        行するのは遅くなる原因である。特に変数の数だけ locale の設定が行われる
        と考えるとこれは避けたい。

      b そもそも LC_ALL は ble.sh の内部では無視するという可能性。LC_ALL は何ら
        かのユーティリティーの振る舞いを強制する為に使う物であって、対話環境で
        の locale を無理矢理に変更する為に用いる物ではない。寧ろ、そういうのは
        LANG を通して変更するべきである。

      c LC_ALL が振る舞いに影響を与えたとしても関知しない。これは一つの手である。
        LC_ALL を設定している時点で変な振る舞いをしたとしても文句は言えないとい
        う立場。然し、そうだとしても例えば Bash は LC_ALL を変更したからと言っ
        て変数名の規則が変わる訳でもないし、一貫しない動作になるのは避けたい気
        がする。

      d 逆に LC_ALL の効果が ble.sh 内部で中途半端に消えたりしても文句は言えな
        いという立場。これは現在の振る舞いに近いと言える。

      f 或いは射影を adjust の段階で実行するというのも手である。うーん。その方
        が現実的な気がして来た。

        LC_COLLTE=C に固定してしまっても問題ないだろうか。ユーザーの側で何か気
        になる事が発生する可能性はあるだろうか。例えば [a-zA-Z] の振る舞いが
        ble.sh 内部 (PROMPT_COMMAND, etc.) で変化してしまうという影響が考えられ
        るが、問題になる事は少ない気がする。例えば fzf の振る舞いが変わってしま
        うという事も考えられるが、実のところ LC_COLLATE=C ではなくてそのロケー
        ルにおける collation を使う必要があるという状況が思い浮かばない。これに
        ついては、ロケールに従った振る舞いにしたければ実際に呼び出す側が fzf に
        LC_COLLATE を設定するなどしてもらうという形で良い様に考える。

      うーん。f の方針で行く事にする。待避するとしたらどの変数を待避する必要が
      あるだろうか。Bash は LANG, LC_ALL, LC_COLLATE, LC_MESSAGES, LC_NUMERIC,
      LC_TIME に対して変更を検知している。これらに対して全てチェックを行う必要
      があるだろうか。

      ? ok: ble/variable#copy-state 関数を使おうと思ったがこの関数は対象が配列
        や辞書である時に問題になる。要素 [0] が存在していないと配列・辞書全体を
        削除してしまう事になる。然し、だからと言って配列・辞書の状態も保存する
        となると大変である。

        どうも bash-4.4 以降であれば unset -v 'a[0]' という具合にすれば、配列変
        数であれば該当要素だけ削除して、通常変数であればその変数を丸ごと削除す
        るという動作にする事ができる様である。うーん。という事は、

        unset -v 'a[0]' || unset -v a とすれば良いのではないだろうか。

      ? reject: (余談) 実は配列かどうかの判定に unset -v 'a[巨大な数]' を使う事
        ができる可能性?  と思ったがそもそも変数すら存在していない時にも unset
        -v 'a[xxx]' は成功する様である。なので、変数が存在している事の確認と共
        に判定を実行する必要がある。然し、空配列に対して変数が存在しているかど
        うかをどうやって判定するのか。declare -p a として確認する必要があるので
        はないか。然し、宣言されているだけで unset な状態になっている場合もあっ
        て、その場合には declare -p a も成功してしまう。

        * declare -p a
        * ((${#a[@]})), [[ ${a[@]} ]] , [[ -v a[@] ]], etc.

        色々考えると余り有用ではない様に思われる。特に bash-4.0 以降では辞書と
        の区別もしなければならないので unset -v だけでは不十分である。

      取り敢えず新しい ble/variable#copy-state を使って実装した。

    既存の LC_ALL= LC_COLLATE=C に対する対策等はもう不要になった様な気もするが、
    ユーザー環境から呼び出される可能性もあるのではないかなど色々考えると、既存
    の対策に関しては今は残しておいて良いのではないかという気がする。

  * vte の paste で LF が CR に化けるという話 (reported by alborotogarcia) [#D1587]
    https://github.com/akinomyoga/ble.sh/issues/120

    最初の報告で自分の手許で試してみても再現しなかったが、端末について確認を取っ
    てみると vte であって、更に LF の代わりに CR が送信されて来ているという事が
    分かった。

    いざ修正しようと思ってコードを確認したら既に workaround は入っている様に見
    える。と思ったが、これはあれだ。連続する CR が入っていると変換しきれていな
    い。修正した。多少速度が下がったかも知れないが仕方がないだろう。

2021-05-30

  * util: stdin, stdout が継承されて新しい端末を開いても元端末に表示される [#D1586]

    これは問題だ。取り敢えず inherit は基本的に止める方が良いのだろうか。
    指定した fd が別の fd と一致しているかどうかを判定する方法は存在するだろうか。
    というか端末 tty の結果が変わったら継承しないという具合にするのが良い気がする。
    端末 tty を取得する方法はコマンド tty を実行するしかないのだろうか。

    というか別に現在の 0 が端末であれば普通に上書きすれば良い気がする。
    その様に修正した。

  * decode: Kitty の modifyOtherKeys でまた問題が生じている (reported by lyiriyah) [#D1585]
    https://github.com/akinomyoga/ble.sh/issues/118

    報告によるとコマンドを実行する前には ESC は ESC としての用を為さないという
    事の様である。そしてコマンドを実行すると動く様になるという事。

    手許で Kitty で試してみた所再現した。modifyOtherKeys を internal/external 0
    に設定すると問題は再現しない。internal 2 にすると再現する。internal 1 に設
    定すると問題が発生してしかもコマンドを実行しても直らない。

    どうも Kitty で 2 に設定すると一回は modifyOtherKeys が有効になるが、それ以
    降は modifyOtherKeys は無効化される? 或いは 2 に設定しようとしても何も起こ
    らないという事だろうか。うーん。2 に設定しようとしても何も起こらないという
    事の様である。然し、それならば不思議なのは ble.sh は 4;2 を設定する前に 4;1
    を送信する様にしているという事。それなのに 4;2 の効果がないというのは不思議
    な事である。実際に手許で試してみても 4;1 に設定して 4;2 に設定すると、4;1
    に設定したのと同じ状態になる。

    問題は二種類ある

    * Kitty で \e[>4;1m の時に送信されるキーシーケンスが ble.sh で認識されてい
      ない。実際に試してみると ESC を押した瞬間に何かしら送信はされている様であ
      る。

      これに関しては具体的に何が送信されているのかを確認する。

      keylog で調べてみると "ESC [ 2 7 u" を送信して来ている。decode.sh を確認
      したがちゃんと認識している。と思ったが isolated ESC ではなくて modifier
      ESC として認識されている気がしてきた。調べてみた所、以下の様な流れで処理
      される事になり、modifier ESC になってしまう。

      ble-decode-char
        ble-decode-char/.getent
          ble-decode-char/csi/consume
            ble-decode-char/csi/.decode
              csistat 設定
          csistat を ent にコピー
        ble-decode-char/csi/clear
        ble-decode-char/.send-modified-key "$ent" "$seq"
          此処で $1 == 27 の時に
          ble-decode-char/.process-modifier Meta を呼び出している。

      csi で受信した文字が 27 の場合には IsolatedESC として処理する事にした。特
      に CSI シーケンスの処理結果として得られた 27 が modifier ESC になる事はあ
      り得ない気がするので csi/.decode の戻り値に対して一括で処理する事にした。

    * Kitty で 2 に復帰した時に \e[>4;0m の状態になっている気がする。
      \e[>4;1m\e[>4;2m で 2 に設定している筈なのに不思議である。手許で自分で設
      定するとちゃんと 4;1 の状態になっている。

      次の問題はこれである…。実際に確かめてみると、そもそも有効化の 4;1; 4;2
      の所に入っていない様だ。確認してみると
      ble/term/modifyOtherKeys/.supported が false になっている。更に調べると
      _ble_term_TERM が vte になってしまっている。

      DA2R を見て判断する事にする。Kitty の DA2R は一体どういう形式なのだろう。
      調べると以下が該当するコードである。

        ./kitty/screen.c:1460: write_escape_code_to_child(self, CSI, ">1;"
        xstr(PRIMARY_VERSION) ";" xstr(SECONDARY_VERSION) "c"); // VT-220 +
        primary version + secondary version

      そしてこれらの値は setup.py に於いて

        constants = os.path.join('kitty', 'constants.py')
        version = tuple( map(int, re.search( r"^version: Version =
          Version\((\d+), (\d+), (\d+)\)", constants, re.MULTILINE ).group(1, 2, 3)
          ))
        cppflags.append('-DPRIMARY_VERSION={}'.format(version[0] + 4000))
        cppflags.append('-DSECONDARY_VERSION={}'.format(version[1]))

      という具合にして初期化されている。kitty/constants.py には以下の様な行がある。

        version: Version = Version(0, 19, 3)

      どうも Kitty の version は永年 0 の様だ? 取り敢えず適当に kitty 用の判定
      条件を追加する事にした。

2021-05-29

  * syntax: \? を着色したい [#D1584]

    色は magenta で良い。\q が現れる箇所はコマンド、"..." である。それぞれ規則
    は異なる。特に後者については規則が分かりにくいので色を付ける対象にしたい。

    $'...' も別枠で着色する様にしたい。これもちゃんと実装した。これで
    $'...' を書く時にどのようなシーケンスが有効でどの様なシーケンスが
    無効か分かる。所で bash version 依存性はどうなっているのか確認する
    必要がある。

  * complete: quote されているコマンド名に対しても補完関数を適切に探索 [#D1583]

    quote していると補完関数が認識されない。例えば git co とすると OK だが
    'git' co とすると反応しない。然し実の所、これは普通の bash でも同様である。
    普通の bash でも 'git' としている時には git の補完関数は呼び出されない。

    unquote した上で補完を探索するべきである気がする。但し、alias 展開などに関
    しては quote された物で実行するという事。comp_line, comp_words に入っている
    のは展開前の quote された物であるので余計な事は考えなくて良い。

  * [reject] complete: そもそも -F に指定する事のできる文字列には制限がある筈である [#D1582]

    これを満たさない場合には強制的に其処で終端させる等の対策が必要なのではない
    か。

    然し、;&| 等が含まれていた場合にどの様に取り扱うべきかは不明である。明らか
    に何かが間違っているけれども、だからと言ってその直前までを関数名と捉えるの
    にも無理がある様な気がする。然し、それ以外に解釈のしようがないとも言える。

    或いは途中に空白がある場合には ble.sh の拡張として関数に余分の引数を渡す事
    にする? 然し、これは最新の bash-5.1 では使えない事なので古い Bash だけで使
    える機能として提供しても仕方がない。結局これは失敗するべきなのではないか。
    そして失敗するのだとしたら現状の動作のままで良いという事の気がする。

  * complete: alias の展開結果で変数代入を除去するべきではないか [#D1581]

    というより実の所 simple-word でできるだけ解析していくべきの気がする。と思っ
    たが、 ; や変数代入があった時の振る舞い、文法エラーがある場合の振る舞いなど
    は用途によってまちまちなので今回は core-complete.sh の側で実装する事にした。

    simple-word の終端しない版というのはあっただろうか。なかったが
    simple_rex_element をそのまま使えば良い。

    * __load_completion を呼び出すと -D に相当する処理が勝手に入ってしまう。
      complete が駄目な気がする。自前で補完定義を探してロードする関数を作ってみ
      たが、その後で気づいたのは __load_completion は別に見つからなかった時に勝
      手に既定の定義を使う訳ではないのだという事。

      以下の自前の定義は結局使われる事はないのだった。

      | _ble_complete_progcomp_bashcomp_initialized=
      | _ble_complete_progcomp_bashcomp_dirs=()
      | function ble/complete/progcomp/.bashcomp-initialize {
      |   if [[ ! $_ble_complete_progcomp_bashcomp_initialized ]]; then
      |     _ble_complete_progcomp_bashcomp_initialized=1
      |
      |     local user repo bin
      |     user=${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions
      |     [[ $BASH_COMPLETION_USER_DIR ]] && user=$BASH_COMPLETION_USER_DIR/completions
      |     ble/string#split repo : "${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
      |     bin=./completions
      |     [[ $BASH_SOURCE == */* ]] && user=${BASH_SOURCE%/*}/completions
      |
      |     local path
      |     for path in "$user" "${repo[@]}" "$bin"; do
      |       [[ -d $path ]] && ble/array#push _ble_complete_progcomp_bashcomp_dirs "$path"
      |     done
      |   fi
      | }
      | function ble/complete/progcomp/.load-bash-completion {
      |   local cmd=$1
      |   ble/is-function __load_completion || return 1
      |   ble/complete/progcomp/.bashcomp-initialize
      |
      |   local dir file
      |   for dir in "${dirs[@]}"; do
      |     for file in "$dir"/{"$cmd","$cmd.bash","_$cmd"}; do
      |       [[ -s $file ]] || continue
      |       source "$file"
      |       return 0
      |     done
      |   done
      |
      |   ((_ble_base>=40000)) || return 1
      |   ble/is-function _filedir_xspec &&
      |     [[ ${_xspecs[$cmd]+set} ]] &&
      |     complete -F _filedir_xspec "$cmd"
      | }

  * complete: "\a" 等のコマンド名の補完で問題が起こる (reported by huresche) [#D1579]
    https://github.com/akinomyoga/ble.sh/issues/116

    [原因]

    | bash_completion との関連でまた問題が起こっている。最新の bash_completion で
    | 再現する事ができた。
    |
    | 何れにしてもこれは bash とのインターフェイスの違いなので修正されるのは
    | ble.sh の方であろう。そして文面を読む限りは "minimal ''" という名前のコマン
    | ドを呼び出そうとしている?  これは parse の問題の様な気もするが…。取り敢え
    | ず何が起こっているのか調べる。

    結局これは ble.sh の側の問題であった。再現条件は bash-5.1 である。
    bash_completion では何故か空文字列に対するコマンドでも complete -F _minimal
    '' を登録する様で、しかも bash-5.1 から complete -p の出力の形式が変化した
    事によって ble.sh が -F の解析に失敗して問題が露呈したという事になる。

    | * "a" では発生しない。"\a" や "$$" では発生する。
    |
    | 取り敢えず再現しているので何が起こっているのか調べる事にする。
    |
    | % うーん。どうやら。simple word じゃない時にコマンド名を決定できず、結果と
    | % して空のコマンド名に対して補完が呼び出されているという形になる。うーん。
    | % この場合にはどうするのが良いだろうか。もう直接 simple-word でない内容を転
    | % 写する?  うーん。それも一つの手である。
    |
    | と思ったが、そうでもない様である。例えば "$$" というのは simple-word である。
    | 改めて何で空になるのか確認する必要がある。
    |
    | "\a" は展開されて \a になるがそれにより補完は最終的に失敗する様だ更に引き続
    | き \\ による補完が呼び出されてそれが evaluate されて \ になる等している。然
    | し、"$$ の場合には数字に展開されて、その後で曖昧補完の為に一文字目 "1" の数
    | 字を使って補完されるという事が起こっている。それでもエラーは発生している。
    |
    | 不思議なのは普通に 1 として入力しても問題が生じないという事。というか、やは
    | り COMP_WORDS が空になってしまっているのが問題なのだという気がする。
    |
    | ? そもそも最初のコマンド名でない場合でも、simple-word でない場合には補完は
    |   どうなっていただろうか。
    |
    | →少し分かった。generate-subwords が5回実行されていて '$$', '', '1', '1',
    | '' となっていて問題のエラーは空文字列で呼び出された時に発生している様である
    | という事。遡って見るとそもそも compgen-helper-func 自体もその様に呼び出され
    | ているという事が分かった。ble/complete/progcomp/.compgen もその様に呼び出さ
    | れている。
    |
    | ? うーん。不思議なのは "a" 等の普通の表記の時にはその様な事がないという事で
    |   ある。何故だろうか。調べてみると普通の場合でもちゃんと空文字列による補完
    |   が呼び出されている。そもそもこの空の状態での補完の要求が一体何故呼び出さ
    |   れているのかという疑問は残るが、現在発生しているエラーメッセージとは関係
    |   がないという事だろうか。
    |
    |   然し空の文字列になる場合を除外してみるとちゃんとエラーメッセージなく補完
    |   が実行される様である。
    |
    | ? ok: 何故空の文字列で補完 compgen が呼び出されているのだろうか。
    |
    |   これは曖昧補完で -I による補完を試みているからである。
    |
    | ? done: 何故普通のコマンド名の場合には空の文字列で補完が呼び出されても問題
    |   が発生していないのか。何故特定の文字列の時にのみエラーメッセージが発生す
    |   るのだろうか。
    |
    |   | うーん。不思議な事だ。どうも調べると compdef に変な文字列が入ってくる。つ
    |   | まり complete -p 自体が予期しない内容の文字列を出力しているという事だろう
    |   | か。
    |   |
    |   | うーん。どうやら空文字列で呼び出されるのは曖昧補完の為に -I でコマンド名
    |   | を保管しようという時の話であって。然し、何故か文字列の種類に応じて -I で
    |   | 呼び出されたり或いは直接コマンド名で呼び出されたりというのが変化している
    |   | という様子。もっとちゃんと書くと何故か文字列の種類によって initial が付け
    |   | られずに compgen が呼び出されるという事。
    |   |
    |   | やはり initial なしで呼び出されるというのは変だ。initial がないという事は
    |   | コマンド引数としての補完を要求している事に他ならない。然し、空文字列での
    |   | 補完なのにそれは起こり得ない筈である。呼び出し元を確認する必要がある。調
    |   | べてみると何故か "$$ の時には source:argument が生成されているのだという
    |   | 事が判明した。一体どういう事なのだろうか。source:command は一切生成されて
    |   | いない。うーん。syntax の context 生成が怪しいという事になるだろうか。
    |   |
    |   | 生成された source を確認してみると declare -a sources=([0]="argument 0")
    |   | が生成されている。うーん。つまり、core-syntax.sh に於いて単語内部の nest
    |   | した文脈からだと argument が生成されてしまうという事である。

    "..." の内部の nest した文脈ではそれがコマンド名か引数内部かに関係なく
    argument が生成されてしまうのが原因だった。

    確認してみると以下の関数で argument 決め打ちにしている。
    ble/syntax/completion-context/.check-prefix/ctx:quote/.check-container-word

    判定の為に nest に登録されている単語情報を確認しているが不思議である。 CMDX
    や ARGX になっている。CMDI や ARGI ではないのだろうか。特に nest が始まった
    のが単語の途中であっても CMDX や ARGX になっている。

    > function ble/syntax:bash/ctx-command/.check-word-begin {
    >   if ((wbegin<0)); then
    >     local octx
    >     ((octx=ctx,
    >       wtype=octx,
    >       ctx=_ble_syntax_bash_command_BeginCtx[ctx]))

    うーん。この部分を見ると wtype は単語が始まった瞬間の文脈を保存している。

    > function ble/syntax:bash/ctx-command/check-word-end {
    >   # 単語の中にいない時は抜ける
    >   ((wbegin<0)) && return 1
    >
    >   # 未だ続きがある場合は抜ける
    >   ble/syntax:bash/check-word-end/is-delimiter || return 1
    >
    >   local wbeg=$wbegin wlen=$((i-wbegin)) wend=$i
    >   local word=${text:wbegin:wlen}
    >   local wt=$wtype
    >
    >   [[ ${_ble_syntax_bash_command_EndWtype[wt]} ]] &&
    >     wtype=${_ble_syntax_bash_command_EndWtype[wt]}

    更に此処で _ble_syntax_bash_command_EndWtype を用いて最終的に記録する wtype
    に変換している。という事は実際の判定でも _ble_syntax_bash_command_EndWtype
    を参照するべきである。

    [修正]

    * done: compcmd が空文字列の時に bash は '' を出力する。つまり微妙に quote
      するという事。

      $ complete -o bashdefault "''"
      $ complete -o bashdefault ''
      $ complete -p

      試した見た限りでは空文字列の時にだけ '' と出力してそれ以外の場合には直接
      出力する様である。これについては一つ対策を入れる必要がある。これは他の問
      題を修正してから取り掛かる。

  * util (assign): Cygwin で assign 一時ファイルの衝突が発生している様だ [#D1578]

    assign 一時ファイルに BASHPID を付加する様にしたら特に問題は発生しない様子。
    なのでやはり assign 一時ファイルの衝突なのだろうと思われる。実際に保存され
    たファイル名を観察するとやはり衝突が起こっているかも知れない。

    特に頻繁に起こるのは background シェルと親シェルに於ける
    ble/function#getdef なのだろうという気がする。取り敢えず、ble/util/assign
    におけるファイル名の確保を関数に纏める事にする。

    呼び出し元を出力して調べてみた所、そもそもサブシェル内部から呼び出しが発生
    しているのは ble/bin/awk の初期化のみの様であった。ble/bin/awk を、
    ble/util/assign が設定されてから即座に初期化する様に修正してみた所、
    subshell 内部からの ble/util/assign は全く発生しなくなった。

    * 他に気になることとしてはファイルの中身が残ってしまっているという事。

      dec する場所で一緒に clear する事も考えてみたが、実際に実装を見てみると一
      時ファイルの中身を呼び出す前に dec している。読み出し中にエラーがあって中
      断した時の事を考えてだろうか。然し、実行が中断してしまう程のエラーが起こ
      る状況が分からない。set -ue は off にしているし failglob は起こりようがな
      い。なので、dec の位置を変更して dec と一緒にファイルのクリアも行う様にす
      るというのは一つの手である。

      特に大量のデータがある場合にはやはりファイルの中身をクリアするのが望まし
      い。これで多少パフォーマンスが落ちてしまうかもしれないが、問題になりそう
      なのは初期化ぐらいの物であって、初期化の場合には色々他にも bottleneck が
      あるだろうという事で余り気にしない事にする。いざ初期化時間を縮めようと思っ
      たらまた何か別の初期化を遅延させる事にするのが良い。何れにしてもプロファ
      イリングした上で決める事である。

      取り敢えず今の所はファイルの中身は消去する事にする。

    対策は取り敢えずそれでよしという事にする。

2021-05-28

  * ble-reload した時に alias が無効になってしまう [#D1577]

    何故だろうか。そもそもshopt -u する様な事はない…と思ったが、うーん。これは
    単純なミスである。

  * history: bash-3.0 で履歴の数が減少していく問題が再発している [#D1576]

    これは対策をした筈なのに何故だろうか。

    取り敢えず対策コードにちゃんと進入しているのかどうかだけでも確認する。

    再現条件が分かった。bashrc からロードしていると発生しないが、コマンドから
    source して attach すると発生する。bash-3.1 では再現しない。

    該当箇所で確認したがちゃんと復元できている様な気がする。history -p で検索し
    てみたらもう一箇所別の場所で呼び出している。其処の判定条件を確認すると
    bash-4.0 未満の場合には無条件でサブシェルで実行している様に見える。と思った
    がよく見たら _ble_bash となるべき所が _ble_base になってしまっている。

    然し、そもそもサブシェルの判定は ((BASH_SUBSHELL)) で判定できるのでこんなに
    複雑な式を用いる必要はない。

    * done: 算術式の中で誤って _ble_base を使ってしまうという事が余りに多いので
      これも make_command.sh に登録しておくのが良い気がする。登録した。

      $ grc '\(\(.*\b_ble_base\b.*\)\)'

      他には同じミスをしている箇所は存在しなかった様である。

  * main: set -u で壊れていないか久しぶりに確認する必要がある気がする [#D1575]

    試してみたら沢山のエラーが発生している。というか本来 set +u で待避している
    筈なのに何故こんなに沢山のエラーが発生しているのだろうか。不思議である。
    一通り attach する迄の部分を修正していったが実は必要なかった。

    何故 set +u できていなかったのかというとそもそも adjust-bash-options 自体の
    guard で未定義の変数を触っていた為に、adjust-bash-options が実行されていな
    かったのが原因だった。それを直したら普通に動く様になった。

  * main: expand_alias の設定を変えるのはやはり良くない [#D1574]

    現在 ble.sh の内部では完全に alias を無効化しているが、そうすると blerc の
    中で alias を使っている場合に対して影響が出るのではないかという気がする。そ
    の場合には関数を使う様に指示する事もできるが、やはり alias が使えないという
    のは特殊な気がする。

    特に何らかのフレームワークを介して意図的に alias を使って様々の事を実現して
    いるという場合も考えられる。そういう事を考えると alias を何もかも動かなくし
    てしまうのは違う様な気がする。

    うーん。expand_aliases が影響を与えるのは主に ble.sh のロード時であって、ロー
    ドが完了した暁には殆ど影響はない? 然し、実際には沢山の eval を使っていて
    eval は影響を受ける。特にキーワードや builtin に名前が一致する様な alias に
    関しては対策を行っている。その他に影響を与える様な変な alias を設定している
    人がいたとしたらそれはその人が悪いのであって、ble.sh の関知する所ではないの
    ではないか。という事を考えるとやはり alias は有効のまま処理するべきの様な気
    がする。

    一応 expand_aliases の adjust を導入した時の議論を確認して問題がないか考え
    る。該当する議論は #D1519 にある。関連する問題として #D1526 があった。改め
    てこれについて考え直すのが良い。

    * 少なくとも adjust builtins をした後には expand aliases は必要ないのではな
      いかという気がする。或いは、adjust builtins で待避する alias の数を増やす
      必要がある気もするが。

    これの修正は簡単だった。他に影響が現れるとも思いにくいが一応確認はしておく
    事にする。

    と思ったらやはり単純ではない様だ。どうやら alias の状態が bind -x を跨いで
    戻ってしまうのは shopt -u expand_aliases している時だけの問題ではなくて、
    shopt -s expand_aliases だった時にも同様の様である。なので、やはりユーザー
    の側でどういう状態になっていたのかという事を記録・復元する必要がある。

  * ble-sabbrev の初期化遅延で内容出力迄も遅延されている (bash-3.*) [#D1573]

    ble-sabbrev の初期化を遅延しているが、内容確認の為の ble-sabbrev ですら遅延
    されて、ロードした時になってから内容が出力される。この振る舞いは修正するべ
    きである。然し、これを検出する為には、ble-sabbrev の一時実装の側で引数を解
    析する必要がある。

2021-05-27

  * canvas: 変数リークしている (buff, trap, {x,y}{1,2}) [#D1572]

    buff, trap は直ぐに見つかったが x1,x2,y1,y2 は使っている所が多いと思われる
    ので探すのは面倒である。とは言え特にプロンプト関係が怪しいと思われる。

    結局 x1,x2,y1,y2 は trace 自体が駄目だった。justify の初期化位置よりも後で
    local x1 x2 y1 y2 が宣言されていたのだった。然し、この justify の初期化位置
    は此処でなければならなかったのか。そういう理由があった様な気もするがこれに
    ついてはテストで確認する必要がある様に感じている。contra によるテストを設定
    して確認する必要がある。contra でテストを実行してみた所、特に問題なくテスト
    が通った。なのでこの部分の順序変更については気にしなくて良いだろう。

  * 新しい ble-face, blehook, bleopt で問題が起こっている [#D1571]

    * fixed: blehook で新しい hook を作成できなくなっている。何故だろうか。これ
      は引数解析のバグである。

    * fixed: ble-face --hel でエラーにならずにコマンドを実行することができてい
      る。これは修正した。他にも '-' に対する処理を blehook, bleopt と共に修正
      した。

    * fixed: ble-face --color=xxxx のエラーメッセージ表示時にエラーが発生する。
      直した。blehook, bleopt についても --color=xxxx と指定した時のエラーメッ
      セージを改善した。

    * done: ble-face の使い方を wiki にまとめる
    * done: --help に color の説明を含める。

  * bash-3.0 の初期化時に bleopt が出力されてしまっている [#D1570]

    % bash-3.1 では特に問題は起こっていない。という事はまた何かの bash bug に嵌っ
    % ているのか或いは場合分けのコードで bash-3.0 専用の部分に問題があるのか。
    %
    % --norc で source すると問題は起こらない。後で source ~/.blerc すると再現
    % する。同じセッションで再度呼び出せば再度発生する。これも解析のバグである
    % 様な気がする。不思議な事に一回目と二回目で起こる bleopt の位置が異なる。
    % 或いは、起こる回数が変わっているという事か。
    %
    % どうやら bleopt a:=1 という形で呼び出すと read-arguments の結果が空になる
    % 様だ。調べるとスカラーに対して ${var[@]/%/=value} 等とすると失敗する様だ。

    これはまた bash-3.0 のバグである。うーん。調べた限りだと、
    ${scalar[@]/xxxx} の形式は全て空になる。

    $ grc '\$\{[a-zA-Z_0-9]+\[[*@]\]/'

    で検索してみるとそんなに沢山は存在しない。取り敢えず全て確認 or 対策をする
    必要がある。また、m scan に含めるべきである。

    * 確認した所、既存のコードは全て配列に対して異実行していたので問題ない
    * m scan にも含めた。

    x local i "${vars[@]}" に変更漏れがあった。これも後で修正する。

    * 後これは遡って適用するべき項目である。なので独立した項目にする事にする。

  * util: gdict 再考 [#D1569]

    gdict について質問された。説明しようとして思ったのだが、現在の gdict の実装
    は ble.sh の中で直接 global dictionary を作る時を想定していて、module の中
    から global dict を作る場合は想定していないのだった。bash-4.0 で関数内から
    source した時には問題が生じる事になる。

    gdict はもっと一般に使う事ができる様にしたい。つまり、必ずしも直接 source
    した所から使うのではなくて、一般のスクリプトから使える様にしたいのである。
    そう思うと gdict は bash-4.2 以上でのみ使う事にして、それとは別に ble.sh 内
    部から使う為の gdict を定義するべきなのではないか。

    うーん。でもグローバルに何かを定義するのは常にグローバルであるという想定は
    妥当な仮定だという気もする。という事を考えると gdict は現在の実装でも良い気
    がする…と考えたが、もしグローバルな文脈でちゃんと定義できるのであればわざ
    わざ gdict を使わなくても dict を使えば良いのだという事になる。

    * 此処で改めて gdict の存在意義について考えてみると、"関数内で source され
      た場合にもグローバルに辞書を宣言したい" という事にある。

      a 一つの方法は何処から source された時にも使える様に 4.2 以上でのみ本当の
        辞書にしてそれ以外では配列実装に切り替えるという方法。

      b 然し、何処かに辞書ごとの実装の種別を記録しておいて、その種類に応じて辞
        書実装を切り替えるというのも一つの手である。然し、そうすると複数の変数
        に記録する事になってしまうので何だか変な感じがする。

        現在の辞書の実装ではキーを x$key にしているので、他の要素は特殊用途の為
        に使う事ができる。つまり、要素 0 に種別を格納しておくという事も可能であ
        る気がする。然し、配列実装の側では要素 0 はちゃんと意味のある要素として
        使っているので其処を変えるのは変な気がする。

        或いは、毎回 is-array を呼び出すという手もあるのかもしれないと考えたが、
        問題の bash-4.0, 4.1 では is-array の判定に assign を使っているので、辞
        書のアクセスの度にファイルの読み書きが発生する事になって気分が悪い。

      c 或いは、bash-4.0, 4.1 の時にだけ実装種別の判定を行う様にすれば良いので
        ある。

        またこの方法の場合には宣言時に [[ $FUNCNAME ]] 等を確認して宣言を切り替
        える必要がある。

        % if [[ $FUNCNAME ]]; then declare -gA X;
        %
        % x もう一つこの方法の弱点。この方法では FUNCNAME が期待通りに動く事を想
        %   定している。然し、ユーザーが unset FUNCNAME をしてしまっていると
        %   FUNCNAME は常に存在しない事になってしまい、誤判定してしまう。実は
        %   FUNCNAME がちゃんと動作しているかどうか確認する為には一回関数を呼び出
        %   して要素数が変化するか見れば良い。
        %
        %   % 類似の変数として FUNCNAME, BASH_LINENO, BASH_SOURCE が存在する。で
        %   % は、これらの変数が全て使用不能になっていたらどうすれば良いのだろう
        %   % か。(改めて確認した所、BASH_LINENO 及び BASH_SOURCE は関数呼び出し
        %   % でなくても常に存在している様である。そして source の場合にも要素の
        %   % 数が変化する。という事を考えると関数内かどうかの判定には使えない気
        %   % がする)
        %
        %   b BASH_LINENO/BASH_SOURCE を使って判定する事は可能だろうか。実際に呼
        %     び出してみてどの様に動作するか確認する必要がある。うーん。両者とも
        %     ファイル名と行数しか表示しないので関数かどうかの判定には全く使えな
        %     い。
        %
        %   c その場合には、caller builtin を使う事ができるだろうか。と思ったがこ
        %     れも駄目の気がする。これは関数であるかどうかに拘らず実行することの
        %     できる関数なので、結局関数内にいるかどうかを判定するのには使えない。
        %
        %     caller の出力を確認すれば一応 "関数名" or "source" を確認する事がで
        %     きる。此処で、"source" 以外の関数名があった時には関数内にいるという
        %     事は確定する。逆に全て "source" だった時にはどうだろうか。取り敢え
        %     ず自分がトップレベルから source されている場合には caller 0 が失敗
        %     する。この場合には "関数内にはいない" という事が確定する。
        %
        %   d reject: 或いは実際にその context で変数を定義してみたら良いのではな
        %     いだろうか。と思ったが、それも駄目である。関数内でもし呼び出されて
        %     いるのだとしたら、結局その関数の文脈にローカル変数が作られるので、
        %     確認する立場からすれば何れにせよ変数が見える事になる。問題は現在の
        %     文脈 (外側の関数) を抜けた時に自分の手元で定義した変数がちゃんと残
        %     存するかどうかという事なのである。
        %
        %   e declare xxxx としてから local で変数が存在するかどうか確認したら分
        %     かるのではないか。
        %
        %   f よく考えたら local が成功するか失敗するかで確実に判定可能なのではな
        %     いか。これだ。これで判定する事ができる…。local が別の理由で失敗
        %     する可能性としてその変数名が特殊変数であったり読み取り専用だった
        %     り型が変換不能だったりという事が考えられるが、_ble_... に選んで置
        %     けば特に問題はない。
        %
        % [source スクリプト内で関数内にいるかどうかの判定方法]
        %
        % 先ず初めに FUNCNAME が特殊な意味を保持しているかどうかを確認する。これ
        % は実際に関数を呼び出してその中で FUNCNAME の要素数が増えているという事
        % を確認すれば良い。もし特殊な意味を保持している場合には、FUNCNAME が定義
        % されていれば関数内にいるし、或いは FUNCNAME が定義されていなければ関数
        % 内ではない。
        %
        % 次に caller の出力を確認する。caller 0 が失敗すれば即ちトップレベルから
        % 直接 source された事を意味しているので、確実に関数外に存在する。caller
        % 0,1,2 を失敗するまで逐次呼び出して行って、途中で source 以外の関数名に
        % 出会ったら関数内部にいる事が確定する。

        local _ble_local_test とでもしておけば関数内部にいるかどうかの判定は可
        能である。というか、現在 FUNCNAME を使って実行しているテストもこれに切
        り替えるべきなのではないか。

        bash-4.2 以上の場合、常に -gA を使う。
        bash-3.2 以下の場合、常に配列を使う。
        bash-4.0, 4.1 の場合は条件分岐する。

        if local _ble_local_test 2>/dev/null; then
          NAME=() NAME_keylist=
        else
          declare -A NAME; NAME=()
        fi

        その様に書き換えた。

      * done: 既存の連想配列に依拠しているコードも、実際に配列が連想配列かどう
        かで判定するべきの気がする。

        現在は _ble_bash_loaded_in_function で判定を行っている。というか面倒な
        ので一部の物に関しては完全に gdict を使った実装に切り替える事にした。3
        つ書き換える事になった。

        - _ble_decode_kbd__k2c
        - _ble_builtin_history_rskip_dict
        - _ble_builtin_trap_n2i

        _ble_bash_loaded_in_function を使っていても gdict による宣言を使ってい
        ない物に関してはそのままにする事にした。

        残っている物は以下の物である。うーんこれらも書き換えてしまうべきだろう
        か。そちらの方が正直な所メンテナンスしやすい。問題は書き換えでバグが入
        らないかという事と、速度的に遅くならないかという事である。特に、現在の
        主なターゲットは bash-4.4 以降であると考えると、古い実装に対して配慮し
        なくても良い様に思われる。

        - ./lib/core-complete.sh:6102:if ble/is-assoc _ble_complete_sabbrev; then
        - ./lib/core-syntax.sh:6290:if ble/is-assoc _ble_syntax_highlight_filetype; then
        - ./lib/core-syntax.sh:6403:if ble/is-assoc _ble_syntax_highlight_lscolors_ext; then

        取り敢えず使われている箇所で速度が気になるかどうかを確認する。結局全部
        新しい実装に置き換える事にした。bash-4.2 以上であれば単に関数呼び出しコ
        ストと、要素が実際に存在しているかどうかの判定コストが増えるだけである。
        結局 s2c のテーブル以外については全て完全に gdict を使う事にした。

      * done: sabbrev の書き換えの際に ble/gdict#keys を使った。
        実装する必要がある。実装した。

    * done: 現在の辞書の中身を表示する為の関数、key の列を取得する為の関数もあっ
      た方が良いのではないかという気がする。

      ble/gdict#keys については既に上で実装した。
      ble/gdict#print については既存の関数を使って実装する事にした。

    * 後、bash-4.0, 4.1 で既に連想配列として宣言されている場合にはそれを流用す
      るべきなのではないだろうか→その様に書き換えた。OK 簡単に確認も済ませた。

2021-05-25

  * util: 設定インターフェイスの細かい修正 [#D1568]
    * ble-face 導入
      * done: ble-color-setface の出力で ref: を認識する
      * done: ble-color-setface で @ の形式に対応する?
      * done: ble-face -r で元に戻せる様にしないと themes の切り替えに困る
      * done: ble-face -u で変更された face を表示する。
    * done: bleopt xxx@xxx=xxxx で一括設定ができる様にする
    * done: bleopt 既定値からずれている物だけ出力する機能
    * done: bleopt 既定値に戻す機能
    * done: blehook internal hook は既定では表示しない機能

2021-05-24

  * global: gA をその場で代入しなければ 4.2 でも大丈夫 [#D1567]

    共通なコードも多くあったので整理して纏める事にした。大分すっきりした。

2021-05-23

  * contrib/git-prompt.sh の変数達は localvar_inherit で駄目なのではないか [#D1566]
    というか他にも同様の変数宣言の仕方をしている箇所は色々ある気がする。
    →検索して修正した。

  * keymap/vi: vim モード表示に関して (reported by huresche) [#D1565]
    https://github.com/akinomyoga/ble.sh/issues/114

    また vim のモード表示に関連する提案・質問が来ている。何処かに纏めておくべき
    であろうと思われる。取り敢えず後で vim mode の wiki ページに少なくとも説明
    かまたは説明へのリンクを載せておく必要がある。

    * done: 取り敢えず keymap_vi_mode_name_xxxx を変更したら mode name の更新を
      予約する様にしなければならない。と思ったが何処で呼び出す様にしたら良いの
      だろうか。現在の実装を確認するとモード変更時に update-mode-name を呼び出
      している。そしてこの関数は即座に表示を行っている。然し、他の関数から mode
      name の設定を変更する場合には、その場で info を表示してしまうと変な事にな
      る。

      a info pane を表示していない時は内部的に変更するに留める? 内部的に入れ替
        えるだけという機能を info に実装する必要がある。また、これだと一連の設
        定を変更した時に各項目ごとに info を表示し直すという事になって効率が悪
        い。

      b やはり更新は遅延させるのが望ましい。然し、遅延させるとしてもどのタイミ
        ングで更新を行うのだろうか。やはり info reveal の瞬間に内容を更新するの
        が良いのではないかという気がする。

      新しく info_reveal hook を追加して b の方針で実装する事にした。

    * vim-airline の API を調べてそれをできるだけ再現するようにするという可能性
      も考えられる。但し、厳密に再現できる訳でもないと思われるが。vim-airline
      の README にはそんなに customization の情報は書かれていない。

      * 単に各フィールドの内容が指定できるというだけの事である。

      * それから、truncation は ble.sh では実装されれていない機能である。うーん。
        これの対応は面倒だ。現在の実装だと trace の中で各フィールドについて計測
        を行って、その上で出力を行っている。なので、truncation も原理的には実装
        可能であるが、(1) 各フィールドの優先順位はどうやって指定するのか (2)
        separator 毎の最大・最小幅をいよいよ実装する必要が出てくる (3) 自動改行
        を抑制する など色々修正が必要である。特にどういう仕様にするのかというの
        が一番面倒である。自然なインターフェイスで separator 毎の最大・最小幅を
        指定できる物だろうか。

      よし。vim-airline を真面目に実装する事にする。

      ? 各セクションが空の時にセクションを潰したい。然し、一方で各セクションの
        内容はプロンプトシーケンスとして実装したい。これの両立は可能だろうか。
        うーん。何だか難しそうな気がする。実際に実体化するまでは各セクションが
        潰れるかどうかは判断できない。という事は先に各セクションを実体化するし
        かない。

        * 二重に処理する事になるがそうすると端末固有の SGR を二重に処理する事に
          なるのでは。うーん。一旦 ANSI 形式で出力するオプションを実装する必要
          がある気がする。

      * done: auto-truncation の実装

      * done: gitstatus に関しては後で vim-airline を実際に入れて動作を確認する
        必要がある。どうも vim-airline は tpope/vim-fugitive を使っている様であ
        る。また、dirty 状態かどうかは出力されない様である。取り敢えずよしとす
        る事にする。

        と思ったが改めて確認したらちゃんと出力されていた。機能を追加した。

      * done: ble/color/g2sgr-ansi を実装する
      * done: trace ansi の実装

      x fixed: prompt_status_line の再描画の時に前回の内容がクリアされない (g=0
        の時)

        うーん。不思議なのは直接 printf するとちゃんとクリアされるのに、
        ble/util/buffer 経由で出力しようとするとクリアされないという事。何故だ
        ろう。内容が消滅している可能性? 或いは、DRAW_BUFF か何処かに出力内容が
        残っている可能性もあるのかもしれない。

        調べてみると ble/util/buffer の中に excursion しているコードが入ってい
        る。うーん。どういう事だろうか。誰が ble/util/buffer に内容を入れている
        のだろうか…。不思議である。と思ったら enter-command-layout で info や
        status を消していて、その為に excursion 状態になっているという事の様だ。

        うーん。そもそも WINCH が起こるとこれまでの panel height も全て消えてな
        くなる訳だから、panel height に対する差分修正では駄目の筈である。高さを
        全て確保し直さなければならない。という事を考えると… height を全て空に
        すれば良いのだろうか。或いは。

        | →これは結局様々な問題が複合した結果だった。高さの完全再配置が実装され
        | ていないのが主な問題。そして LINES COLUMNS が反映される迄にどうやら時間
        | がかかる様だというのがもう一つの問題。後者については仕方がないので待ち
        | 時間を入れる事にした。
        |
        | と思ったがこの後者の問題はウィンドウサイズを変更する時に contra がリア
        | ルタイムに大量の WINCH を発生させるのが原因の様である。bash trap はシグ
        | ナルの回数を覚えていないので単に一回だけ発生している様に見えただけだっ
        | た。contra の実装が悪いとも言えるが、然し滑らかにサイズ変更をする端末で
        | は普通に起こって良い事なのでこれに対する対策を入れるのは良い事である。

        問題は最後の WINCH を捕まえる事ができないという事である。trap handler
        を実行している間は実行がブロックされている。WINCH の処理の最後で再度
        LINES COLUMNS が変化していないか確認すれば良いのではないか。
        →その様に変更したら可也振る舞いが改善した。

      x fixed: SIGWINCH で乱れる問題。実は tput で端末の大きさを取得すれば良い
        のでは。というか (:) 等を実行しても checkwinsize で更新されるのではない
        か。と思ったが tput で取得しても LINES COLUMNS で取得してもずれがある様
        である。

      x fixed: prompt_status_line が WINCH で再描画されていない?
        none になっている時に塗りつぶしを省略しているのが原因である。
        huresche にも改めて指摘されたのだった。

      x fixed: menu-complete が動かなくなっている。trace に手を入れたのが原因だ
        ろうか。

        あー。多分、合成がうまく行かなくなっている。改めて実装を確認する。と思っ
        たら動く様になっている。これも WINCH をした後に生じる問題だろうか。うー
        ん。その様だ。WINCH によって何故動かなくなるのが…謎である。

        menu#render-item はちゃんと呼び出されている。ちゃんと出力も構築されてい
        る気がする。出力までもちゃんと行っている気がする。ああ。分かったかもし
        れない。これは info が invalidate された儘になっているという事なのだろ
        う。直した。

      * done: https://itchyny.hatenablog.com/entry/20130820/1376978742
        此処で紹介されている landscape という配色がなかなか良いのではないか。
        と思って確認してみたがコードはなかなか面倒な事をしている。
        後でどういう結果になるのか調べてみる事にする。

        設定を抜き出しては見たが実際にやってみると白背景だと微妙な感じだ。

      * done: theme の設計を考えると eval-after-load ができる様にするべきでは。
        うーん。現在の実装だと eval-after-load は def.sh に登録している。然し、
        そうではなくて ble-import の枠組みの側で提供するべきなのではないだろう
        か。

        これは大きな変更になりそうな気がするので後回しにする。
        →結局そんなに大きな変更ではなかった。簡単だった。

2021-05-22

  * main: set -e の時にロードできない [#D1564]

    またロードできなくなっている。これは本当は定期的にテストしなければならない
    事の気がする。

    * adjust-builtins で失敗している。alias 定義を読み取る時の alias ... と、
      alias を削除する時の unalias に於いて存在しない alias を取り扱おうとする
      と exit status が 1 になって駄目の様である。

    * prompt attach の際にも問題が生じていた。二箇所条件の書き方を変更した。

      * blehook でも失敗している。中に於ける if builtin eval ... ; then ... が
        駄目の様だ。試してみると

        false || true # OK
        eval false || true # OK
        builtine eval false || true # 駄目

        という具合の動作になっている。bash-4.4, dev で確認した。3.0, 3.2 でも同
        様の振る舞いである。これは後でバグ報告に持っていく事にする。

        問題の箇所は eval を使わない形式に書き換える事にした。

    これでまたロードできる様になった。本当は blehook, ble-bind その他のインター
    フェイスについても set -e に対する対策をするべきの気もするが取り敢えず何も
    設定しない限りに於いては動くので良しとする事にする。そもそも set -e で対話
    シェルを使おうとする事自体があり得ない想定なので余り深く考えなくて良い。

  * 2021-05-16 complete: tar xf groff-1.19.2.ta[TAB] でエラーが発生する [#D1563]

    と思ったらこれは bash-completion だった。また確認してみたところ、これは5週
    間前に既に修正されていた様だ。

2021-05-20

  * 2021-05-13 tmux-resurrect により vi_imap が empty になる問題 (reported by RakibFiha) [#D1562]
    https://github.com/akinomyoga/ble.sh/issues/109

    "ble.sh: The keymap 'vi_imap' is empty." というエラーメッセージが出るとの事
    だが他には何もメッセージは出ないのだろうか。試しに keymap.vi を空にしてロー
    ドしてみると…再現した。

    * bash ble.sh --clear-cache オプションを実装した方が良い。

    * ファイルが存在するかどうかのチェックをしている箇所は、全て有限の大きさを持っているかどうかを確認した方が良い。

    * 空の keymap になっていたらキャッシュ無しで初期化し直す機能を付けた方が良いかもしれない。

    うーん。何と再現しなくなってしまった様である。
    こうなるとコードを見て憶測で修正するしかなくなる。

    # {
    #   ble/decode/keymap#load isearch dump
    #   ble/decode/keymap#load nsearch dump
    #   ble/decode/keymap#load vi_imap dump
    #   ble/decode/keymap#load vi_nmap dump
    #   ble/decode/keymap#load vi_omap dump
    #   ble/decode/keymap#load vi_xmap dump
    #   ble/decode/keymap#load vi_cmap dump
    # } 3>| "$fname_keymap_cache"

    あー。もしかすると原因が分かったかもしれない。そもそも前に自分が問題を経験
    した時にもそうだったが、ble/decode/keymap#load を改名した事が原因なのであっ
    た。此処で、ble.sh が部分的に更新されていたりすると問題になるという事なのだ
    ろうという気がする。tmux-resurrect が一体何をしようとしているのかは結局謎な
    のであるが、うーん。

    そもそも報告者が最新の物でも再現するとかしないとか言っていた時に、毎回 make
    をしていたのかというのも疑問の一つである。と思ったが rebuilding と言ってい
    るので、其処の所はちゃんとやっているのだろうという気がする。

    a あー。もしかすると複数の異なる ble.sh を使っていて cache が混合していると
      いうのは十分考えられる可能性である。と思ったが本当にそれで問題が発生する
      だろうか。何れにしても呼び出す vi.sh は同じディレクトリにいる ble.sh から
      呼び出される筈で中途半端に更新されていない限りは不整合は起こらない筈なの
      である。

      或いは tmux-resurrect が下手に関数等を保存しているのだとすると変な事が起
      こっても仕方ない → 試しに関数を定義して保存・復元して見たが関数は消滅し
      ていた。つまり、そういう事は関係ない。

      或いは vi.sh の timestamp が偶然未来に設定されてしまったりする様な場合に
      も問題が起こったりするかもしれない。

      うーん。やはり timestamp が壊れない限りはこれによって変な事が起こったりす
      る可能性は低い気がする。

    b 後タイムスタンプが nfs などによってずれていたりするとそういう事があったり
      するかもしれない。timestamp が信用できない時にはどうしようもない。これは
      個々の使用者の側で注意して時刻を合わせてもらうしかない。

    * done: 失敗したとしても端末の状態が壊れない様にする。

    ? コードを見てみると初期化に失敗した時には完全に空 map になってロードされな
      いのではなくて safe keymap に fallback する筈なのだが何故そうなっていない
      のだろうか。

      これは再現できるので修正はそんなに難しいことはない筈。

    2021-05-20 もう返事もないし再現もできないし、向こうでも何だか解決した様な雰
    囲気を出しているので取り敢えず対症療法を push する事にする。

    * 他にも似たような現象が起こる可能性があるのでキャッシュファイルについて全
      て -s を用いてチェックする事にする。
    * この際なので _ble_base_cache 内の構造・ファイル名についても整理する事にし
      た。

  * syntax: ${a~} に対応していない [#D1561]

    何れ消えると思っていたがどうも未だ消える気配はない様だ。取り敢えず使える環
    境ではちゃんと着色した方が良い様に思われる。

    後気付いたのだが実は ${a^^} や ${a,,} も bash-4.0 から使えた様だ。tolower,
    toupper の実装に使えるのでは。と思って確認した所、既に 4.0 以上ではこれらを
    使う様になっていた。

    軽微な修正だがこれだけ放置していても仕方がないのでもう push する。

  * prompt: update "PS0" between multiple commands (motivated by tycho-kirchner) [#D1560]

    複数のコマンドが一度に実行される時に、それぞれのコマンドについて PS0 が呼び
    出される。然し其処から参照される $# の値が更新されない様だった。調べてみる
    と、PS0 の更新をチェックする時に、更新の必要があるかどうかの判定をする hash
    値が複数のコマンドの間で変化がない為に更新が省略されていたという事。
    →hash に $# ($_ble_edit_CMD) も含める様にして対処する事にする。

  * decode (ble-bind): ble-bind -m KEYMAP で全ての keymap が出力されている (fixup 750ca38) [#D1559]

    これは指定した keymap を表示する様にした方が良い。というか元々そのつもりだっ
    た筈で単に対応を忘れていたという事の気がする。

  * main: bash ble.sh --test の終了ステータス (fixup bbc2a90) [#D1558]

    subshell からのロードを検出する様にした変更に於いて終了ステータスが意図しな
    い物になっていた。これは return $? || exit $? に於いて二個目の exit が
    return の $? を拾う様になってしまった為。

    a 面倒なので、_ble_init_exit は削除しない様に変更して見た。

    b しかし別の修正方法として eval を使う物を思いついた。うーん。eval を使う事にする。

    棄却した a の修正は此処に供養する。
    | diff --git a/ble.pp b/ble.pp
    | index c9a11d8..d172c7d 100644
    | --- a/ble.pp
    | +++ b/ble.pp
    | @@ -1398,9 +1398,9 @@ function ble/base/initialize/.clean-up {
    |    # 一時グローバル変数消去
    |    builtin unset -v _ble_init_version
    |    builtin unset -v _ble_init_arg
    | -  builtin unset -v _ble_init_exit
    |    builtin unset -v _ble_init_command
    |    builtin unset -v _ble_init_attached
    | +  #builtin unset -v _ble_init_exit
    |
    |    # 状態復元
    |    if [[ $_ble_init_original_IFS_set ]]; then
    | @@ -1444,18 +1444,17 @@ ble-import -f lib/_package
    |  if [[ $_ble_init_command ]]; then
    |    ble/base/sub:"$_ble_init_command"; _ble_init_exit=$?
    |    [[ $_ble_init_attached ]] && ble-attach
    | -  ble/util/setexit "$_ble_init_exit"
    |  else
    |    ble/base/process-blesh-arguments "$@"
    | +  _ble_init_exit=$?
    |  fi
    |
    |  #%if measure_load_time
    |  ble/debug/measure-set-timeformat Total nofork; }
    |  _ble_init_exit=$?
    |  echo "ble.sh: $EPOCHREALTIME load end" >&2
    | -ble/util/setexit "$_ble_init_exit"
    |  #%end
    |
    |  ble/base/initialize/.clean-up 2>/dev/null # set -x 対策 #D0930
    | -{ return $? || exit $?; } 2>/dev/null # set -x 対策 #D0930
    | +{ return "$_ble_init_exit" || exit "$_ble_init_exit"; } 2>/dev/null # set -x 対策 #D0930
    |  ###############################################################################

  * global: v0.3-master へのパッチ適用の際に気付いた細かい修正 [#D1557]
    細かい修正が溜まって来たので此処で一つずつ修正を適用してしまう事にする

    * Makefile で run ではなくて tmp を作っていた。ディレクトリ名を変更した時
      に一緒に変更するのを忘れていた。
    * ble/function#suppress-stderr に不要なごみ引数 { を渡していた。
    * C-w M-w の振る舞いを変更したが、blerc に以前の設定に戻す設定例を入れた。

    * IFS の異なる環境に対する対策としてできるだけ _ble_term_IFS を local IFS
      にコピーする様に変更していたが、この際なので直接 $' \t\n' と記述してい
      る部分をできるだけ全て $_ble_term_IFS に置き換える事にした。
    * src/benchmark.sh は独立したファイルとしても使える様にしてきたつもりだっ
      たが、ble/util/print, ble/util/print-lines を使う様になっていたので、こ
      れらの関数が定義されていない時には定義する様に修正した

2021-05-19

  * README: 様々な機能へのリンクを貼った方が良いのではないかという事 [#D1556]

  * 現在の初期化だと ble.sh session で source --test 等すると [#D1555]

    変な事になるのではないか。これは取り敢えず独立した項目として取り扱う事にする。

  * main: subshell 内部で source/reload したら何が起こるのか [#D1554]

    source した場合には何も起こらない。うーん。これは単に attach 戦略が prompt
    だから attach する前に終了しているという事の気がする。

    reload については reload が実際に実行されて色々と _ble_base_run のデータが
    破棄される。この状態で ble-detach を実行すると制御できなくなる。tty 状態は
    別に問題はない様だ。

  * main: AUR blesh-git について [#D1553]

    * ok: requirements: ble-update の為に git, gawk があった方が良いのかもしれ
      ない? 然し、最終的に AUR helper を呼び出すのであれば余り関係ないのかもし
      れない。特に package としては fallback になる事は想定していないので。

    * ok: (("$helper_prog" != 0))
      https://aur.archlinux.org/cgit/aur.git/tree/blesh-update.sh?h=blesh-git#n29

      (()) の中の quote のルールは変更されている。然し何故か PKGBUILD はそのま
      ま何事もなく動作しているどういう事だろうか。shopt が調整されているのだろ
      うか。或いは bash の version が違うのだろうか。適当な PKGBUILD を作ってそ
      の辺りを出力させたらはっきりするのかもしれない。何れにしても将来的に変更
      されるかもしれないという事などを考えると修正した方が良い。

      と思ったが改めて試してみたが問題はない様だ。単に手許で試す時に
      (("$xxx"!=0)) が ((!=0)) に展開されてエラーになっていただけなのであった。
      bash-5.1 で振る舞いが変更されたのは '' による quote の方であった。

    * local variables
      local PRE_VERSION
      local POST_VERSION

      恐らく他の所で使うという訳ではないだろう。というか、この関数は PKGBUILD
      で使われるのではなくて ble.sh から呼び出しているのであるから他の場所から
      使っているという事はない気がする。

    * _package.sh は実の所 source するだけなので実行属性は必要ない。唯、source
      path を経由して source したい時には実行属性がついている必要があるのだった
      か? man bash を確認したがちゃんと実行可能である必要はないとの事が明記され
      ている。

      というか今知ったがカレントディレクトリよりも PATH の方が優先されるのだそ
      うだ。だとすると結構変な事が起こるの可能性もあったのでは。今試しに ~/bin
      に ble.sh を登録して、bash --norc から ble.sh ディレクトリの外で source
      ble.sh を実行したらちゃんとロードされた。うーん。

    * done: contributing に lib/_package.sh を追加する

    取り敢えず残っている物については簡単に纏めてこの項目はOKとする。

2021-05-17

  * util: inherit special file descriptors [#D1552]

    #D1549 で setsid をしたら /dev/tty が見つからなくなって動かなくなった。
    /dev/tty が壊れてしまうという事態に対応する為に最初に確保した
    _ble_edit_io_std{out,err} を他の場所でも積極的に使う様にするのはどうか。

    * 更に考えると毎回 bash を起動する度に新しく fd を確保するのは無駄である。
      なのであれば、export して共有してしまえば良いのではないかという気がする。

    * また、ふと思ったのだが毎回 /dev/null を開いているのはどうなのだろうか。
      dup の方が軽かったりしないのだろうか。然し、/dev/null を dup できるのかと
      いうのも疑問である。然し、fork した途端に使えなくなるというのも変なので
      /dev/null は dup しても大丈夫なのだという気がする。

        $ ble-measure 'echo hello >/dev/null'
        7.439 usec/eval: echo hello >/dev/null (x10000)
        $ exec {fd}>&14; echo $fd
        14
        $ ble-measure 'echo hello >&14'
        5.035 usec/eval: echo hello >&14 (x20000)
        $ ble-measure 'echo hello >&$_ble_base_fd_null'
        5.821 usec/eval: echo hello >&$_ble_base_fd_null (x20000)

      やはり dup の方が高速である。然し、そもそもの処理時間が短いので気にしても
      仕方がないレベルではある。Cygwin でも同様の結果になるだろうか。

        $ exec {fd}>/dev/null
        $ echo $fd
        16
        $ ble-measure 'echo hello >&16'
        24.920 usec/eval: echo hello >&16 (x5000)
        $ ble-measure 'echo hello >/dev/null'
        41.100 usec/eval: echo hello >/dev/null (x2000)
        $ ble-measure 'echo hello >&$_ble_base_fd_null'
        28.320 usec/eval: echo hello >&$_ble_base_fd_null (x5000)

    →Cygwin でも dup の方が高速である。変数に入れると少し遅くなる。然し本当に
    置き換えてしまっても問題が生じないのかというと分からない。例えば
    _ble_base_fd_null がユーザーによって削除または書き換えられてしまったら何が
    起こるだろうか。大量のエラーメッセージが出て色々と悲惨な事になる気がする。
    後、/dev/null への redirect は可也基本的な事なので、もし置き換えるのだとし
    たら何よりも先立って初期化したい気がする。実装を確認すると ble/fd は
    ble/array を使用している。

    * 取り敢えず fd#alloc のコードや stdin/stdout/stderr のコピーのコードを整理
      して、

      (1) stdin/stdout/stderr は常にコピーを保持する様に変更する。

      (2) bash-4.1 以上では {fd}> ... を使う様にしていたがこれだと
      10,11,12,... という番号を使ってしまい、間違って上書きした時に大変な事にな
      るかもしれないので、昔の様に 30,31,32,... を使う様に戻す。但し以前はなかっ
      た上書き確認を行う。此処で問題になるかもしれないのは、他のフレームワーク
      が上書き確認をせずに 30,31,32,... を使おうとした時の事であるが、それは仕
      方がない。比較として考えれば 10,11,12,... よりは安全として差し支えないだ
      ろう。

      (3) openat_base 等のオプションは ble.sh ロード時のオプションから指定でき
      る様にする。

    * done: wiki で openat_base の項目を編集する

  * macOS で groff のエラーが出る (reported by killermoehre) [#D1551]
    https://github.com/akinomyoga/ble.sh/issues/112

    groff -k というオプションが使えないという事。macOS の groff は v1.19 らしく
    これは 2004 の version である。実に17年前の groff である。このオプションは
    UTF-8 の man を処理する為に追加した物。実質的に preconv | groff と同じらし
    い。しかし、そもそも macOS には preconv がないそうだ。というか。そもそも
    groff 1.19 は Unicode に対応しているのだろうか。

    取り敢えず groff をインストールして確かめてみる。うーん。全然駄目。そもそも
    utf8 device が存在していない様である。何か別の物をインストールすれば良いと
    いう訳でもなさそう。device として ascii, latin1, cpxxxx しかない。ascii に
    するしかない。man は LANG=C で探す。

    然し英語の man を探したとしても本当に groff -man が使えるのかも怪しい。と思っ
    たが検索してみると一応 -man には対応している様な気がする。と思ったが -man
    ではなくて -m man としなければならない?
    https://www.unix.com/man-page/osx/5/groff_tmac/

    どうも試してみたら最新版でも -m man で動作している気がする。 -man と -m man
    は synonym という事だろうか。取り敢えず groff -T ascii -m man <<< X | uniq
    が動くかどうかを確認する。

    と思ったが返信がない。取り敢えずこれで良いのかどうか分からないが #D1550 と
    一緒に変更を加えてみる事にする。それでも治らなかったら使う事にする。何か変
    更し残している事はあるだろうか?

    2021-05-17 と思ったら返事が来た。どうも macOS の groff で -T utf8 も一応は
    使える様子である。うーん。という事は \[uXXXX] も取り扱えるのだろうか。

    * もし \[uXXXX] が取り扱えるのであれば適当に \[uXXXX] に全て置換してしまえ
      ば良い。。。と思ったがどうやってやるのか微妙である。awk で変換しようにも
      awk では文字コードを取り出せないので uXXXX の形式に変換するのにも苦労する。
      うーん。od を使って binary に変換してそれから nawk で色々処理して、それか
      らまた od で元に戻すという様な面倒な処理を実装しなければならない。

      % と思ったが binary に戻す方法は不明である。うーん。調べると bash の
      % printf \x??  経由で出力するという事になっている? awk の printf は NUL
      % が出力できないとしている。他の文字は大丈夫だろうか。というより何故 NUL
      % が出力できないのだろうか。

      awk の printf を使うとしたらテストが必要? と思ったが macOS で動けば良いの
      だから BSD awk で動けば十分である→今試した限りだと nawk, mawk, gawk で何
      れもちゃんとできる。NULもちゃんと出力できるのでOK。

    * もしそのまま通過してくれるのであれば特に気にする事はない。が恐らくそうい
      う事はないのだろうという気がする。

    * 或いは結局全然駄目の可能性もある。うーん。どうなんだろうか。

    返事があった。\[uXXXX] で行ける様である。取り敢えず .preconv を実装した。手
    許で試してみる限りは動いている気がする。まあ、実際に動かして変な事が起こっ
    たらその時にまた考え直せば良い。取り敢えず遠隔で実装できるのは此処までであ
    る。

  * complete: ssh -option の後の補完が固まる (reported by rlanore, riblo) [#D1550]
    https://github.com/akinomyoga/ble.sh/issues/98

    $ alias ssh='TERM=xterm ssh'

    で再現するとの情報を得た。他に man -w が現れたり消えたりするという情報も。
    つまり、一つの man -w が 100% になっているのではなくて man -w が繰り返しルー
    プで呼び出されている? また、cache dir に大量のファイルができているという話
    も。つまり、ble/util/assign で無限ループを起こしている可能性がある。

    $ complete -r
    $ source ~/.fzf.bash
    $ TERM=xterm ssh -w[TAB]

    TERM=xterm ssh -bash: 一致しません: /home/murase/.ssh/config.d/*

    ble/complete/source:argument/.generate-from-mandb を見ると alias で展開され
    る限りは無限ループする可能性のあるコードがある。但し、重複判定はしている筈
    なので alias が有限である限りは無限ループにはならない気がするが…。うーん。
    分からない。或いは alias 展開で空文字列になった時に問題が生じる可能性?

    OK! 再現できた!

    - 自分の手元で再現できなかったのはどうも何か別の設定が勝手に
      bash-completion を読み込んでしまうからだった様である。一体何の設定が勝手
      に読み取るのかは謎だが、complete -r を実行しても何故か設定が読み込まれて
      しまう。と思ったが… ble.sh が __load_completion が存在している時には勝手
      にそれを呼び出す様にしていたのだった。そういう設計も考え物といえば考えも
      のである。但し、これも unset -f __load_completion すれば解除する事ができ
      る筈なのである。

    * fixed: 分かった。 ble/complete/source:argument/.contains-literal-option が
      variable leak して ret を書き換えしてしまっている。直した。

    * done: 更に alias で TERM=... としていても対応できる様に読み飛ばし機能も追
      加した。

    x fixed: 然し ssh のオプションを抽出するのに失敗している。何故だろうか。改
      めて振る舞いについて調べる事にする。ble/util/assign を ble/assign と書い
      ていた。修正した。

    x fixed: 未だ駄目。と思ったら man を探索する部分で $command とするべき所が
      $man になっている。

    x fixed: それでも駄目。調べると ssh の man を gzcat する所まではできている。
      其処から関係のありそうな物を抽出する所で失敗している。うーん。man から
      mdoc に変化するという場合もある様だ。どちらでも良い様に色々書き換える。然
      し、それでも nroff の形式がよく分からないので行き当たりばったり的な実装に
      なってしまう。取り敢えず Dd, Nm, Xo-Xc に対応した。また後段で __ble_key__
      と __ble_desc__ が同じ行になってしまった場合でも動く様に修正した。

    x fixed: エラーが出る groff -[TAB] ... これは nawk に日本語のコメントを渡し
      たのが行けなかった。日本語のコメントは除去する様にした。

    x fixed: 空白が沢山表示される。連続する空白は1つに縮約する様にしたい。

2021-05-16

  * work around Kitty bugs (reported by NoahGorny) [#D1549]
    https://github.com/akinomyoga/ble.sh/issues/110

    | bash-it に追加する事について考えると言っているがどの様な形で追加するのだろ
    | うか。コードを直接追加するのだろうか。その場合には色々と微妙。
    |
    | * 先ず ble.sh の codebase は bash-it よりも巨大だ。どかんと入れる事が良い事
    |   なのか分からない。
    |
    | * ble.sh 自体巨大だし UX 自体を大きく書き換える。それ単体として Issue/PR が
    |   頻繁にある。もし単純にスクリプトを追加すると、bash-it に issue が沢山立つ
    |   事になる。それよりは ble.sh の側に Issue が来て欲しい。
    |
    |   * 実は結構好みが別れる様であるという事。autosuggestion を off にしたいと
    |     いう人もいたりするし、syntax-highlighting が遅いという人もいる (これは
    |     完全なる思い込みだと思うが…)。
    |
    |   * 独立した設定ファイルが存在するという事から、ユーザーにちゃんと説明する
    |     必要があるという事。
    |
    | * 自分勝手な事だけれども、bash-it の一部として普通になってしまうと star が
    |   こっちに来なくなる。bash-it の方がメインだと思われるのは嫌である。
    |
    | * bash-it 自体にパッケージマネージ機能などがあればそれを通してインストール
    |   して貰うのが良いという気がする。それがなくても単に git clone etc. を内部
    |   的にして貰うのが良いという気がする。
    |
    | * theme の充実を図りたい。これは渡りに船なのではないか。然し、bash-it にも
    |   theme があるのだという事。
    |
    | * gitstatus.plugin.bash を見ると別に他のプロジェクトをそのまま追加している
    |   という訳ではない様である。存在が確認できた時に追加の設定を行っている様に
    |   見える。

    何だかそういう雰囲気でもなくなったので気にしない事にする。

    未だ Kitty で変な状態になるそうである。例えば setsid 関係で何か変な事が起こっ
    ている可能性? と思ったがもしそうだとするともっと滅茶苦茶な事が起こる様なの
    でこれは多分関係ないのだと思う。

    ble-detach をした後でも問題が再現しているという事を述べている。うーん。試し
    てみたら分かった。これは modifyOtherKeys の解除ができていない。\e[>4;0m が
    効いていないという事なのだろうか。と思ったら、どうもそういう訳でもない。
    printf $'\e[>4;0m' を送ったらちゃんと動く様になる。

    改めて詳しく見てみると…どうも external の既定は 1 の様である。取り敢えず
    workaround を追加する。

2021-05-15

  * package: AUR package (suggested by huresche, help by oc1024) [#D1548]
    https://github.com/akinomyoga/ble.sh/issues/108
    Ref #M0020 PKGUBUILD の書き方

    AUR の PKGBUILD の提案を受けた。PKGBUILD の内容を確認してみる。

    | > arch=('x86_64')
    |
    | arch=('any')
    |
    | > makedepends=('git')
    |
    | makedepends=('git' 'gawk')
    |
    | > pkgver() {
    | >     cd "${srcdir}/${_pkgname}"
    | >     printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
    | > }
    |
    | >     install -Dm644 ./note.txt "${pkgdir}/usr/share/doc/${_pkgname}/note.txt"
    |
    | `note.txt` is just a private note but not a part of the documentation.

    というか既にパッケージにしている人がいる。
    https://aur.archlinux.org/packages/blesh/
    https://aur.archlinux.org/packages/blesh-git/

    PKGBUILD の説明は此処にある
    https://wiki.archlinux.org/title/VCS_package_guidelines
    https://wiki.archlinux.jp/index.php/PKGBUILD
    https://wiki.archlinux.jp/index.php/%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90#.E9.96.A2.E6.95.B0_pkgver.28.29

    * fixed: 自分で試しに install を実行してみた所 644 になっていない。うーん。
      644 もしくは 755 になる様に umask 022 とした。

    ble-update を実行すると何が起こるのだろうか。
    取り敢えず複数の方法を組み合わせて対応するのが良い。

    a /usr/* /opt/* etc であって、
      ファイルが存在するけれど書き込み権限がないという時には、
      sudo bash "$_ble_base/ble.sh" --update を実行する。
      sudo の存在チェックも一応する必要がある気がする。

      (a) repository の書き込み権限がない場合と、(b) install 先の書き込み権限が
      ない場合の二つがある。(c) それから repository が見つからなくて、install
      先の書き込み権限がない場合もある。(a) と (c) の場合には全体を sudo で実行
      し直せば良い。但し、(a) の場合には他のユーザーのディレクトリを sudo で更
      新してしまうと変な事になるのでユーザーのチェックは必要である。権限昇格し
      た後に [[ -O file ]] でチェックすれば良いのだろうか。取り敢えずその方針で
      行く。

      この為に ble.sh --update に対応する必要がある。

    そもそも勝手にアップデートして良いのだろうか。複数のユーザーが勝手にアップ
    デートしたらどうなるのだろうか。と思ったが sudo 権限を持っているユーザーが
    勝手に物を実行するのが悪い。sudo を使ってインストールするのだからそれなりに
    他の人に気を遣うべきである。

    b アップデート用のスクリプトを作って sticky bit を付けて無理やりアップデー
      トを実行するという手もある。これは他のユーザーが同時にアップデートしたり
      する危険性が高いし、管理者権限で現在の ble.sh の状態を管理する事が不可能
      になるので駄目。

    c package manager が存在したらそれを使うという手を安易に提案されたが、それ
      だと package manager を使わずにインストールされたのに勝手に package
      manager 経由で再インストールされてしまうという事になりかねない。まあ、
      /usr/share に入っている時点で何らかの package manager を経由しているとい
      う事は明らかなのだから、余り気にしなくて良いのかもしれない。

      と思ったが現在の所は AUR ぐらいしか存在しない。そして AUR ではどの様にアッ
      プデートしたら良いのかよく分からない。単に再インストールすれば良いのだろ
      うか。或いは一旦削除してそれから入れるのだろうか。

    d done: package maintainer の用意したファイルを source するという提案。これ
      も確かに一つの手である。例えば lib/init-package.sh を使う。

      * 名称について: もしくはlib/init-PACKAGE.bash 等の方が良いかもしれない。
        もしこれらのファイルが存在したらそれを source する事にする。PACKAGE と
        大文字にしていると PACKAGE の部分を package manager の名前に置き換える
        のだと勘違いする人がいるかもしれない。やはり此処は init-package.sh にす
        るべきだろうか。然しそうすると今度は他の普通のファイルとの見分けが付か
        ない。或いは単に lib/package.sh とするか。或いは、lib/_package.bash と
        いう形にするのが良いだろうか。

        うーん。lib/_package.bash もしくは lib/_package.sh という事にする。内部
        で、ble/package/update なる関数を定義してもらう事にする。

    * README にリンクを貼る。README が長くなるのも面倒だし、そもそも普段使って
      いる人はコマンドを見なくても分かる筈。という訳で取り敢えずはパッケージ名
      だけ分かる様にしておく。

      一つ一つのコマンドについては Wiki にページを作る事にすれば良いだろうか。
      然し、Wiki のページに跳ぶのも面倒である。それにリンクが沢山あるのも変な感
      じがする。或いは、リンクは Wiki のページだけに向かわせる事にする。パッケー
      ジ名は単なる文字列とする。それが良い気がする。

    2021-05-23 oc1024 に間違いを指摘された。修正する。

2021-05-11

  * bind: 無引数 ble-bind で現在の binding を表示。現在の binding の着色 [#D1547]

  * complete: ble-sabbrev の出力の着色 [#D1546]

  * edit: やはり \C-x\C-v で ble.sh の version を表示したい気がする [#D1545]

    ble.sh, version 0.4.0-devel3+c89aa23 (noarch)

    Issue template での要求項目も簡単になる。現状だとユーザーに長いコマンドを入
    力させている。

  * 2019-02-09 うーん。git や bash-it の様に ble.sh でも ble コマンドの様な物を提供するべき? [#D1544]
    cf #D1543

    % と思ったが既に何処かには ble という名前のコマンドが存在していて、
    % これらは Bluetooth のサービスの開始・終了などを実行するのに使われている様子である。
    % もしこれらが広範に用いられている物なのだとしたら使いにくい。
    %
    % また、ble の名前の由来である zle コマンドの事を考えると、
    % ble widget の様な使い方を想像してしまうのではないかとの問題もある。
    %
    % 混乱を防ぐためには ble ではなくて ble.sh または blesh の様な名前が良いだろう。
    % しかしそうすると現状の ble-import だとかの機能を呼び出すのに余り適していない気がする。
    % つまり、blesh import ... で ble-import が呼び出されるというのは分かりにくい。
    % 或いは現状の ble-import を blesh-import に改名するという手もあるかもしれないが、
    % そういう事を考え始めると全ての関数を ble から blesh に改名したくなる。
    % それは面倒だし、元の zle という名前から離れていくので余りやりたくない。
    %
    % 実のところ、現状のまま ble-* の方が自動的に補完が効くので嬉しい。
    %
    % bash.env は bash.env という名前のコマンドを提供する様である。
    % https://github.com/midwire/bash.env
    % そういう事であれば ble.sh でも ble.sh という名前の関数を提供すれば良い気がする。
    % しかし ble.sh が入力しやすいのかというと微妙ではある。
    %
    % bash-it の場合には bash-it-update だとか bash-it::update だとかだと
    % 格好が悪いので bash-it update という形の関数名になるというのは分かる。

    結局 ble という名前で定義する事にした。既に同名のコマンドが存在している場合
    には、引数を認識できない時に限り元のコマンドを呼び出す事にした。

  * main: BLE_ONLOAD [#D1543]
    https://github.com/akinomyoga/ble.sh/issues/107

    shournal という plugin の作者が PS0, PS1 を使ってコマンド開始・終了を検出し
    ようとしている。それはそれで良いのであるが、ble.sh は PREEXEC, POSTEXEC と
    いう物を用意している。考えてみれば他の枠組みで使ってもらう為には、ble.sh の
    ロードの順序に関係なく PREEXEC, POSTEXEC が存在すればそれに attach できる様
    に記述したい。

    % ble.sh がロードされた時に呼び出す配列も用意した方が良いのではないか。
    % ble.sh がロードされた段階では blehook コマンドは使えないし、blehook の内
    % 部形式を上書きしようにも _blehook_h_... だとか様々な配列があって直感的で
    % ない。ロードした時に関しては特別に BLE_ONLOAD 的な配列を用意しても良いの
    % ではないだろうか。

    という事を考えると ble.sh が後からロードされた時の為に

      BLE_ONLOAD

    という配列を用意して其処に初期化用のコードを登録させるというのが手である。

    然し、ble.sh をロードしているからと言って attach しているとは限らない。
    plugin が動作を切り替えるのに使える関数を用意するべきなのではないか。現在
    ble.sh がロードされていてかつ attach していて更にユーザーコマンドの実行中で
    ない時という判定をする必要があるのではないか。

    取り敢えず zle を真似て ble という関数で現在の状態を検出できる様にしようと
    したが…。ble.sh がロードされていない状況にも対応する為には結局変数に頼るべ
    きなのではないか。実のところ特に ${_ble_attached-} をチェックすれば良いので
    はないかという気がする。問題は _ble_attached は明らかに内部変数といった形に
    なっていて公開に躊躇するという事。

    a _ble_attached を BLE_ATTACHED に改名する?

      値を設定している箇所は ble.pp 内部の5箇所のみである。なのでこの部分の変更
      はそんなに大変ではない。然し参照している物の内には fzf-marks も含まれてい
      る。うーん。

    b _ble_attached と共に BLE_ATTACHED も使える様にする?

      変更している箇所が 5 箇所なので連動して変更するのは簡単である。

      また、bash-4.3 以降では nameref を使える。唯、nameref 属性を追加する為に
      は -g が必要である。と思ったが -g は 4.2 から使えるので問題はない。

      そうは言っても version 毎に連動して変更するコードを実行するしないというの
      を切り替えるのも面倒なので、やはり常に明示的に連動して変更する様に書く方
      が楽である。

    * done: BLE_ATTACHED を公開変数にする。

    * done: ble コマンドで現在内部にいるかどうかを判定できる様にする?
      [[ $_ble_attach && ! $_ble_edit_exec_inside_userspace ]]

      0neGal が ble という名前のコマンドを作っていた。勝手に他の人がコマンドを
      作成する前に ble コマンドを予約しておくのが良い気がする。然し、他のコマン
      ドと被った時の為に本当の関数名は別にしておく? だとすると何が良いだろうか。
      調べると blesh というのも既に Bluetooth Low Energy の CLI ツールとして存
      在はしている様である。然しだからと言って blectl だと更に Bluetooth Low
      Energy の制御に使うコマンドの様である。ble-cli だとか blecli も同様である。
      或いはユーザーから直接使って貰う可能性は考えずに ble/dispatch にするとい
      う考えもある。然し、ユーザーに使われる事を想定しないのであれば、抑々別名
      として退避する意味もよく分からない。

      名前に関しては 2019-02 に既に議論が存在している。ble.sh という名前の関数
      を定義するという手についても示唆されている。bash.env や bash-it はそのま
      まプロジェクト名がコマンド名になっている。然し、ble.sh は既に沢山の関数を
      ble... としているのでやはり ble が最適である様に思われる。

      うーん。やはり ble -> ble/dispatch という事にする。と思ったが面倒なのでも
      ういきなり ble を定義している。後で問題になった時に処理すれば良い。と思っ
      たがやはり ble/dispatch を定義した。

    * done: blehook ATTACH, DETACH 対応した。

  * PS0 の中での \# の展開結果が異なるという話 (reported by tycho-kirchner) [#D1542]
    https://github.com/akinomyoga/ble.sh/issues/107

    これはそもそも ble.sh ではコマンドの受付と実行を分離しているからである。こ
    の様に疎結合にしたのに逆にその場で実行する様に書き換えるのは設計として許容
    できない。それに実際にその様に実装しようとすると色々と複雑になってしまう。
    なので、現在の枠組みの範囲内でそれを再現する様に実装しなければならない。

    もう一つの問題は ble.sh では同時に複数のコマンドを実行する可能性があるとい
    う事。そして、PS0 は各コマンド実行の直前に実行する物であって、PS1 はプロン
    プト表示の前に実行する物であるという事。という事を考えると、

      [PS0]
      COMMAND1
      [PS0]
      COMMAND2
      [PS1]
      PROMPT

    という形になる可能性もあるのである。

    [修正]

    * fixed: うーん。時々 Cygwin でプロンプトが表示されてからコマンドが実行され
      たりする原因が分かった気がする。これは queue に何かあるのにも拘らず直ぐに
      ユーザー入力が来て、それによって再度プロンプトが表示されて、その上でコマ
      ンドを実行するから起こることである。

      今となっては複数行入力の検出や bracketed paste mode など色々とユーザーの
      誤貼り付けに対する対策が整ってきているので、この様な遅延の対策は不要であ
      る。という事を考えると、queue に何かある時にはコマンドを実行する様に変更
      するというので良い。


    * OK: ble-edit/exec:gexec/process は誰も使っていない気がする。これは削除で
      良いのではないか。と思ったら勘違いだった。ちゃんと呼び出されている。

    x fixed: 改行が含まれる空コマンドの時に ble.sh は実行している気がする。但し、
      履歴には登録していない。少なくとも CMD が一個増えてしまっている。何が起こっ
      ているのだろうか。

      →空かどうかのチェックで空白とタブしか判定していなかった。一方で history
      に登録されていなかったのはまた別のフィルタが働いていたという事だろう。

      ? 履歴展開の展開結果が空の時には何が起こるのだろうか。と思ったが有限の文
        字列から空の履歴展開になる事もない様な気がする。いや !:5 等としたら空に
        なるのだろう→と思ったら bad word specifier というエラーになる。やはり
        空に展開する事はないという事なのだろうか。

        普通に history -s '' としたら空の履歴を登録する事ができて、!履歴番号で
        空に展開させる事ができる。空に展開される時にはコマンド実行としては取り
        扱われないが、改行はカウントされる。但しカウントされる改行は展開後では
        なくて展開前の行数になっている様子である。

    x done: 改行が含まれるコマンドの時に LINENO を増加させる。

    * done: \# 及び LINENO の振る舞いについて調べる

      \# は LINENO ではなくて _ble_edit_CMD を使わなければならない。というか、
      LINENO 等の振る舞いに関しても bash の PS0, PS1 の振る舞いに従わなければな
      らないのだろうか。両者の振る舞いについて確認する事にする。

      うーん。どうやら LINENO の方がペアを特定するのには便利な気がするが何故
      CMD の方を使っているのだろうか。

      ? どの様な時に LINENO と CMD がずれるのだろうか。normal bash で確かめてみ
        ると、どうやら不完全なコマンドを入力して "> " (PS2) で続きを入力した時
        にずれる様である。

        他に LINENO はコマンドを実行せずに Enter を押した時にも増えるし、一まと
        まりのコマンドの中に改行が含まれている時にも改行の数だけ余分に増える。

        C-c でコマンドをキャンセルした時にも増える様である。これについては
        ble.sh で試したらちゃんとその様になっていたので気にしなくて良い。

      ? Bash で \# に対応する変数はないのか。もしあるのであれば同様の名前で提供
        するべきなのではないだろうか。

        何処で \# の処理がされているのかと思ったが parse.y:6162
        (decode_prompt_string) の中にあった。current_command_number という変数
        を参照している。そしてこれは eval.c の中で incr されている。そも他の箇
        所では全く使われていないので、これは別に Bash の内部の値を取り出そうな
        どとはしなくて良い。

    * fixed: \# の振る舞いを PS0 の評価後に変化する様に変える

      % 取り敢えず \# はコマンドを登録する時に番号を保存する様にする。もし保存
      % されていたら其処で振る舞いを書き換える事にする。

      _ble_edit_CMD の increment を内部に移動する事にする? この変数は \# を通し
      てしか定義されない物の様なので他の場所で影響が出てくる事はない様に思われ
      る。なので PS0 の直後で increment する様に変更してしまって問題ない気がす
      る。

    * Note: どうやら normal bash でも PS0,PS0,PS1 という感じの組み合わせになる
      事がある様である。C-v C-j として改行を挟んで独立したコマンドを複数入力し
      た場合になる。この時には LINENO は PS0 前に inc されて CMD は PS0 直後に
      inc されている様に見える。PS0 に関してはこの振る舞いに倣うのが適切だろう。

    元々の報告では PS0 と PS1 が必ず pair になる事を期待しているのだろうか。そ
    もそも PS0 はコマンド開始前に出力する物で、PS1 はプロンプト表示前に出力する
    物なので必ずしも組になっているとは限らない。

    組になっている事を期待するのであれば PREEXEC 及び POSTEXEC を利用するべきな
    のである。但し、shournal が単に計測対象開始として PS0 を使って、計測対象終
    了として PS1 を使っているというだけなのであれば、PS0 が重複していても特に問
    題は生じないのである。

    もし PREEXEC, POSTEXEC を使うというのであれば ble.sh が後からロードされた時
    にもちゃんと有効化される様に記述する必要がある。。

2021-05-10

  * syntax: PS0 から stderr に出力できないという報告を受けた (reported by tycho-kirchner) [#D1541]
    https://github.com/akinomyoga/ble.sh/issues/107

    一体何をしたいのか謎だがまあ元の bash で動く以上はその動作を利用する設定も
    あるだろう。元々その様に実装していたのは set -x の出力を防ぐ為だったが、よ
    く見たら PS0 の出力は restore-bash-options の前だったのでこの段階では 2 を
    端末に出力しても OK.

  * 2021-03-21 gitstatus.plugin.sh の alias builtin で builtin eval 他が破壊されている [#D1540]
    https://github.com/akinomyoga/ble.sh/issues/93
    https://github.com/romkatv/gitstatus/pull/235

    * 取り敢えず暫定的な対策として source ble.sh の時に unalias builtin 等を実
      行する事にした。

    * 他に source ble.sh した後に gitstatus.plugin.sh が実行されて、更にその後
      になって ble-attach した時の事も考える必要がある。

    gitstatus.plugin.sh の側で対策できないのか。
    34e21707

    https://github.com/romkatv/gitstatus/issues/154
    ここで本人が builtin を置き換えるのは良くない事だという事を述べている。

    > It's generally not a good idea to redefine builtins. If you also redefine
    > things like true, local, unset, etc., gitstatus won't work. Please don't
    > file a bug in this case but rather fix your config.

    eval ... pos parameters
    source ... pos parameters
    source ... function scope or not (declare var の振る舞い)
    unset ... previous-scope dynamic-unset or value-unset
    exec ... persistent redirections
      これは実際に問題になるという事を確認した。

    これは報告したらもっと別の方法で exec bash を検出する方法について議論が始まっ
    た。幾つか結構怪しい方法も含めて紹介した。その内の一つの方針で実装してテス
    トしてみるそうである。

    これも返信が来て色々議論して alias を全く使わない様に向こうが修正してくれた。
    しかも後で気づいたのだが gitstatus の作者はあの powerlevel10k の作者でもあっ
    た。powerlevel10k は ble.sh と同じく zsh ではあるがシェルで色々と複雑な処理
    をゼロから真面目に実装している奴である。

  * highlight: 1>&a.txt のファイル名着色 [#D1539]

    着色だけでなく補完にも一緒に対応する。

    x fixed: 実装してみたが動かない→2箇所 RDRD2 になっていた。CTX_RDRD2 に直す。

    x fixed: 3<&- や 3<&4- 等の redirection に対してエラー着色になっている。

    x fixed: 1>& 1 に対して補完が効かない→check-prefix に登録していなかった。

    x fixed: 1>& に対して補完が効かない。ファイル名だけが生成される。check-here
      でもしかすると別の ctx になっている?  →調べたらそもそも ARGX になってい
      て其処から RDRD2 等に変わっていないので ARGX だと思って補完が開始されてい
      るのが原因である。何が問題かというと、次の単語がない時に redirection で
      stat を設置していないのが行けない。然し、そもそも RDRD2 等は単語の種類で
      あって解析の状態ではないのではないか? と思ったが別にそういう訳でもないら
      しい。ちゃんと RDRD2 という ctx になって解析されている。

      ここで問題になるのは RDRD2X 的な文脈が存在しないという事にある気がする。

      a 或いは一文字も入力されていなくても勝手に RDRD2 を開始してしまうべきなの
        だろうか。と思ったが RDRF, etc は nest の中にいるという事を前提とした実
        装になっているので、そのまま ctx を設定する訳には行かない。然し、そうは
        言っても空の nest を生成する事もできない。

      b 或いは stat か何処かの配列に次に来るべき者についての情報を記録するとい
        う事にする? 他の所ではその様な事をしていないのに此処だけでその様に処理
        するのも変である。

      c というかそもそも check-prefix で ARGX の時に redirection を検出するべき
        なのではないだろうか。

      最終的に c が正しい実装である。そもそも check-here は fallback 的な位置づ
      けであり此処に来た時点で実は変な補完になってしまう事は運命づけられている。

    * 他に << 及び <<- の後の補完も定義されていなかったのを定義した。適当に
      EOF:END:HERE 等としたがもっと別の物を追加するべきかもしれないし、あるいは
      ユーザーが設定できる様にするべきかもしれない。

    * 全般に fd の補完もできる様にした。

  * MSYS2 patch .inputrc [#D1538]
    https://github.com/akinomyoga/ble.sh/issues/104
    https://sourceforge.net/p/msys2/mailman/msys2-users/thread/CAFLRLk-UX7S%3DTAerNix7HvxDAv4aY2FwZuFZz%3DU%2BTLBAWxCLEg%40mail.gmail.com/#msg37275646
    https://github.com/msys2/MSYS2-packages/pull/2490
    https://github.com/git-for-windows/build-extra/pull/341

    Ref #D1534

    特に問題の行は削除するべきであると考えているが返信は未だない。
    強い口調で書き過ぎたから無視されているのかも知れないし、
    単にこの mailing list には誰もいないという事なのかもしれない。
    archive を遡ってもこの mailing list は活発であるとは言い難い。

    GitHub にソースを見つけたので PR を出してみた。
    こちらも直ぐには返事が来ない。
    一応ちゃんと変更の要求は取り込まれた。

    https://github.com/msys2/MSYS2-packages/pull/2490

    然し本当に git bash の msys と msys2 は一緒なのだろうか…。MSYS2 をインストー
    ルして、それから Git Bash もインストールしてみる。Git Bash の方は個人のディ
    レクトリには .inputrc はなくて、/etc/inputrc が読み取られている様である (実
    際に /etc/inputrc を編集して影響を与えている事を確認した)。そして、実は
    /etc/inputrc の内容と MSYS2 の .inputrc の内容は異なるという事も確認できた。

    ? ok: MSYS2 の /etc/inputrc はどうなっているのだったか→MSYS2 では
      /etc/inputrc は存在していない。なので、今回の変更だけで大丈夫のはず。

    ? ok: Cygwin の方にも inputrc があるのではないか→調べたら
      /etc/skel/.inputrc があったが、これはちゃんと変な binding は削除されてい
      た。検索した感じだとそもそもこの壊れた binding は cygwin の inputrc から
      来ていた様な気がする (違ったかもしれないが面倒なのでもう確認しない) ので、
      Cygwin の側では誰かが何処かの時点で気づいて削除したという事だろうか。

    ? done: Git Bash の /etc/inputrc にも変更要求を出さなければならない

      https://github.com/git-for-windows/git-sdk-64/blob/main/etc/inputrc
      https://github.com/git-for-windows/git-sdk-64/blob/main/etc/skel/.inputrc
      https://github.com/git-for-windows/git-sdk-32/blob/main/etc/inputrc
      https://github.com/git-for-windows/git-sdk-32/blob/main/etc/skel/.inputrc

      以上にファイルを見つけたがどうも違う様な気がする。これらのリポジトリのコ
      ミットを見ると自動的にアップデートされている。なので、これは別の場所に
      upstream があるという事を示唆しているのではないか。然し検索してみても関連
      する物は見つからない。

      https://github.com/search?q=org%3Agit-for-windows+%22msys2+mailing+list%22&type=code

      /etc/skel/.inputrc は MSYS2 から継承されるのだと考えたとしても、では
      /etc/inputrc は何処から来ているのだろうか。謎である。うーん。もしかして
      msys1 が起源になっている? というか Git Bash の MSYS は MSYS2 ではなくて
      MSYS1 なのだろうか。MSYS の version は何処でチェックできるのだろうか。

      改めて色々読んでいると build-extra も言及されている。適当にディレクトリを
      覗いたら inputrc があった。どうも GitHub の検索はファイル名本体には全く一
      致しないようだ。

      https://github.com/git-for-windows/build-extra/blob/main/git-extra/inputrc

      https://github.com/git-for-windows/git/issues/62 では PR は OK と言ってい
      るが何処に出したら良いのかについては何も言及していない。msysgit という物
      も存在する様だ…そちらにも PR を出す必要があるだろうか、と思って確認した
      ら msysgit は Git for Windows の前身であり同じ人が管理していて既に
      archive されていた。

    ? ok: MSYS-1.0 にも出した方が良いだろうかと思って活動を確認したが Mailing
      list は 2013 から動いていないし、最新版も 1.0.12 の 2016 年なので、此処で
      修正しても仕方がないと判断する。そもそも、ble.sh の側でも対策を入れたので
      実質的に問題は発生しない筈。

2021-05-08

  * decode: 初期化時にエラー (reported by RakibFiha) [#D1537]
    https://github.com/akinomyoga/ble.sh/issues/106

    一番最近の commit を観察したが特に怪しい所はない様に思われる。

    キャッシュが壊れている可能性? 然し、キャッシュをクリアしてしまうと問題が再
    現しなくなる可能性があるので後回し。
    もし ble-update を実行する過程でキャッシュが壊れるのだとしたらどれかの
    version から最新版に更新した時に問題が再現するかもしれない。そう思って
    026432d 9125795 79d671d 0506df2 032f6b2 からのアップデートを試したが再現は
    しなかった。

    どの commit で問題が起こる様になったのだろうか。改めて怪しい変更がないか
    commit を眺めて見る。試しに bind '"hello":"world"' としたら再現した。改めて
    decode-char の呼び出し部分を確認する。もしかするとここを "${chars[*]}" にし
    ていたり変数に代入したりする過程でその様に加工してしまっているかもしれない。
    と思ったら、本当に "${chars[*]}" にしてしまっていた。一文字の修正である。

2021-05-07

  * bind: fix a problem that "bind '"seq":"key"'" causes a loop macro "bind -s key key" (reported by thanosz) [#D1536]
    https://github.com/akinomyoga/ble.sh/issues/105

    これはどうやら OpenSUSE の inputrc にある、テンキーの / のエスケープシーケ
    ンスを / に翻訳する keybinding の問題だった。ble.sh は左辺をキー列に翻訳し
    てから bind する。という事なので、

      "escape-sequence": "key"

    の様な binding が存在すると、key: "key" という形に翻訳されてしまう。そうす
    ると無限ループに変換されてしまうという事である。

    これの対策は単に左辺と右辺が一致している時に binding を無視するというだけで
    良いのだろうか。或いは、それだけでは駄目なケースが存在するだろうか。例えば、

      "escape-sequence-long": "escape-sequence-short"

    という形になっていたとすると、

      key: escape-sequence-short

    という形になってしまって結局無限ループになってしまうのではないだろうか。現
    在の実装について改めて確認する→やはり左辺が keys で右辺が chars になってい
    るので単純に keys と chars を比較するのでは駄目である。結局 chars を keys
    に翻訳してから比較する事にした。実装した。テストした。動いている。OK

2021-05-06

  * progcomp: aws_completer が呼び出されない (reported by Archehandoro) [#D1535]
    https://github.com/akinomyoga/ble.sh/issues/102

    これは原因は分かった。complete -p の出力結果が quote されているのに、ble.sh
    はそれを直接解釈しようとしているのが原因であった。"'aws_completer'" という
    名前のコマンドを実行しようとして失敗している。

    そもそもこれは complete -p の出力結果が quote されていたりされていなかった
    りするのが原因である。version 毎にどうなっているか確かめてみる事にする。

    * コマンド名: コマンド名に関しては現在に至るまで一切 quote されない。

    * -C の引数について: bash-3.2 までは裸で引数が出力されるだけであった。

    * -F の引数も一切 quote されない。と思ったら bash-5.1 以降で -F を設定する
      時にチェックが入る様になった。然し、それでもブレース展開や履歴展開、変数
      展開も含める事ができるのでそのまま eval する訳には行かない。

    * -WGXPS の引数: 常に quote される

    * 引数が出力される順番は固定の様である。問題の -F func -C callback cmd はこ
      の順序で必ず最後に出力される。と思ったが、bash-4.0 以降では -C c -F f cmd
      の順序に変更になった。

    まとめると、

    * bash-3.2まで: complete [OPTIONS] -F str -C str    cmd
    * bash-4.0以降: complete [OPTIONS] -C 'str' -F str  cmd
    * bash-5.1以降: complete [OPTIONS] -C 'str' -F func cmd
      5.1 で安全になったかと思いきや func に !${} を含められるので駄目。

    うーん。コマンド名に関しては末尾から削除すれば良い。quote をちゃんと辿って
    行けば -F が現れた時点でこれは確実に本物の -F である。更に -F の引数に関数
    名として不正な物を指定する理由もないので、-F の直後は一つの単語だけ読み取れ
    ば良い。すると残るのは (もしあれば) -C callback 名という事になる。

    どの様に実装するか。結局どの bash version であっても -F func が quote され
    ないので eval するのは危ない。そもそも callback を設定する時点でその補完が
    呼び出された時点で駄目な訳だけれども、取り敢えず滅茶苦茶な事が起こらない様
    にする為には真面目に parse するのが良い。

    a 後ろから parse するのは問題ないだろうか? ... これは危険である。例えば -F
      が見つかったとしてもこれが本当に -F なのかは分からない。偽物の -F で、実
      は其処よりも前にも quote されていない引数が潜んでいる可能性がある。

    うーん。手順としては先ず初めに末尾にコマンド名が一致していればそれを除去す
    る (一致していなかった場合はどうするのかは謎)。次に正規表現で読める所まで読
    んで、それを eval する? 読みきれなかった部分については変数に残して置く。読
    めた部分を解析する。途中で -F に行き当たったら残りの文字列を特定して、続き
    は真面目に parse する事によって結果を得る? というか残りについては " -C " が
    含まれているかいないかで取り扱いを変更すれば良い気がする。然し、何らかのオ
    プションが -F の後に続いているという事もあるかもしれない。

    取り敢えず実装した。動いている。もう一つの問題として aws の補完結果は末尾に
    空白を含めているのにも関わらず noquote 等の処置をしていないという事。うーん。
    これに関しては…。仕方がないので aws_completer 用の WA とする事にした。また、
    コマンド名なのに偶然でディレクトリ名に一致して suffix がついてしまう事につ
    いても workaround とした。但し、考えて見るに -F もしくは -C で生成した候補
    に対して suffix を付けるのも変な気がする。これについては改めて考えても良い
    のかもしれない。

  * MSYS2 で Backspace で行全体が削除されるという話 (reported by n1kk) [#D1534]
    https://github.com/akinomyoga/ble.sh/issues/104
    https://sourceforge.net/p/msys2/mailman/msys2-users/thread/CAFLRLk-UX7S%3DTAerNix7HvxDAv4aY2FwZuFZz%3DU%2BTLBAWxCLEg%40mail.gmail.com/#msg37275646

    取り敢えず MSYS2 の .inputrc が怪しいという事で msys2-users に報告した。そ
    れとは別に ble.sh の側でも対策する事は可能だろうか。

    a 例えば MSYS2 にいる時には .inputrc は読み取らない (--noinputrc) 様にする?
      然し .inputrc だけ読み取らない様にしても仕方がない。ユーザー設定も読み取
      らない様にしないと bind で自動的に読み込まれた設定を読み取ってしまう事に
      なる。

    b INPUTRC=/dev/null を設定してから bind で初期化する事により bashrc で設定
      されたユーザー設定だけを読み取るという手もある気がするが、これも source
      ble.sh よりも先に bind 関連の設定にユーザーが触れていると駄目である。

    c 上記の問題は inputrc にある他の設定も全て潰してしまうという事である。それ
      ならば、C-? に対応する設定だけ ble.sh default に強制的に設定する様にすれ
      ば良いのではないだろうか。

    取り敢えず c の方針で実装する事にした。この様にしたとしても C-x C-r で
    inputrc を再読込するとまた変な状態になってしまうが、これは仕方がない。

  * complete: bash-completion bug workarounds (reported by oc1024) [#D1533]
    https://github.com/akinomyoga/ble.sh/issues/97

    自分の手許でも色々エラーメッセージが出てうるさい。

    bash-completion で修正を掛けるのは面倒だし時間がかかりそう。更に、各種
    distribution に波及する迄に更に時間もかかりそうなので取り敢えず暫定的に、
    ble.sh の側で bash-completion の実装を上書きする事にしてしまう。

    * 2021-05-06 bash-completion
      https://github.com/akinomyoga/ble.sh/issues/97
      https://github.com/scop/bash-completion/pull/492
      Ref #D1533

      python のテストを自分で実装したりしなければならず面倒である。
      実装した。PR を update した。これは向こうの反応待ち状態である。

  * 2021-04-06 localvar_inherit で動かなくなっている  [#D1532]

    或いは元から動いた事はなかった可能性も?

    * localvar_inherit をしていると local -r a した変数に対して、
      内側の関数で同名の変数を定義できなくなってしまう。

    うーん。それでも未だ色々動かない。というか、バグというかちゃんと書
    かれていないコードを洗い出すのに使えるかもしれないとは思う。

    * どうやら localvar_inherit になっていると local BASH_COMMAND としても
      BASH_COMMAND の値が変化する性質は受け継がれてしまう様である。

      | RANDOM でも同様の現象が発生している。
      |
      | $ f1() { local RANDOM=hello; echo $RANDOM; RANDOM=world; echo $RANDOM; }
      | $ shopt -u localvar_inherit; f1
      | hello
      | world
      | $ shopt -s localvar_inherit; f1
      | 20034
      | 20034
      |
      | 何が起こっているのだろう。元の変数がそのまま見えているという事だろうか。
      | と思ったがそうでもない。unset RANDOM して見たが元の変数が消えるという事は
      | なかった。恐らく localvar_inherit の時には値が受け継がれるのではなくて、
      | setter/getter が引き継がれてしまっているのが原因なのだろうと思われる。
      |
      | bash を確認すると subst.c (expand_declaration_argument) では
      | localvar_inherit が設定されている時には declare は declare -I と同様の振
      | る舞いになる。 declare -I の説明を declare --help で確認すると値と属性を
      | 継承すると書かれている。
      |
      |   if creating a local variable, inherit the attributes and value of a
      |   variable with the same name at a previous scope
      |
      | と思ったが実装をよく見ても inheriting の値が一切使われていない気がする。
      | 不思議である。未実装なのだろうか。或いは何かを見落としている? どうもこの
      | 関数は arr=() の形式の引数を処理する時にだけ使われているという事だろうか。
      |
      | 実際に localvar_inherit の処理を具体的に処理しているのは variables.c の方
      | である様に思われる。特に以下の部分 (variables.c:2738) が setter/getter を
      | 継承するコードである。
      |
      |   if (localvar_inherit || (flags & MKLOC_INHERIT))
      |     {
      |       /* It doesn't make sense to inherit the nameref attribute */
      |       new_var->attributes = old_var->attributes & ~att_nameref;
      |       new_var->dynamic_value = old_var->dynamic_value;
      |       new_var->assign_func = old_var->assign_func;
      |     }
      |
      | 明示的にコピーしているという事を考えるとこれを覆すのは難しいかも知れない。
      | 具体的に変な振る舞いをする例を作ってそれを呈示すれば何か考えて貰えるかも
      | しれない。getter/setter が関わっている関数は他にあるだろうか。
      |
      | INIT_DYNAMIC_VAR で検索するとそういった関数の一覧が得られる。
      |
      | - "SECONDS", (v ? value_cell (v) : (char *)NULL), get_seconds, assign_seconds
      | - "FUNCNAME", (char *)NULL, get_funcname, null_assign
      | - "BASH_ARGV0", (char *)NULL, get_bash_argv0, assign_bash_argv0
      | - "BASH_COMMAND", (char *)NULL, get_bash_command, (sh_var_assign_func_t *)NULL
      | - "BASH_SUBSHELL", (char *)NULL, get_subshell, assign_subshell
      | - "RANDOM", (char *)NULL, get_random, assign_random
      | - "SRANDOM", (char *)NULL, get_urandom, (sh_var_assign_func_t *)NULL
      | - "LINENO", (char *)NULL, get_lineno, assign_lineno
      | - "BASHPID", (char *)NULL, get_bashpid, null_assign
      | - "EPOCHSECONDS", (char *)NULL, get_epochseconds, null_assign
      | - "EPOCHREALTIME", (char *)NULL, get_epochrealtime, null_assign
      | - "HISTCMD", (char *)NULL, get_histcmd, (sh_var_assign_func_t *)NULL
      | - "COMP_WORDBREAKS", (char *)NULL, get_comp_wordbreaks, assign_comp_wordbreaks
      |
      | TERM の場合はどうなっているのだろうか。これは special_vars という事になっ
      | ていて、値が変更した時に特別の関数が呼び出される様になっている。他に
      | TERM* や LANG, LC_* 等様々な変数がこれに相当する。これらは local に関係なく
      | 常に値が変更したら何か処理する事になっているので今回の振る舞いには関係ない。
      |
      | やはり勝手に上書きするのが悪いという結論になりそうな変数しか存在しない。
      | 敢えて言うならば RANDOM か LINENO ばかりだろうか。LINENO の方も確認したが、
      | やはり LINENO に対する代入は無視されて現在の行数が常に表示される様になっ
      | ている。因みに LINENO=1234 eval 'echo $LINENO' に関しては
      | localvar_inherit を設定しても特に変わりなく同名の tempvar が作成される。

      bash のバグか或いは confusing behavior かどうかは別として、古い version
      に対しては取り敢えず修正しなければならないので、対策は行う事にする。時間
      があれば bash に報告・相談もする事にする。

    * もう一つの問題は local -a buff とした後に ble/array#push としていると、前
      の配列の内容が既にあった場合にそれの続きとして値を push してしまうという
      事。こう言った使い方をしている箇所はないと思っていたが、確かめてみると古
      いコードを中心にして沢山あった。と思ったがそんなには無かった。合計で4箇所
      だけだった。

    上記の事を直したら取り敢えず動いている様に見える。残りは具体的に問題が生じ
    てから対処する事にする。

  * 2021-04-28 keymap 初期化に失敗した時にそれを検出しているのにも拘らず操作不能になる [#D1531]

    $_ble_base_cache/keymap.emacs が空の時、The keymap 'emacs' is empty 等の様
    にメッセージが表示されて空かどうかのチェックが為されている筈なのに、その後
    に何も操作できなくなる。

    ble/decode/attach の中でチェックが起こっている気がするが、その場合には
    attach せずに終わって操作不能にはならない筈なので関係ないかもしれない。

    今試しに keymap.emacs を空にして bash --norc から ble.sh をロードしてみたが、
    stty の状態が変になる物の操作不能になる訳ではない。set -o vi でスタートさせ
    てset -o emacs で切り替えようとすると問題が再現する。つまり、detach して
    attach した時の問題である。

    調べてみるとどうもコマンドは実行されている様である。stdout.off の状態になっ
    ている事によって操作できなくなってしまっているという事の様である。そしてそ
    れは、ble/decode/attach の呼び出し元の .check-detach の更に呼び出し元におい
    て、bind/.tail 経由で改めて stdout.off が実行されているという事になる。これ
    を抑制する為に、.check-detach の中で rebind に失敗した時には改めて
    .check-detach を呼び出して抜ける処理を実行する事にした。

    →然しそれでもやはり stdout.off が呼び出されてしまう。と思ったが、どうも
    .check-detach の戻り値を使って実際に detach が起こったかどうかを伝達してい
    る様である。ちゃんと再帰的に呼び出した .check-detach の終了ステータスを外に
    伝播させる。これで問題なく抜ける様になった。

  * 2021-04-06 main (--rcfile): 通常ファイルしか許可していないが [#D1530]

    <() や /dev/null を食わせたい事もあるだろう。後、ファイルが見つからなかった
    時に結局 ~/.blerc を読み取ってしまうのは不便。ファイルが見つからなかった場
    合には何も読み込むべきではない。

    --norc オプションにも対応した。

  * syntax: eval() { echo yes; } が構文エラーになっている [#D1529]
    local, declare も同じ。

    これは意外と簡単だった。処理順序を変えるだけで良かった。builtin の処理と
    keyword の処理が結合しているから切り離すのに時間がかかるのではないかと思っ
    たが、実際には builtin の処理は独立にしても問題ない様な実装になっていた。

  * main: freeze-utility-path が一時実装を置き換えなくなっている [#D1528]

    ble/bin/sleep を初期化する前に sleep の機能についてテストしている気がする?
    と思ったが最初に ble/bin/sleep を絶対パスではなくて command sleep で定義し
    ているので問題は起こらないのだった。というより、最近 freeze-utility-path で
    既存の関数がある時には上書きをしない様に変更したが、これは駄目だ。元々上書
    きする様になっていたのはこの一時的な実装を置き換える為であったのである。

    然し、上書きする様に変更してしまうと freeze-utility が ble/bin/awk を上書きしてしまう。

    a そうすると一時的な実装とそうでない実装を区別できる様に、関数か変数をマー
      カーに使う?

    b 或いは初めからもう定義してしまって呼び出した時点でパスを決定する事にする。
      初期化の順序によっては fork コストがかかる可能性もあるが、
      それも少しだけなので余り気にしなくても良いかもしれない。

      問題は ble/util/assign がちゃんと動作する迄に時間がかかるという事だから、
      ble/util/assign が準備できたかどうかを変数に記録しておけば良いのでは。

    c 或いは ble/util/assign が準備できた時点で .freze-utility を改めて呼び出す
      事にする。直接呼び出しても良いし、それだと密結合になるというのであれば、
      hook か何かを準備しても良い。

    d 或いは今まで通り freeze-utility は上書きをしてしまう様にする。awk に関し
      ては上書きしない様にリストから削除しておくか (然し削除の為にまたコードを
      書かなければならない。初期化時点では ble/array#remove もない)、或いは
      ble/bin/awk.protected か何かの様にして上書きをしない様に関数を定義する。

    うーん。大きく変更するのも面倒なので ble/bin/awk.protected を定義するという
    方針にする。と思ったが関数が存在するかどうかのテストはやはり util.sh を待た
    なければならない。

    ? ok: alias が定義されている時に freeze-utility は正しく動作するだろうか?
      →これは大丈夫。type -P としているから。

2021-05-04

  * util: bleopt/check-all で obsolete な設定も読み取ろうとしてエラーになっている [#D1527]
    obsolete なオプションに対しては初期設定のチェックは行わなくて良い。

  * syntax: 着色決定時に expand_aliases 設定が退避されている (reported by 3ximus) [#D1526]
    https://github.com/akinomyoga/ble.sh/issues/103

    0860be0 に於いて内部では alias が展開されない様に shopt -u expand_aliases
    を設定していた。然し、よく考えてみたら構文着色等に於いて expand_aliases が
    有効かどうかによって処理を変えていた。つまり expand alias の処理の際にちゃ
    んと退避した設定を確認する必要がある。

    実際に修正しようとしたら話はそう単純ではない様である。そもそも自分で shopt
    -s/-u expand_aliases を変更しようとしても完全に無視されてしまう。次のユーザー
    状態になる頃には勝手に元の値に戻ってしまっている。何故? 例えば
    POSIXLY_CORRECT を手で弄っている所為だろうか。或いは expand_aliases の保存
    復元の呼び出しタイミングが混ざっているからだろうか。それとも bind -x の中で
    変更した expand_aliases の状態は抜けると消えてしまうという事なのだろうか。

    やはり自分では何も操作していないのに expand_aliases の設定が変わってしまっ
    ている。うーん。という事は…どうすれば良いのか?

    * 内部で shopt -u expand_aliases にしたいというのは…。毎回 bind head で設
      定し直すぐらいしかできない→ bind/.head で再設定する様にした。

    * ユーザーが設定した設定が保持されないという事に関しては。これは明示的に自
      分で保存復元する必要がある。特に restore する時には shopt -u
      expand_aliases も明示的に実行する。→これは bind/.head で設定する様にした
      ので、わざわざ自分で実行しなくても良い。

    * エイリアスを展開する時に一時的に shopt -s expand_aliases 状態を復元する。
      と思ったが、それでは駄目だった。様々な所で ble/util/type を呼び出していて、
      その結果が alias にならないとそもそも expand-alias 関数自体が呼び出されな
      い。修正するべきは expand-alias ではなくて ble/util/type の方である。こち
      らを修正したら動く様になった。

  * util: test-canvas.sh ext/contra 依存性の解消 [#D1525]

    test-canvas.sh がエラーを出す様になっている。試すとテストを取り入れた時から
    既にエラーになっている。どういう事だろうか。と思ったが、テスト自体が
    ext/contra もしくは contra を前提としていた為に起こっていたエラーだった。存
    在しない時には通る様に書いたつもりだったがそうなっていなかった。

  * awk で {m,n} は使えないという事 [#D1524]
    https://unix.stackexchange.com/questions/354553/awk-repetition-n-is-not-working
    Ref #D1522

    更に nawk, mawk では十六進表記 0xHHHH も使えない。規格的には optional に対
    応しても良いという事になっている様だ。

    更に mawk は match("AAA", /AA?A?/) としても2文字しか一致しない。/A(AA?)?/
    という具合にしなければならない。

    過去の互換性の為であると言っている割に POSIXLY_CORRECT=always を指定しても
    対応するという気配はない。

    →特にこれらに引っかかりそうな箇所は今の所は見つからなかった。然し、
    今後の為にちゃんと記録しておく必要がある→ #M0019 に残す事にした。

  * nawk の方が軽いので既定で nawk を使う様に変えてみる [#D1523]
    Ref #D1522

    gawk 特有の振る舞いに依存している部分を洗い出す為にもこの変更は有用だろう。

    x nawk を使う様にして試してみた所、初期化時に "function" というメッセージが
      沢山表示される → これは nawk とは関係なくて freeze-utility で追加したコー
      ドで既存の ble/bin/??? が定義されているかどうか確かめる type の出力を
      /dev/null に繋いでいなかったのが問題であった。

    x また、use-solaris-xpg4 が他から参照されている。mshex にも
      akinomyoga.dotfiles にも use-solaris-xpg4 はない気がする。何処由来だろう
      か? →これは単に ble.pp に古いコードが残っていただけだった。

    他にも様々な問題が発生した様に思われたが全て最近行われた別の変更によるバグ
    だった。一通り修正できたので改めてテストを行う。取り敢えず動いている様な気
    はする。

  * 2021-03-15 巨大なディレクトリで TAB 補完が遅い (2) (reported by timjrd) [#D1522]
    https://github.com/akinomyoga/ble.sh/pull/65#issuecomment-798551355
    Ref #D1512

    修正したと思ったが依然として時間がかかっている。

    (1) 調べてみると、どうもconditional-sync が終わった後の
      builtin eval -- "$def"
      を実行する時に時間がかかっているという事。

      これを高速化する方法はあるだろうか。というか assign-array では駄目なのだ
      ろうか。と思ったが、ファイル名に改行が含まれている可能性などを考えると駄
      目という事?

    後気付いたのだが、ファイル名に改行が含まれている場合には何が起こるのだろう
    か。source:file はファイル名のチェックをしない様に今回書き換えたが実はこれ
    によって改行が含まれているファイル名の断片も生成される様になってはいないか。
    然し、eval-pathname-expansion で変な分割のされ方をしない限りは問題は起こら
    ないはずである。また、eval を経由して親に結果を渡す事によって、改行を含むファ
    イル名でも対応できる様になっている。

    うーん。eval の中でも時間がかかっている様に思われたが、これも eval するため
    の文字列を構築するのに時間がかかっているという事なのだろう。

    $ files=(*)
    $ time eval ': "${files[@]@Q}"'
    280ms
    $ time eval ': "${files[@]}"'
    216ms
    $ time for a in "${files[@]}"; do break; done
    235ms
    $ time echo ${#files[@]}
    0ms

    これらの結果を見るに、インデックスでアクセスする様にするべきという事か。

    $ time data=("${files[@]}")
    300ms

    a ${files[@]:offset:length} を使って切り分ける?
      →これは遅い。

      $ time : "${files[@]:0:100}"
      72ms
      $ time : "${files[@]:0:1000}"
      77ms
      $ time : "${files[@]:0:10000}"
      89ms

      うーん。これ自体にも時間がかかっている。然し、1000 単位で分割しようとする
      と 200k の場合には全て処理するのに 20s かかる。10000 単位ならば 200k ファ
      イルに対して 2s 以下で処理できるが、元から 200ms かかっていたのが 2s に増
      えるのは微妙な気がする。等の事を考えると、これにかかる時間は仕方がないと
      諦めるべきか。

      →単に ${arr[@]:xx:yy} が遅いというだけの様だ。

    b 直接要素にアクセスする。

      以下の様に直接アクセスすれば、全体を一気に置換した時と比べて遜色のない速
      度が出る。約2倍程度の速度低下で済んでいる。

      $ time for ((i=0;i<200000;i++)); do v=${files[i]}; done
      500ms
      $ time for ((i=0;i<10000;i++)); do v=${files[i]}; done
      29ms


    ? 高速な配列の初期化と言えば history.sh である。結局どの様な方法を用いてい
      たのだったか。やはり eval だったような気もする。確認する。

      うーん cygwin かそうでないかで場合分けしている。Cygwin 以外では mapfile
      を使って読み出している。改行を含む要素に関しては後で補正処理を行うという
      方法を用いている。Cygwin に於いては source している。中では恐らく直接巨大
      な配列のリテラルを指定している。

    $ time x=$(declare -p files)
    72ms

    実は declare -p 自体はそんなに低速ではない。
    現在の実装では quote を ${file[x]@Q} を用いて処理しているが、
    declare -p を用いれば多少の改善はできるかもしれない。

    $ time eval "$(time ret=(*); time declare -p ret)"
    real    0m0.326s
    real    0m0.071s
    real    0m1.345s

    $ cd /path/to/big-directory
    $ time files=(*)
    $ time def=$(declare -p files)
    $ time def=ret=${def#*=}
    $ time eval "$ret"

    具体的に timjrd に計測してもらったがやはり eval "$def" で結構な時間がかかっ
    ている様子である。特に 33k の項目に対して 0.87s かかっている。手元では 200k
    項目に対して 0.40s かかっている。(線形時間を仮定すれば自分の手元では 33k に
    対しては 0.066 で処理できるので余り気にならなかったのだろう。)

    因みに手元では配列のコピーも 0.27s かかっている。これはそんなに長くはないが、
    向こうでは 0.6s ぐらいかかるのだという事を示唆している。つまり、配列コピー
    も気安く行う事はできないのである。

    手元でより高速な方法を模索してみる事にする。

    a eval "$def" の処理時間は 200k 項目に対して 0.40s である。展開と読み取りに
      は 0.67s かかっている。total では 1.07s である。

    b printf '%s\0' "${ret[@]}" で出力した結果を mapfile -d '' で読み取る方法を
      試してみた。結果、読み取りに 0.74s かかっている。実は eval による手法より
      も時間がかかっているという事になる。展開も含めた total の時間は 1.17s で
      ある。total で考えれば手法 a とそんなに変わらないが、中断できないという事
      が問題である。

      更に mapfile -d "" は 4.4 以降でしか使えないので、4.3 以下でも使える様な
      read -d '' による方法の速度を計測してみた所、75s かかった。

      | if ((_ble_bash>=40300)); then
      |   printf '%s\0' "${ret[@]}"
      | else
      | fi
      | if ((_ble_bash>=40400)); then
      |   time ble/util/assign-array0 ret 'ble/util/conditional-sync "$sync_command" "" "" "$sync_opts"' &>/dev/null; local ext=$?
      | else
      | fi 2>/dev/tty

    c source にしたら total 時間を減少させる事ができるだろうか。

    2021-05-01 時間が空いてしまったので改めて現状を整理する。問題は subshell で
    得たファイルリストをどうやって親シェルに伝達するのかという事。500k の文字列
    配列を現実的な時間内に親シェルに伝達し、更に中断も可能である必要がある。

    例を交えて説明するとしたい事は以下の事である。現状で、eval "$(< a.tmp)" が
    遅いというのが問題である。合計時間が長いというのは未だ良いのだが問題はユー
    ザーからの interrupt があった時に中断できないという事にある。

    (
      a=({000000..500000})
      declare -p a > a.tmp
    ) &
    wait $!
    eval "$(< a.tmp)"

    declare -p a の実行自体はそんなに時間はかからない。また mapfile も比較的高
    速である。問題は declare -p a だと eval (遅い) で読み出す必要があって、
    mapfile にする為には要素を printf で出力する必要があるという事。

    a printf '%s\0' / mapfile -d '' (2.5 + 1.6)

      そうだとしても printf '%s\0' で出力して mapfile -t -d '' で読み出すのが一
      番高速でかつ中断可能の気がする。と思って試してみた所、mapfile は -d '' を
      指定した瞬間に遅くなってしまった。どういう事だろうか。最新版 bash でも同
      様である。

    b echo / mapfile -t (3.2 + 0.1)

      この方法は高速であるが代わりに改行を含む様な要素について特別な対処が必要
      である。また時間のかかっている部分での中断も容易である。

      特別な対処を実装したら合計で 3.2+0.1 になった。それでも他の方法よりは高速
      である。これが現実的な解であるような気がする。合計の処理時間は2倍以上になっ
      てしまうが。

    c declare -p a | awk ???

      declare -p を awk で処理する事を考えたが awk には行に含まれる文字数の上限
      があるのではなかったか。本当にそれを正しく処理できるのだろうかという懸念
      は残る。もしそうだとしても物凄く長い行を処理しても処理能力の低下は起こら
      ないのだろうか→文字数の制限が厳しいのは sed 実装だった気がする。POSIX 的
      には awk も制限があったけれども実際の実装ではそんなに問題にならなかったの
      だという気がする。

      読み取りの速度を考えると mapfile-nfix で読み取れる形式に変換するのが良い。
      つまり、declare の parse を awk で行うという事である。declare の形式は
      version によって異なっていたりバグがあったりするが…。

    やはり速度という観点で一番良いのは declare -p a | awk して mapfile-nfix で
    読み取るという物の様に思われる。それとは別に何故 mapfile -d '' が遅いのかと
    いうのは気になる所ではある。

    ? 何故 mapfile -d '' は遅いのだろうか。

      | 確認してみると delim が \n 以外の場合には unbuffered read に切り替える様
      | になっている。何故だろうか。zgetline の実装を見ると delim を引数に受け取
      | る様になっている。更に、zgetline は zread もしくは zreadc を呼び出してい
      | る。最終的に buffered の場合には read(fileno, buf, bufsz) を呼び出して、
      | unbuffered の場合には read(fileno, buf, 1) を繰り返し読む様になっている。
      | 実装を読む限り \n かそうでないかで振る舞いを変更する理由もない様な気がす
      | る。不思議である。理由について尋ねても良いだろうか。
      |
      | Greg に最終的な目標は何なのか。不適切な事を Bash で実行しようとしているの
      | ではないか、という様に文句を言われるかもしれない。その時の為に説明を書く
      | のが良い気がする。
      |
      | get_file_list() {
      |   (files=(*); declare -p files > tmpfile) & bgpid=$!
      |   while :; do
      |     if has_background_completed "$bgpid"; then
      |       eval -- "$(< "$tmpfile")"
      |       return 0
      |     elif has_user_interrupted; then
      |       cancel_everything "$bgpid"
      |       return 1
      |     else
      |       my_sleep 0.1
      |     fi
      |   done
      | }
      |
      | $ a=({000000..500000})
      | $ printf '%s\n' "${a[@]}" > tmp
      | $ mapfile -t a < tmp
      |
      | $ printf '%s\0' "${a[@]}" > tmp
      | $ mapfile -d '' a < tmp
      |
      | builtins/mapfile.def L187..L194
      | > #ifndef __CYGWIN__
      | >   unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
      | > #else
      | >   unbuffered_read = 1;
      | > #endif
      | >
      | >   if (delim != '\n')
      | >     unbuffered_read = 1;

      これは報告した。

    さて declare -p | awk を実装してみたが遅い。実装している内に気づいたが、awk
    では文字列の途中から一致させる事ができないので、一致範囲を毎回切り出す必要
    があって、これを巨大な文字列に適用すると大変な事になる。今迄の実装で
    declare -p | awk が使えていたのは正規表現で一気に全体を置換するという様な簡
    単な処理しかして来なかった為である。

    →これについては split(s, a, / /) で分割して各要素について処理する様にした
    ら改善した。

    然しそれでも unescape の処理によって格段に時間がかかっている事は確かである
    様な気がする。もっと手っ取り早く変換する事はできないだろうか。例えば "..."
    と $'...' の何れかしか使われないという仮定で単純化できないか等。しかし、例
    えば空白一文字取って見ても " " の内部と、要素と要素の間の " [...]=" を明確
    に区別できる様な正規表現はない様に思われる。或いは "..." 全体に一致する様な
    正規表現を書ければ、特定の文字列を []="..." の直後に挿入して、更にその後に
    その特定の文字列を使って分割する事が可能だろうか。然し、その為には & または
    \1 等による後方参照で元々の文字列を置換後に参照する必要がある。gawk の
    gensub を使えば可能かもしれないが、その儘の awk では難しいのではないだろう
    か→改めて確認した所、

    ? 今試している awk 実装では問題になっていないが、この様な巨大な処理をすると
      なると awk 実装によってはとても遅くなる可能性があるのではないだろうか。

      | →試してみたらそもそも動作していなかった。動かないと思ったらそもそも nawk
      | は {m,n} に対応していない?
      |
      | $ echo '000' | nawk '/[0-9]{3}/'
      | $ echo '000' | mawk '/[0-9]{3}/'
      | $ echo '000' | gawk '/[0-9]{3}/'
      | 000
      |
      | この様な事態になっている。これは大変な事である。つまり、ERE は使えると思っ
      | て書いていると痛い目を見るという事である。更に調べると gawk-3.0 でも
      | --posix または --re-interval オプションを指定する必要があった様だ。
      |
      | https://unix.stackexchange.com/questions/354553/awk-repetition-n-is-not-working
      |
      | gawk であれば --posix または POSIXLY_CORRECT=always を指定すれば良いそう
      | だが、どの道他の実装では使う事ができない。という事を考えると一概に使えな
      | いと思っておくべきである。
      |
      | * 更に 0xHHHH もエラーメッセージなく勝手に 0 と解釈されていた。
      |
      | * また printf("%s\0",line) は普通に \0 が null-terminated と見做されて 0
      |   は出力されない。これは gawk の振る舞いの方が特殊である様に思われる。
      |   printf("%s%c", line, 0) で出力する事にする。
      |
      | * mawk は /[0-9][0-9]?[0-9]?/ としても /[0-9][0-9]?/ になってしまう。

      色々互換性の問題を修正した。見た感じだと nawk も mawk も gawk よりは高速
      である。余り気にしなくても良さそうである。

    ? 更に変な内容がなければもっと高速化できるのではないだろうか。

      例えば全て []="..." の形式だったならば、最初に " []=" を全て他と当たらな
      い様な物 (例えば ^A) に変換して、その後で "" の中身の unescape 処理をして
      から分割すれば良いのではないか。unescape は \\ -> ^B, \" -> ", \$ -> $,
      \` -> `, ^B -> \ とすれば良い。

    取り敢えず新しく実装した ble/util/{read,write}array を使う様に変更してみた。

  * main: ble-reload するとプロンプトの計算の箇所で問題が生じる [#D1521]

    これは当初 nawk のテスト時に気がついた問題なので nawk に関連して生じている
    のかと考えたが、gawk で試しても同様の問題が生じた。

    遡って調べてみると実は 82c5ece で発生する様になった問題の様である。
    取り敢えず bleopt/check-all でエラーが発生しているのかもしれない。
    →これが原因だった。これは独立な問題として commit する事にする。

  * set -o posix の時、ユーザーが read -e を呼び出すと [#D1520]
    何にも動かなくなるのではないか。

    a 然し、read -e 自体が posix の範囲外なので仕方がないという見方もできる。

    b 或いは、set -o posix の時には set -o emacs / set -o vi の切り替えを利用して
      read が使える様に調整するという事も原理的には可能である。その場合には実際に
      bind する対象の keymap が反転するので大幅な改修が必要かもしれない。

      x 然し、vi mode 及び emacs mode に切り替える機能も存在した筈である。これを
        呼び出されると結局 ble.sh の管理下の keymap が前に出てきて問題になる。
        read の中から呼び出された事を検出してどうにかその場で取り繕う事は可能だろ
        うか。

    c 別の方法で read が呼び出される瞬間を検出できないだろうか。或いは read -e に
      よって最初に widget が呼び出された瞬間に POSIX を始めとする様々の設定を回復
      する? その場合には C-c で read をキャンセルした場合にまた元に戻す事を忘れて
      はならない。

    d ユーザーがコマンドを実行する度に realine 設定を完全 unbind して、終わったら
      再度 bind し直す。でも、これは文法エラー等によってコマンド実行が中断された
      時に、ble.sh session に復帰せずに通常の readline の状態に落ちてしまう。

    →どうやら set -o posix でも本来の意味を取り戻す builtin とそうでない
    builtin が存在する様で、read の場合には set -o poix であっても関数が定義さ
    れていればそちらが呼び出される様である。なので気にしなくて良い。本当に問題
    が起こるのは builtin read -e が実行された時になるが、これは元から動いていな
    かった。

    実の所、builtin read -e に対しても制御を全く失う様な事態にならない様にした
    いが、それはまた別に考えた方が良いのでは? と思ったが、此処での考察はその場
    合にも同様に適用できる→別項目に残す事にした。

2021-04-30

  * 2021-03-21 set -o posix してから source ble.sh すると失敗する [#D1519]

    先に source ble.sh してから set -o posix する分には即座に問題は起こらない。
    然し ble-attach に失敗するという可能性は存在する。うーん。
    関数を新しく定義するという事をしなければ特に問題は発生しない?

    POSIX モードに対する処理は関数の外で実行する事にした。同時に順序を変えて一
    番最初に POSIX モードを ble.sh 内部状態として調整する事にする。

    ? done: 実のところ、enter/leave でユーザーの設定した同名の alias/function
      を保存し、それからまた後で復元するという事も原理的には可能なのではないか

      …と思ったが、果たして其処までの事をする必要はあるだろうか。保存の為にま
      た色々コマンドを走らせなければならなくなるが重くはならないだろうか。と思っ
      たが、alias ... declare -pf ... を呼び出すだけなので実はそんなに処理とし
      て重い訳ではない。問題は alias や declare が勝手に置き換えられていた時に
      ちゃんと動作するのかという話である。

      結局実装する事にした。

    ? done: 現在二段階に分けて unset -f しているが POSIXLY_CORRECT しているのだ
      から、builtin も unset も本来の意味を取り戻している筈で、それならば一回の
      unset -f で十分なのではないか。

    x fixed: 現在 set -o posix, +o posix を使ってモードを切り替えているが、これ
      は setを上書きされていた場合に使えない。直接変数に代入するべきである。更
      に言うと、local ... も使えるとは限らない。local が上書きされているかもし
      れないから。という事を考えると、これも直接グローバル変数の値を変数代入で
      変更するべきである。

      →これは確認した所、元から殆どその様になっていた。新しく追加したコードだ
      けで set を使っていたので、これを全て POSIXLY_CORRECT=y 及び \builtin
      unset -v POSIXLY_CORRECT に書き換えた。また、unset は -o posix の時にだけ
      実行する様に変更した。-o posix の時には \builtin unset は本来の意味で解釈
      される事が保証されているからである。

      ? と思ったが、unset を使って解除する場合には見えている一番上の
        POSIXLY_CORRECT が解除されるだけで、更に呼び出し元のスコープで定義され
        ている POSIXLY_CORRECT が存在した場合には依然として set -o posix のまま
        になるのではないか。

        $ f1() { local POSIXLY_CORRECT=y; f2; echo f1:$SHELLOPTS; }
        $ f2() { local POSIXLY_CORRECT=y; f3; echo f2:$SHELLOPTS; }
        $ f3() { set +o posix; }
        $ f1
        $ f2

        試して見た所、unset POSIXLY_CORRECT だとやはり、更にその上の階層の状態
        が見える様になるだけである。そして、set +o posix も全く同じに作用すると
        いう事が分かった。

        但し考えて見るに ble.sh はトップレベルで動いていてその途中で
        POSIXLY_CORRECT を設定して動作するという事もないので、unset が途中の関
        数スコープの POSIXLY_CORRECT に当たるという事もない。従って、普通に
        unset -v POSIXLY_CORRECT を一回実行するだけで問題ない。

        何か問題が起こるとすれば、ble-attach もしくは source ble.sh を実行した
        時に複数の local POSIXLY_CORRECT=y の中で実行された時である。然し、この
        場合にはどうにも対策の仕様がない。unset -v を繰り返し呼び出す事によって
        POSIXLY_CORRECT を解除する事はできるが、然しこれを実行すると呼び出し元
        で実行した local POSIXLY_CORRECT の意図を壊してしまい呼び出し元で問題が
        生じる可能性がある。

        実はこの事まで考えると set +o posix や set -o posix で POSIX 状態を操作
        するのは不味いのではないかという気がする。呼び出し元で設定した
        POSIXLY_CORRECT の動作を破壊してしまう。

    x posix にしていても eval の中の alias 置換を防ぐ事はできないのでは。
      alias 展開をオプションで無効にする必要があるのではないか。
      そして alias は割とあらゆる箇所で影響が出る。
      これは大丈夫だろうと思っている if や [[ 等も対象である。

      | a builtin に関しては危ない所を全て \builtin 等に書き換えてしまえば問題ない。
      |
      |   grc '(^|[[:space:];|&('\''"])builtin\b' --exclude={wiki,ext,memo}
      |
      | b 或いは shopt expand_aliases を off にして処理を行う? うーん。ble.sh の内
      |   部では expand_aliases を off にするのが良い気がしてきた。
      |
      | c と思ったが ble.sh に影響を与える様な alias だけを off にすれば良いので
      |   あって全ての alias を off にする必要性もない。そして ble.sh に影響を与
      |   える様な物に関しては、ble.sh の処理中には unalias してしまっている筈な
      |   ので殆どの場合は大丈夫な筈なのである。
      |
      |   ユーザー実行環境で ble.sh 関数が呼び出されて、その ble.sh の中で eval
      |   をした時に alias 置換が発生するという状況は考えられるが、まあ、その様な
      |   場合にまで気を配る必要は今の所ないと考えている。
      |
      |   取り敢えず、adjust-builtin-wrappers が呼び出される所までは \builtin の
      |   様にして escape する必要がある。後、adjust-builtin-wrappers 自体の処理
      |   でも対策が必要になる。
      |
      |   * 特に、adjust-builtin-wrappers の中で eval を実行しているが、其処で
      |     alias 展開が起こると問題である。特に ble/util/assign によって実行され
      |     る eval が問題になるのではないか。
      |
      |   後、ble/util/assign の中でも

      結局 expand_aliases を off にする事にした。ble.sh を読み込んで
      expand_aliases を無効にする迄の部分を \builtin の様に quote すれば良い。
      一旦関数を定義してしまえば実行時に書き換わる事はないので、気にしなくて良
      い。気にするべきは eval で実行される文字列 (新しく解析される文字列) であ
      る。

    * resolved: 保存・復元の時に sed を使っているがこれを置き換えられないか。

      | これは ble.sh 読み込み時の最初の最初の部分なので sed が PATH に含まれてい
      | ない可能性も考える必要がある。sed の代わりに使える物はないだろうか。
      |
      | a 例えば extglob を有効にしてパラメータ展開で置換を実行するというのは一つ
      |   の手である。
      |
      |   この方法だと一回 type の出力を変数に格納する必要がある。従って、余分に
      |   $(subshell) を実行する事になってしまって非効率的である。と思ったが、パ
      |   イプにする事によっても subshell が 2 つ余分に生成されるのだから、$() に
      |   しても特に overhead にはならない気がする。
      |
      |   然し extglob を on/off するのはそれはそれでまた面倒である。
      |
      | b どうにかして sed の binary を見つけてそれを先に ble/bin/sed に登録して
      |   しまう? 然し、その為に色々の処理が必要で、その処理を不明な環境で安全に
      |   実行するのもまた面倒である。
      |
      | 後、最初の実行時には注意深い実装が必要かもしれないが、一旦初期化が終わっ
      | てしまえば、ble/bin/sed を使っても良いし、ble/util/assign も軽い実装を利
      | 用する事ができる。いっその事、初めから初期化前用の実装と、初期化後用の実
      | 装に分けても良い気がする。

      汚いが extglob で処理する事にした。

      実際に動かしてみると bash-3.0 で滅茶苦茶遅い。何故だろうか。bash-3.1 では
      特に問題は起きていない。調べてみた所、+([[:lower:]]) とすると遅い。
      +([a-z]) は遅くない。直接書く様に修正した。

    * 現在の待避コードの順序について考える。

      posix だとそもそも ble/* という関数自体定義する事ができない。一旦関数さえ
      定義できてしまえば関数呼び出し自体はできる。

      FUNCNEST の設定。関数定義はできるが関数呼び出しができないという状態だと駄
      目なので。

    * 一応各 builtin について動作確認をしておく。

      builtin, unset, eval はOK
      return, break, continue, local もOK

      % declare は駄目だった。というのも関数定義を抽出するのに使っているから。set
      % -o posix していても declare は回復できないのだという事。うーん。つまり
      % builtin か declare のどちらかは必ず先に unset しないと動かないという事。
      %
      % local の方を諦める事にした。local を上書きしてもローカルに変数が作られる
      % 事になる為、期待した効果を再現する事は不可能になる。なので敢えて上書きし
      % ようという人はいないだろう。declare だと機能を勘違いしている人が上書きし
      % ている可能性がある。また最初の local POSIXLY_CORRECT が効果を失うのも避け
      % たい。

      やはり他にも色々動かない物があるので local を諦めるだけでは済まない。やは
      り builtin の復元を諦める事にする。そもそも builtin を置き換えようとする
      事自体が異常である。何か一つ置き換えを禁止するのだとしたら builtin にする
      のが自然ではある。

      x fixed: : は保存できていない。もしかすると set -o posix の時には declare
        -pf で定義を出力できないという事? 確かめてみたが別にそういう事はない様
        である。という事は逆に定義する時に失敗しているという可能性?

    x fixed: ble-reload 後に ble-detach を実行すると以下のメッセージが出る。

      | bash: builtin: is: シェルのビルトイン関数ではありません
      | bash: enable: is: シェルのビルトイン関数ではありません
      | bash: enable: a: シェルのビルトイン関数ではありません
      | bash: enable: shell: シェルのビルトイン関数ではありません
      | bash: unalias: is: 見つかりません
      | bash: unalias: a: 見つかりません
      | bash: unalias: shell: 見つかりません
      | bash: unalias: builtin: 見つかりません
      | bash: return: is: 数字の引数が必要です

      これを見るに何らかのエラーメッセージがコマンドとして実行されている?

      然し、ble-reload の後に履歴が可笑しくなっているのも、ble-detach の後に変
      な状態になっているのも治っていない。これらはまた別の問題という事か。

      どうも _ble_bash が変な値になっていて、それによって別のコードが呼び出され
      ていたという事。そしてそのコードはちゃんとテストされていなかったので元々
      バグを持っていて、それが発現していたという事の様である。そもそもそのコー
      ドは set -o posix でも動く関数定義取得の為に declare -pf と type を切り替
      えて使っていた物だったが、そもそも関数名が通常の識別子である限りは
      declare -f を常に使っていれば特に問題はない。基本的には declare -f を使っ
      て、: だけは bash の version で切り替える事にした。

      以前使っていた declare -pf / type の切り替えによるコードは以下に残して置
      く。

      | if ((_ble_bash>=40300)); then
      |   builtin local defs
      |   ble/base/adjust-builtin-wrappers/.assign '
      |     \builtin declare -pf "${builtins1[@]}" :
      |     \builtin alias "${builtins1[@]}" "${keywords1[@]}" :'
      | else
      |   builtin local fname
      |   ble/base/adjust-builtin-wrappers/.assign '
      |     \builtin declare -pf "${builtins1[@]}"
      |     \builtin alias "${builtins1[@]}" "${keywords1[@]}" :'
      |   defs=$'\n'$defs
      |
      |   # Note: bash-3.0 だと何故か extglob +([]) の中で [:alnum:] や [:lower:]
      |   #   を使うと滅茶苦茶遅い。何れにしても locale 依存になるのは避けたいので、
      |   #   直接 a-z と書くのが良い。
      |   builtin local pattern=$'\n+([][{}:a-z]) is a function\n'
      |   if builtin shopt -q extglob; then
      |     defs=${defs//$pattern/$'\n'}
      |   else
      |     builtin shopt -s extglob
      |     defs=${defs//$pattern/$'\n'}
      |     builtin shopt -u extglob
      |   fi
      | fi

      さて、これで問題は "何故 _ble_bash が消えて無くなるのか" という事に集約さ
      れる。(履歴の振る舞いが変になるのも古い bash の history -s の振る舞いが変
      だという事と関係しているのだろう。また、C-d の反応が悪いのも関係している
      だろう。)

      実際に _ble_bash が空になっているという事が確認できた。

      そしてそれは何故かというと ble/base/unload-for-reload で _ble_bash を
      unset しているのが原因だった。つまり、unload-for-reload を呼び出す迄は
      _ble_bash 等の初期化は遅延した方が良いという事なのだろう。builtin に対す
      る対策は _ble_bash には頼らずに version 判定するべきなのである。→結局ど
      の bash version でも動作する様に常に type を使って関数定義を得る事にした。

    x fixed: ble-reload すると何故か履歴項目が最後の項目に対する追記の様になっ
      てしまっている。ble-reload ではなくて source ble.sh しても同様の問題が発
      生する。bash --rcfile out/ble.sh としても発生している事を考えると mshex
      等の他の設定との組み合わせで起こっている問題ではなくてそれ自体として発生
      している問題である。

      遡って見ると #D1519 の問題であるという事が判明した。これは #D1519 の下で
      議論するべきであろう。然し、そうだとしても何が原因になっているのかは謎で
      ある。構文着色も動いている様に見えて何だか不思議な動作をしている。原因を
      特定する為に幾つか振る舞いを変えて試してみる必要がある。

      * 保存していた builtins を復元しない様に変更したが特に変化はない。依然と
        して変な振る舞いを続けている。

      * adjust/restore-builtin-wrappers を使わない様にしても変な振る舞いを続け
        ている。

      うーん。コードを見ても怪しい所は見つからない。明らかに機能不全を起こして
      いる箇所があるのだから其処を手掛かりに原因を探る方が懸命である様に思われ
      る。

      ble-detach で発生するエラーについて調べようとしたが原因の設定では再現しな
      い様である。再現する為の条件があるという事か? 或いは ble-detach で発生す
      るエラーに関しては実は adjust/restore-builtin-wrappers が関係しているとい
      う事だろうか。

      これの原因は前の項目で判明した _ble_bash の消滅だという事が分かった。一緒
      に治った。

2021-04-28

  * blerc にユーザーが使いそうな ble-bind を載せても良いのではないか (motivated by Alyetama) [#D1518]

    ble-bind -f up 'history-search-backward immediate-accept'
    ble-bind -f down 'history-search-forward immediate-accept'

    やその他の Vim の説明に書いた ble-bind など。
    magic-space の効果をなくす為の ble-bind も。

  * nsearch の再設計について (motivated by Alyetama, rashil2000, carv-silva) [#D1517]
    https://github.com/akinomyoga/ble.sh/issues/101
    https://github.com/akinomyoga/ble.sh/issues/80

    一旦は bleopt オプションを追加すると書いたが、ここは widget の引数として
    opts を受け取る様にして、readline settings を読み取る時の振る舞いは適当に
    Bash に合わせる様にする方が良いのではないかという気がする。或いは、多少はユー
    ザーが期待する様な振る舞いに調整しても良い。

    * 実際に history 内部を移動するかどうか。現在の振る舞いは history の中から
      "load" するという振る舞いになっているが、本当は isearch と同様に history
      の内部を "移動" するという振る舞いの方が分かりやすい。

      action=load
      action=move

    * 空文字列の時に唯の行移動に fallback するかどうか。
    * 空文字列の時に前回と同じ文字列で検索するという手もある。

      empty=line-move
      empty=graphical-line-move
      empty=logical-line-move
      empty=history-move
      empty=previous-search

      空文字で検索する事はない様に変更する。

    * カーソル位置を何処に置くか。
      point=end
      point=begin
      point=preserve

    * nsearch status を表示するかどうか。
      hide-status
      % hide-status-on-empty

    * 下を押し続けた時にまた元の状態に戻る様にする。
      これはオプションにしなくて良い。

    C-x p 等の時には以下の設定で実行する。

      action=move:point=preserve:empty=line-move

    readline function 経由での呼び出しではできるだけ Bash の振る舞いを再現する?

      action=load:point=preserve:empty=line-move

      % うーん。実は Bash も空文字列の検索に対しては特別の挙動をしている様だ。
      % つまり、今まで議論で一貫性のある振る舞いについて考えていたが、これは既
      % に Bash が自然な形で破っているので Bash に従うべきなのである。

      →改めて Bash を試してみた所、やはり単純に行を移動しているだけではない様
      に見える。カーソルを行末に移動しているが、それによって次の検索内容が変化
      するという訳でもない。実際、ble.sh の実装に於いて、空文字列に対して単に行
      移動の widget に委譲してしまうと、次の up の呼び出しの時に新しくロードし
      た文字列全体に対して再度検索が走ってしまう。

    point=end をリクエストされたが正直これはデフォルトにしなくて良い。
    変更したければ自分で nsearch に point=end を指定して ble-bind して貰う。

    色々考えると実は hide-status-on-empty は実装しなくても良いのではないかとい
    う気がしてきた。理由付けとしては空文字列検索を行うオプションはそもそも存在
    しないから。というか、hide-status 自体表示する必要がないのかもしれないとも
    思った。然し、一応実装しても良い気がする。


    [疑問]

    * ok: isearch に対する疑問。現在履歴位置の古い内容に一致しないのか。

      % よく分からないのは現在履歴項目を遡った状態であった時に、現在の履歴の内容
      % に一致したらどうするのかということである。うーん。isearch はちゃんと遡っ
      % ている時にはその内容に一致している気がする。が、それは何でかというと他の
      % 場所に周遊している時にはその時の編集している内容は履歴に反映させている為
      % である。此処での疑問は、cyclic で検索している時に、現在の編集内容では消え
      % ているが、現在位置の履歴に残っている文字列に一致する場合に何が起こるのか
      % という事
      %
      % →うーん。試そうとしたが isearch で入力している内に最初の方に入力した文字
      %   に一致する項目にジャンプするので実の所、この様な状況が発生する事は滅多
      %   にない。
      %
      % しかし原理的には現在位置の古い内容に一致してしまう事がある気がする。これ
      % を回避するには検索を開始する前に現在の編集内容を履歴に反映させておくか、
      % 或いは、cyclic で検索するにしても現在位置には一致しないようにしておくか。
      % 現在の実装ではどちらかになっているのだろうか。
      %
      % コードを確認した所、気になる部分を見つけた。#D1025 で同様の問題があって部
      % 分的な修正が行われた様に見える。何れにしても基本的には isearch は非
      % cyclic な検索になっているので、そもそも巡回して現在の位置が検索対象になる
      % 事がないので気にしなくて良かった。

      →isearch は現在履歴位置については自分でテストして、それ以外については非
      cyclic な検索で次の項目から検索する様にしているので、現在履歴位置の古い内
      容に一致する事はない。

    [実装]

    * ok: 先ず初めに down を続けた後に元のコマンドライン文字列を回復する機能に
      ついて考える。

      ? そもそも既に history の途中に移動している状態で nsearch を始めた時はど
        うなるのか? →変な振る舞いになっている。#1 から更に down を押したら元に
        戻るべきなのに、改めて上方向に検索して #2 という状態になっている。更に
        付け加えるならば "echo" という文字列には一致しない。

      うーん。元のコマンドライン文字列に戻った時に、nsearch 状態が継続している
      とするか、或いは、nsearch 状態から抜けるか。again または input の時には、
      元のコマンドライン文字列に戻ってしまうのは変である。元のコマンドライン文
      字列に必ずしも一致するとは限らないので。(然し、逆に言えば元のコマンドライ
      ン文字列に一致する場合にはどの様に動作するのが自然だろうか?)

      | ? 現在のコマンド文字列から検索対象を拾った場合には、元の位置まで戻って来
      |   たら nsearch 状態を抜けるのは自然である。と思ったが、それはそれで変であ
      |   る。例えば C-x up で検索を初めて、その後は up/down で移動していた時に突
      |   如として nsearch から抜けてしまうと不便である。という事を考えると
      |   nsearch 状態から抜けるというのは変な話である。
      |
      |   そういう観点から考えると、やはり勝手に nsearch 状態から抜けるのではなく
      |   て、現在文字列に一致している状態にするのが自然である。一方で、stack の
      |   先頭に記録しているのは、現在の一致状態ではなくて、nsearch 開始前の状態
      |   である。
      |
      |   例えば、現在のコマンドラインから検索対象を拾った場合に
      |   は、_ble_edit_nsearch_stack に初めから余分に record を追加しておくのが
      |   良いのではないだろうか。つまり、検索開始時に最初に
      |   _ble_edit_nsearch_stack に検索開始前の状態を保存すると共に、カーソル位
      |   置を point=* で指定したのに対応する位置に初期化してしまう。
      |
      |   と思ったが空文字列で empty=previous-search によって検索開始した時には現
      |   在のコマンドラインに一致しているとは限らない。など考えると明示的に現在
      |   のコマンドラインに一致するかどうかはチェックするべきである。
      |
      | ? input/again の時に元のコマンドライン文字列に一致する場合にどの様に取り
      |   扱うか。これは action=load にしているか action=goto にしているかでも振
      |   る舞いを変えるべきかもしれない。
      |
      |   →input/again でなくても現在のコマンドラインに一致しない可能性があるの
      |   で、これは input/again かどうかの問題としてではなくて、検索が初期コマン
      |   ドライン文字列に一致するかどうかの問題として捕らえるべきである。


      検索開始時点で現在の状態は _ble_edit_nsearch_stack に記録しておく。次に現
      在の行に対して一致するかどうかをチェックして、一致していたらそれも記録に
      残す。そしてその次の一致を調べる。

      うーん。何だか分からなくなってきた。もし現在のコマンドラインだけに一致す
      る時に nsearch をそもそも開始するべきかどうか? という話にもなる。現在の実
      装を確認してみた所、一応 nsearch は開始する様だ。然し、highlight も何も起
      こらない。うーん。これは実は highlight しても良いのではないだろうかという
      気がする。

      じゃあ、input 等で指定された検索対象が現在の内容にも履歴にも見つからない
      場合にはどの様に振る舞うべきなのだろうか。この場合には、選択範囲も何もな
      い状態で nsearch に入るという事の気がする。

      振る舞いとしては (1) 何処にも一致しない場合には現在の内容から少しも動かな
      いが、それでも nsearch 状態には入る。(2) 現在位置に一致して他に一致しない
      場合は、現在位置に一致した状態で固定。 (3) 現在位置にも他の位置にも一致す
      る場合には、他の最初に見つかった位置に移動するが down 等で現在位置に戻っ
      てくる事ができる。(4) 現在位置に一致せず他の位置に一致する場合には、他の
      最初の位置に移動するが down 等で現在位置に戻ってくる事はできない。という
      ので良い気がする。

      この振る舞いにするのであれば別に難しい事はない気がする。単に最初に現在位
      置に一致するかどうかをテストして、一致していたら stack に記録して状態を書
      き換えれば良いのである。

      実装を確認した感じでは現在のコマンドラインの内容は検索で参照しないし、中
      で実際に呼び出している検索処理である isearch も履歴の内容しか参照していな
      い。つまり、現在のコマンドラインの内容に対する一致は呼び出し元でちゃんと
      処理するという前提になっている。という事を考えると、この実装でも現在の内
      容に対する一致は呼び出し元でチェックすれば良い。というより古い内容に一致
      しない様に現在位置の一致は自前でする必要がある。

    * ok: 実装を確認した所、既に opts は受け取る様になっていた。これに色々とオ
      プションを追加すれば良い。

    * done: 空文字列の振る舞いとして単に行移動するだけの実装だと再検索で問題が
      起こるという事が判明した。これの対処方法は二種類ある。

      a 一つは行移動した時に必ず行頭に移動するという事。但し、その場合には検索
        文字列は改行を含まない物として、行頭から抽出するという様に振る舞いを変
        えなければならない。

        問題が起こるのはカーソル位置から検索文字列を取り出す時だけである。でも
        一貫性を考えれば、別に常に先頭に移動するという実装で問題ない気がする。

      b もうひとつの方法はやはり hide-status-on-empty で対処するという事。或い
        は empty=hide-status で良いのかもしれない。

      取り敢えず二種類をオプションで指定できる様にした。

    * done: opts hide-status

    * resolved: 検索対象の文字列を行頭迄にして見たが、実際の検索にはコマンドラ
      インの一番最初からの一致しか考えていないので、自分自身に一致することがな
      い。これは何だか変な気がする。或いは、現在行だけ置換するという手も考えら
      れなくもないが、それはそれで機能として複雑すぎる気がする。やはり、検索対
      象はコマンドライン先頭から抽出する事にして、更に、空文字列 up down の移動
      後もコマンドライン先頭に移動するべきである。という事を考えると、line-move
      というのは変である。history-move しか nsearch とは相容れない気がする。

      →line-move は機能として削除する事にする。

    x fixed: 今気づいたのだが read -e が動かなくなっている。どうも 856cec2 がい
      けない気がする。と思って確認したが別に read -e が動かなくなる様な要因はな
      い気がする。或いはもっと最近の修正が原因だろうか。どうも調べてみた所、最
      新の ble-bind --cursor の commit によって動かなくなっている様である。何故
      だろうか。refactoring で変更漏れがあっただろうか。

      refactoring 関連を確認してみたがぱっと見た感じでは変更漏れはない気がする。
      だとすると何が変わったのだろうか。何処で失敗しているのか read の中に入っ
      て行くべきだろうか。

      →分かった。これは ble/decode/keymap/push が 1 を返す様になってしまってい
      たのが原因だった。push の一番最後の行に [[ $cursor ]] && do something を
      入れた所為で、カーソルが設定されていない keymap/push が失敗する様になって
      しまっていた。カーソルの設定に関係なく 0 を返す様に修正した。

    x fixed: C-x up/down で移動する内に履歴が書き換わっている気がする。これは
      goto と load が入り混じっているからの気がする。ちゃんとその辺りを修正して
      からテストするべきである。

    x 下方向に検索できない状態になっている。というか goto-match で常に backward
      になっているのは変である。

      そもそも検索開始位置は現在の履歴位置とするか或いは末端とするのかという問
      題がある→確認してみた所、一応検索開始位置は現在の履歴位置になっている様
      である。

      ? 検索方向を反転する時に古い履歴内容に一致してしまうのではないか。

        検索開始位置の履歴項目には含まれていた単語を、編集でそれを消した後に検
        索すると、最初の一致が当初の検索方向に離れた箇所で起こる。その時に検索
        方向を反転させようとすると、過去の履歴に一致してしまう可能性がある。

        この時にはどの様に対処すれば良いか。先ず、検索方向の反転は stack の内容
        が1個しか残っていない時に起こる筈である。この時には、検索再開位置は現在
        項目か或いは検索開始項目でより検索再開方向に進んだ物を採用する必要がある。

    * 既定の動作をどの様にするのが良いのかよく分からなくなってきた。そもそも何
      故 nsearch という表示を隠す必要があるのかという事。

      特にカーソル位置を末尾に移動するという設定と組み合わせると、連続して同じ
      コマンドを実行した時には "カーソル前の文字列を検索する" という動作は最初
      の一回だけであり、それ以降には最初の一回で使った検索文字列を繰り返し使う
      という動作になっている。つまり、連続で実行している時には通常と異なる状態
      になっているというのは明らかである。という事を考えるとその事が分かる様な
      表示が必要になる筈である。単に上下で履歴内部を移動するのとは訳が違うので
      ある。

      zsh の振る舞いを調べてみた所、別にカーソル位置を変な所に移動するという事
      はしていない。と思ったが、どうやら history-search-end というモジュールが
      あって、それに history-beginning-search-backward-end 等の様な、末尾にカー
      ソルを移動する様な同じ機能の物が存在する様である。
      https://unix.stackexchange.com/a/97844/121088

      取り敢えず C-x up 等によって使える物については自分の思う様に実装する事に
      する。先ず action=load ではなくて移動。nsearch status は表示する。point
      は現在位置。explicit に呼び出しているのだから空文字列でも普通に nsearch
      に入る。

      readline 経由で up に割り当てている時には。

      a やはり2回 RET して実行されるというのは、保持する。そうすると nsearch
        status も表示して置くのが良い。Bash の元々の動作と思うと action=load は
        保持した方が良い様な気もする。空文字列の時に空文字列で検索するか、とい
        うと微妙。うーん。空文字列の時は history-move が良い気がする。うーん。

      b 或いは bash と完全に同一の動作を目指すのであれば、
        action=load:hide-status:immediate-accept 等と指定すれば良い。が、それは
        それでユーザーが便利にならない。ble.sh の便利さを押し出していきたいので
        あればやはり便利な動作を既定の動作とするのが良い気がする

        hide-status:immediate-accept:action=load:empty=empty-search:point=end

    [Note]

    * 空文字列移動: 行指向の通常移動に fallback する選択肢を考えたが、コマンド
      ラインの途中に移動すると、カーソル前の文字列が非空になるので、続けて移動
      しようとすると予期しない nsearch が始まってしまう。代わりに常に行頭に移動
      して検索文字列を行頭から抽出する様にすると、今度は自分自身に一致しなくな
      るので動作として分かりにくい。

    * C-x up で始めた時は empty=previous-search で良い気がする。うーん。ユーザー
      に入力させた時には空文字列を指定したのに前の文字列で検索が始まったら変で
      ある。なので既定の動作を previous-search にするのは変である。然し、コマン
      ドラインから検索文字列を抽出した時にだけ empty=previous-search にするのも
      分かりにくい気がする。

    [修正]

    x fixed: 描画で一番最後の文字が欠けてしまう。何らかの座標計算が間違っている
      という事だろうか。

      どうも point=end を指定すると振る舞いがおかしくなる。然し、可笑しな事が起
      こる余地などない様な気がする。或いは、_ble_edit_ind の値を勝手に此処では
      変えてはいけないという事なのか、或いは、${#_ble_edit_str} の値がここでは
      大きな値になっているか。

      どうも get-selection によって発生している様な気もする。もしかして空の
      selection range を指定すると発生する現象なのだろうか。試してみると、空の
      range の数だけカーソル位置がずれるという事が分かった。

      分かった。buffer を構築する時に空 range があると "SGR${buff[@]::0}" になっ
      て、これが 0 要素に展開されれば良いが、SGR がある為に 1 要素に展開されて
      しまって、結果として buffer の要素数が増えてしまっているというのが原因で
      あった。そもそも空 range については要素の追加自体を実行しないという形で対
      処する事にした。

      それとは別に空文字列で検索している時には _ble_edit_mark_active を設定する
      必要もない。判定条件を見たら、_ble_edit_ind==end だった時の条件がそのまま
      になっていたのが悪かった。これも修正した。

    x fixed: 最新行が空文字列の時、最新行に空文字列検索で移動できない。これは
      isearch の実装の問題だろうか。或いは最新行が空文字列の時は移動しても登録
      されないという事なのか。或いは isearch の検索範囲の判定で有限文字列化空文
      字列かで振る舞いが変わるという事か。

      →分かった。最新行が空文字列の時に移動しても登録されない事態になっていた。
      dirty かどうかの判定で文字列比較を行って同じであれば処理をスキップしてい
      たが、そもそも登録されていない時にも "空文字列" になってしまうので、"空文
      字列" を登録しようとしても登録されずに終わってしまうというバグであった。
      これは修正した。

    * done: wiki: widget についての説明を書く。これは rasheil2000 への説明を調整して
      乗せれば良い→書いた。

    * done: wiki: Q&A から説明へのリンクを書く→書いた。

    * done: wiki/Q&A: リンクが間違っている物があった→修正した。

    * done: wiki: key bindings について RET, TAB, ESC 等についての説明をちゃん
      と書く。
      https://github.com/akinomyoga/ble.sh/issues/101#issuecomment-828340592

    * done: blerc に何か書いても良いのかもしれない? 或いは Alyetama の言う様に
      wizardを作って其処から設定を選択できる様にする。取り敢えず今は blerc には
      書かない事にする→やはり書いた。

2021-04-26

  * util: 既定の cursor-shape の時には DECSCUSR は出力しない (motivated by jmederosalvarado) [#D1516]
    https://github.com/akinomyoga/ble.sh/issues/95

    % cursor shape を変更しない場合には external/internal の切り替えでも
    % DECSCUSR は出力しない様にするオプション?
    →オプションではなく固定でその様な動作に変更した。

    そもそもその様な実装になっていると思っていたが…。恐らく一番最初の状態が
    unknown になっているのが原因? もし最初の状態が 0 になっていたとして emacs
    mode の場合にはそのまま DECSCUSR が全く呼び出されずに済んだ可能性はあったろ
    うか。

    →実際に試しに最初の状態を unknown から 0 に変更した所、ちゃんと最初のカー
    ソル状態が保持される様になった。

    ? no: 然し、コマンドを実行した後にカーソル形状を元に戻すという操作が強制で
      入っている可能性はあるだろうか?

      →確認してみたが、特に external/internal は意識していなくて、また外部コマ
      ンドがカーソル形状を変化させてしまうという可能性は考えていない。外部コマ
      ンドが停止する時にカーソル形状を戻しておくべきであるという前提に基づいて
      いるのであろう。

      取り敢えずその前提は仮定する事にする。

    条件判定を変更したが、実は初めから値を 0 に設定しておけば同じ動作になるので
    はないだろうか…。此処で実装するべきは空文字列だった時と 0 の区別ではないか。
    と思ったが、0 を意図してブロックとして指定するユーザーがいるかも怪しい。ブ
    ロックであれば 1 を指定すれば良いからである。

    諸々考えると単に初期値を unknown から 0 にすれば良いという気がする。

  * term/edit: keymap 毎のカーソル形状 (motivated by jmederosalvarado) [#D1515]
    https://github.com/akinomyoga/ble.sh/issues/95

    現在の実装では auto-complete, menu 等の mini mode 等でカーソル形状は変わら
    ないと仮定して、emacs, vi_?map の間の変更だけでカーソル形状の再設定を行って
    いる。然し、今後 mini mode におけるカーソル形状の変更も考えると、もっと統一
    的にカーソル形状を管理する必要がある気がする。

    例えば keymap 毎にカーソル形状を設定できる様にして、keymap の切替時に設定さ
    れたカーソル形状に変更する様にする。指定した keymap にカーソル形状が設定さ
    れていない場合は、keymap stack 内の前の keymap を参照する。

    * この時、既存のカーソル形状の設定はどうするのか。

      現在の vi におけるカーソル形状の設定: imap,nmap,omap,xmap,smap,cmap
      ... これらの設定に応じてカーソル形状を変化させる様になっている。然し、実
      際の実装ではこれらの map は参照せずに設定している気がする… と思ったが確
      認したらちゃんと keymap を参照してカーソルを切り替えていた。

      設定の方法は bleopt keymap_vi_?map_cursor を介して行っているが、もし
      keymap 毎にカーソル形状を管理する様にするという事だと、(1) 既存の設定は翻
      訳しなければならない (2) 新しい方法に移行する様に情報を提示する必要がある。

      或いは、bleopt keymap_KEYMAP_cursor を一般に使える様にするという手もある
      が、これはこれで bleopt 内に名称の構造を作成する事になるので避けたい。

    * emacs に対応する。

    ? ok: cursor-state を decode.sh から参照しても依存関係的に問題ない
      か。cursor-state は何処で実装されているか? → util.sh で定義され
      ている様なので大丈夫。

    [変更]

    * done: 設定の変数名を決める ... _ble_decode_KEYMAP_kmap_cursor

      取り敢えずは bleopt_keymap_KEYMAP_cursor を参照して実装する? と思ったが後
      の調整が色々面倒になりそうなので、もうこの時点で変数名も決めてしまう事に
      する。

      元々の keymap の設定は _ble_decode_KEYMAP_kmap_@ に保持している。同様に
      _ble_decode_KEYMAP_kmap_cursor を使おうと考えたが、これだと dump/save で
      記録されてしまうので微妙である。また、どういう設定コマンドで設定するべき
      かという問題もある。

      a ble-bind を使って設定を行う? と思っても直感的に変である。例えば
        ble-bind -m KEYMAP --cursor 5 とか設定する事になる。うーん。そんなに変
        ではないかもしれない?

        後、これの呼び出しも遅延する事にすれば実は dump で記録されてしまう問題
        も気にしなくて良い気がする。KEYMAP に紐付いているという事を考えても、直
        観的に特に問題はない様な気もしてきた。

        この場合には ble-bind -P で出力する時にカーソル設定も出力する様にする必
        要がある。

      a 新しくカーソル設定だけの為のコマンドを用意する? というのもユーザーが覚
        える事が増えるだけで余り良くない。

      c 或いはやはり bleopt keymap_cursor_KEYMAP という感じにして、多少構造化さ
        れた名前の bleopt に変更するに留めるか。

      今は取り敢えず a の方針で考える事にする。

    * done: ble-bind にオプションを追加する。
    * done: ble-bind に於ける遅延初期化について確認する。
    * done: refactor: ble-decode-key/dump 其他。

    * done: 実装する。keymap/push, pop の際に cursor shape を再設定すれば良い。

      % 遡ってもカーソル形状が指定されていない場合には何もしない? 今までに何も
      % 設定されていなければ何もしない。今までに何か特別な物が設定されていた場
      % 合には 0 または空の文字列で DECSCUSR を呼び出してカーソル形状の設定をク
      % リアする。これは実は cursor-shape の側で設定を行っている筈なので気にし
      % なくて良い。

      遡ってもカーソル形状が指定されていない場合はカーソル形状をクリアする。

    * done: keymap_vi_?map_cursor の設定を翻訳する。

      書き換えの指示を表示する事にした。然し、遅延ロードで設定が読み込まれる為
      に表示が乱れてしまう。これに対応する為にはメッセージを受け取った時に表示
      する様にしなければならない。どの様にするのが良いか。或いは invalidate す
      る? と思ったが座標計算のずれまでは解決しない。

    * reject: term_vi_?map についても keymap 側に設定を移行するべきなのではないか。

      然しこれに関しては大して系統的に管理しようとはしていないし、もし何かしよ
      うと思う場合でも __attach__ で実行すれば良いのではないか。ただ
      し、__attach__ はその keymap を push した時にしか実行されない。一方で、
      term は pop して表に出てきた時にも実行する必要があるという点が異なる。そ
      ういう意味で ble-bind --cursor と同様に取り扱っても良いのではないか。とい
      うより、ble-bind --cursor を止めてもっと汎用的な hook を用意する可能性?
      と思ったが、やはり cursor は cursor で管理するのが良い気がする。

      term_vi_?map についてはユーザが設定したい時に利用する物なので、現状の儘
      naive な実装をするままで良い。複雑な仕様にするとユーザーが混乱する。

    * done: vi における動作テストを行う。

    * done: wiki: ble-bind に追記
    * done: wiki: 既存の keymap_vi_?map_cursor を廃止。
    * done: update blerc

  * 2021-04-04 keymap/emacs: emacs mode でも cursor shape を設定できる様にする [#D1514]
    https://github.com/akinomyoga/ble.sh/issues/95

    % keymap/vi と同様に実装した。本来は auto-complete や menu 等の mini mode の
    % 中でカーソルの形が変化することも考慮に入れて、もっと統一的な枠組みでカーソ
    % ルの形状を管理するべきな気もするが、現在は external/internal 及び major
    % mode の切り替えのみでカーソル形状を変更する取り決めにして、直接カーソル形状
    % の設定を各 major mode の切り替えで記述している。
    %
    % 2021-04-26 設定を変更した時に直ぐに反映する様にするには? →取り敢えず
    % keymap/vi と同様にカーソルの形状はトップレベルで決まっていると考えて、基底
    % keymap　が emacs かどうかだけで変更を適用する様にした。然し、既に上の段落で
    % 記述した様に、mini mode 毎にカーソル形状を変更する為にはちゃんと構造化して
    % カーソルを変更する仕組みを整備しなければならない。
    %
    % * 今の暫定実装だと、emacs モード内で vi に移行している時に意図しない動作に
    %   なる。vi は毎回自分の状態に応じてカーソルを設定しようとするとので、emacs
    %   の中で vi に移行していたとしても関係なくカーソル形状を変更してくる。なの
    %   で、emacs 内の vi でも vi のカーソル形状の設定は有効であると考えるべきで
    %   ある。
    %
    %   暫定実装では基底が emacs かどうかで判定しているが、そうではなくて、keymap
    %   stack の内部でカーソルが設定されている一番上の keymap を使って判定するべ
    %   きなのではないだろうか。
    %
    %   これも keymap ベースの判定方法なので、やはり keymap を基準にした実装に切
    %   り替えるべきの気がしてきた。

    この変更は結局 #D1515 の実装に伴ってキャンセルした。一応変更は
    memo/D1503.stub.patch に残しておく。

2021-03-15

  * 2021-03-03 syntax: 実は "${v#...}" の中身も tilde 展開の対象の様である [#D1513]
    https://lists.gnu.org/archive/html/help-bash/2021-03/msg00003.html

    bash-1.14 から bash-dev まで一貫して再現する。
    bash -c 'v=/home/murase/test; echo "${v##~/}"'

    : の後は特に展開対象という訳ではない様だ。変数代入形式の単語でも特に展開は
    しない。つまり本当に先頭に ~ がある時にのみ展開が発生する。

    $ bash -c 'v=x:/home/murase/test; echo "${v##x:~/}"'
    $ bash -c 'v=a=/home/murase/test; echo "${v##a=~/}"'
    $ bash -c 'v=a=x:/home/murase/test; echo "${v##x:a=~/}"'

    序でに、この振る舞いについては実はマニュアルにちゃんと記載されている。

    > In each of the cases below, word is subject to tilde expansion,
    > parameter expansion, command substitution, and arithmetic
    > expansion.

    対象は ${v-w} ${v+w} ${v?w} ${v=w} ${v#w} ${v%w} である。他は関係ない。

    * 他に posix モードに於いては変数代入形式の単語についてチルダ展開は起こさな
      い→これの対策も実装した。OK

  * 巨大なディレクトリで TAB 補完が遅くなる (reported by timjrd) [#D1512]
    https://github.com/akinomyoga/ble.sh/pull/65#issuecomment-798551355

    再現する事ができたので対応する事にする。200k のファイルまたはディレクトリが
    存在する所で TAB を押して少ししてから別のユーザー入力を押した時に直ぐにキャ
    ンセルされない。時には数秒待たされる事もある。現在の実装では補完時に別のプ
    ロセスを使っているので展開自体に時間がかかっているとしてもすぐにキャンセル
    される筈?

    ? 然し、本当にユーザー入力に対して即座にキャンセルするという事にして良いの
      だろうか。ある程度の interval は置くべきなのではないだろうか。と思ったが、
      実際の所、現在の実装で既にユーザー入力がある時にはすぐにキャンセルする動
      作になっていて、単にキャンセルが成る迄に待たされてしまうという動作になっ
      ているという事を考えるとこれは気にしなくて良い。

      →元から即座にキャンセルになる。ただ現状の実装ではキャンセルに時間がかかっ
      ているだけ。

    どうも TAB 補完の時には conditional-sync による実行がされていないのではない
    かという気がする。取り敢えず何処で時間がかかっているかを確認する。

    →絞り込みをかけていった所、ble/complete/source:file に於いて、生成したファ
    イルの存在確認とディレクトリかどうかの確認に時間がかかっていた。

    ? 然しそもそもこの確認は必要なのだろうか。現在の実装では nullglob を設定す
      る様にしているので存在しないファイル名が生成される事はないのではないか。
      やはり確認してみると nullglob を設定しているので改めてファイルの存在確認
      を行う必要はない筈。-e または -h で確認を行っているがこれは全ての生成され
      たファイル名に対して真であると考えられる。従ってこの処理は不要である。

      →特にファイル名の生成の時にはチェックはしない様に変更する事にした。ディ
      レクトリの場合にも予めパターンに / を含めているので、ディレクトリ以外が混
      入するとも考えられない。従って、全て使う事にする。但し、末尾の / は除去す
      る。

    然し、これまでの処理ではファイルの存在確認を全てのファイルに対して再実行し
    ていた。つまり、-d -e -h を実行していた。stat を何度も繰り返す事になるし、
    そもそもループで 200k ものファイルを回していたという事になる。なのに、手元
    の計算機ではかなり短い時間で処理できていた。bash は意外と遅くないという事な
    のだろうか。何れにしても環境によってはこれらのファイルアクセスに時間がかか
    るというのは理解できる。

    実のところこれが本当に報告された問題に関係しているのかは分からないが、少な
    くとも性能の改善はあるだろう。他にも bottleneck があるかもしれないがこれで
    良い事にした。

  * 2021-03-07 bleopt 初期化時に最初から存在する設定をチェックする? [#D1511]

    というのも ble-update や version up に従って設定名が変わるかもしれないから。
    ただ、今までに設定を破壊的に変更した事はないので余り気にしなくても良いのか
    もしれない。

    % その場でチェックをする為にはチェック用の関数が bleopt/declare の時点で存在
    % している必要がある。check 関数が定義されている時にはそれが bleopt/declare
    % よりも前になる様に書き換えていく。
    %
    % x 以下の関数は定義時にちゃんと関数群が存在しているか確かめているが、その関
    %   数群は未だ定義されていなかったりする。これらの初期化順序についてちゃんと
    %     再考する必要があるのではないか。
    %
    %   - canvas: bleopt/check:char_width_mode
    %   - util: bleopt/check:input_encoding
    %
    % 或いは値の設定に関しては ble.sh の基本的な初期化が終わった後に一括してチェッ
    % クを行う様にする? そうすると既定値を何処かに記録しておく必要があるのでは
    % ないか。

    その場でチェックする様にすると dependency injection 的に用意される設定値の
    場合に (オプションを宣言した時点では設定値が登録されておらず、後で各設定値
    が補助関数の定義などを通して登録される場合) 問題が起こる。

    結局、様々のモジュールを読み込んだ後で最後に一括してユーザによって指定され
    た値のチェックを行う事にした。既存の設定に関してチェック用関数の順序を変更する必要はない。

2021-03-09

  * README: uninstall に .cache の事が書かれていない [#D1510]
    書いた。

  * README: 0.3 に関しては release note の側に書いておくべきなのでは [#D1509]
    記入した。0.1..0.3 の情報を書いた。各 Release ページに使い方を記入した。

  * 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]
    https://github.com/akinomyoga/ble.sh/pull/65#issuecomment-791932281

    試しに complete -r して見ると発生しなくなる。

    という事は bash_completion が悪さをしているのだろうか。

    * fzf completion も勝手にロードされている。fzf completion の実装が悪いのか
      と思って fzf の completion をロードしない様にしたがそれでも問題は発生する。

    * highlight_filenme= としても特に問題は改善しない。逆に
      complete_auto_complete= として highlight_filename=1 のままの場合には特に
      問題も生じない。着色もそんなに時間をかけずに実行できている。という事を考
      えるとやはり progcomp 特有の問題である様に思われる。

    * bash の progcomp の場合には特に問題は生じていない。という事は -F で呼び出
      した関数を強制的に中断する機能があるのか、或いは -F の関数の呼び出し自体
      にはそんなに処理時間がかかっていなくて後の処理で時間がかかっているという
      事なのか。何れにしても計測が必要になる。

    実際に処理をブロックしているのは以下の関数の呼び出しの様だ。

    $ _minimal 'echo' '' 'echo'

    然し普通に呼び出してもそんなに時間がかかる事はない。

    ----

    _minimal の呼び出しに時間計測をかける。結局 _filedir の中にあるループがいけ
    ないのだという事。うーん。ble.sh の中で実行すると 20 秒も待たされるが、bash
    progcomp から呼び出すと 1.2 秒で終了する。何故だろう。

    実際に候補を bash progcomp 内で生成しているのか確認してみるとちゃんと候補は
    生成されている。

    もしかして read で変な処理をしているのが行けないという事だろうか。でもそん
    なに重い処理はしていない。うーん。オプションの処理をしているが、bash
    progcomp の時にも現在 attach しているかどうかのチェックは行っている。そんな
    に差が開く物なのか。

    実際に unset -f と read() { ble/builtin/read "$@"; } で囲んでみたら 0.6s に
    縮まった。1/60 の時間になった。

    ----

    これに対する対策はどのようにするのが良いか。

    a progcomp で compgen する時だけは unset -f read する? と思ったが、この状態
      で read -e を内部で呼び出されるなどすると変な事になってしまう。

    b decode-detach/attach するのは処理量的に好ましくない気がする。特に
      auto-complete で何度も呼び出されるのに、実際に時間がかかるかどうか分から
      ない処理のために毎回 detach/attach するのは大変。

    c 或いは _filedir 等の各関数に対して .advice around で unset -f read を行う?

    d 或いは read の中に complete_polling_cycle を仕込む。うーん。これが一番
      smart な気がしてきた…。

  * canvas: Kitty が CSI ; r に対して何もしない (reported by timjrd) [#D1503]
    https://github.com/akinomyoga/ble.sh/pull/65#issuecomment-791932281

    抑 CSI ; r にしていたのは DECSLRM CSI ; s に合わせる為であり、DECSLRM を
    CSI ; s にしていたのは、SCOSC と区別する為に引数の数に基づく heuristics を
    用いている為である。CSI r 自体については SUNSCRL と conflict が存在している
    が、SUNSCRL を実装している端末は Solaris console ぐらいしかないだろう。なの
    で、CSI r をそのまま出力しても問題ないと判断する。

    然し、引数の省略をすると動作しないというのは Kitty のバグなのではないのか。
    まあ Kitty の全体的なデザイン等について知らないので、もしかすると Kitty は
    全体的にそういう感じなのかもしれない。何れにしても Kitty の端末エミュレーショ
    ンは元より滅茶苦茶なので気にしても仕方がない。

2021-03-03

  * 2021-02-28 canvas/trace: align=right,center に対応する [#D1502]

    高さについても同様に対応しても良いのかもしれないがそれは必要になってからで
    良い。

    rps1 の各行右揃えに対応しようと思ったが問題がある。範囲計算がちゃんとできな
    いという事。rps1 が横幅一杯に広がれる様にする為には trace の計測開始点は
    x=0 でなければならない。然しこれで measure-bbox すると範囲が x=0..COLUMNS
    になって横幅一杯になってしまう。一方で、rps1 を表示する時には実際に文字が出
    力される範囲を取得したい。これはどの様にするのが良いか。

    a 描画開始点を実際に文字が出力される範囲の bbox の左上になる様にする? 然し
      それは最後まで範囲計算をしないと求められない。一番最後に、出力シーケンス
      の先頭に移動シーケンスをつけ加えれば実装できるが実装が汚くなる。特に右寄
      せしていない場合でも同様の機能を提供する等の事を考えると変である。

      更に、bbox の左上の位置というのが分かりやすいのかも不明である。何故なら呼
      び出し元は配置の結果として何処が bbox の左上になるのかという事を知らない
      からである。これは、呼び出し元で bbox の中身の配置について全く関知せずに、
      一つの blackbox として取り扱うという場合にのみ妥当である様に思われる。

    b 或いは描画開始点を右上にするという手も考えられる。右寄せの場合にはその方
      が自然に思われる。

      b1 計測の時には取り敢えず x=0 にして計測を行って、その後でユーザーが指定
        した (x,y) を起点とした描画シーケンスを構築するのである。然し、その時に
        は左に向かうシーケンス等が何処で壁に当たって止まるのかという振る舞いが
        変わってしまう。

      b2 代わりに unbounded な空間で計測をしてから再配置をするという事を考える
        と、今度は折角計測した内容が実は一行の中に収まらなかったという様な自体
        が生じる可能性もある。然し、これに関しては現在の実装でも似たような物で
        ある。しかし、少なくとも一つのフィールドの幅が行内に収まっていればOK。
        一つ一つのフィールドについて絶対範囲ではなくて幅や高さで制限をかける事
        になるが、それはまた実装が無駄に複雑になってしまう。

    c 或いは measure-bbox で文字列の範囲とカーソル移動の範囲の二種類のどちらを
      計測するか指定する事ができるようにする?

      両方の情報が欲しい場合も考えられるので、x1 x2 y1 y2 に加えて、x1c x2c y1c
      y2c 等を用意する? 少なくともカーソル移動は文字列を包摂するべきである。変
      数が増えるのも面倒なので x1[1] x2[1] y1[1] y2[1] 等の様に配列にしてその第
      二要素以降に値を格納するという考え方もある。然し、これはインターフェイス
      として分かりにくい。

      measure-bbox の振る舞いを切り替えられる様にするというのはやはり問題がある
      気がする。何れにしても両方の情報が必要になるからである。justify で配置を
      する時に出力された文字列の範囲を元にして配置を行うと、端にぶつかった時に
      座標計算がずれてしまう可能性がある。一方で、right align の大きさを調べる
      為には right を表示する必要がある。

    d 行毎に ret x1 x2 y1 y2 x y を算出する。これらの変数を全て配列にする。各行
      の bbox の左上 (x1,y1) を ret の出力開始点とする? (x1,y1) への移動に関し
      ては自前で実行する。その他の align も全て自分で処理する。

      これは微妙。これならそもそも trace に実装する必要もない様な気がする。
      (一応 sc/rc で囲んでいる部分やシーケンスを跳ばすという処理が非自明だが)
      そもそも trace に渡す前に分割して指定していれば良かったのである。

    % 調べて見た所、実は現在の実装は既に文字を出力した範囲の bbox を使う様になっ
    % ていた。という事は…。現在の実装で既に right を指定した時の範囲も表示して
    % いる物の範囲になっているという事?
    % →勘違いだった。ループの最後で記録しているが、これは制御機能によって移動
    % した後でも通過する場所に書かれている。

    表示が乱れる場合の事を考えると right の時には一旦右端に移動してから其処から
    の相対移動で描画するのが良い気がする。これは right の時の特別な取り扱い。

    * 現在の範囲追跡のコードを整理するという可能性。現在は移動を伴わないエスケー
      プシーケンスであっても記録を行う様になっている。これは無駄な気がする。

      また、全てに対して一律に範囲追跡を行っているので、文字列出力のみに対して
      計算する等の事ができない。と思ったが、結局最終的に文字列範囲とカーソル移
      動範囲の両方の情報が必要になるのであれば、文字列出力範囲に関しては独立し
      たコードで実装を行う筈で、これは気にしなくて良い。

    opts measure-gbox として出力した文字列の範囲を計算する事にした。

    * justify の時に最後に jg[xy][12] から g[xy][12] に転写する

    * main-loop の下部の ((w>0)) の処理について

      * 何故折返し処理を此処でしているのだろうか? w として有限の幅を設定する制
        御機能は限られている。調べた所、print+ と単一文字の時の二通りしか無い。
        単一文字に関しては行に収まらない場合には事前に改行を実施している。行に
        ぎりぎり収まる時の振る舞いはどうなっているか。うーん。

      * gbox は此処で処理するべきの気がする。有限幅の文字列がある時には此処に来
        るのだから。というよりこの処理自体を関数にしても良いのではないかという
        気もする。

      * そもそも此処で行っている処理は put-ascii や put-atomic で行うべきなので
        はないだろうか。

      →全て各制御機能及び print の内部で measure-bbox, gbox の処理を行う様に変
      更した。

    取り敢えず rps1 の複数行も実装して動作確認した。OKだと思う。

2021-02-28

  * 2021-02-06 render-defer.idle の優先順位を下げたい [#D1501]

    現在の実装では ble/textarea#render-defer.idle が menu-filter, auto-menu,
    auto-complete よりも先に来ているが、これは後に来るべき。特に menu-filter よ
    りも先に来ないと絞り込み状態の着色がずっと残ってしまう。

    menu-filter を render-defer.idle よりも前に挿入するべきである。どの様にすれ
    ば良いか。

    a 特定の要素の前に挿入するという操作を実装しても良いと思ったが、その為だけ
      に関数を用意するのも変である。それよりはオプションで指定できる様にする方
      が実装としては自然である。その時に挿入点よりも後に詰まって存在している要
      素はシフトする。

    b 或いは初めから各 background の優先順位を指定して登録してしまうという手も
      ある。というよりその方が自然である。どうせ決め打ちになるのでその方が柔軟
      に対応できる。

      現在 background idle (10000+) に登録される処理は以下の通り
      - ble/util/msleep/calibrate
      - ble/textarea#render-defer.idle
      - ble/complete/menu-filter.idle
      - push-background ble/complete/auto-complete.idle
      - push-background ble/complete/auto-menu.idle

    うーん。単に menu-filter を 9999 に登録すれば良い? これが単純で分かりやすい
    対応であろう。

  * 2021-01-31 complete: change bleopt complete_limit default [#D1500]

    実は今回の subshell による実行でしなくても良くなったのではないか。と思った
    が、元の報告だと別にグロブパターンと関係なく遅いという話だった気がする。と、
    思ったが補完の話だったのでやはりグロブパターンというかファイル名補完に関係
    がある。

    うーん。やはり 500 というのは上限としては小さすぎる様な気がする。
    auto-complete の 200 というのも小さすぎる様な気がする。もっと増やしても良い
    のではないかという気がする。5000 vs 2000 ぐらい。というか tab 補完に対して
    制限する必要があるのだろうか。

    ? globpat を含んでいるかのどうかの判定は実は failglob を使った方が早いかも
      しれない。現在の正規表現に基づく実装と速度を比較する価値はあるかもしれな
      い。しかし、../../.. みたいなパスが含まれている可能性等も考えると下手な事
      はできない。

  * [自然解消?] 2021-02-01 complete: slow tab completion after globstar words (reported by 3ximus) [#D1499]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-770390986

    パス名展開を compvar 構築時に全ての単語に対して実行しているのが原因かと思っ
    て#D1457 で compvar 用の timeout を導入してみたがどうも関係なかった様だ。報
    告に依ると globstar の着色が終わった後でも遅いという話だ。これはこちらの手
    元では再現しないという事が分かった。恐らく cache が働いているのだろうと思う。

    2021-02-04 新しい commit で改善したそうであるが、それでもパターンがない時よ
    りも遅いそうである。

2021-02-27

  * canvas/panel: set-height で高さ拡張時にその時の sgr0 が bce で適用されてしまう [#D1498]

    < /dev/tcp/..../80 で赤色になっている時に実行すると赤い行ができてしまう。
    これは sgr0 をせずに set-height を実行する事によって発生している事態である。
    そもそも赤い状態をそのままにして放置している事自体が変なのかもしれないが、
    取り敢えず set-height をする前に sgr0 をする必要はある気がする。

    $_ble_term_sgr0 を出力する様にしてみた。

    しかし、どうも ble/canvas/goto.draw する時にまた $_ble_term_sgr0 を出力する
    様なので、重複してしまう。問題が発生するのは、ble/canvas/goto.draw の時に既
    に目的地にいる場合で、その時は既定では sgr0 の出力も省略されてしまう。
    goto.draw の opts=sgr0 は、例え移動が起こらなくても sgr0 の出力を行うという
    物であった。→方針を変更して goto.draw に sgr0 を指定して其処で強制的に
    sgr0 を出力するという事にした。

  * エラーメッセージ "bash: ((: '0': syntax error:" (reported by rux616) [#D1497]
    https://github.com/akinomyoga/ble.sh/issues/92

    [状況]

    bash: ((: '0': syntax error: operand expected (error token is "'0'")

    * 最近発生する様になったという事。

    * 一度発生し始めると色々なキーを入力する度にメッセージが出るという事。

    * RET TAB BS 及び function keys が全滅。0-9 や numpad key も駄目。
      何故か # や & 等の記号は OK

    これは decoder が関係している気がする→2021-02の変更点を探してみたが特に怪
    しい所はない。

    * 連想配列が配列に化けてしまって発生しているという可能性もある。
      然し、連想配列の添字に quote 付きの文字列を指定する事があるだろうか。
      そもそも連想配列の添字に指定した '' が除去の対象だったかどうか怪しい。
      →試してみた所、どうやら展開の対象の様である。

    最初は発生していなくて途中から発生する様になるというのも不思議な事である。

    再現できた。というか空の blerc でも再現できた。どうも set -o vi だと発生し
    なくて set -o emacs だと発生する様だ。

    bleopt default_keymap=vi でも起きなくなる。
    bleopt default_keymap=emacs; set -o vi だと起きる。
    bleopt default_keymap=safe でも起こらない。

    うーん。emacs.sh の問題かとも思ったが最近変更した内容に関係のありそうな箇所
    は存在しない。だとすると別の場所で発生した問題が emacs.sh の中でたまたま見
    える様になっただけと考えるのが自然だろうか。

    取り敢えずなにかエラーメッセージが出ているという事はその場所を特定するとい
    うのは簡単の筈である。

    | 取り敢えず PROLOGUE と EPILOGUE の間だという事は分かった。decode byte 関
    | 連ではない。home を押しても一組しかエラーメッセージが出てきていないという
    | 事と、keymap safe, vi では発生していないという事から考えるに。だとすると
    | 残っているのは widget 実行辺りなのだが、様々な widget で発生している事か
    | ら __before_widget__ が怪しい。
    |
    | →確かに __before_widget__ だった。特に ble-edit/undo/add の中でエラーが
    | 発生している。
    |
    | % 更に ble-edit/undo/.get-current-state の内部で実行が途絶えている。と思っ
    | % たがそうでもなかった。その次の行の辺りだった。
    | %
    | % _ble_edit_undo_index に整数が入っている筈なのに history という文字列が入っ
    | % ている。と思ったら勘違いだった。_ble_edit_sttr に history という文字列が
    | % 入っているだけだった。
    |
    | やはり .get-current-state だった。調べると _ble_edit_undo_index の中に
    | '0' という文字列が設定されている。これは何処から来るのか調べる必要がある。

    分かった。配列を保存・復元する時に quote-words 的な処理で囲んだ要素を eval
    で評価するべき所が単に split-words で評価していたのが原因。最初は
    quote-words 的な処理にに書き換えたのが原因かと思ったが、逆で eval していた
    所を split-words に書き換えてしまったのが原因だった。つまり、犯人は 5f9adfe
    だった。IFS の調整として分割を全て split-words に置き換えた時に余分に書き換
    えてしまったのが原因。

    修正した。

    * ok: 他に似たような書き換えミスがなかったかどうか確認してみたが大丈夫の様
      である。

    後で改めて見てみたら修正によって破壊している。最近どうも全然駄目だ。毎回修
    正する時に新しいミスを導入にしている。改めて修正した。

2021-02-24

  * Makefile: keymap/*.txt に対する規則を削除してはいけなかった (reported by nihilismus) [#D1496]
    https://github.com/akinomyoga/ble.sh/issues/91

    f25a6e8 が悪い。22日15時過ぎに push したと思うから大体1.5日の間壊れていた事
    になる。これは良くない。修正した。動作確認もする必要がある。

2021-02-23

  * util: vbell で座標計算がずれる [#D1495]

    [状況]

    | 座標計算がずれる様になっている。ble.sh のディレクトリで空コマンドラインで
    | TAB 補完を実行しようとすると、complete_limit に達すると同時に sabbrev 候補
    | の \ が一次挿入される。この時に座標が一つ左にずれる。
    |
    | 8856a04 では問題は起こっていない。3cadd54 では問題が発生している。37363be
    | でも発生している。3cadd54 は ecb8888 に対応する。
    | 取り敢えず問題の commit は 69228fa にあると分かった。
    |
    | * bleopt edit_vbell= にすると問題は発生しなくなる。
    | * visible-bell の先頭で return して実際の処理を行わない様にすると発生しなく
    |   なる。
    |
    | 問題の commit では vbell に対する修正も色々入っている。やはりこの辺りが怪し
    | い。
    |
    | これは sc/rc による問題だろうか。然し、_ble_term_sc= _ble_term_rc= としても
    | 問題は再現している。fork の直前で return 0 すれば問題は生じない。つまり
    | .show 自体の問題というよりは出力が混ざる事による問題の様な気がする。
    | 然し buffer.flush を fork 直前に挿入しても何も効果はない。
    |
    | うーん。タイミングが丁度悪いという事なのだろう。

    あー。分かった。save-position/restore-position しているが、この時に
    _ble_canvas_{x,y} を参照している。然し、これらの値は subshell の中では更新
    されない。これが理由で座標計算がずれてしまうのである。

    [解決法]

    どの様に対策すれば良か。何が問題かと言うと…bottom-dock に対応する為に
    SC/RC を使っていて、それが visible-bell の使っている SC/RC と衝突していると
    いう事。コマンドライン上に居る時には visible-bell の為に SC/RC しても良いが、
    bottom-dock にいる時には visible-bell が SC/RC すると本来のコマンドライン上
    の位置が失われてしまって問題になる。これを防ぐ為に visible-bell では一旦コ
    マンドライン上に復帰してから visible-bell を表示する事にしている。

    どの様に解決するべきか。

    a IPCか何かを使って vbell の状態変化を親シェルに伝達して描画は親シェルで行
      う様にする? 然しどの様に伝達するのが良いだろうか。

      - シグナルは bind -x の内部ではチェックされない (もしくは bash の内部的に
        はチェックされているのかもしれないが対応する trap handler の呼び出しが
        遅延される)。然し、或いはそれでも良いのかもしれない。例えば現在
        bash-3.0 における C-d の読み取りは外部プロセスに行わせていて、C-d を検
        出したらファイルに書き込んでシグナルを送信する仕組みになっている。

      - tty に文字を挿入する事ができれば decode の枠組みに自然にイベントを組み
        入れる事ができるが、実際の所 tty に文字を外部から挿入する事はできない。
        シグナルを

      - FIFO か何かを使って通信するというのはよくある方法だが、現在の実装では
        visible-bell を実行する度に新しくプロセスを立ち上げているので、pipe を
        沢山管理しなければならないので非効率的である。

      - ファイルを使って処理をするという手が考えられる。bash-3.0 C-d でやってい
        る様にファイルに書き込んでからシグナルで通知する。然し、複数のプロセス
        が走っている場合には出力が混ざりあった時に問題が発生する。mkdir 等を使っ
        て同期するという手も考えられなくはないが益々処理が重くなってしまう。

        プロセスごとにファイルを作って処理するという手も考えられる。そして、読
        み取り用のプロセスは一つに絞る事にする。というか実は親プロセスで読み取
        りを実行すれば良いだけの気もする。ファイル書き込み中の同期に関しては、
        現在既に visible-bell でやっている様に複数の状態通知様ファイルを作って
        ファイルが空かどうかで判定する様にすれば良い。

    b そもそも別のプロセスを作る必要があるだろうか。全て親シェルで実行すれば良
      いのではないだろうか。折に触れて状態をチェックしつつ sleep して時間が来た
      ら親シェルが書き換え・消去を行う。

      然し、この方法の問題点は Bash 3.0 である。read -t 0 がないので、ユーザー
      入力が来た事の判定ができない。ユーザー入力があると想定してすぐ抜ける様に
      していると、実際にユーザー入力がなかった時に bind -x による制御が戻ってこ
      ないので、次にユーザー入力があるまで vbell の処理をする事ができなくなって
      しまう。ユーザー入力がないと想定して処理を続けると、vbell が表示されてい
      る間ユーザー入力が処理できなくなって固まった様になってしまう。

      そうするとやはり別プロセスに任せてそれをシグナルで処理するという事になる
      のだろうか。実際の所、シグナルハンドラーの中での処理は色々と怪しい事が起
      こるのでやりたくない。

      複数のサブシェルとメッセージをやり取りする様な一般的な枠組みを整えるのも
      手なのかもしれないと思う。

    c 取り敢えず今まで通り sc..rc が自由に使える前提で処理する

      今まで問題が起こっていなかったのは SC したまま放置される様な状況がなかっ
      たからである。その為いつでも SC...RC を気兼ねなく用いる事ができて親シェル
      の _ble_canvas_{x,y} の状態に依存せずに実装する事ができていた。本当の所、
      タイミングが悪ければ SC...RC が overlap して描画が乱れる可能性は 0 ではな
      いが確率的にはとても小さい筈。というのもシーケンスの書き出しは buffer に
      貯めてできるだけ atomic に行っているので。

      実は現在の所は SC/RC によって bottom-dock を実現しているとは言え、カーソ
      ルを bottom-dock に放置する様な事はしていない。なので、visible-bell の書
      き換えを行う時には常に SC..RC は閉じていると想定して良いのではないか。

    取り敢えず現在は c の方針で回避する事にする。

  * tui: trace に align/justify 機能を実装する [#D1494]

    prompt_status_line に右寄せの内容と左寄せの内容を表示するという需要はある。
    原理的にはユーザーの側で自前で実装してもらう事は可能である。然し、文字幅を
    考慮に入れる等すると実は非自明である。

    * prompt_status_line の中で適当に文字列を分割・計測したりして処理する方法も
      考えたが非効率な気がするし、エスケープシーケンスの中に justify の文字が含
      まれていたり、或いは prompt 展開の結果として justify の文字が現れる場合な
      どにも対応したいと思うとより下流で処理するべきである。

    * また、prompt_rps1 に於いても現在の実装では描画内容全体を一塊として右寄せ
      しているが、各行について右寄せをする様にしたい。

    その様に考えると trace の中で一括して実装した方が理に適っている気がする。

    * justify のデザイン

      | justify 用の文字の幅を保持するかしないかという問題が存在する。空白で
      | justify する場合にはどんなに狭くても空白一個分は開けなければならない。そ
      | うでないと英単語が互いにくっついてしまう事になる。他の制御文字等でフィー
      | ルドを区切る場合にはどうするか。うーん。その場合でも空白一個分は開けて置
      | きたい気がするが、しかし一方で | 等の様な記号を含める場合にはフィールドセ
      | パレータの分の空白があると邪魔なのではないか。
      |
      | 後、間を埋める文字についても指定できて良いのではないかという気がする。つ
      | まり、...... で埋めたり ------ で埋めたりするという事。実際に Emacs は
      | ---- で余分な部分を埋めているし、TeX の目次の様に .... で埋める様な機能が
      | あっても良い様な気がする。
      |
      | 指定方法について考える事にする。例えば、図形文字を sep に指定した場合には
      | 少なくとも 1 文字は其処にあると想定する。間を埋める場合にはその図形文字を
      | 繰り返す。制御文字を sep に指定した場合には幅が狭い時には零幅になる事を許
      | 容する。sep として複数の文字を指定できる様にし、それぞれの sep に応じて振
      | る舞いを変える。
      |
      | この方法の問題点は本文の中に fill 文字と同じ文字がある時に困るという事。
      | そう考えると fill 文字はやはり外部から指定できる様にした方が良いのではな
      | いか。でもそうすると間隔毎に異なる fill を使う事ができない。必ずしも sep
      | と fill を同じにしなくても良い。各 sep 毎に fill を指定できる様にするとい
      | うのも手である。但し、その場合にどうやって引数を指定するのかは謎である。
      |
      | というか空白の時にだけ特別扱いすれば良いだけなのでは。空白で justify する
      | のは英文の場合である。似たような文脈で空白以外で justify するという状況は
      | 考えにくい。

      仕様: 連続する同じ SEP がある時、その数はその SEP によって挿入される間隔
      の weight を表す。同じ SEP が離れて複数ある場合は、その SEP の間の文字列
      をその SEP に対応する FILL と解釈する。例えば SEP SEP -- SEP の場合はこの
      SEP の間隔の weight は 2 で fill は "--" と考える。

      最小間隔は通常 0 であるが SEP が空白の時は特別で 1 である。これは通常の英
      文の様なものを想定した特別規則である。

    実装方法について考える。やはり put-atomic, put-ascii を修正する事になる。
    clip とは相容れない。clip も処理しようと思ったら先に配置を決めておいて、
    その後で再び trace に入れて clip を実行する等という具合にする必要がある。

    clip と同様に出力する文字だけちゃんと配置できれば問題ない。
    その上で気にする必要があるのは "現在の塊" の範囲と、
    span weight である。

    うーん。measure についても justify が設定されている場合には注意が必要である。
    これも clip と同様に最初の実行では justify 用に使用して、後の実行に於いて改
    めて計算し直すのが適切である用に思われる。

    はみ出そうになった場合はどうするべきか。これは confine 等の取り扱いにも依る
    のではないかという気がするが、それらの処理は put-atomic, put-ascii の外側で
    為されている気がするので後で個別に考えれば良い。

    うーん。put-atomic 等の中では実は何も気にしなくて良い気がする。

    * reject: というか sep が図形文字の場合には、最初の各セグメントの幅計測時に
      は取り敢えず sep の幅も考慮に入れても良いのではないだろうか。うーん。やは
      り考慮に入れない方が自然の気がする。

    * done: xI yI を記録する。変数名は jxI jyI 等の方が良いのかもしれない。
      →jx0, jy0 という名前にした。

    * resolved: 現在の実装だとはみ出る場合にどうすれば良いか想定していない。という
      よりはみ出る場合に対して対策する必要はあるのだろうか。そもそも最初の点と
      最後の点だけ記録して、measure-bbox の内容は反映しなくても良いのではないか。
      その方が柔軟に設定できる様な気がする。

      →各フィールドについて初期位置と最終位置だけを元にして配置を決定する様に
      変更する事にした。

      然し、これだと右端を超えて描画されてしまう可能性が排除できない。うーん。
      その場合には適切に shift か clip を行う必要がある気がする。やはり初期位置
      と最終位置ではなくて幾何的に位置を決定する必要があるだろうか。でも、x1:x2
      が初期位置・最終位置の範囲外にはみ出ているという事は元からフィールド間で
      overlap があるという事に他ならないのだから、overlap してしまう事自体は問
      題ないのではないか。

      範囲外に収まらない時にのみ位置を shift するという処置を導入する事にする。
      →その様に修正した。

    * resolved: xenl の問題について。

      一番右端に寄った時に改行してしまう様な端末の場合、下手に一番右まで fill
      してしまうと描画が壊れてしまう。一番最後に出力した文字が右端に接触してい
      る時に改行が起こると想定しても良いかもしれないが、もし描画の途中で複数回
      右端に接触するという様な事があった場合、やはり描画が崩れてしまう。

      xenl のある端末の場合には一番右端まで領域を使ったとしても問題がないのかと
      思いきや、実は相対移動で左に移動しようとした時に結局ずれが生じてしまう。
      基本的に relative で移動している時には右端は使えないと考えるべきなのであ
      る。

      [実装] 然し、status line ではやはり右端まで使いたい。やはり一番右端に接触
      するのは、それぞれの行に於いて唯一回最後だけという想定をして良いだろうか。
      うーん。一応一番最後の位置と x2 が一致しているか確かめて、もしそうであれ
      ば一番右端に一番最後に接触したと想定する事にする。

      →そうするとやはり結局 measure-bbox は有効にする必要がある。

    x ok: ble/canvas/trace/.process-overflow に関しては justify に対して
      opt_relative を入れる事にすれば問題ない筈だが…。うーん。

      これは微妙だ。xenl cap のない端末ではそもそも最後の文字を出力しない様にし
      なければならない。というかそういう観点で言ったら実は、現在の
      opt_nooverflow の実装は駄目なのでは…。xenl のない端末で改行が発生してし
      まう。でも、opt_relative の時には OK である。

      少し xenl の取り扱いについて調整した。

    x ok: 現在の実装では !xenl の時に ble/canvas/trace で無駄な改行が入ってしま
      うのではないか。少し確認が必要である。どの様に検証するか。うーん。

      と思ったが問題の計算をしている所では opt_clip || opt_relative を仮定して
      いたので、そもそも端に接触するという事はないと考えている。なので、勝手に
      新しく改行が挿入されてしまうという心配は要らないという話だった。一方で、
      新しく導入した justify が関係して来る時には何が起こるだろうか。うーん。す
      ぐに .NEL を実行していて、更に .NEL の中では x==cols かどうかについてチェッ
      クしている訳ではないので大丈夫の筈。というか、justify の時には最初に仮想
      的な領域に書き込んでいて、右端で改行してしまう事に関しては後の再配置の時
      に処理する事になっているので気にしなくて良い。そういう意味では、後の xenl
      の処理に関しても同様。

    * done: 他に改行が必要になりそうな箇所を一つずつ探していく事にする。

      * ble/canvas/trace/.put-ascii.draw は justify の時には途中で改行する可能
        性のある動作はしない様にしてある。大丈夫の筈。

      * その他の通常文字(全角)の挿入の場合も範囲に入る時のみに文字列を出力する
        様にしてあるので勝手に改行が発生する事はない筈。

      * done: VT, CR, IND, RI でどの様に処理するのが良いかは微妙。別の行に移っ
        たと見做すのか或いは、また同じ行に戻ってきたら align するのか。というか、
        行った先でまた出力など起こす事を考えると、うーん? でも CR 以外は列番号
        は保持される。という事を考えると水平配置は途切れないと考えるのが自然な
        のではないか。

        VT/IND/RI に関しては何も処置はしない事にする。

        CR に関しては微妙である…。新しいフィールドという事にするか? 然しそれだ
        と指定もしていない sep が有効になっている感じで変である。うーん。jx0 に
        戻るというのが自然な振る舞いの気がする。

      * ok: CUU,CUD,CUF,CUB に関しては相対移動なので同じフィールド内での移動と
        解釈する事にする。

      * ok: HPA,CUP,CHA 等に関しては列番号を直接操作するので水平位置が途切れる
        様な気がする。然し、だからと言って別の行に移る訳でもないし…。これで移
        動しても同じフィールドの中にいるという事にする。

      * done: SC/RC に関してはどの様に取り扱うのが良いか。SC/RC についても
        SC/RC の内部にいる間はsep・改行も含めて特別な処理はしない様にするのが良
        い気がする。

      * done: \1..\2 による保存・復元。これに関しては field を跨いで復元される
        と微妙な感じだが…。うーん。或いは \1..\2 の内部では field の処理は無効
        化する?  それが自然な気がする。これは後で実装する事にする。

    * done: 空白文字の sep については特別扱いする。前の要素に空白文字を含めてし
      まって良い→と思ったがそれだと行折返しが発生した時に行末に余分な単語が含
      まれてしまう。

      ここは単に右に一文字ずらす事で span を最低限保つという方式にした。

      然し、この時の問題点は、他の種類の sep と混合していた時に、必ずしも空白に
      対応する sep に確保した span が割り当てられるとは限らない事。うーん。各
      span に対して "最低限これだけの幅は確保する" という制御は必要になるだろう。
      最初の計測の時点でその情報を参照するのだから、その情報も sep の記録に一緒
      に記録することにするのが良い気がして来た→その様に書き換えた。

    * ok: opt_relative を imply する。opt_measure も imply する。これらは判定を
      flags を用いて行う様にしたい。

      →これらは適当に実装した。

      1 現在の実装では opts=relative -> R, opts=measure-bbox -> M, opts=justify
        -> J を割り当てた。
      2 更に、char flags だと算術式の中で使えないので、別に変数 opt_relative (R),
        opt_measure (M or J) を用意した。
      3 他に、xenl についても opt_relative の時には自動的に imply する様にした。

    * done: $trace_flags == *M* が設定されている時に、範囲を改めて計算する。
      →実装した。

      特に center align している時に範囲を正確に抽出できているか確認する。でき
      ている。OK

    * done: test: フィールドの x1:x2 が範囲外にはみ出る時に正しくシフトできてい
      るか。

      →うーん。右端に一文字余裕を残した実装になっている。これは意図的な物だっ
      たか。確認する。うーん。xlimit が 29 になっている

      % →と思ったらこれは意図的な物だった。範囲を右端にはみ出ているので xenl
      % のない環境では xlimit を一文字減少させている。

      しかしよく考えたら、シフトを実装した今この取り扱いは不要な気がする。つま
      り、xenl のある端末では別に一番右端まで行っても良い。シフトがあるので右端
      を超えてしまう事はない。一方で、xenl のない端末の場合には常に駄目。

    * ok: 行末で begin-line してその後に改行が入るとどうなるのか。
      即座に end-line して空で終われば良し。そうでなければ対策が必要。

      →うーん。その様な状況があるのだろうか。元々何故このような事を考えたのか
      思い出せない。要するに $'\nhello' 等の様になっている時にどうなるかという事?
      この時は空の文字列が作られて終わるだけの気がする気にしなくて良い。

      と思ったが、現在の実装だと空の行に対しても無駄に処理をしている。この辺り
      は最適化の余地がある。取り敢えず justify_fields と DRAW_BUFF の中身を確認
      して空ならそのまま戻る様にした。

    * done: clip している時にも対応する。これの対応はどの様にするべきか。

      a 内部で再帰的に trace を呼び出して二回処理を行う。この時 opts を構築する
        のが面倒そうである。

      b trace の中身の中心部分を別の関数に分けてそれを二回呼び出す様にする。

      思うに殆どの opts は一回描画内容を決定したら継承しなくて良い気がする。
      寧ろ clip 処理は clip だけに徹するべきの気がする。という観点から考えると、
      方針 a に従って後で clip 用に trace を一回実行するのが良い気がする。

    * reject: 改行をしても別のフィールドには移らないオプション? 同じフィールド内で改行
      を行う。その時には xI:y+1 に戻る。

      また、フィールド内での CR はそのフィールドの開始位置に戻るべきでは。と思っ
      たが元からそういう実装になっていた。

      うーん。そういう事をしたければ \r\v 等とすれば良いのではないか。実際それ
      で動く筈。

    x justify:confine が変な動きをしている。一方で justify:truncate は動いている。
      →これは confine の側のバグだった。修正した。

    * done: 空白の時は空白で fill する。

    [追加修正]

    x \r が含まれている時に振る舞いが変である。→これは \r でフィールドの先頭に
      移動した時に追跡座標 x を正しく設定していなかったのが原因だった。修正した。

    o \v の動作については確認した。恐らく大丈夫。IND/RI も試していない
      が大丈夫だろう。

  * 2021-02-06 tui: trace に clip 機能を実装する [#D1493]
    Ref #T0007

    Note: これは元々 tui 計画の一部として実装した物だったが prompt_status_line
    や prompt_rps1 の為の align 実装に使う為に、trace を大幅に拡張したいという
    事で、独立な commit として適用する事にした。

2021-02-22

  * prompt: status line が最初の起動時に表示されていない [#D1492]

    | 何故だろうか。。。うーん。プロンプトが初期化される前だから? でもプロンプト
    | が初期化されたら…うーん?
    |
    | screen の中だと遅れて statusline が表示されるが、contra の中にいると次に何
    | か新しく表示されるまで何も表示されない。そもそもこの違いは何処から来るのだ
    | ろうか。screen の場合には誰かが invalidate しないと再描画がなされない筈なの
    | である。
    |
    | * screen で何故再描画が実施されるのか。調べてみると何らかのデータを受信した
    |   折に screen の中での再描画が走っている。
    |
    |   DA2R を受信した時に再描画が走っているのだろうと思ったがそうでもない様だ。
    |   contra でも DA2R は受信している。また、DA2R を受信してから一拍置いてから
    |   再描画が走っている様に見える。
    |
    |   もう少し詳しく受信しているバイト列を確認する事にする。
    |
    |   % うーん。分かった気がする。screen が CPR に応答した時に char_width_mode
    |   % が変わって invalidate が起こっているのではないかという気がする。contra
    |   % については CPR に応答していないが為に char_width_mode による invalidate
    |   % が起こっていない、という事なのだろう。
    |   %
    |   % →と思ったがやはり CPR ではない様である。先ず contra は一切 CPR に返事を
    |   % しないのは予想通り。一方で、screen はそもそも char_width_mode についての
    |   % CPR 要求はしていない。何故なら char_width_mode に emacs を指定しているか
    |   % ら自動判定にはなっていないのである。代わりに DECSTBM の判定に使っている
    |   % CPR を受信している。然し、その受信した CPR を完全に無視する様に書き換えて
    |   % もやはり再描画は発生しているのである。
    |
    |   再描画が起こっている理由について調べる。$caret_state が変化している事によ
    |   る再描画の様子である。
    |
    |   ? yes: というより本当にこの dirty の判定の所まで到達しているのだろうか。
    |     もっと前の段階て撥ねられていないだろうか。と思ったが、大丈夫の様だ。こ
    |     の判定の部分までは到達している。
    |
    |   caret_state の値について出力して確認してみる。
    |
    |     contra 内部       screen 内部
    |     ----------------  ------------------
    |     old=0:0:0:::      old=0:0:0:::
    |     new=0:0:0:::      new=0:0:0:::
    |     dirty:2           dirty:2
    |     old=0:0:0:::      old=0:0:0:::
    |     new=0:0:0:::      new=0:0:0:::
    |     dirty:clean       dirty:clean
    |     old=0:0:0:::
    |     new=1:0:0:::
    |     dirty:3
    |     chars=(DA2R...)   chars=(DA2R CPR)
    |                       CPR ble/term/t
    |     old=1:0:0:::      old=0:0:0:::
    |     new=1:0:0:::      new=0:0:0:::
    |     dirty:clean       dirty:clean
    |     old=1:0:0:::      old=0:0:0:::
    |     new=1:0:0:::      new=1:0:0:::
    |     dirty:clean       dirty:3
    |
    |   起動の振る舞いを見ると contra の場合には、CPR DA2R の応答を貰うよりも前に
    |   再描画の機会がある様だ。うーん。
    |
    |   ? 不思議な事に keymap_vi_load の実行は比較的最初に済んでいるという事であ
    |     る。もう一つの不思議な事は contra の内部でも dirty:3 が発生しているのに
    |     も拘らず prompt update が実行されていないという点。prompt の update の
    |     条件についても確認するべき気がする。
    |
    |     どうやらプロンプトが更新されたりされなかったりするのは history を読み込
    |     んだり読み込まなかったりする事による物のようである。何故端末が異なると
    |     history の読み込みに影響が出るのかは謎である。しかも、確率的にではなく
    |     て確実にそれぞれの端末で異なる一貫した動作になっているのも不思議な事で
    |     ある。

    [状況]

    最初に描画する瞬間は未だ keymap も読み込んでいない状態なので keymap_vi_load
    を経由して設定される prompt_status_line も表示されない。その後で
    keymap_vi_load が実行され、更にその後で再描画がかかる。

    違いは再描画がかかるタイミングが contra の中と screen の中で何故か異なる事
    によって出てくる様に見える。

    * keymap_vi_load との前後関係は実は関係ない。再描画がかかるのは何れにしても
      既に prompt_status_line が初期化された後の話なので、もしプロンプトの更新
      がかかるのであればどちらの場合でもちゃんとステータスラインが表示される筈
      である。

    * 代わりにコマンド履歴の読み込みのタイミングとの前後関係が問題になっている。
      screen の中では DA2R, CPR を受信した後に再描画が起こるが、この段階でコマ
      ンド履歴が読み込み済み状態になっている。これにより再描画に際してプロンプ
      トの再計算が実施される。一方で contra の場合には DA2R を受信する前に再描
      画がかかって、この時には未だコマンド履歴が読み込まれていない。この為に、
      プロンプトの更新の必要がないと判定されてプロンプトの更新無しで再描画だけ
      が行われている。

    何れにしても設計としてはプロンプトの設定を変更したら ble/prompt/clear を実
    行するべきで、更に、ble/prompt/clear を実行する時には
    ble/textarea#invalidate も実行するべきという事。

  * global: IFS 対策 [#D1491]

    多くの関数は IFS が普通の値になっているという事を前提にして書かれている。
    ble.sh の中では一時的に IFS を設定して動作する様になっているが、
    ユーザーから使用された時に IFS に変な値が設定されている可能性は排除でいない。

    * 引数を $* で渡された時の対策は取り敢えず grc -F で ${* もしくは $* に一致させて確認した。
    * 配列に対する単語分割 =($...) に関してもチェックは行った。

    * 他に配列を結合する処理に関しても注意が必要になる可能性がある。
      つまり、aa="${arr[*]}" の形の処理である。

      grc '\$\{[[:alnum:]_]+\[\*\]' --exclude={test,ext,wiki}

      取り敢えずこれも大体対応した。

    * builtin read も IFS に依存して振る舞いが変わる。

    他にも IFS が影響を与える様な状況はあるだろうか。恐らく他にもあると思うが、
    すぐには思い浮かばないので取り敢えずこれぐらいで良いだろう。

  * global: 現在様々な関数が引数として text... を受け取っているが [#D1490]

    実の所複数の引数を受け取る事に意味は余りない。
    実際に複数の引数をこれらの関数に渡している箇所があるとは思えない。
    現在は毎回 IFS を設定してこれらの引数を結合する様にしているが、
    そもそもその様な処理すら必要ないのではないか。

    * done: (main) ble/util/put
    * done: (main) ble/util/print
    * done: (util) ble/string#escape-*
    * done: (util) ble/string#{toggle-case,toupper,tolower}
    * done: (util) ble/string#[lr]?trim
    * done: (util) ble/string#capitalize
    * done: (util) ble/util/buffer
    * done: (util) ble/string#split-lines
    * done: (util) ble/util/idle.push
    * done: (vi) ble/keymap:vi/string#encode-rot13
    * done: (complete) ble/complete/cand/yield
    * done: (canvas) ble/canvas/put.draw
    * done: (edit) ble-edit/hist_expanded.update
    * done: (edit) ble/widget/(in|ex)ternal-command
    * done: (edit) ble/widget/execute-command

  * global: ロード時にエラーが出る (reported by 0neGal) [#D1489]
    https://github.com/akinomyoga/ble.sh/issues/85

    bash: ((: 4 0: syntax error in expression (error token is "0")

    うーん。 "4 0" という文字列が何処から混入するのかという事。
    "4 0" という文字列があるという事は何処かにそういう変数が存在しているという事?
    と思って declare -p の結果を grep で検索して 4 0 の組み合わせを探そうとしたが見つからない。
    配列に、要素を跨ってその様な値が格納されているのかとも思ったが、そうでもない。

    だとするとグローバル変数ではなくて内部で一時的に生成された文字列に問題が起きているという事?

    ((${#aaa[*]})) となるべき所を ((${aaa[*]})) にしてしまっているというのが怪しい。
    と思ったが m scan で引っ掛からない。
    sub:scan/array-count-in-arithmetic-expression でちゃんとチェックしている。

    3588158 で発生している。前に動いていた時はいつの version かと思ったが、
    どうも 0.3.3 を動かしていた様なので実は 0.4 でも前からずっと問題があった可能性もある。

    うーん。エラーメッセージから察するに "4 0" が完全な算術式として評価されよう
    としているという事。これにより ((...)) の形のコマンドで発生しているとすると
    かなり発生箇所を制限する事ができる。

    | ./lib/core-complete.sh:2847:      ((${simple_ibrace%:*})) && comps_fixed=1
    | ./lib/core-complete.sh:3282:      if ((${simple_ibrace%:*})); then
    | ./lib/core-complete.sh:3293:      if ((${simple_ibrace%:*})); then
    |
    |   simple_ibrance に値を設定している箇所は限られている。そしてその何れの場所
    |   でも確実に 数字:数字 の形になっているので、変な事が起こる余地はない。
    |
    | ./src/canvas.sh:1725:    (($3)) && ((x=0,y++))
    |
    |   ble/textmap#hit/.getxy.cur の第三引数…ではなかった。ここでは textmap 配
    |   列に含まれる単語を分割している。もしかして IFS に変な値を設定されていると
    |   いう事? と思ったがその影響が残っているのだとしたらもっと色々な大変な事が
    |   起こってしまう筈。そして実際に IFS= にして起動してみたが特にエラーメッセー
    |   ジは出ていない。
    |
    |   もう一つここが違いそうな理由は、報告によると起動時のみに問題が起こるとい
    |   う事であった。然し、もしここが本当に問題になるのだとしたらそれ以降もずっ
    |   と危ない感じになる気がする。
    |
    |   何れにしてもこの部分はもっとまともな実装に置き換えて良い気がする。
    |
    | ./src/color.sh:955:    (($name)) && return 0
    |
    |   name=_ble_faces__$1 としているので此処からは '4 0' という値は出てこない。
    |
    | ./src/util.sh:3244:    (($2))
    |
    |   これは ble/util/test-rl-variable の第二引数である。使用箇所を確認したが第
    |   2引数はそもそも指定していないか指定していたとしても 1 か 0 である。なので、
    |   これも違うだろう。

    然し、変数に alpha='4 0' 等の値が入っていてそれを ((alpha)) 等として実行し
    た場合にも同じエラーメッセージが発生するので本当にこの部分で発生しているの
    かというのは分からない。一方で $(()) の中で実行した場合にはエラーメッセージ
    が異なる物になるので、やはり (()) の中で発生しているというのは確定して良い。

    もしかすると bashrc の内部で ble-attach すると問題が発生する可能性?

    できた。再現できた。IFS= を ble-attach の直前に記入すると問題が生じる。

    どうやらコメントに依ると unset IFS にしている様である。という事は…。ble.sh
    をロードした時に unset 状態の IFS を保存して復元する時に空文字列になってし
    まうのが問題の原因になっている。

    * done: IFS の unset 状態も復元する様にする。復元する様にした。

    更にその後で空文字列の IFS が問題を引き起こしている。掘り下げていくと
    textarea#redraw の中で問題が発生している。

    * done: 空の IFS でも単語分割ができる様に個々の関数を書き換える。

      * 結局 ble/textmap#getxy.cur の問題だった。先に上で修正したと思っていたが
        修正漏れがあった。これで動く様になった。

      * 他にも IFS=$' \t\n' でないと動かない様なコードはないだろうかと調べると
        ble/canvas/trace の sc/rc がそれだった。修正した。

      * 他にも ble/textmap#update の中でも単語分割を使っている様子だったが、こ
        れは関数の先頭で IFS を設定しているので問題にならない。
        ble/string#split-words で書き換えようと思ったが performance の問題だろ
        う。そのままにしておく事にした。

      * 他のファイルも探したら沢山あったのでこの際全て修正する事にした。他にも
        IFS の値で振る舞いが変化する物は沢山あるのでこれだけで local IFS=$'
        \t\n' しなくてよくなったりはしないが、念の為変な動作を起こさない様にし
        ておく。

    x fixed: 全部直した筈だと思ったが ble-bind がエラーを出力している。
      →"$*" の類も全て IFS を気にする必要がある。取り敢えず util.sh の関数については
      IFS の値に拘らず動作する様に修正した。

  * keymap/vi: vim mode strings の設定をもっと柔軟にできる様にする (motivated by 0neGal) [#D1488]
    https://github.com/akinomyoga/ble.sh/issues/85

    Note: 0neGuyDev は名前が 0neGal に変化した様だ。

    * done: wiki vim のページ hook の説明で := の : が余分。
    * done: wiki vim の設定のページで全ての項目に注意書きを書く。

    何れにしても Cygwin での IL/DL の問題 (#D1482) に取り敢えずの決着をつけてから。
    →IL/DL の問題を解決したが未だ status line の問題 (#D1487) は残っていた。
    その後 status line の問題も解決した。

    どうやら Vim では mode() を用いて現在のモードを表現する文字列を取得する事が
    できるらしい。然し、mode() だけでは表しきれない情報も存在する様である。取り
    敢えず似た関数を用意さえすれば既存の枠組みを使って mode を status ilne に表
    示する事ができるのではないか。

    | Mode                                                                                          | `mode()` |
    |:----------------------------------------------------------------------------------------------|:---------|
    | INSERT                                                                                        | i        |
    | REPLACE<br/>VREPLACE                                                                          | R        |
    | NORMAL<br/>(insert)<br/>(replace)<br/>(vreplace)                                              | n        |
    | VISUAL<br/>(insert) VISUAL<br/>(replace) VISUAL<br/>(vreplace) VISUAL                         | v        |
    | VISUAL LINE<br/>(insert) VISUAL LINE<br/>(replace) VISUAL LINE<br/>(vreplace) VISUAL LINE     | V        |
    | VISUAL BLOCK<br/>(insert) VISUAL BLOCK<br/>(replace) VISUAL BLOCK<br/>(vreplace) VISUAL BLOCK | ^V       |
    | SELECT<br/>(insert) SELECT<br/>(replace) SELECT<br/>(vreplace) SELECT                         | s        |
    | SELECT LINE<br/>(insert) SELECT LINE<br/>(replace) SELECT LINE<br/>(vreplace) SELECT LINE     | S        |
    | SELECT BLOCK<br/>(insert) SELECT BLOCK<br/>(replace) SELECT BLOCK<br/>(vreplace) SELECT BLOCK | ^S       |

    これらは基本的にはそのモードに入る為に使うコマンドが使われる。
    然し、normal の n や select の s は名前から来ている。

    これに倣えば。拡張するとしたら VREPLACE は gR になるだろうか。
    insert, replace, vreplace は それぞれ i^O R^O gR^O になる。
    でもどうせ組み合わせるのであれば、実の所 ^O は必要ないのではないか。

    つまり、/(i|R|gR)?(n|v|V|^V|s|S|^S)?/ - ε (4x8-1=32-1=31種) という事になる。

    うーん。サンプルを見ると Rv というのが存在しているが実際に試してみると R に
    なっている。何故だろうか。後、やはり gR というのは都合が悪い気がする。
    vreplace の文字はまた別に考えたい。小文字の r を考えたがどうやら既に PROMPT
    というのの為に使われている様だ。だとすると ^R という事になるだろうか。うー
    ん。取り敢えず ^R という事にする。そもそも制御文字を使うとうのが良い事なの
    か微妙だが。RSTUV で何れも近い値というのも比較的良い事の気がする。

    * テストに用いた vimrc を移動する。

  * edit: prompt_status_line の表示が崩れる [#D1487]

    | prompt_status_line を試しに組み合わせて見たら表示がおかしくなっている。うー
    | ん。status の報告する文字列の高さが間違っているのが原因かとも思ったがそうで
    | もない。常に高さ1を強制する様に書き換えてみたがそれでも同じ問題が発生してい
    | る為である。
    |
    | という事はスペースを確保する時のコードが間違っているという事だろうか。これ
    | は丁度 stub branch で議論している物と関係する。というより stub branch の方
    | で何か修正を入れた気がする。その修正を適用してからこの問題が未だ継続してい
    | るか調べてその上で対処するべきだろう。
    |
    | →どうやら問題は継続している様だ。何故だろうか。なぜか知らないが高さを確保
    | できていないのが原因である。

    [再現]

    prompt_status_line を表示してかつ keymap_vi_mode_show= を使って vim mode
    string を表示しない設定にすると、一番下の行でコマンド実行した後に status
    line が消去されずに複製されて残ってしまう。

    振る舞いを調べると高さの確保は一応している様子である。毎回 1->2 に増やして
    いる。コマンドを実行した直後には高さ 1 という事になっている為であろう。然し、
    問題点が幾つかある

    * コマンド実行中にはステータス行は消去する筈なのに消去されていない。うーん。
      実装によるとコマンドを実行する前に ble/prompt/status#collapse を呼び出す
      事になっている。そして其処では set-height を用いてステータス行を消去する
      事になっている。然し消去できていない。

      調べてみるとそもそも status#collapse が呼び出されていない?? いや、これは
      呼び出されている。という事は set-height の途中で消えているという事であり、
      それはつまり元から高さが 0 だったという事。高さが増える事なく status line
      が表示されていたという事である。

    うーん。何かと思ったら reallocate-height.draw が呼び出されていない。現在の
    実装では他のパネルの高さが不整合になっていない限り reallocate-height.draw
    は呼び出されないのである。うーん。取り敢えず status#panel::render の中で
    reallocate-height.draw を試みるべきだろうか。

    status#panel::render の中で現在の高さを確認して足りなければ再配置を要求する
    様に変更した。これで OK の筈。これによって textarea の方に皺寄せが行く可能
    性もあるが、取り敢えずはこれで良い事にする。また後で reallocate-height につ
    いては考え直すのが良い→別項目を立てた。

  * decode: rlfunc.txt ファイルを移動する [#D1486]

    * .srcoption の中身も更新した。
    * GNUmakefile も書き換えた。
    * decode.sh も書き換えた。
    * 他に make_command.sh と vi.sh の中で言及していたファイル名を書き換えた。
    * 序でに散らばっていたテスト用のファイルをリポジトリに追加しておく。

  * term: screen で attach した時に時々 _ble_term_* が壊れる現象 [#D1485]

    screen で attach すると何故か色々壊れる現象があったが、どうも contra からの
    DA2R がそのまま screen の内部の shell に伝播しているという事の気がする。
    DA2R を受信した時に最初に受信した時の値を保持する様にするべきではないか。
    もしくは一旦受信したら blehook で削除しておく。

2021-02-21

  * decode (rlfunc): vi-replace in imap, vi-editing-mode in nmap (reported by onelittlehope) [#D1484]

    それから vi-replace in imap 及び vi-editing-mode in nmap は未実装である。

    * vi-editin-mode in nmap: 先ずは vi-editing-mode を vi-command で使うと何が
      起こるのかについて確認する。→どうやら vi_nmap を抜けて imap に戻る様であ
      る。うーん。これは単に vi_nmap/insert-mode にすれば良い気がする。

    * vi-replace はどうやら replace-mode に入る為のコマンドの様だ。そしてこれは
      insert と同じで良いのではないか?? と思ったがうーん。vi-command では "R"
      に割り当てられている。つまり、文字幅に応じた replace-mode に入るべきであ
      る。

      | vi_imap でも同等の replace-mode に入るための widget を追加するべきだろう
      | か。と思って、vi_imap/normal-mode-without-insert-leave &
      | vi_nmap/replace-mode を組み合わせて新しい widget を作りかけていたら、どう
      | やら既に存在していた様だ。vi_imap/overwrite-mode である。というより、既定
      | の insert がこれになっていた。
      |
      | なので作りかけた以下の関数は廃止。
      |
      | function ble/widget/vi_imap/replace-mode {
      |   ble-edit/content/clear-arg
      |   _ble_edit_mark_active=
      |   _ble_edit_overwrite_mode=R
      |   _ble_keymap_vi_insert_overwrite=R
      |   ble/keymap:vi/update-mode-name
      | }

      所で、既存の vi_imap/overwrite-mode は ble-edit/content/clear-arg がない
      が良いのだろうか。と思ったが、よく考えたら vi_imap では引数を指定する方法
      が存在しない。という事を考えたら別になくても良いという事なのだろうか。ま
      あ、ble-edit/content/clear-arg して困る事はない。もしかすると誰かが
      vi_imap でも arg を設定できる様に binding を追加するかもしれない。

    結局二つとも既存の widget を辞書に登録するだけで済ませる事にした。

  * decode (rlfunc): 既存の束縛の読み取り時にエラー (reported by onelittlehope) [#D1483]
    https://github.com/akinomyoga/ble.sh/issues/89

    二種類の問題がある。

    * 一つは LC_CTYPE であろう。現在のエンコーディングに一致しないバイト列が文
      字列に含まれている場合、bash の正規表現は一致に失敗する。もしくは何か変な
      一致の仕方をする。

      $ alpha=$'"\x9B": self-insert'
      $ rex='^"[^"]*$'
      $ [[ $alpha =~ $rex ]]

      然し実際に試してみたがそんな事は起こっていない。susu-linux の regcmop は
      振る舞いが違うという事なのだろうか。これについては no closing ... という
      メッセージを出している部分をもう少し詳しく見る必要がある。

    * もう一つは vi_imap/vi_nmap で vi-replace/vi-editing-mode に対応していない
      という事。これは単に対応していないというだけの事なのでできるだけ対応する
      様にする。

      然し、以下は期待通りに動いている。

      rex='^"([^\"]|\\.)*$'
      [[ $'"\x9B": self-insert' =~ $rex ]]; echo $?

      できた。再現できた。

      bind '"\x9b1;2H": beginning-of-line'
      source ble.sh

      更に良くメッセージを見ると正規表現でテストを実行する前に既に文字列が削れ
      て '"' だけになっている。

      →これについては修正した。

    https://github.com/akinomyoga/ble.sh/issues/89#issuecomment-782824259
    追記: 簡単なミスをしていた。修正する。

    https://github.com/akinomyoga/ble.sh/issues/89#issuecomment-782827987
    追記: まだ駄目だった。何度でも同じミスをしている…。ちゃんと実際にテストしなければならない。

2021-02-20

  * term: Cygwin console で最終行で IL/DL すると画面消去されるバグ [#D1482]

    Solaris に加えて Cygwin console も何だか変な振る舞いをしている。
    どうも一番下の行で .insert-newline をすると画面の内容が全て消える。
    分かった。どうやら一番下の行で IL すると問答無用で画面クリアされる。
    これは明らかにバグである。Cygwin をアップデートしてみる事にする。

    →cygwin を update して見たが修正されていない。なので、結局 ble.sh の側で対
    策をしなければならない。この様な壊れた IL に対して対策を実行する事は可能な
    のだろうか。

    * 取り敢えず現在位置が分かっていれば対応は可能である様に思われる。一番下の行
      にいる時には IL の代わりに CSI 2K を実行すれば良い。それ以外の行にいる時に
      は特に問題は起こらない様だ。

      うーん。最下部にいるかどうかで振る舞いを変えるのは難しい気がする。取り敢
      えず複数行の IL, DL の時にはちゃんと計算ができていれば最下行になる事はな
      い。問題は単一行の IL 及び DL で以下に最下行での IL/DL を避けるかという事。

      最下行にいない時には以降の内容を下に一行ずらす役割がある。うーん。それよ
      り下に内容があると分かっている場合には IL/DL を実行し、それより下に内容が
      ないという場合には DL を実行するというのが可能な対策方法である。

      うーん。かなり面倒臭い。というより CYGWIN の側で修正してもらえばこの様な
      面倒な事はしなくても良い筈なのである。取り敢えずこの workaround の為に本
      体の描画アルゴリズムを変更する事はしない事にする。

      IL/DL の中だけで対策可能であればそれを実施する。そうでなければ何もしない。

      例えば IND CUU を実行して一番下の行にダミー行を挿入して、その上で DL/IL
      を実行してから、RI かスクロールを実行してまた元に戻すという実装は可能だろ
      うか。→ SD,SU を実行してみたが消えてしまった行は戻ってこない様である。RI
      も同様に一度消えた内容が戻って来る物ではない。うーん。現在最下行にいるか
      どうかを判定して動作を切り替えるしかないのか。

    | a 結局 DSR(6) で現在位置を問い合わせて一番下の行にいる時には CSI 2K で行
    |   消去する事にした。
    |
    | x これで以前よりも全画面消去が起こる場面は減ったが、それでもやはり全画面消
    |   去が依然として発生している。何故だろうか。IL/DL を実行している箇所は既に
    |   全て抑えてある。とすれば IL/DL とは別に未だ全画面消去を引き起こす物が存在
    |   しているという事。
    |
    |   問題が発生している場所での出力内容を確認すると
    |
    |   ^[(B^[[m^[[1B^M^[[2K^[[1M^[(B^[[m^[[1A^[[31C^[(B^[[m
    |
    |   printf '\e(B\e[m\e[1B\r\e[2K\e[1M\e(B\e[m\e[1A\e[31C\e(B\e[m'
    |
    |   うーん。全消去が起きそうな気配は何処にもない気がする。と思ったが、よく見
    |   たら DL(1) が含まれている。これは一体何処から現れたのだろう…。あー。分かっ
    |   た。。DSR(6) で問い合わせする前に flush しないと駄目だ。
    |
    |   そして各スタックにある DRAW_BUFF にアクセスして出力予定の内容を全て集めて
    |   flush しなければならない。然し、DRAW_BUFF の中には取り敢えず内容を構築し
    |   て保存する為の物だったり、後で再解釈する為の物だったりする可能性もあり、
    |   一律に出力して良い内容7日どうかも分からない。という事を考えると put-il,
    |   put-dl の中で現在位置を検出して出力するという対策は全然駄目である。
    |
    |   | if ((_ble_bash>=40000)) && [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $TERM == xterm-256color ]]; then
    |   |   # Cygwin console (pcon) では最終行で IL/DL すると画面全体がクリアされる。
    |   |   function ble/canvas/.put-il.workaround {
    |   |     local count=$1
    |   |     ((count==1)) || return 1
    |   |
    |   |     # Cygwin console 以外なら対策不要
    |   |     [[ ! $_ble_term_DA2R ]] || return 1
    |   |
    |   |     # 現在のカーソル位置の取得
    |   |     local reply=
    |   |     printf '\e[6n' >/dev/tty
    |   |     IFS= read -r -d R -t 0.1 reply </dev/tty
    |   |     local rex='([0-9]*);([0-9]*)'
    |   |     [[ $reply =~ $rex ]] || return 1
    |   |     local l=$((10#${BASH_REMATCH[1]}))
    |   |     local c=$((10#${BASH_REMATCH[2]}))
    |   |
    |   |     ((l==LINES)) || return 1
    |   |
    |   |     DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2
    |   |     return 0
    |   |   }
    |   |   function ble/canvas/put-il.draw {
    |   |     local value=${1-1}
    |   |     ((value>0)) || return 0
    |   |     ble/canvas/.put-il.workaround "$value" && return 0
    |   |     DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_il//'%d'/$value}
    |   |     DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
    |   |   }
    |   |   function ble/canvas/put-dl.draw {
    |   |     local value=${1-1}
    |   |     ((value>0)) || return 0
    |   |     ble/canvas/.put-il.workaround "$value" && return 0
    |   |     DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux
    |   |     DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value}
    |   |   }
    |   | fi
    |
    | b 別の手段を考える。一番上の行を犠牲にする事になるが SU/SD を組み合わせる。
    |
    |   DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[S\e[A\e[M\e[B\e[T'
    |
    |   うーん。一応動いている様な気がするが、この対策法の問題点は DA2 を返さない
    |   端末で SU/SD に対応してない物があると描画がずれてしまうという事である。
    |
    |   あとちらつきが激しく出ているという事。やはり対策を実施するのは最
    |   低限にしたい。
    |
    | c また別の手法。一番下の行は諦めて DL/IL をする前に必ず IND/CUU を実行して
    |   一番下の行は使わない様にするという作戦。これは実際に試してみた所レイアウ
    |   ト崩れるので使えない。

    改めてそれぞれの方法の問題点について整理する

    a DSR(6) で問い合わせて判定する方法。

      o この方法は出力をキャッシュしていなければ確実に最終行を判定できる。

      x 然し実際にはカーソル移動なども含めて出力内容を複雑にキャッシュしている
        ので、その場で現在位置を取得したとしても全く意味がない。キャッシュを
        flush するにしても、それぞれのキャッシュがその場で画面に出力する事を想
        定した物でない場合もあり困難。

    b SU/SD の組み合わせを用いる。

      x 一番上の行の内容が犠牲になる。
      x 画面がちらつく。

        o これについては panel 内部で動作している限りは panel の最終行にいる時
          にだけ対策をする。これでちらつきはある程度抑える事ができる。それでも、
          panel の最終行にいる時にはちらつきが出るが、そもそも本当に最終行にい
          る時のちらつきは抑える事ができないので、我慢する。

      x Cygwin console であると誤判定した時に、その端末が SD/SU に対応していな
        いと悲惨な事になる。

    c 一番下の行は常に空になる様にしておく。

      x 使える領域が一行減ってしまう。
      x 今までの座標計算が狂ってしまうので注意深く全体を書き直す必要がある。

    d panel で一番下の行にいると分かっている時は単に EL(2) で良い。

      panel で一番下の行にいるという事が分かっている場合には、IL を一番下の行
      で実行する代わりに単に端末の最上部で DL をすれば良いのではないだろうか。
      と思ったが全然違う結果になるので駄目だ。

      或いは panel で一番下の行にいるという事が分かっているのであれば何処か別
      の行で IL/DL すれば良いのではないか。と思ったが、それだと端末最終行にい
      なかった時にずれるべき内容がずれずに残るのではないか。と思ったが、そも
      そも panel 外の内容に関しては関知しなくて良い。

      整理すると panel で一番下の行にいる時、panel の最上部で IL/DL を実行す
      る。その上で panel の最下部で EL(2) を実行すれば良い。うーん。実は最下
      部で EL(2) を実行するだけで良い気がしてきた。

    結局 b に d を組み合わせて実装した。どうも既存の IL/DL は全て panel 管理下
    にある様だ。という事なので実は実質的に d だけでうまく行くという事。

    x fixed: と思ったがどうも SU/SD の対策がコマンドを実行する度に発動している
      様子だ。と思ったがこれは単純ミスだった。opts=$2 を忘れて opts を使ってい
      た。

    ? IND を \n にして見たが微妙かもしれない。端末によっては現在の x の位置をずらしてしまうから。
      然し、現在の設計では ind によって位置がずれてしまう事も想定しているのではなかったか。

      と思ったが IND に対応していない物も沢山ある様だ。なのでやはり \n に頼るべきなのだろう。

      IND を使っている箇所について改めて確認する必要がある。ちゃんと x=0 にしているか?

      →どうも _ble_term_ind の使用は canvas.sh の中で閉じている様子である。
      put-ind.draw も内部でしか使われていない。殆どの箇所で既に対策済みか或いは
      元から column 0 にいる状態で使っている。

      問題に成るのは ble/canvas/put-move-y.draw の内部での使用で、mc の中で動作
      している時には CUU の代わりに IND を使っている。put-move.draw が何処で使
      われているか確認すると相対移動・noscrc で使っている。_ble_term_{sc,rc} も
      使えないし、相対移動なので後で絶対位置を指定して補正というのも使えない。
      ここは IND/LF で col が移動しない状況で使われていると期待するしかない。

      →うーん。現在の init-term だと LF が優先されてしまう。IND に端末が対応し
        ている事を期待して $'\eD' を使った方が安全に思われる。

  * term: sum (Solaris console) IND/RI が使えない。他色々動いていない [#D1481]

    * RI が使えない時にどの様にすれば良いか。

      * 使っている箇所の一つは vbell である。

        例えば prompt の上の行に一行 IL するという方針だと…。vbell を表示する度
        にずれてしまう。今ここで欲しいのは "上に一行も余裕がない時限定で一行確保
        する" という機能である。

      * ble/canvas/put-ri.draw

        これは2箇所から使われている。両方とも
        ble/canvas/panel/ensure-tmargin.draw という関数の中から使われていて、この
        関数は vbell から使う為の物である。

      * ble/canvas/panel#clear-after.draw
        これは単に cuu に置き換えれば良い気がする→置き換えた。

      結局 vbell が問題になる。_ble_term_ri が空の時に別の手法で vbell を表示す
      る?

      a 例えば xterm_title を使って表示するか。

        元から設定されている値を保存・復元したりするのが面倒である。push/pop の
        エスケープシーケンスも存在するかもしれないが、それに対応しているかどう
        かの判定も面倒である。というより RI を対応していない端末が xterm title
        等に対応しているとは思えない。この手法は追求しても余り意味がない。

      b 或いは、一番下の行に表示するというのは可能だろうか。

        この方法を取る場合には現在の canvas の tmargin の取り扱いを工夫しなけれ
        ばならない。というか RI が使えない場合には canvas の tmargin も振る舞い
        が微妙な気がする。

      c もしくは _ble_term_ri を使わずに被っても良いので先頭行を使う。

        然し、やはり内容が上書きされてしまうというのは都合が悪い様に思われる。

      d もしくは毎回一番上に行を挿入する。

        この方法だと bell が表示される度に行がどんどん下の方に移動してしまって
        余り嬉しい事にはならない。一応 IND を使って下に行きすぎない様に調整する
        事はできる。top/bottom dock に分かれている場合には制御が面倒である。

        現在の ble/canvas/panel/ensure-tmargin.draw の実装について確認する。
        DECSTBM が存在する場合には、スクロール領域を設定して bottom dock を固定する。
        その上で RI を実行して canvas 原点の上に tmargin 行だけスペースを確保する。

        それ以外の場合には即座に RI で canvas 原点の上にスペースを確保する。
        bottom に関しては破壊されてしまうのは我慢して invalidate する。

        さて、RI が使えない場合にどの様に内容をシフトするのか。場合分けして考え
        る。DECSTBM が使える場合にはやはり bottom dock を固定して於いて、その上
        で、top_height+tmargin だけ IND を実行する。これで少なくとも top dock
        の下に tmargin だけのスペースができる。その後で IL を一番上で実行すれば
        良い。

      うーん。完全ではないが d の方針で何とか誤魔化す事にした。

    * done: modifyOtherkeys がそのまま出力される。

      これは linux や minix と同様に出力しない様に変更。

    * done: home csi 214 z / end csi 210 z

      これは contra の escseq.html にまとめてある物に一致する気がするので確認する。

    * done: OSC がそのまま出力されている

      面倒なので xterm_title の所で直接 term の判定を行って切り替える。
      OSC を無視できるかどうかを各 OS のコンソールで確認する。
      freebsd, linux, haiku ではちゃんと無視できている。
      minix 及び sun は失敗している。

    * prompt_eol_mark 関連のカーソル移動に使われているシーケンスにも問題のある
      物がある。_ble_term_sc, _ble_term_rc の既定値が \e[s, \e[u になっていたが、
      これらは寧ろ少数派なので \e7, \e8 に切り替える事にした。Solaris では
      terminfo に \e7, \e8 は載っていないが実際には使える。

      また _ble_term_xenl に関しても terminfo になかった事から既定で 1 になって
      いたが、Solaris では 0 にする必要がある。修正した。序でに xenl がない時に
      は 0 ではなくて空文字列にする事にする。

    x ok: RI がない時の vbell の振る舞いが駄目。再度実装を確認する。
      うーん。幾らか修正して、更に必要な時にだけ高さを確保する様に変更した。

      そもそも sun console は下から出ていくと上に戻るという変な振る舞いをするの
      でまともに対応するのが難しい。適当な所で良しとするのが良い。

    * done: delete キーで ^? (DEL) が送信される。これについては TERM=sun* の時
      に ^?  を delete に変換して対策する事にした。実は既に infocmp kdch1 が ^?
      の時にはこの対策が実施されていたが、sun* の terminfo に kdch1 が登録され
      ていなかったのが原因だった。

    x 文字 x が入力できない。emacs にするとちゃんと入力できる。.blerc を別名に
      すると入力できる。と思ったがこれは set -o vi が実行されなくなるからだった。
      更に時々 segfault もする。またランダムな文字列を実行しようともする。

      これは恐らく "x?" で bind が形成されてその後でそれが削除される事により、
      x 単体の入力に対して出鱈目な文字列が実行されているという事なのだろう。
      では誰が x に bind しているのだろうか。。不思議である。

      うーん。inputrc は存在していないし、bind は特に直接呼び出されてはいない様
      だし、という事を考えると ble.sh で呼び出している builtin bind が問題を起
      こしているという事なのだろうか。

      generate-source-to-unbind-default の出力を保存してそれを読ませてみたら
      問題が発生するという事が分かった。特に問題のある行もない…と思いきや、

      builtin bind -r 'x1c' (bash-4.1)

      という変な行が混入している。これは一体何処から出てきた物だろうか。普通に
      動いている環境で実行してみると

      builtin bind -r '\x1c' (bash-4.4)

      という結果になっている。つまり、これは bash-4.1 特有の処置ではなくて一般
      に行われている処置である。

      問題の箇所を確認してみると awk で sub(/.../, "\"\\x1c\"") としている。
      つまり Solaris awk はこの \\ を消してしまうという事。と思っていたら、
      既にその問題点についてコメントに書かれていた。'\'' に対しては対策されていたが、
      直接 \ が現れる場合については対策されていなかったのが原因。
      特に \x の組み合わせが x に変換されてしまうという問題の様である。
      \x についても対応すると共にコードの整理を行った。

  * complete/mabdb: man awk の内容を抽出しきれていない [#D1480]

    先ず .PD という行が挿入されている事が原因の様である。
    .PD という行は皆無視しても良い様な気がしたので無視する。
    更に、複数のオプションに対して一つの説明がなされている場合に対応した。

    キャッシュファイルは LANG 毎に別にするべき気がする。特に LC_MESSAGES に従って
    設定するべき。

  * edit: "echo " の状態で \C-x\C-v するとバージョン情報が灰色 [#D1479]

    これは外部コマンドを実行する時に sgr0 をちゃんとしていないのが原因。何処で
    sgr0 をすれば良いのかと悩んだが取り敢えず insert-newline は新しい行に行くと
    いう意味なのだから sgr0 するのが自然である。他に外部コマンドを実行する瞬間
    にも sgr0 を実行する。

  * bash-4.4 で emacs mode で C-x * が効かなくなっている [#D1478]

    vi から emacs モードに切り替えると emacs モードで C-x が効かない。
    keyseq-timeout が長い時には問題は起こらない。

    [状況]

    | これは keyseq-timeout が関係している様だ。更に、一度 emacs モードにしてしま
    | うと、vim モードに戻しても依然として効かない状態が続いている。
    |
    | keyseq-timeout を長く設定してみたところ問題は発生しなくなったので、これはつ
    | まり "C-x ?" の組み合わせで 登録してキーを読み取ろうとしている事自体に何ら
    | かの問題があるという事なのだろう。という気がする。
    |
    | 然し vi に戻しても問題が持続しているのは不思議な事である。詳しく調べてみる
    | と vi に戻すと C-x 一回の入力に付き C-x が2回入力されている様子である。不思
    | 議な事である。
    |
    | * 普通に emacs モードから始めた場合には問題は起こらない。
    | * 同じモードで detach/attach しても問題は起こらない。
    | * 一回のコマンドで ble/decode/detach; ble/detach/attach しても問題は起こらない。
    | * ble-detach して set -o して ble-attach すると再現する。
    |
    | % 問題の一部は分かった。unbind cache に於いて "C-x ?" の組み合わせについて
    | % emacs モードの時にしか unbind していない。然し、これはモードに拘らず
    | % unbind するべきではないのか。つまり、set -o でモードを切り替えた時には元々
    | % と異なる keymap になっている為に [[ -o emacs ]] で判定したのと異なる
    | % keymap に作用する可能性がある? と思ったがそれは変だ。[[ -o emacs ]] になっ
    | % ているのであれば実際にその keymap になっている筈だし、unbind する時には一
    | % 旦元の keymap にしてから戻す様にしていた筈である。実際に
    | % ble/decode/detach においてその様に処理している。
    |
    | * ble-bind -m emacs -P で確認した限りは特に違いは見られない。という事を考え
    |   るとやはり bind の側の問題であろう。何故違いが生じるのだろうか。
    |
    | 全く同じ binder を用いていても問題が生じる物なのだろうか。何より異なる
    | keymap に対して作用しているのに影響が出るのは何故だろうか。うーん。
    |
    | うーん。builtin bind の呼び出しを全て検査すれば大丈夫だろうか。
    | と思って builtin を置換する実験をして見たら滅茶苦茶になる。
    | 何かと思ったら eval を通して $* を参照する場合には、
    | 関数の中から実行すると $* が変わってしまって駄目という事。
    | なので、builtin を置き換えて bind の呼び出しを監視する作戦は使えない。
    |
    | 直接 bash のソースを弄ってデバグする? うーん。
    | そもそも一体どういう状態になっているのかというのが謎である。
    | vi の時には何故二回連続で C-x が受信される事態になっているのか。
    | 本当に C-x が二回連続で受信されているのだろうか。。
    | 或いは C-xC-x の entry が xmap にされていると
    | C-x に対しても勝手に C-x C-x のマッピングが呼びされてしまうという事なのか。
    | もしそうだとしたら再現は簡単で良い。

    というより version 毎にちゃんと動いているか確認する。

    bash-4.4 vi: 動いている
    bash-4.4 vi->emacs: 駄目(何も受信されない) #1
    bash-4.4 vi->emacs->vi: 駄目(C-x が二回受信される) #2
    bash-4.3: 全部OK
    bash-4.2 vi: 動いている
    bash-4.2 vi->emacs: 動いている
    bash-4.2 vi->emacs->vi: 駄目(何も受信されない) #3
    3.0..4.1 は 4.2 と同じ振る舞いである。

    取り敢えず 4.4 の振る舞いだけは修正したい。

    うーん。#2 については何が起こっているか分かった気がする。以下で再現できる。

      $ bash-4.4 --norc -o vi
      $ bind -x '"\C-x":echo X'
      $ bind -x '"\C-x\C-x":echo XX'
      $ bind -r '\C-x\C-x'
      kbd <C-x><500ms> → XX と表示される

    #1 についても何が起こっているか分かった気がする。

      $ bash-4.4 --norc
      $ bind -r '\C-x'
      $ bind -x '"\C-x\C-x":echo XX'
      $ bind 'set keyseq-timeout 1'

    この状態だと C-x を押して timeout すると何も起こらない。
    keyseq-timeout を短く設定してしまうのが問題という事。

    問題 #3 では何が起こっているのだろうか。何も受信できていないというのが気に
    なる。emacs に移動した時に既に \C-x\C-x の bind -x & bind -r は終わっている
    筈である。この時点で cmd_xmap は問題がない筈。

    #3 に関しては以下の様にして再現する事ができる。

    $ bind -x '"\C-x\C-x":echo XX'
    $ bind -r '\C-x\C-x'
    $ set -o vi
    $ bind -x '"\C-x":echo X'
    kbd <C-x>

    [対処]

    | 敢えて \C-x\C-x の場所に何か変な値を設置しておく?
    | というかこれは元々の \C-x を検出する時の問題に関係するのではないか。
    | 実は以下のようにおけば問題ないのでは。
    |
    |   bind -x '"\C-x\C-x":C-x 用の文字列'
    |   bind -r '\C-x\C-x'
    |   bind -x '"\C-x":C-x用の文字列'
    |
    | 少し実験してみる事にする。
    |
    | 取り敢えず問題の再現から。bash-4.2 で以下で落ちる事を確認した。
    | bash-4.1,4.0,3.2 でも同様に落ちる。bash-3.1,3.0 では変な文字列を実行しよう
    | として失敗する。以前の実験で 3.2 だけ無限ループになったのは偶々だったのでは
    | ないかと思われる。
    |
    |   bind -r '\C-x\C-b'
    |   bind -x '"\C-x":echo X'
    |   kbd <C-x><C-b>
    |
    | さて、これの WA として \C-x\C-x を一回 bind してから unbind すると
    | いうのは有効か確認する。うーん。
    |
    | o 一応この対策をして置けば何れの場合にも crash はしなくなる。
    |
    | o bash-4.4 の場合にはこれで完全にOK。- 但し、bash-3.0..4.2 の場合にはこれを
    |   実行すると shadow binding timeout が発生しなくなってしまうので、-o emacs
    |   の時にだけ実行する様にした方が良い。
    |
    | 0 bash-3.0..4.2 の場合には vi->emacs->vi とした時に C-x で何も受け取れなく
    |   成る問題 #3 は持続している。然しそれでも、従来行っていた "C-x ?" に全て
    |   bind する作戦と同等の振る舞いを一つの binding で実現できているので、これ
    |   だけでも新しい手法に移行する価値はある。
    |
    | vi の側でも bind -x & -r を実行すれば検出できる様にはなるが、C-x 単体での検
    | 出ができなくなってしまう。でもそれは emacs keymap を一度でも使うのであれば
    | 避けようがないので、受容するしかない。或いは、emacs でも vi の上で動作する
    | 様にすれば良いのかもしれないが…。
    |
    | 取り敢えずこれがどの bash version でも再現するのかを確かめる。Bash-4.0 以下
    | では C-x を押すと行が新しくロードされる。これが意味する所は、 bind -x によっ
    | て unix_execute_command は呼び出されているが、対応する文字列の探索に失敗し
    | ているという事の気がする。
    |
    | ? 或いは一度は却下した bind -s '"\C-x": "\xC0\x98"' を用いる方法について再
    |   検討しても良いのかもしれない。遅延が生じるという事が述べられているが、ど
    |   の bash の version で起こるのか等について記録が残っていない。
    |
    |   * 先ずは遅延を再現しなければならない。そしてどの様な状況で問題になるのか
    |     を確認しなければならない。
    |
    |     →うーん。bash-4.4 で bind 'set keyseq-timeout 500' にしたら再現できた。
    |     これは何故発生しているかと言うと C-x ? が (過去に) 存在していた時に
    |     '"\C-x":"\xC0\x98"' を実行する為には結局 timeout/mismatch が必要だから
    |     である。
    |
    |     然しこの遅延に関しては "C-x ?" 全バインドの手法を取ったとしても共通であ
    |     る。特に問題になるのは C-x C-x と連続で入力した時に、この C-x C-x の組
    |     で認識されれば即座に反映されないという事である。"C-x ?" なら即座に反映
    |     される。'"\C-x":"\xC0\x98"' だと
    |
    |       C-x C-x
    |       \xC0 \x98 C-x
    |
    |     の様な形になるので余った C-x が残ってしまう。
    |
    |   x 更に、bash-4.2 で '"\C-x":"\xC0\x98"' を適用してみたが、結局遅延が存在
    |     する事には変わりがない様で、意味がない。bash-4.3 以降は現在は問題なく動
    |     作するので、対策は bash-4.2 以下に対してになるが、bash-4.2 以下では
    |     keyseq-timeout を指定する事もできないのでこの遅延をどうにかする事はでき
    |     ない。
    |
    | ? というかこの単一 bind 手法だと結局 C-x C-x とした時に遅延が生じるのではな
    |   いだろうか→確かめた。実際にそうだった。やはり単一 bind は駄目である。
    |   bash-4.4 ならば keyseq-timeout を短くすれば未だ何とかなるが bash-4.2 以下
    |   では次の操作をしない限りは C-x C-x に対して結果を受信する事ができない。

    [対処法比較]

    単一C-x (C-xC-xを一旦設定)

      4.4 ... keyseq-timeout の分だけ遅延が生じる。keyseq-timeout を 0 にすれば
        問題ない。何故 timeout 遅延が生じるのかと言うと、元々 emacs keymap には
        C-x ? の組み合わせが登録されていて、それらが全て削除されていたとしても
        (或いは削除しきれていないのかもしれない)、確定状態にならないからなのだ
        と言う気がする。

        ※C-xC-xを一旦設定する措置をしないとコマンドが登録されていない旨のエラー
        が発生する。

      4.2 ... timeout がないので key 一個分だけ遅延してしまう。keyseq-timeout
        を 0 にする訳にも行かない。

        ※C-xC-xを一旦設定する措置をしないとそもそも、次の key が来ていざ確定し
        た時にクラッシュしたりランダムな文字列を実行したりして問題になる。

    全 "C-x ?" の束縛 (C-x は unbind しておく)

      4.4 ... keyseq-timeout により timeout が発生すると "C-x" 単一で確定が為さ
        れるが、その時に何も実行されない。keyseq-timeout を十分長くすれば気にな
        らなくなる…かもしれないが、それでも振る舞いとしては微妙。

        ※C-x にも bind する様にしておくと今度は C-x に対して C-xC-x に対応する
        コマンドが実行されてしまう。

      4.2 ... key 一個分の遅延はない。emacs では特に何も問題は発生しない。但し、
        一旦 emacs で "C-x ?" の組み合わせに対して全 bind を実行していると、vi
        の側で単一 C-x に対して bind しようとした時に支障が出る。

        これを防ぐ為には "C-x ?" の組み合わせについて直接 -x を設置するのではな
        くて、文字列マクロ経由で読み取る様にするべきではないか。という事。この
        時の問題は…。やはり \C-x が再び現れると key 遅延が発生する事。つまり、
        bind '"\C-x\C-x":"\xC0\x98\x18"' 等とすると、\x18 (\C-x) に対して再び
        key 一個分の遅延が発生する。なので、'"\C-x\C-x":"\xC0\x98\xC0\x98"' と
        する必要がある。

        * 一方で、"\xC0" や "\x98" に関しては複数バイトの束縛は行わないので、
          "\xC0" の timeout/key 遅延について問題が新しく発生する事はない筈。

    Bash 4.4 では単一 C-x を採用する。Bash 4.2 以下では今まで通り "C-x ?" を全
    束縛するが、vi に影響が出ない様にマクロ経由で束縛する事にする。

2021-02-18

  * syntax: !; 及び time; の後の文脈 [#D1477]

    !; 及び time; の後の文脈で } fi done esac を要求しているが実際は任意のコマ
    ンドの筈である。少なくともそうなっている様に見える。問題の部分では #D0592
    を参照しているが、これは大きな書き換えなので特にこの部分で何故この様にした
    のかは謎。コメントには明示的に CTX_CMDXE と書かれている。そんな事はない筈な
    のに不思議である。

    よく #D0592 を見てみたら "time ; echo" でエラーになると書かれている。
    うーん。bash の version かと思って試したらそうだった。bash 4.3 以前は
    "time ; echo" がエラーになるのであった。一方で 4.4 以降は OK

2021-02-15

  * 2017-10-01 syntax: case $x in (a b) : ;; esac のパターン "a b" はエラー [#D1476]
    これも #D1474 で対応した。此処に挙げられているテストケースは有用だった。

    どうやら一個の単語までしか駄目な様子?

    更に case aaa in ((aaa)) echo;; esac 等の様に () の入れ子もエラーになる。
    shopt -s/-u extglob に拘らずエラーになる。
    一方で extglob の @() に関しては中で () の入れ子が可能である。
    つまり、case の中の (...) と extglob @(...) の文脈は異なる。

    他にも違いはある。@(<>) は許されるが、in (<>) は許されない。
    @(&&) は許されるが in (&&) は許されない。
    in (a|a|a) は許されるが in (a||a) や in (||) は許されない。
    in (&), in (|), in (;), in (<), in (>) は何れも駄目。
    in (a&b), in (a;b), in (a<b), in (a>b) も何れも駄目。

    どうも全然違う文脈の様に思われてきた。

    現在の実装では ble-syntax:bash/ctx-case から CTX_PATN に突入している。
    (他に CTX_PATN に入っている箇所を探すと、
    関数の引数の括弧に何か変な物が入っている場合と、
    コマンドの途中で突然括弧が現れた場合である。
    これらはエラーに対する復帰としての CTX_PATN なのでそんなに気にしなくて良い)

    どうも振る舞いを観察すると ctx-conditions と ctx-globpat の中間のように思う。
    単語を設置しなければならないという観点で言うと ctx-conditions に近い。
    一方で対応している構文の集合という観点で言うと ctx-globpat が幾らか近いように思う。

    2017-11-27 追記
    どうやら () の中の単語ではチルダ展開も有効のようだ。以下で hello が出力される。
    case a=~ in (a=/home/murase) echo hello; esac # これは対応済み
    case a=/home/murase in (a=~) echo hello; esac

  * syntax: case x) とした時の ")" の着色が括弧でちゃんと囲んだ時と異なる [#D1475]
    これは #D1474 における再実装で一緒に修正した。

  * syntax: case a in @) で @() と入力すると fatal error [#D1474]

    case a in ) の状態でパターンに @() を入力しようとするとシフトエラーになる

    | もっと具体的に調べてみると case a in @) の状態で @ の直後に ( を挿入する
    | となる。シフトエラーになるという事は case a in @) と入力した時点で壊れて
    | いると考えられる。
    |
    | | 先に ) を入力した時
    | | $ case a in @)
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a    000 'c' | stat=(CMDX w=- n=- t=-:-)
    | |  | a    001 'a' |
    | |  | a    002 's' |
    | |  | a    003 'e' + word=CMDI:0-4/(wattr=d)
    | | 39 a    004 ' '   stat=(CARGX1 w=- n=- t=$4:-)
    | | 40 a    005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-)
    | | 41 a    006 ' '   stat=(CARGX2 w=- n=- t=$6:-)
    | | 42 a    007 'i' | stat=(CARGX2 w=- n=- t=$6:-)
    | |  | a    008 'n' + word=CARGI2:@5>7-9/(wattr=d)
    | | 34*a    009 ' '   stat=(CASE w=- n=- t=$9:-)
    | | 30*a    010 '@' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-)
    | | 30*a  s 011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9)
    | |  |    s 012 ^@   stat=(CMDX w=- n=- t=$12:-)
    | |
    | | 先に @ を入力した時
    | | $ case a in @)
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a    000 'c' | stat=(CMDX w=- n=- t=-:-)
    | |  | a    001 'a' |
    | |  | a    002 's' |
    | |  | a    003 'e' + word=CMDI:0-4/(wattr=d)
    | | 39 a    004 ' '   stat=(CARGX1 w=- n=- t=$4:-)
    | | 40 a    005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-)
    | | 41 a    006 ' '   stat=(CARGX2 w=- n=- t=$6:-)
    | | 42 a    007 'i' | stat=(CARGX2 w=- n=- t=$6:-)
    | |  | a    008 'n' + word=CARGI2:@5>7-9/(wattr=d)
    | | 34 a    009 ' '   stat=(CASE w=- n=- t=$9:-)
    | | 30*a    010 '@' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-)
    | | 30*a    011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9)
    | |  |    s 012 ^@   stat=(CMDX w=- n=- t=$12:-)
    |
    | これら二つを比較しても違いは 011 の位置の s という記号のみである。この s
    | というのが何であるかは覚えていないが、実のところこの二つの両方で問題が再
    | 現するので @ を先に入力するか ) を先に入力するかは問題には関係ない。
    |
    | @の代わりに X を挿入した場合にどうなるか調べる。X に引き続いて (
    | を挿入しても問題は発生しない。
    |
    | | $ case a in X)
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a    000 'c' | stat=(CMDX w=- n=- t=-:-)
    | |  | a    001 'a' |
    | |  | a    002 's' |
    | |  | a    003 'e' + word=CMDI:0-4/(wattr=d)
    | | 39 a    004 ' '   stat=(CARGX1 w=- n=- t=$4:-)
    | | 40 a    005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-)
    | | 41 a    006 ' '   stat=(CARGX2 w=- n=- t=$6:-)
    | | 42 a    007 'i' | stat=(CARGX2 w=- n=- t=$6:-)
    | |  | a    008 'n' + word=CARGI2:@5>7-9/(wattr=d)
    | | 34 a    009 ' '   stat=(CASE w=- n=- t=$9:-)
    | | 30 a    010 'X' | nest=(CMDX w=- n=- t=$9:-) stat=(CASE w=- n=- t=$9:-)
    | | 30 a    011 ')' + word="none":@8>10-12 stat=(PATN w=- n=@10 t=-:$9)
    | |  |    s 012 ^@   stat=(CMDX w=- n=- t=$12:-)
    |
    | 然し木構造を調べても X の時と @ の時で全く同じ状態になっている。な
    | のにシフトでエラーが発生するというのは不思議である。
    | →改めて確認した所、一番最初に発生するエラーはシフトエラーではなかった。
    |
    | | ble/syntax/tree-enumerate/.initialize/FATAL2
    | |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:4 (ble/syntax/tree-enumerate)
    | |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:6 (ble/syntax/print-status/.dump-tree)
    | |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:8 (ble/syntax/print-status)
    | |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:74 (ble/highlight/layer:syntax/update)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:13 (ble/highlight/layer/update)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:10 (ble/textarea#update-text-buffer)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:76 (ble/textarea#render)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble-edit/bind/.tail)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:18 (ble-decode/EPILOGUE)
    | |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:79 (ble-decode/.hook)
    |
    | print-status の段階でエラーが発生している。つまり、直前の状態が問
    | 題なのではなくて ( を入力した直後の状態が壊れているのである。
    |
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a e  000 'c' | stat=(CMDX w=- n=- t=-:-)
    | |  | a e  001 'a' |
    | |  | a e  002 's' |
    | |  | a e  003 'e' + word=CMDI:0-4/(wattr=d)
    | | 39 a e  004 ' '   stat=(CARGX1 w=- n=- t=$4:-)
    | | 40 a e  005 'a' + word=ARGI:@3>5-6/(wattr=d) stat=(CARGX1 w=- n=- t=$4:-)
    | | 41 a e  006 ' '   stat=(CARGX2 w=- n=- t=$6:-)
    | | 42 a e  007 'i' | stat=(CARGX2 w=- n=- t=$6:-)
    | |  | a e  008 'n' + word=CARGI2:@5>7-9/(wattr=d)
    | | 34 a e  009 ' '   stat=(CASE w=- n=- t=$9:-)
    | | 31*a e  010 '@' | nest=(PATN w=- n='none':10- t=-:$9) stat=(CASE w=- n=- t=$9:-)
    | |  |*a e  011 '(' |
    | |  6*a es 012 ')' + word="none":10-13 stat=(PATN w=- n=@10 t=-:-)
    | |  |    s 013 ^@   stat=(PATN w=- n=@10 t=$13:$9)
    |
    | というか、")" が存在しなくても普通に @( と入力しただけでエラーになってい
    | る。a@( としている時には大丈夫である。これはつまり単語と nest が同じ場所
    | で始まる事によってエラーになっているという事だろうか。うーん。確かに a@(
    | とすると a の位置と @ の位置の両方に nest が設定されている。という事は、
    | @( を入力した時に同時に二箇所に nest を設定しようとして状態が破壊されてい
    | るのである。だとすると $( でも問題が発生する筈→発生した。" でも問題が発
    | 生した。うーん。根本的に nest を再考する必要があるのかもしれない。

    [状況]

    以下の何れでも問題が発生する。原因は同じ位置に2つの nest を設置しようとして
    いる事にある。

    - case a in @(
    - case a in $(
    - case a in "
    - case a in (x);;"

    nest の位置をずらそうとしても " の場合には一文字しか無いのでずらす事ができ
    ない。逆にパターンの側の nest の位置を一文字前にずらすという事も考えたが、
    必ずしもパターンの前が空白とは限らない。例えば ;; など。この場合には結局同
    じ位置に nest を設置するしかない。或いは ;; の位置に nest を設置してしまう
    という手もあるのかもしれないが、それは不自然だし色々とまた変な問題が発生し
    そうである。

    [修正]

    やはり解決策としては同じ位置に nest を設置できる様にするという事。然し、現
    状のコードで nest が同じ位置に設置されないという前提は何処で使っていただろ
    うか。場合によって単に対応するだけでは済まないかもしれない。

    或いはもう一つの方法として、そもそも case パターンを nest にする必要があっ
    たのかという事。この方法の方が確実に簡単に修正できる気がする。然し、nest に
    した理由は何だろうか。単に既存の CTX_PATN を使いたかったからというのであれ
    ば簡単である。

    コードを確認してみたがやはり nest を使わないとすると新しい文脈値が必要にな
    りそうである。更に、元から case pattern の中は単語が一個だけになる様に制限
    を加える予定だった。これに対応する為には結局新しい文脈値が必要だったのだ。
    case pattern の単語数も一緒に対応してしまうのが良いだろう。

    うーん。実はコマンド文脈で読み取った方が良い? とも思ったがそうでも
    ない気もする。例えば | の取り扱いが異なる。& や ; 等他の delim の
    場合にはエラーにする必要がある。|| は一まとまりではなく一文字ずつ取る。
    | の直後は再び単語を受け付けて OK。など。

    - done: ble/syntax:bash/ctx-command-case-pattern

    実装したが無限ループになってしまう。調べると parse の中で同じ位置に対してずっ
    と計算している。

    parse (i=19): ctx=78 ble/syntax:bash/ctx-command-case-pattern-expect

    $ case x in @() echo ;; esac

    問題は ;; の直前で起きている様だ。これは BASH_REMATCH が途中で書き換わって
    いたのが見落としだった。修正した。OK 動いている。

    ----------------------------------------------------------------------

    2021-02-19 assertion failure が出た。

    assertion failure: ((_ble_syntax_bash_command_isARGI[ctx]))
    invalid ctx=79 in words
      @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:15 (ble/syntax:bash/ctx-command)
      @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:86 (ble/syntax/parse)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7 (ble-edit/content/update-syntax)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:75 (ble/textarea#render)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble/textarea#panel::render)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:5 (ble/function#try)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:8 (ble/canvas/panel/render)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble-edit/bind/.tail)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:18 (ble-decode/EPILOGUE)

    [再現]

    | 以下のコマンドラインに於いて "'; の ; の前にカーソルを置いて、其処から BS
    | の autorepeat で削除を行うと確率的に上記のエラーが発生する。不思議なのは
    | ctx=79 は最近追加した CTX_CPATQ であり、これは case の時にしか発生しない筈
    | の物であるという事。現状では何処にも case はないので ctx が 79 になる事はな
    | い様に思われる。core-syntax.sh の中を再度確認してみたが混入する事はない気が
    | する。
    |
    | $ debug/builtin() { unset -f builtin; IFS=" " eval 'echo "[$*]"'; builtin "$@"; local _ext=$?; echo "[$* ($_ext)]";
    |   builtin() { debug/builtin "$@"; }; return "$_ext"; }
    |
    | $ d() { unset -f builtin; A=" " : ': "[$*]"'; : "$@"; : a=$?; : "[$* ($a)]"; }
    |
    | $ : helloworldhelloworld; A=" " :; : a=$?; : "[$* ($a)]"
    |
    | あー。成程。79 が現れたのは BS で消す途中に ;; が現れる為である。確率的に発
    | 生していたのは、丁度 ";;" の時に文法の再解析が起こるか起こらないかである。
    | 一つずつ BS を押していれば必ず発生する。
    |
    | $ :; :;: a=$?;:
    |
    | OK. 以下が最小再現コードである。以下の状態から間の空白を削除するとエラーになる。
    |
    | $ ; ;a=1
    |
    | というより変な事をしなくても普通に以下で問題が発生する。
    |
    | $ case x in a=1

    取り敢えず 79 が出るのは別にバグではないという事は確認できた。
    そして修正は簡単だった。これは fixup にする。

2021-02-10

  * ble/builtin/read: 空文字列の時 C-d でキャンセルしない [#D1473]

    使い心地が変だと思って plain Bash で試してみたら C-d でちゃんとキャンセルに
    なる。ble/builtin/read もこれと同様に振る舞うべきである。

    →これも実装した。これは簡単な修正。

  * ble/builtin/read: 全く描画されなくなっている [#D1472]

    これは ble/canvas/panel/render において描画するかどうかを各パネルの高さで決
    定しているが、textarea は textarea#render の中で高さを決定する事にしている。
    なので高さがいつまでも 0 の儘になってしまって結局全く描画されないという事態
    になっている。

    | 本来は描画を実行する前に高さを決定するべきなのである。然し、現在の実装では
    | 中身の計算が重いために必要になるまで計算しない事にしている。うーん。
    | getHeight を受け取った時点で中身の計算を終わらせるべきだろうか。然し、希望
    | の高さを伝えたからと言って必ずしもその高さが通るとも限らないし、結局結果に
    | よっては再計算する必要が出てくる可能性は変わらない。
    |
    | その様に考えると結局現在の様な実装でも変わらないのではないかという気はする。
    | 或いは 0 という高さは特別な高さという事にして中身がある場合には必ず有限の高
    | さを指定する事にする?
    |
    | 然し、0を特別扱いする事にすると一時的に高さを 0 にして再び後で高さが有限に
    | なる可能性がある時、そしてその高さが有限になる機会が render の中で得られる
    | 場合に困る。なので、0 であってもやはり render は呼び出すべきなのではないだ
    | ろうか。
    |
    | うーん。然しそうすると… textarea を隠したい時にも必ず textarea が表示され
    | てしまうという事になってしまう。或いは、textarea を隠したい時には
    | _ble_textarea_panel には -1 などの値を代入しておくというルールにする? とい
    | うよりそもそも表示・非表示という状態は height とは別に持っておくべきなので
    | ある。

    * 表示・非表示の状態は height とは別に持っておくべき。現在の実装では取り敢
      えず各実装に任せる事にする。

    * render では取り敢えず高さ 0 であっても全ての panel について
      $class#panel::render を呼び出す事にする。これは render の中でレイアウトを
      計算する時に高さを変更したくなるかもしれないからである。

    * reject: 将来的には textarea#render を textarea#layout と textarea#render
      に分ける事も考えるべきかもしれない。

    | 少し textarea#layout と textarea#render に分ける事も考えたが、これをして
    | も結局何も変わらない。というのも、textarea#layout で高さを計算する時に自
    | 身の高さを変更すると結局、他のパネルの高さも全て再計算になる。なので、再
    | 帰的な高さ変更の可能性は、高さ計算を textarea#layout に分離したとしても本
    | 質的には解決していない。何か利があるとすれば最後の描画処理が省略できるだ
    | けである。そして最後の描画処理は ble.sh ではそんなに重い処理ではないので
    | 意味がない。
    |
    | また、今まで問題が起こらなかった理由でもあるが textarea は高さを要求する
    | が、info は高さが足りなければ他から奪おうという事はしないので、高さの更新
    | が再帰的になる事はない。特に textarea よりも info の方が後に render を行
    | うという事もあるので特に問題になっていない。(実は今までは info が描画した
    | 内容を textarea が truncate するという事になっていたのではないかという気
    | がするので、現在の実装のほうがよりまともなのであろう)

    * 結局 height 更新の無限ループは可能性として排除できない。それは render の
      中で height 設定をしても、layout の中で height 設定をしても同じことである。
      最終的には誰かが皺寄せを食うという事にしておけば何れにしても問題にならな
      いし、そうでなければそもそも解が存在しない。現在の実装では info が皺寄せ
      を食う事になっている。

  * global: 今度はまた別の連想配列のエラーが出ている (reported by 0xC0ncord) [#D1471]
    https://github.com/akinomyoga/ble.sh/issues/86#issuecomment-776165286

    新しいシェルを開いてもエラーが出ていると書いているが本当だろうか?
    もしこれが同じシェルだとしたら ble-update で駄目な事になるというのは理解できる。
    取り敢えずその為の修正だけは入れる事にした。

  * global: 連想配列の中身が bash-4.2 関数内ble.shソースで消滅する (reported by 0xC0ncord) [#D1470]
    https://github.com/akinomyoga/ble.sh/issues/86

    4.2 で動かないという話。調べると問題の _ble_builtin_trap_n2i は連想配列であ
    る。という事は -g の指定が怪しい。実際に ble.sh を関数内で source したら再
    現できた。

    然し、手元で reduced case を作ってみると動いている様な気がする。WINCH に対
    するシグナル番号を取得する時に結果が空になってしまってい
    る。_ble_builtin_trap_n2i から引いている。然し、 _ble_builtin_trap_n2i の値
    を見るとちゃんと SIGWINCH に対して 28 が割り当てられている様に見える。と思っ
    てよく見てみたら、途中で _ble_builtin_trap_n2i の中身が空になっている。もし
    かして、bash-4.2 だと属性は global まで適用されるが、値が local になってし
    まっているという事か。

    実際に試してみると確かに中身が空になる。うーん。今までは -gA を 40200 以上
    という条件で使っていたが、これは 40300 以上という条件に引き上げるべきだろう。

    * 結局最小再現コードは以下の様になった

      $ bash-4.2 -c 'a(){ declare -gA d=([k]=v);};a;declare -p d'
      declare -A d='()'
      $ bash-4.3 -c 'a(){ declare -gA d=([k]=v);};a;declare -p d'
      declare -A d='([k]="v" )'

    * reject: 判定条件を変数に入れて再利用できるようにする? と思ったがどうせそ
      の次の判定で細かく場合分けするので全体の条件だけ変数に入れて再利用しても
      却って分かりにくいだけである。これは棄却。

    * reject: 連想配列の使い方に応じて declare -gA を使う bash version を切り替える?

      使い方によっては引き続き 40200 でも大丈夫かもしれない。つまり、ble.sh を
      source した段階では空の儘で、実際に使っていく中で中に値をキャッシュすると
      いう場合。或いは、単にキャッシュとして使うという場合にも問題は起こらない。
      然し、実際に関数の中で値が初期化されるかどうかは attach の仕方にも依存す
      る。更に、これは関数内で ble.sh を source するという特殊な場合に於いての
      み影響が出るので余り細かい最適化を考えても仕方がない。

    全て 40300 に書き換えた。まあ、これで何も起こらないだろう。

2021-02-09

  * 2021-02-01: spike branch で tab completion で crash する (reported by 3ximus) [#D1469]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-770390986

    Ref: これは #D1452 / #D1468 と同じ問題。詳細は #D1468 で議論。

    eval-pathname-expansion の中で死んでいるのだろうか。failglob などの判定に失
    敗している可能性もある。つまり、shopt -s failglob が設定されている時に、
    globpat が含まれているのに含まれていないと判定された時に、set -f 等の操作を
    行わずにパス名展開を直接実行して、それにより強制的に終了してしまっている可
    能性。

    →でも元々 failglob があっても大丈夫な様に eval を使って評価していた筈→本
      当だろうか。eval だけで failglob を回避する事ができていたのだろうか。
      syntax の方で .set-result という関数を用意したのは何か理由があったのでは
      ないか。と思ったが、.set-result は failglob を避ける為の物ではなくて展開
      結果を格納する為の物だった。

    →更に、現在の判定方法で globpat を見逃すとも考えづらい。

    実際に手元で failglob の設定下で補完を試みたが変な事は起こっていない。bash
    version の違いかもしれないとも思ったが別に 5.1 でも dev でも変な事はない。
    3.2 や 4.0 4.3 4.4 で試しても違いはない。

    →hangは観測できたという話をしたらどうやら正確にはcrash ではなくて hang し
    ていた様だ。そして振る舞いを見る限りに於いては自分の手元で観測した hang と
    全く同じである。

  * 2021-02-03 TAB completion に於いて conditional-sync で hang する [#D1468]
    Ref: #D1452 と #D1469 は実はこの問題と同一であった。

    chatoyancy で再現している。

    3ximus の報告した crash は観測されていないが代わりに linux 上で hang すると
    いう現象は起こっている。親 shell が固まっていて一方で子 shell はいつまで経っ
    ても終了しないという状態になる。これはどういう状態だろうか。子 shell に対し
    て kill を実行するとその時点で終了して親 shell も使える様になる。時々、再び
    子 shell を生成してそれが固まるという現象は発生している。subshell が発生し
    ている状態で固まっているという様子を見る限りは恐らく conditional-sync で変
    な問題が起こっているのだと思われるが分からない。

    * 親shellの CPU が微妙に動いている。
    * ユーザー入力しても何故か親シェルが中断しない

    改めて condtional sync の実装を確認してみると2回 fork している。1つの fork
    はジョブ管理によって変なメッセージが発生するのを避ける為。2つ目の fork が実
    際に & で bg job を起動する為の物。症状として見られていた hanging shell は
    実は worker ではなくて最初の subshell の様だ。更に詳しく調べてみるとどうや
    ら msleep の中で停止してしまっているようだ。つまりこれは Cygwin 上で発生し
    ていた #D1452 のフリーズと全く同じ問題である。

    Cygwin のテストケースと同じ物で再現できるだろうか。

    ( echo {1..1000} & builtin read -t 0.000100 v < /dev/udp/0.0.0.0/80 ) >/dev/null

    Linux では /dev/udp ではなくて fifo を使っている筈。

    OK 再現した。

    $ mkfifo a.pipe
    $ exec 9<>a.pipe
    $ test1() { (eval "echo {0..$count}" & builtin read -u 9 -t 0.001 v) >/dev/null; echo ok $((count++)); }
    $ bind -t '"\C-t":test1'

    これは結局 bash のバグなので別の場所で議論する事にした。

    workaround を考える。

    A 一つの方向は先ず変な事が起こる発生確率を下げるという事。
      然し、それでも read -t がブロックする可能性は 0 ではない。
      これは実の所 /dev/zero を使っていても同様の筈である。
      とにかく変な事が発生する確率は 0 ではないという事。

      変な事が起こる確率を下げる為に。もう一つの可能性は以下の様に、
      $() を使って fork して、その後で read timeout を
    一番外側で実行するという事。

        { pid=$({ echo OK >&3; sleep 10; } &>/dev/null & echo $!); } 3>&1

      疑問としは孫シェルを wait できるのかという事。→うーん。駄目だった。

        bash: wait: pid 9447 はこのシェルの子プロセスではありません

      wait できない。という事は終了ステータスを検知する方法がない。或いは
      ble/util/assign と同様に終了ステータスは自前のファイル経由で読み取るとい
      う手もあるのかもしれないが…。とにかく面倒になってしまうという事は避けら
      れない。

      そもそもこの方向で問題を軽減できるのかどうかも非自明である。

    B read timeout を使わない方法を模索するべきなのかもしれない。
      然し read timeout が使えないとなるとやはり方法は絞られてくる。
      一つの方法は普通にコマンドの sleep を呼び出すという事。

      然し、spawn のコストと、更に sleep の分解能が秒単位しか無いという可能性が
      ある。そう考えると read timeout はどのシステムでも使う事ができるかなり便
      利な機能だったのである。

    c というよりそもそも conditional-sync ではデフォルトでユーザの入力を待って
      いるのだから、read -t を sleep に使うのではなくて、直接ユーザー入力を検出
      するのに使えば良いのではないのか? と思ったが駄目だ。read -t 0 ならばユー
      ザー入力を読み取らずに検査する事ができるが、read -t 0.001 だとユーザー入
      力を消費してしまう。そうなると気軽に実行できない。或いは、ユーザー入力を
      読み取る事ができた暁にはその場で ble-decode-char するという手もある?

      うーん。然し、_ble_bind_hook の中で実行した bind/.tail の中で
      ble-decode-char するとすると、例えば其処でコマンド実行が _ble_bind_hook
      に大して設定された時に、それがその場で実行されない可能性がある。更に、設
      定した物が実行される前に消滅してしまう可能性すらある。ble-decode-char を
      その場で実行する方式にすると色々木にしなければならない事が多い。

    d conditional-sync に限っては ALRM を subshell から投げれば良いのでは。と思っ
      て試してみたが、何も設置していない状態で kill -ALRM $$ すると親シェルが終
      了してしまう。ALRM に何か無視する様に ble.sh でハンドラを設置しても良いが、
      それはそれでまた面倒事が増える。

    うーん。二つの方向性がある。全般に msleep の問題を解決するという事と
    conditional-sync の問題を解決するという事。今までの発生頻度から考えると
    conditional-sync の対策だけをしても当面は大丈夫な気もするが、何れは msleep
    の問題を完全解決したい。そうなった暁には conditional-sync の対策は不要にな
    るし、また conditional-sync の問題だけ解決するのは臭いものに蓋をしているだ
    けで本質的問題の解決にはなっていない。それよりは msleep 自体の問題を解決す
    る様に考えたいのである。

    仕方がないので cygwin と同じ手法で回避する事にした。

    2021-02-13 /dev/zero による workaround を追加したがよく考えたら /dev/zero
    が全ての環境にあるとは限らないし、ある環境でも read をブロックしてくれるか
    は微妙である。と思ったが /dev/zero で止まるかどうかは bash の側の実装の問題
    なので、もし /dev/zero が 0 を出力し続けるのであれば、ちゃんとブロックはす
    るだろうと思われる。

    /dev/zero が存在する環境について一度確認はしておきたい。Solaris, Minix に存
    在する。FreeBSD, Haiku にも存在した。当然 Cygwin と Linux にも存在する。
    MSYS2 でも OK だった。何れも read -t 0.2 < /dev/zero がちゃんと期待通りに動
    いた。という事を考えれば基本的に全ての環境で /dev/zero が使えると考えて良い
    のではないだろうか。

2021-02-04

  * global: read timeout は $?==142 とは限らない [#D1467]

    read timeout は本当に常に 142 なのか。と思ったが現在の用例では 142 は
    conditional-sync によって固定で返されているので気にしなくて良い。因みに
    bash のソースコードを確認する限りは 142 は hardcoded ではない。

    * edit (ble/builtin/read/.loop): うーん。予め 142 に対応する終了ステータス
      を調べておくか、或いは 128 以上を一括で timeout と解釈するか。マニュアル
      には "128 より大きな値になる" とだけ書かれている。マニュアルに従った判定
      にするのが良い気がする。

    * util (ble/util/msleep/.use-read-timeout): これは現在は使っていない。何れ
      にしても Cygwin/MSYS の時にだけチェックする様にすれば、これらのシステムで
      は 142 固定と期待されるので大丈夫。

  * util (bleopt): bleopt でパイプに繋いでいても _ble_term_sgr0 が出力されている場合がある [#D1466]
    追加で関連する関数に於いて --color オプションで着色を制御できるようにする。
    * "--color" options for bleopt, blehook, ble-color-setface

  * 2021-02-01 highlight: highlight_timeout_sync=0 にしても遅い (reported by 3ximus) [#D1465]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-770390986

    % OK. Sorry, I actually reproduce this level of delay at my side too, but I
    % haven't regarded it as *terrible*. That's probably because I know what
    % `ble.sh` is doing in the background. I felt that it's actually doing a good
    % job considering how strange things `ble.sh` is doing in the background.
    %
    % →と思ったが、bleopt highlight_timeout_sync=0 を実行していなかった。これを
    % 実行したら自分のところでは特に問題もなく動く様になった。当初は実装のバグか
    % とも思ったが、一部の host の上でだけ動作しないという事があるだろうか。
    %
    % Do you think it is related to `ffmpeg` running in the background? I see in
    % the `top` pane multiple instances of `ffmpeg` are running, but the load
    % average is smaller than 2, which means that those `ffmpeg` instances are
    % waiting for an interrupt in more than half of their running time. If those
    % `ffmpeg` are encoding some video clips, they may be waiting for disk I/O.
    %
    % →と思ったが disk I/O 待ちだと status D になる筈である。画面を見る限りはそ
    % うなっていない。更に -x11grab というオプションについて調べてみるとこれはス
    % クリーンキャプチャである。つまり、これらの ffmpeg は単にこの説明を作るため
    % に起動しているだけで、問題には関係してこない。

    何れにしてもこれは background highlighting におけるユーザー入力による中断速
    度に関係している。でもどの部分が悪さをしているのか分からない。

    1. 入力検出?
    2. 生存検出?
    3. 或いは kill & wait だろうか。

    どうも background highlighting のユーザー入力によるキャンセルの応答が遅い様
    である。自分の手元では残念ながら再現しない。取り敢えず勘で可能性のある時間
    のかかりそうな箇所に関連した時間計測を依頼したがぴんと来ない。多分、別の所
    に原因があるのではないか。

    2021-02-04 追加報告では遅い時もあるしそうでない時もあるそうだ。後、遅いとは
    言っている割にそれ程遅い訳でもない気がする。単に複数のパス名展開が試みられ
    るのでそれぞれについてタイムアウトが試みられて遅くなっているというだけなの
    ではないか。という訳で、取り敢えずの修正として一度 timeout を起こしたら後続
    の eval も即刻で timeout する様に修正した。

    それから conditional-sync をチェックする頻度も変更する事にする。取り敢えず
    これで改善するかどうか判断する事にする。

    | 後、timeout は total でカウントするべきなのかもしれない。或いは一つ
    | timeout したらそれ以降は timeout が必要になる物はもう処理しない様に変更す
    | る。

    2021-02-05 新しい報告で上記の cumulative timeout & shorter polling interval
    で改善するという事が確かめられた。問題は現在の cumulative timeout によって
    本来短時間で着色できる単語が着色されずに残ってしまう可能性について。

    然し、そもそも cumulative timeout で本当に改善しているのかというのは謎であ
    る。今 highlight_timeout_sync=0 にしている。とすると highlight_timeout_sync
    が効いていないか、或いは highlight_timeout_async の側での cumulative
    timeout が効いているか。highlight_timeout_async の側での timeout が効いてい
    るとすると何故なのか。ユーザー入力がある場合には何れにしても has-input の
    チェックによってキャンセルされるのではないか。うーん。手元で試してみたが余
    り違いが分からない。

    * done: syntax_eval_polling_interval について doc を記述する

  * 展開済みであっても展開される単語の数に比例して遅い (reported by 3ximus) [#D1464]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-772529714

    * 以前大量の入力を与えた時に遅いという事を解決した時に似たような事があった
      気がする。パス名展開がなかったとしても大量の単語を含む配列をコピーすると
      遅いという話。

      前に経験した時にはどの様な事が原因でどのように対策したのだったか。記録を
      漁ってみると #D1302 に関連しそうな内容が書かれている。

      > chars=("${...[@]}" "$@") が 13 秒もかかっている。何故?

      うーん。改めて試してみたがそんなに遅くない。関数経由で代入して改善したと
      いう事が書かれているが、実際に試してみても関数経由で代入すると却って遅く
      なる。またパス名展開の影響かとも思ったが set -f しても大して変化しない。
      結局再現はできない。

      再現ができないので現在発生している問題が具体的にどういう物なのか調べる事
      もできない。取り敢えずまた計測をお願いするしかないのだという気がする。予
      想では cache が巨大である為に起こっている事ではないか。

    * reject: そういう意味では既に議論した様に、単語ごとに展開済みの単純な情報
      を記録する事にして必要になった時は eval まで取りに行くのではなくて一部だ
      け記録する事にするという手もある。

      →今は其処までしなくても良いという気がする。

    取り敢えず simple-word/eval のキャッシュとして完全な情報を記録する物と、最
    初の単語だけ記録する物を用意して、highlighting の内部では主に最初の単語だけ
    を参照する様に変更した。

  * syntax: tilde で始まる単語の着色がされない? (reported by 3ximus) [#D1463]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-772529714

    と思ったがそうでもない。条件が不明

    % notilde 関連かと思ったが違った。どうも evaluate-path-spec が after-sep の時
    % に変な振る舞いをしている。spec の抽出に失敗している。
    %
    % $ ble/syntax:bash/simple-word/evaluate-path-spec '~/work/idt/**/*.sh' after-sep
    % $ declare -p spec path
    % declare -a spec=([0]="~/wo" [1]="~/work/id" [2]="~/work/idt/**/*." [3]="~/work/idt/**/*.sh")
    % declare -a path=([0]="/home/murase/wo" [1]="/home/murase/work/id" [2]="" [3]="/home/murase/work/idt/agh/src/addon/make_latex_embedfont_css.sh")
    %
    % と思ったら単に evaluate-path-spec の使い方を間違っていただけだった。
    % 正しく sep を指定したら evaluate-path-spec の結果は期待した物になった。

    改めて evaluate-path-spec の中で何が起こっているのか調べたら確かに失敗している。

    wtxt='~/**/*.sh' path_opts='stopcheck:timeout-highlight:cached:after-sep' ext='1'
    spec=('~/' '~/**/' '~/**/*.sh')
    path=('/home/murase/' '' '')

    どうも stopcheck の有無で結果が変わる様である。
    ble/syntax:bash/simple-word/eval '~/**/*.sh' stopcheck; ext=$?; ble/debug/print-variables ext ret

    問題を狭めて行った所、原因が分かった。これは単純なミスである。
    command="print-result $word" とするべき所を 'print-result $word' にしていた。修正した。

2021-02-03

  * edit: status line に対応しても良いのではないか [#D1462]

    →改めて確認してみた所、prompt_status_line という設定が既に存在していた。

    ? terminfo tsl/fsl に対応している TERMは存在するのか

      これは terminfo の tsl fsl を使って何かを表示する物だが、実のところ
      tsl/fsl に対応している TERM はなかなかない。少なくとも screen, xterm は違
      う。

      * tmux の term entry には tsl/fsl が存在しているが、シーケンスを見るとこ
        れは prompt_xterm_title と同じ OSC であって間違っている。terminfo の説
        明を読む限りに於いては、tsl/fsl は端末の特別な行で内部ではエスケープシー
        ケンスなども普通に使える物と見られる。という事を考えると、tmux の様に振
        る舞うのは間違っている気がする。

      * cygwin も tmux と同様である。但し、OSC 0 ; ではなくて OSC ; になってい
        る。0 は省略可能という事なのだろう。

      * kterm には \e[?E\e[?..T ... \e[?F という物が登録されている。
      * aixterm は \e[?..T ... \e[?F
      * aixterm は \e[?..T ... \e[?F

      うーん。何れにしても最近の端末エミュレータに存在する様な物ではない気がする
      ので、取り敢えず prompt_status_line は ble.sh の新しい機能の為に使う事にし
      てしまって良い。

    既存の tsl/fsl によるタイトルは別名の設定にする事にする。
    prompt_terminfo_status という名前にでもするか。terminfo だけでなく termcap
    にも存在するようだから、prompt_termcap_status の方が良いのかもしれない。或
    いは、prompt_term_status にするか。

    * status line の区別がやはり付きにくい。背景色を設定できる様にしても良いのではないだろうか。
      元々 trace にその様な機能があった様な気がする。改めて確認する。なかったので新しく実装した。

  * syntax: echo ${!_} と入力すると誤った代入ですというエラーメッセージが表示される [#D1461]
    そもそも "${!_}" を実行しようとするとエラーメッセージが出るが、
    これが着色等の際に発生するのは良くない。何処で発生しているのか確認する必要がある。

    これは新しく追加した ble/syntax:bash/simple-word/is-simple-noglob の中で起
    こしている展開に対して2>/dev/null を付加すれば良かった。未だ master に push していない
    修正なので commit を fixup しようかと思ったが、実装ログが面倒な事になるので、
    下手に fixup するのは止める事にする。

  * benchmark: EPOCHREALTIME は LC_NUMERIC 依存 (reported by 3ximus) [#D1460]

    報告の画像で出ているエラーが何だろうと思って ble-measure の実装を
    見たが変な事はない。と思ったが此処で気づいた。EPOCHREALTIME の小数
    点は locale 依存である。という訳で対策する事にした。

  * global: help の類の整理 [#D1459]
    * bleopt: --help に対応していない
    * blehook: --help が単純すぎる

  * canvas: status line を最終行に表示する可能性 (suggested by 0neGuyDev) [#D1458]
    https://github.com/akinomyoga/ble.sh/issues/85

    元々の提案は vim の mode 名という事だったが、vim の mode 名だけを最終行に表
    示するのか、或いは補完候補等の情報も全て最終行付近に表示するのかという可能
    性がある。Emacs 等を考えると補完候補も最終行に表示するのが自然な気がする。
    なので、実装としては info を丸ごと一番最後に表示する可能性について考えて良
    い気がする。

    最終行に表示する為に必要な事。

    a 一つの方法は \e7 \e8 で現在位置を記録するという事。これは visible-bell で
      既にやっている事。問題になるのは info の内容を構築する時に \e7 \e8 を使え
      ないという事。trace に明示的に禁止・代替するオプションを付ける必要がある
      かもしれない。

    b もう一つの方法は DSR(6)/CPR で問い合わせるという方法。実はこの方法は未だ
      ble.sh には積極的に取り入れた事はない。とはいいつつも歴史的な端末でも軒並
      みこれに対応しているので、全ての端末で使えると思って良い。問題になるのは
      応答に時間がかかるので頻繁に問い合わせる訳には行かないという事。どのタイ
      ミングで問い合わせるのが良いのか非自明であるという点。

    取り敢えず実装としては a の方針を試すのが自然な気がする。実は canvas の
    panel を調整するだけで、他の部分は触れずに実装できてしまうのではないだろう
    か。前にも似た様な事を考えた事があるような気がしないでもない。

    自身の高さ変更だけでなく他の panel の高さ変更の時にも注意が必要。
    特に高さを増やす時。

    * ok: bell を表示する為の行が canvas origin の一つ上に確保されている事に注
      意する。と思ったが、\e7\e8 で移動するのであれば実は余り関係ないという気が
      する。

    ? reject: 間に適当な高さの空 panel を設置すれば良いのではないか、と思ったが
      間の高さが不明なので関係ない。

    * vfill 以降の高さが 0 の時に変な事が起こらないか
      →これについてはちゃんと意識して実装する事にした。

    うーん。取り敢えず実装した。canvas.sh に対する修正だけで大体動いているが細
    かい所で変な事が起こっている。

    x fixed: C-l をしても画面の一番上に移動しなくなってしまう。何故だろうか。
      →これは clear-screen する時に下部に excursion している状態で行っていたので、
      その後 textarea を描画する時に _ble_term_rc で位置が復元されるのが原因だった。

    x 空コマンドを実行した時に info が押し出されて消える。実装を見ると
      ble/widget/.insert-newline の *:keep-info:* が該当する部分だがちゃんと動
      きそうな気がする。と思ったら canvas.sh の panel#increase-total-height が
      未実装だったのを思い出した。

      % と思ったがよく見たらちゃんと実装できている気がする。然し整理した。それで
      % も動かない。そもそも普通に C-q C-j で改行を入力した時も info が消えてしまっ
      % ている。うーん。increase-height に失敗している?

      やっぱり実装できていなかった。端末の高さが十分に高い時は、全体の高さは増
      えない。うーん。制御機能を工夫してこれを何とかする方法は実際に存在するの
      だろうか。勿論 CPR や他の機能を使えば可能なのだろうと思うが基本的な移動と
      IND RI の組み合わせでできない物だろうか。

      うーん。無理の気がする。CUU&CUD の累積でできるのではないかと考えたが、累
      積させる方法が存在しない。


      やはり DECSTBM 等に依存するしかないのだろうか。或いは CPR を利用する。も
      しくは、再描画する。再描画が現実的な気がする、と思ったがサイズが変化する
      可能性がある場合全般に問題が発生するので、やはり現実的ではないように思わ
      れる。うーん。CPR を毎回発行して現在位置を記録する様にした方が良いのだろ
      うか。

      a reject: CPR の可能性について→余り現実的でない気がする

        ble/term/enter の辺りで CPR を発行する様にする事を考えたが。或いは
        ble/textarea#invalidate を発行する度に実行した方が良いのではないか。うー
        ん。然し、描画しようとしている時に即座に返答が帰ってくる訳でもない。と
        いって CPR が帰って来るまでブロックするというのも変だし、続きを async
        に処理するとういのも変である。やはり CPR は飽くまで補助的に使うべきなの
        だという気がする。或いは、画面の大きさが変わる時に初めて CPR 要求を出す
        という考え方もある。然し、そうすると async に処理しなければならなくな
        る…或いはその場で入力を待っても良いのかもしれないが…やはり駄目。別の
        入力を先に受信したりすると変な事になる。

      b done: 再描画の可能性について→呼び出し元で再描画が必要化判定するのは困難なの
        で event を発火するなどして対処する。

        実の所、再描画の為の関数を用意する筈だったので丁度良いのではないか。うー
        ん。再描画というよりは invalidate して、後で再描画するという形にするの
        が良い。invalidate については…。全体を invalidate するというのも考えら
        れるが一部を invalidate するというのも考えられる。矩形で invalidate さ
        れた領域を記録できる様にするのが良い気がする。

        →invalidate を呼び出してそれからそれを記録して、更に次の render の時に
        改めて反映させるというコードを ble-edit/info について新しく書いた。
        ble/textarea に関しては既に実装した関数を適当に呼び出すだけで良いという
        事にする。

      c done: DECSTBM を使う可能性について。取り敢えず最近の端末はこれに対応している
        だろうと想像されるのでこれを使うというので良い気がする。ble.sh 起動時に
        DECSTBM に対応しているかどうかを検出する。

    * done: DECSTBM の判定コード
      取り敢えず判定コードを書いた。

      →と思ったら行が消滅してしまう。うーん。→ IND の代わりに CUD を使って
      DECSTBM をテストする事にした。動いている。OK

    x fixed: cursor-position (DECSTBM が使えない場合) が info の中になってしまっている
      _ble_canvas_panel_focus という変数を用意した。
      然し、それでも振る舞いが変である。

    x fixed: (DECSTBM が使えない場合) 一番最後の行での描画が重複している。

      DECSTBM の有無で振る舞いが逆になってしまっている。これは明らかに
      set-height の振る舞いに (少なくとも片方は) 間違いがあるという事。

      →これは単純にバグだった。

    x fixed: DECSTBM を使っている時に一番最後から二行目が使われない。

      DECSTBM を使わない場合にはちゃんと動いているのでここにも何が間違いがある。

    * util (visible-bell) との干渉について

      x fixed: 実は visible-bell の実装にバグがある。

        RI を使って現在編集のコマンドと被らない様にしているが、実は現在行と被らな
        い様にしているだけであって、実際には編集文字列の2行目以降にいる時には
        visible-bell が上書きしてしまう。

      x fixed: 先頭行の visible-bell で info が消滅する。

      * resolved: _ble_term_{sc,rc} ... util.sh で使っている箇所がある

      * ok: visible-bell の中の trace で sc rc を使えない様にするべきでは? と思っ
        たが、visible-bell は純粋な text という事になっているので今は関係ない。
        将来的には esc seq も指定できる様にする可能性もあるが今は考えない。

    * resolved: ble/canvas 内で他にも _ble_term_{sc,rc} を使っている箇所がある。
      これは曖昧文字幅の問い合わせに使っていた。

    * ok: _ble_term{sc,rc} は edit.sh でも使っている箇所がある。
      →adjust-eol で使っている。これは大丈夫の筈。

    * ok: ble/canvas/panel#report-cursor-position 等については影響がないか確認
      が必要。ble/canvas/panel#get-origin についても。

      get-origin に関しては core-complete.sh で menu の構築で使われている様だが、
      絶対位置として他の panel の座標系と混ぜて使っている訳ではないので問題ない。

      report-cursor-position に関してはパネルの局所座標を引数に指定しているので
      呼び出し元は気にしなくて良い。特に問題も無い様に思われる。

    * done: trace で SC/RC を emulate する (with opts=noscrc)

    * done: bleopt で制御できる様にする

    * blerc に bleopt info_display を追記する。

2021-02-01

  * complete: support "bleopt complete_timeout_compvar" (motivated by 3ximus) [#D1457]
    https://github.com/akinomyoga/ble.sh/issues/82#issuecomment-770390986

    これは progcomp の関数を呼び出す時にパス名展開を実行しているからである。
    一応、応答がなくなるという事はないが補完に不自然に時間がかかるのは避けたい。
    progcomp の為に展開する時は noglob で展開する事も考えたが、
    展開した文字列を quote しているので、noglob で呼び出すと例えば *.txt
    が '*.txt' 等になってしまって意図しない結果になってしまう。

    どの様にするのが良いのかは不明である。或いは timeout したら '*.txt' にして
    しまうというのでも良いのかもしれない。

    bleopt complete_timeout_progcomp_glob=200 等の設定にして、timeout したら
    noglob で呼び出すというので良い気がする。

    retry-noglob-on-timeout という opts を追加する事にする。

    新しい bleopt の変数名は何が良いだろうか。

      complete_timeout_progcomp_glob だと長い。
      それに似たような変数が沢山あって気になる。
      そもそも単に timeout としていると何の timeout か分からない。

      ちゃんとした名前にするなら glob_timeout が良いが長い。
      一単語でこれを表現できないか。fsys_timeout, path_timeout, ...
      やはり専用の単語は存在しない以上は一単語にするのは難しい。
      また、似たような設定をまとめるという立場からすると以下の様な
      変数名で良いのではないかという気もしないでもないが、微妙。

        glob_timeout_progcomp
        glob_timeout_sync_highilght
        glob_timeout_async_highilght
        glob_timeout_auto_complete

      やはり highlight_*, complete_* という名前にしたい。

        highlight_timeout_sync
        highlight_timeout_async
        complete_timeout_auto
        complete_timeout_compvar

    →これは実際に試してみたが改善していない。

  * setup を動詞の様に使っている箇所が多くて気になるので修正する [#D1456]

    set up に代わる動詞を探しても余り良いのが見つからない。文脈に応じて全く違う
    表現に改めた関数もある。set up だけの場合には関数名としてはくっつけて setup
    としても良い事にした。setup-xxx というのは気になるのでせめて set-up-xxx の
    様に変更した。

2021-01-30

  * edit: emoji の表を更新する (reported by endorfina) [#D1455]
    https://github.com/akinomyoga/ble.sh/issues/84

    更新しようと思ったが現在のコードを確認すると色々工夫して高速化している。
    少し面倒である。取り敢えずデータのダウンロードだけは行う事にする。

    https://unicode.org/Public/emoji/

    色々考えて現在のコードの構造に近い形で再実装した。実は以前の実装に
    はバグがあった。

    以前のテーブルは https://github.com/vim-jp/issues/issues/1086 から
    拾ってきた物だったが、これは 2017 年の物だったので報告のあった
    flamingo の絵文字 (2018) は含まれていなかったのだ。

  * syntax: 構文解析で無限ループになっている [#D1454]

    特定のコマンドの編集で固まってしまったので gdb でアタッチしてみたらstack が
    300 段ぐらいまで成長している。問題の起こるコマンドを探ってみると、[[ ]] が
    あるかどうかで振る舞いが変わる様だ。

    [再現]

    $ for f in *; do [[ ]]; done

    に於いて、* の直前に "out/" を挿入しようとすると無限ループになる。 [[ ]] で
    はない別のコマンドの時には発生しない。


    [原因]

    | 構文構造を確かめてみると確かに構造が破壊されている。正常な場合にはちゃんと
    | 単語の chain が繋がって木構造を形成している。しかし、問題が起こるコマンドの
    | 場合、[[ ]] の兄要素が記録されていない。唯、これだけで無限ループになるとい
    | うのも変である。無限ループになってしまう原因も探りたい気がする。
    |
    | 正常時
    |
    | | $ for f in *; do :; done
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18*a    000 'f' | stat=(CMDX w=- n=- t=-:-)
    | |  |*a    001 'o' |
    | |  |*a    002 'r' + word=CMDI:0-3/(wattr=d)
    | | 16*a    003 ' '   stat=(FARGX1 w=- n=- t=$3:-)
    | |  7*a    004 'f' + word=ARGI:@2>4-5/(wattr=d) stat=(FARGX1 w=- n=- t=$3:-)
    | | 36*a    005 ' '   stat=(FARGX2 w=- n=- t=$5:-)
    | | 37*a    006 'i' | stat=(FARGX2 w=- n=- t=$5:-)
    | |  |*a    007 'n' + word=FARGI2:@4>6-8/(wattr=d)
    | | 58*a    008 ' '   stat=(FARGX3 w=- n=- t=$8:-)
    | | 31*aw   009 '*' + word=ARGI:@7>9-10/(wattr=m1:72057594037934596) stat=(FARGX3 w=- n=- t=$8:-)
    | | 12*a    010 ';'   stat=(FARGX3 w=- n=- t=$10:-)
    | | 68*a    011 ' '   stat=(CMDXD w=- n=- t=$10:-)
    | | 20*a    012 'd' | stat=(CMDXD w=- n=- t=$10:-)
    | |  |*a    013 'o' + word=CMDI:@9>12-14/(wattr=d)
    | | 17*a    014 ' '   stat=(CMDX1 w=- n=- t=$14:-)
    | |  2*aw   015 ':' + word=CMDI:@13>15-16/(wattr=72057594037930241) stat=(CMDX1 w=- n=- t=$14:-)
    | | 12*a    016 ';'   stat=(ARGX w=- n=- t=$16:-)
    | |  1*a    017 ' '   stat=(CMDX w=- n=- t=$16:-)
    | | 19*a    018 'd' | stat=(CMDX w=- n=- t=$16:-)
    | |  |*a    019 'o' |
    | |  |*a    020 'n' |
    | |  |*a    021 'e' + word=CMDI:@15>18-22/(wattr=d)
    | |  |    s 022 ^@   stat=(CMDXE w=- n=- t=$22:-)
    | | \_ 'for'
    | | \_ 'f'
    | | \_ 'in'
    | | \_ '*'
    | | \_ 'do'
    | | \_ ':'
    | | \_ 'done'
    |
    | 異常時
    |
    | | $ for f in *; do [[ ]]; done
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a    000 'f' |  stat=(CMDX w=- n=- t=-:-)
    | |  | a    001 'o' |
    | |  | a    002 'r' +  word=CMDI:0-3/(wattr=d)
    | | 16 a    003 ' '    stat=(FARGX1 w=- n=- t=$3:-)
    | |  7 a    004 'f' +  word=ARGI:@2>4-5/(wattr=d) stat=(FARGX1 w=- n=- t=$3:-)
    | | 36 a    005 ' '    stat=(FARGX2 w=- n=- t=$5:-)
    | | 37 a    006 'i' |  stat=(FARGX2 w=- n=- t=$5:-)
    | |  | a    007 'n' +  word=FARGI2:@4>6-8/(wattr=d)
    | | 58 a    008 ' '    stat=(FARGX3 w=- n=- t=$8:-)
    | | 31 aw   009 '*' +  word=ARGI:@7>9-10/(wattr=m1:72057594037934596) stat=(FARGX3 w=- n=- t=$8:-)
    | | 12 a    010 ';'    stat=(FARGX3 w=- n=- t=$10:-)
    | | 68 a    011 ' '    stat=(CMDXD w=- n=- t=$10:-)
    | | 20 a    012 'd' |  stat=(CMDXD w=- n=- t=$10:-)
    | |  | a    013 'o' +  word=CMDI:@9>12-14/(wattr=d)
    | | 17 a    014 ' '    stat=(CMDX1 w=- n=- t=$14:-)
    | | 12 a    015 '[' || nest=(ARGX0 w=- n=- t=-:-) stat=(CMDX1 w=- n=- t=$14:-)
    | |  | a    016 '[' |+ word=CMDI:15-17/(wattr=d)
    | | 32 a    017 ' ' |  stat=(CONDX w=- n=@15 t=$17:-)
    | | 12 a    018 ']' || stat=(CONDX w=- n=@15 t=$17:-)
    | |  | a    019 ']' ++ word="none":15-20>@19 word=CONDI:@16>18-20/(wattr=d)
    | | 12 a    020 ';'    stat=(ARGX0 w=- n=- t=$20:-)
    | |  1 a    021 ' '    stat=(CMDX w=- n=- t=$20:-)
    | | 19 a    022 'd' |  stat=(CMDX w=- n=- t=$20:-)
    | |  | a    023 'o' |
    | |  | a    024 'n' |
    | |  | a    025 'e' +  word=CMDI:@19>22-26/(wattr=d)
    | |  |    s 026 ^@    stat=(CMDXE w=- n=- t=$26:-)
    | | \_ '[[ ]]'
    | | |   \_ '[['
    | | |   \_ ']]'
    | | \_ 'done'
    |
    | どうも auto-complete が有効になっていると発生する様だ。
    | 入力のタイミングにも依る。一旦構文解析が終了してから無限ループに入る。
    |
    | 無限ループに入る時の構造
    |
    | | $ for f in out/*; do [[ ]]; done
    | | _ble_syntax_attr/tree/nest/stat?
    | | 18 a    000 'f' |  stat=(CMDX w=- n=- t=-:-)
    | |  | a    001 'o' |
    | |  | a    002 'r' +  word=CMDI:0-3/(wattr=d)
    | | 16 a    003 ' '    stat=(FARGX1 w=- n=- t=$3:-)
    | | 26 a    004 'f' +  word=ARGI:@2>4-5/(wattr=d) stat=(FARGX1 w=- n=- t=$3:-)
    | | 36 a    005 ' '    stat=(FARGX2 w=- n=- t=$5:-)
    | | 37 a    006 'i' |  stat=(FARGX2 w=- n=- t=$5:-)
    | |  | a    007 'n' +  word=FARGI2:@4>6-8/(wattr=d)
    | | 58 a    008 ' '    stat=(FARGX3 w=- n=- t=$8:-)
    | | 59*a    009 'o'    stat=(FARGX3 w=- n=- t=$8:-)
    | |  |*a    010 'u'
    | |  |*a    011 't'
    | |  |*a    012 '/' |
    | | 31 a  s 013 '*' +  word=ARGI:@10>12-14 stat=(FARGI3 w=FARGX3:9- n=- t=-:$8)
    | | 12 a  s 014 ';'    stat=(FARGX3 w=- n=- t=$14:-)
    | | 68 a  s 015 ' '    stat=(CMDXD w=- n=- t=$14:-)
    | | 20 a  s 016 'd' |  stat=(CMDXD w=- n=- t=$14:-)
    | |  | a  s 017 'o' +  word=CMDI:@13>16-18/(wattr=d)
    | | 17 a  s 018 ' '    stat=(CMDX1 w=- n=- t=$18:-)
    | | 12 a  s 019 '[' || nest=(ARGX0 w=- n=- t=-:-) stat=(CMDX1 w=- n=- t=$18:-)
    | |  | a  s 020 '[' |+ word=CMDI:19-21/(wattr=d)
    | | 32 a  s 021 ' ' |  stat=(CONDX w=- n=@19 t=$21:-)
    | | 12 a  s 022 ']' || stat=(CONDX w=- n=@19 t=$21:-)
    | |  | a  s 023 ']' ++ word="none":19-24>@23 word=CONDI:@20>22-24/(wattr=d)
    | | 12 a  s 024 ';'    stat=(ARGX0 w=- n=- t=$24:-)
    | |  1 a  s 025 ' '    stat=(CMDX w=- n=- t=$24:-)
    | | 19 a  s 026 'd' |  stat=(CMDX w=- n=- t=$24:-)
    | |  | a  s 027 'o' |
    | |  | a  s 028 'n' |
    | |  | a  s 029 'e' +  word=CMDI:@23>26-30/(wattr=d)
    | |  |    s 030 ^@    stat=(CMDXE w=- n=- t=$30:-)
    | | \_ '[[ ]]'
    | | |   \_ '[['
    | | |   \_ ']]'
    | | \_ 'done'
    |
    | うーん。変だ。やはり構文解析で起こっている無限ループではない様だ。とすると
    | 何が別の箇所で無限ループになっている。特に auto-complete で起こっているとい
    | う事、応答もしなくなる (SIGINT にも反応しない) という事から、
    | eval-pathname-expansion が怪しいのではないか。
    |
    | やはり /dev/zero で問題が発生しているという事なのだろうか…と思ったが、
    | msleep を read -t を使わない手法に置き換えても同様に無限ループになる事から
    | read -t ... /dev/zero の問題ではない。(それに [[ ]] によって構文構造がおか
    | しくなっている時にのみ発生するという事だから、やはり構文構造に関係のある問
    | 題なのだろう)。
    |
    | * 一つ怪しい箇所は extract-command である。core-complete.sh 関連でコマンド
    |   ライン内部の文法構造に関連する所と言えばこれしかない気がする。→実際に確
    |   かめてみたが無限ループは extract-command とは関係ない所で起こっている様だ。
    |
    | * パス名展開の中で起こっているとも考えにくい。何故ならばファイルの少ない場
    |   所でも問題が発生しているから。それに関数呼び出しが何十段にもなる事から、
    |   関数呼び出し自体で問題が発生しているというのは明らかである。
    |
    | 呼び出されている関数名を調べる事ができれば簡単なのだが難しい。
    |
    | * そもそも本当に auto-complete.idle の中で発生しているのだろうか。と思って
    |   確かめたらどうやら違う様だ。だとすると、bgworker による textarea#render
    |   が怪しい?
    |
    |   調べてみたらそうだった。更に textarea#render の中で怪しい所に絞り込みをか
    |   ける。どうやら update-text-buffer の中で問題が発生している。update-syntax
    |   の問題ではないようだ。update-text-buffer の中では layer/update を呼び出し
    |   ているので、恐らく layer:syntax/update が変な事になっているのだろう。
    |
    |   やはり ble/highlight/layer:syntax/update-word-table の中で無限ループになっ
    |   ている様だ。
    |
    |   ble/syntax/tree-enumerate-in-range で無限に要素が列挙されているか、或いは
    |   ble/highlight/layer:syntax/word/.update-attributes/.proc の中で無限ループ
    |   になっているかである。後者だった。
    |
    |   ble/syntax:bash/extract-command-by-noderef が怪しい。実際に中を調べるとど
    |   うやら ble/syntax/tree#previous-sibling が無限に兄要素を生成している様だっ
    |   た。何故その様な事になるのか。
    |
    | OK. 原因が分かった。
    | 1. 木構造が壊れている
    | 2. 単語情報のシフトに失敗する
    | 3. 兄要素の位置がずれて何も単語が登録されていない位置を参照している
    | 4. 空の単語情報なので兄の相対位置が '' = 0 に評価されて自己参照している。
    | という具合にして空単語でループが出来上がっている。実際に問題が起こっている
    | 時の木構造を見るとその様になっている。

    まとめると二つの問題がある。

    * [[ ]] の解析で構文木の兄情報が欠けてしまっている。nest-push する時に何故
      か tprev が記録されていないのが原因であろう。

    * 木構造が壊れている時に ble/syntax:bash/extract-command-by-noderef の中で
      兄ノードを探索する時に、一旦、空の単語情報に行き当たると自己参照して無限
      に兄ノードを取得してしまうという問題がある。

    [修正]

    後者に関しては、単語がちゃんと登録されているかどうか確認する様に実装を変更
    した。構文木の欠陥があった場合にそれを出力する様にした。これで構文木が壊れ
    ていても無限ループにはならない。

    前者に関しては何処で問題が生じているか分かった気がする。word-cancel した時
    に tprev の情報を復元しきれていないという事。然し、不思議なのは word-cancel
    は単語が設置された後に呼び出されるのだから tprev は既にその新しい値になって
    いる筈だという事。なので、改めて tprev を計算する必要はない筈なのである。

    うーん。もしかして二回連続で word-pop が起こった為に情報が消滅しているとい
    う事だろうか…。つまり nest-pop も既に終わっている状態という可能性?

    →恐らく2回連続で word-pop をした時に、外側の word から順に pop しているの
    がいけないのではないか。内側の word から順に pop するべきという事の気がする。
    いや、それも変だ外側の word を pop する時に内側の単語も全部削除するべきなの
    ではないか。うーん…? 或いは単語を設置する直前の状態に復元するというのが正
    しい振る舞いだろうか。

    改めて振る舞いについて何が起こっているのか考える事にする。

    A B [ [ X Y ] ] という状態になっている。但し [...] が単語の範囲である。そも
    そもどう言った情報が記録されているかというと。

    * 外側の単語については、tchild=(Yの位置), tprev=(Bの位置) になっている。
    * 内側の単語については、tchild=- tprev=- になっている。
    * 二つの単語を設置し終わった時の解析状態は、tchild=(Yの位置) tprev=- である。
    * 一つ単語終端を削除した時の解析状態は tchild=(Yの位置) tprev=(Bの位置) であるべき。
    * 更にもう一つ単語終端を削除した時の解析状態は tchild=- tprev=- になる。
      → word-cancel を2回施した時はこの状態を復元しているという事。

    実際の振る舞いを見ると tprev が初めから空になっている。これは nest-push を
    実行した為の気がする。nest-pop もちゃんと実行しておくべきの気がする? うーん。
    確認してみると別に nest-push した事によって tprev になっている訳ではない気
    がする。どういう事だろうか。そもそも inest=-1 になっている。変だ。

    ※現在の解析状態は "もしここで単語を閉じたらその単語にどの様な tchild,
    tprev が割り当てられるか" を表している。つまり、現在の文脈における
    tchild/tprev ではなくて、一つ上に上がった時の tchild/tprev である事に注意す
    る。

    よく分からなくなった。取り敢えず現在の実装を理解することは諦めて、改めてど
    の様に実装するべきかについて考えてみることにする。word-cancel は二種類の考
    え方がある。それぞれについて適切な実装は何だろうか。

    a 閉じてしまった単語を閉じる前の状態にする。

      この場合には実は単純に word に格納されている tclen tplen をそれぞれ
      tchild tprev に変換すれば良い。

    b そもそも単語がそもそも始まるよりも前の状態に戻す。

      この場合には tchild は記録されている単語の tprev で、tprev については変化
      はない。という事を考えると…。実は現在の実装はこちらを狙った物であると考
      える事ができる。

      この場合には word-cancel は実は一回だけしか呼び出さなくて良い。そして、一
      番外側の単語を削除すると同時に中に設置されている単語も全て削除するべきで
      ある。中に設置されている単語を削除するにはどうすれば良いか。tchild を辿っ
      て削除していく必要がある。面倒な事である。というか、tprev に至る迄を全削
      除で良いのではないだろうか。

2021-01-28

  * syntax/simple-word/eval: キャッシュ機能を付ける [#D1453]

    特に一回の着色 (layer:syntax/update) の中では同じ評価は一回しかしない様に工
    夫したい。キャッシュは dict に保存したいが二種類の問題がある。

    1. eval の展開結果は配列なのでそれをどうにか再評価可能な形式に変換する必要
      がある。bash-4.4 以降であれば ${ret[@]@Q} を用いれば良い。古い bash では
      この形式に合わせて記録を行う。

    2. bash3 では dict がないので工夫が必要

    取り敢えずこれは必要である。

    | うーん。それどころか一つのキーストロークの中でずっとキャッシュしても良いの
    | ではないか。tail 辺りで clear すれば良い。と思ったが余り変な事をしても駄目
    | な気もする。これだと bind 以外の枠組みで syntax/simple-word/eval を呼び出し
    | た時にキャッシュが全くクリアされなくて問題に成るのではないか。
    |
    | 例えば ble/builtin/read を使った時にキャッシュクリアが全くされないという事
    | になってしまう。但し、現在は read に対しては構文着色も auto-complete も有効
    | にしていないが。うーん。或いは widget を呼び出すタイミングでキャッシュをク
    | リアするという手もあるかもしれない…が、やはり ble/textarea#render と同じタ
    | イミングでクリアするのが自然な気がする。うーん。
    |
    | ble/textarea#render の中で clear してしまう? と思ったが、それはそれでやはり
    | 問題になる。将来的に textarea ではない物に対するキーボード操作も考えたいと
    | いう事を思うと、textarea#render の中からキャッシュをクリアするというのはや
    | はり変だ。
    |
    | そもそも汎用性を考えるのだとしたら cache は opts に指定した時にだけ使うとい
    | うので良い気がする。キャッシュをクリアする関数も別に公開しておいて、cache
    | を使う場合には自分でキャッシュの管理をせよという事にすれば良いのである。


    * done: dict を整備する。
    * done: キャッシュする様にする
    * done: キャッシュクリア用の関数を公開する

  * 2021-01-26 util: Cygwin 上で ble/util/msleep がフリーズしてしまう [#D1452]

    | 何故だろうか。普通にユーザコマンドとして実行した場合には特に問題は発生して
    | いない。サブシェルで実行しても問題は発生していない。内部 stty でサブシェル
    | で実行すると問題が起こる?
    |
    | →どうも繰り返し実行すると発生する様である。
    |
    | 以下を実行するとかなりの確率で固まる。
    | ( echo {1..1000} & builtin read -t 0.000100 v < /dev/udp/0.0.0.0/80 ) >/dev/null

    以下によって通常の bash でも固まるという事が分かった。Cygwin 特有の振る舞い
    である。Linux 上で試した限りでは問題は起こらない。

    ( echo {0..1000} >/dev/null & builtin read -t 0.001 v < /dev/udp/127.0.0.1/80 )

    他の実装だと exec 9<(sleep) を起動して置くという物や、builtin sleep を使う
    という物がある。

    a builtin sleep

      builtin sleep はコンパイラが利用可能なときにしか使えないのでこれに依存し
      たくない。飽くまで exec 9<(sleep) を使って実装して可能であれば builtin
      sleep を使うという様にする形になる。

    b 現在の /dev/udp/0.0.0.0/80 を弄って解決できないか

      うーん。不思議だ。'echo {1..1000}' を a.sh に書き出して置いて以下の様にす
      ると再現しない。

      ( . a.sh >/dev/null & builtin read -t 0.001 v < /dev/udp/127.0.0.1/80 )

      関数を function a { echo {1..1000}; } として a>/dev/null とした場合は再現する。

      * builtin read は read に置き換えても発生する。
      * 0.0.0.0 を 0.0.0.1 にすると通信エラーになって別の意味で使えない。
      * 127.0.0.1/80 でも再現する。
      * >/dev/null を >a.txt にしても再現する。
      * read を試みる前に様々なリダイレクトをしてみても状況は変わらない。
      * {0..1000} の部分や 0.001 の部分を変えると発生確率が下がる。

      うーん。微妙。というか環境が Cygwin だけというのであれば、最初からバイナ
      リを用意しておくという手もある。

      うーん。やはり Cygwin ではもっと別の実装を考えた方が良いだろうか。

    c exec 9< <(sleep)

      改めて exec 9< <(sleep) を試してみた所、遅延は殆どない様なので、これを採
      用する事にする。

    思えば今までにも時々あった Cygwin で固まってしまう問題はこれが原因だったの
    かもしれない。直前に fork してから is-stdin-ready を確認する機会が余りなかっ
    たり、或いはその他の条件で発生しにくかったりして再現しにくかったという事の
    気がする。という事を考えるとやはり /dev/udp/0.0.0.0/80 は今後は使わない方が
    良い気がする。

    →c の方法を使う事にした。古いコミットを参考にしてコードを復元する。
    8bb54be acb7163 d14557c f53c26d

    また udp によるコードを使いたくなるかもしれないので、取り敢えず今の所は
    bleopt internal_msleep_socket というオプションで udp 方式に切り替えられる様
    にしてコードを残しておく事にする。

    ----------------------------------------

    procsubst による実装に切り替えてもやはり同様の問題が発生する様だ…。
    うーん。どうした物だろうか。というかこれは bug-bash に報告しても良いのではないか。
    然し、normal Bash で再現させようとしても再現しない。然し症状としては同じなので、
    Cygwin における read のタイムアウトに問題があるという事は確かなのだろう。

    うーん。やはり Cygwin 用に特別にコンパイル済み sleep builtin を提供する?

    今試したら fifo が Cygwin 上でも動く様になっている。最近動く様になったのだ
    ろうか。或いは cygwin バージョンの問題だろうか。うーん。取り敢えず試しに動
    かしてみて、それで失敗したら procsubst に切り替えるという作戦にする。

    →駄目。やはり同じ問題が発生する。FIFO でも駄目という事。
    read -t を使うのが本質的に駄目という事なのだろう。
    唯、確率は格段に小さくなっている。

    sleep 10 | { echo {1..1000} >/dev/null & read -t 0.001 v; echo end; }

    この様にしている時には特に問題も発生しない様だ。

    builtin read -t "$v" v < "$$.pipe"

    この実装にしても固まる時には固まる。

    % 何と、builtin sleep を使っても同様に固まるという事が判明した。
    % つまり、read -t の問題ではない。Cygwin 自体に問題があるという事?
    % スレッドが停止するともう二度と動かないという種類の何か…。
    % →と思ったら勘違いだった。builtin sleep を使っているつもりが、
    % 別の方式をつかっていたのだった。

    一応 /dev/zero は期待通りに動く。但し、CPU 100% になるという事には注意する。
    短時間の sleep であれば /dev/zero に頼っても良いかもしれない。と考えたが、
    短時間の sleep を繰り返し使う場合などを考えるとやはり cpu100% になるのは好
    ましくない気もする。

    /dev/ptmx を試してみた。これはちゃんとブロックするし、勝手に停止してしまう
    事もないが代わりの問題として bash が終了しなくなってしまうという物がある。
    然し、通常の bash で同様の事をしても特に問題は発生しない様だ。何故だろうか。
    というか exec 9<&- を実行しようとしただけで固まってしまう。これは問題である。

    ble/util/msleep/.use-read-timeout socket check
    ble/util/msleep/.use-read-timeout fifo.exec2 check ||
      ble/util/msleep/.use-read-timeout procsub
    ble/util/msleep/.use-read-timeout fifo.open1
    ble/util/msleep/.use-read-timeout zero.open1
    ble/util/msleep/.use-read-timeout zero.exec1

    --------------------------------------------------------------------------

    結局 loadable builtin を使う事にしようと思って実装したが…。loadable
    builtin のライセンスはどうなっているのだったか。普通に考えるとこれは GPLv2
    に感染する気がする。という事は loadable builtin のソースコードをつけて配布
    するのは難しいという事になる。うーん。loadable builtin ならば OK という訳
    は…ないだろう。GPLv2 的に。調べたら正にそういう項目について記述されていた。

    https://www.gnu.org/licenses/gpl-faq.ja.html#GPLAndPlugins

    従って loadable builtins を使う方針は採用できない。結局、他の手法について考
    える必要があるのである。或いは確率が小さければ cygwin でも read -t を使って
    大丈夫だろうか、と思ったが conditional-sync を使っている限り、従来よりも格
    段に問題が起こる確率が高い。やはり read -t は諦めるべきだろうか。

    或いは conditional-sync の時だけ別の方法を用いるという可能性もある…。が、
    別の方法に心当たりがある訳ではない。どうしようもない。バイナリを添付する訳
    にも行かない。

    --------------------------------------------------------------------------

    取り敢えず /dev/zero では未だ hang が起きた事はないので、これで様子見する事にする。

  * util,syntax,complete: 配列内容の記録時に @Q を使った print に切り替える [#D1451]
    大した高速化ではないと思うがコードの整理も兼ねて。

  * syntax: auto-complete 内部の pathname-expansion についても conditional-sync を使う (motivated by 3ximus) [#D1450]
    https://github.com/akinomyoga/ble.sh/issues/82 (for auto-complete)

    取り敢えず [[ :$comp_type: != *:sync:* ]] の時には stop_check で実行して、
    それ以外の場合には強制的に実行するという方針で行く。

    ble/complete/util/eval-pathname-expansion に関してはそんなに面倒そうではない。
    ble/complete/util/eval-pathname-expansion は常にグロブパターンを伴って呼び出されるので場合分けは必要ない。
    常に conditional-sync を使えば良いのではないかという気がする。
    うーん。 *:sync:* が含まれる時だけはそのまま展開を実行する。
    →eval-pathname-expansion については対応した。恐らくこれで良いだろう。

    次に complete の内部から沢山の simple-word/eval を利用している。
    これらについても一つずつ確認して行く必要がある。

    以下の四つの関数が core-syntax.sh における stop_check を指定して実行するべき関数である。
    実際に使われているのは前者2つだけの様である。

    - ble/syntax:bash/simple-word/eval
    - ble/syntax:bash/simple-word/evaluate-path-spec
    - ble/syntax:bash/simple-word/detect-separated-path
    - ble/syntax:bash/simple-word/locate-filename

    |   $ grc 'simple-word/(eval|locate|detect)' lib/core-complete.sh
    | f lib/core-complete.sh:1970:    ble/syntax:bash/simple-word/eval "$subword" "$eval_opts"
    | f lib/core-complete.sh:1980:      ble/syntax:bash/simple-word/eval "$subword" noglob
    |   lib/core-complete.sh:2006:  ble/syntax:bash/simple-word/eval "$ret"; local value1=$ret
    |   lib/core-complete.sh:2011:      ble/syntax:bash/simple-word/eval "$ret"
    |   lib/core-complete.sh:2072:    ble/syntax:bash/simple-word/eval "$ret"; word=$ret
    |   lib/core-complete.sh:2093:          ble/syntax:bash/simple-word/eval "$ret"; left=$ret
    |   lib/core-complete.sh:2806:      ble/syntax:bash/simple-word/eval "$word" &&
    |   lib/core-complete.sh:2861:    ble/syntax:bash/simple-word/eval "$ret*" && ((${#ret[*]})) &&
    |   lib/core-complete.sh:3048:  local ret; ble/syntax:bash/simple-word/eval "$pattern"
    |   lib/core-complete.sh:3050:    ble/syntax:bash/simple-word/eval "$pattern*"
    |   lib/core-complete.sh:3223:    elif ble/syntax:bash/simple-word/eval "$reconstructed"; then
    |   lib/core-complete.sh:3229:        ble/syntax:bash/simple-word/eval "${reconstructed::${simple_ibrace#*:}}"
    |   lib/core-complete.sh:3234:      # Note: failglob により simple-word/eval が失敗した時にここに来る。
    |   lib/core-complete.sh:3624:  ble/syntax:bash/simple-word/evaluate-path-spec "$word0"; spec0=("${spec[@]}") path0=("${path[@]}")
    |   lib/core-complete.sh:3625:  ble/syntax:bash/simple-word/evaluate-path-spec "$word1"; spec1=("${spec[@]}") path1=("${path[@]}")
    |   lib/core-complete.sh:3705:        if ble/syntax:bash/simple-word/eval "$common_reconstructed" &&
    |   lib/core-complete.sh:3731:             ble/syntax:bash/simple-word/eval "$notilde$ret" noglob &&
    |   lib/core-complete.sh:3733:             ble/syntax:bash/simple-word/eval "$notilde$common_reconstructed" noglob &&
    |   lib/core-complete.sh:3761:                 ble/syntax:bash/simple-word/eval "$ret" &&
    |   lib/core-complete.sh:4206:      ble/syntax:bash/simple-word/eval "$ret"
    |   lib/core-complete.sh:4706:        ble/syntax:bash/simple-word/eval "$ret"
    |   lib/core-complete.sh:4930:  ble/syntax:bash/simple-word/eval "$ret"
    |   lib/core-complete.sh:5573:      if ble/syntax:bash/simple-word/eval "$ret" && local compv_new=$ret; then
    |   lib/core-complete.sh:5968:      ble/syntax:bash/simple-word/eval "$ret" || continue

    - ble/complete/progcomp/.compvar-generate-subwords/impl2
      この関数は eval を呼び出している。複数の単語に展開される時にそれを全て取得している。

    - ble/complete/source:argument/.contains-literal-option
      この関数は noglob を指定して変換を試すべきの気がするのでその様に変更する。

    - ble/complete/progcomp/.compvar-quote-subword

    - ble/complete/source:argument
      failglob で展開に失敗した時に * を付加して再度挑戦するのに使っている。
    - ble/complete/source:glob
    - ble/complete/candidates/.pick-nearest-sources
    - ble/complete/candidates/determine-common-prefix
    - ble/complete/candidates/determine-common-prefix/.apply-partial-comps
      ここでは evaluate-path-spec を使っている。
    - ble/complete/insert-common

    以上は候補生成時に使われる関数群である。
    全てユーザー入力があったらキャンセルという形で良い気がする。
    元々 148 を返す仕様の関数になっているので 148 の伝播についても面倒な対応は不要。

    - ble/complete/menu-filter
      これは .filter-candidates の戻り値を返すのを忘れている気がする。
      →修正した。

    - ble/widget/auto_complete/self-insert
      これは微妙。どの様にすればよいだろうか。
      timeout はまあいらない気がする。
      ユーザー入力によって interrupt されたらそのまま false を返せば、
      auto_complete モードから抜けるという動作になる。これで良い。

    - ble/complete/source:sabbrev
      % 展開した結果が使用されていない。バグが有る気がする。
      % →と思ったが iniitialize の中で参照されていた。

    [修正]

    * done: 毎回 timeout 等を設定するのは大変なので関数を用意する。
    * done: simple-word/{eval,evaluate-path-spec} の呼び出しを置き換える。

    x timeout した時に 142 を返すのを 148 に置き換えているが、
      これだと auto-complete 内部で timeout した時に、
      後続の idle まで中断してしまうのではないだろうか。

      →これは idle.do の側で修正する事にした。そもそも IS_IDLE で条件を差し替
      える事ができるようにしているので、呼び出した task の終了ステータスを信用
      する訳には行かない筈なのだ。

      此処で気になるのは complete における 148 の意味が必ずしもユーザ入力ではな
      くて、auto-complete における timeout の場合もあるという事になってしまった
      事だが、これが重大な結果を生み出す様には思われないので、取り敢えずはこれ
      で良いとする。

  * highlight: グロブパターンが含まれるファイル名の着色が遅い (reported by 3ximus) [#D1449]
    https://github.com/akinomyoga/ble.sh/issues/82 (for highlighting)

    glob expansion を subshell で実行してユーザー入力があったら timeout させる
    方針について考察。timeout は必要だろうか。

    * 或いは、もういきなり中断しても良いかもしれない。着色は次の rendering の時
      に反映させれば良いという発想。然し、その場合には再 rendering を発生させる
      為にどうにかして部分 invalidate しなければならない。或いは再描画の条件に
      着色未完の状態を含めても良いのかもしれない。着色の更新に関しては
      ble/textarea#update-text-buffer を呼び出した時に実行される。実は dirty
      range の有無に関わらず毎回 layer/update は呼び出される様だ。考えてみれば
      region の着色等は dirty range に関係なく変化する可能性があるので、この振
      る舞いも妥当である。

      一般に単語着色に関してはユーザーの入力があったら中断してしまって良いので
      はないだろうか。background worker の方で処理する事にすれば良い (但し、
      bash3 だと判定できないので難しい。bash3 に関しては loadable builtin が使
      えれば自前でそれを使ってしまうという手もある)。

    * キャッシュする可能性。同じ単語が繰り返し使われている場合に処理を短縮する
      為。これは特殊な場合にしか効果が現れない。余り効果はないのではないかとい
      う気がする。

    * globpat が含まれる場合にだけ subshell 実行する?
      globpat があるかどうかに関しては正規表現で判定すれば良い。

      "**" が含まれる場合にだけ subshell 実行するという可能性も考えたが、"*" や
      "?" だけでも大量のファイル名に展開される可能性もあるので、"*" だけ特別扱
      いしても仕方がない。

    * reject: ファイル数が多いディレクトリだけで subshell 実行する?

      ディレクトリ移動はそんなに頻繁に行わない筈なのでファイル数をディレクトリ
      移動をする度に確認すれば良いのではないか。と思ったが引数に
      dir1/dir2/... と指定する事もできるのでファイル数が多いディレクトリに現在
      いるかどうかという情報は余り当てにならない。

      "/" が含まれるかどうかを事前に判定する可能性もあるが、変数展開の中に / が
      含まれる可能性もあるので、完全に判定するのは難しい。

    * そもそも単語が単純な場合には展開の操作すら必要ないのではないか。

      {} も quote も history expan も param も ~ もない場合。

    [実装]

    * done: 取り敢えずユーザーからの入力がある場合には着色を中断する。サブシェ
      ルの中で実行する。後で着色し直す可能性については取り敢えず考えない。

      取り敢えず実装してみたが、微妙。とにかく入力を続ければ応答が全くないとい
      う訳ではないが、常に位置文字分だけ遅延している。何故だろうか。一文字だけ
      次の文字が来ている場合に次の文字が来ているという事を検出できていないとい
      う事だろうか。うーん。ble/decode/has-input の問題であろう。

    * done: simple-word/eval-noglob を eval ... noglob に書き換える

    * done: 以下の関数の呼び出し元で適切に stop_check を設定する様にする?

      ble/syntax:bash/simple-word/detect-separated-path
      ble/syntax:bash/simple-word/evaluate-path-spec
      ble/syntax:bash/simple-word/locate-filename

      特に bash3 で stop_check を行うかどうか。bash3 で stop_check をしたとして
      も常に is-stdin-ready は false になるので、唯単に今まで通りにブロックされ
      るだけである。然し、そうであるならば最初から subshell を生成する必要もな
      い。やはり bash3 では stop_check を省略する様に工夫する必要があるのではな
      いか。と思ったが、それならば simple-word/eval の側で bash3 では
      stop_check しないという様にしても良い気がする。
      →その様にする事にした。

      結局上記の3関数では常に stop_check を指定して、
      bash3 についての特別な取り扱いは simple-word/eval の側で実装した。

    * done: 以下の関数について 148 を返した時の振る舞いを正しく実装する。

      148 を返した時に現在はエラー着色にしているが、
      そうではなくて着色せずに抜ける事にする。

      ble/syntax:bash/simple-word/evaluate-path-spec [done]
        ble/syntax/progcolor/word:default/.highlight-filename [done]
          ble/syntax/progcolor/word:default [ok]
      ble/syntax:bash/simple-word/locate-filename/.exists [done]
        ble/syntax:bash/simple-word/locate-filename [done]
          ble/syntax/progcolor/word:default [ok]
        ble/syntax:bash/simple-word/detect-separated-path [done]
          ble/syntax/progcolor/word:default/.detect-separated-path [done]
            ble/syntax/progcolor/word:default [ok]

      取り敢えず ble/syntax/progcolor/word:default まで行って抜ければ、
      単語情報として何か間違った物が登録される事はない。

    x ok: ble/decode/has-input で次の文字が来ている判定しているが、一文字分だけずれ
      がある様に見える。何が起こっているのか調べる必要がある。

      調べてみると既に次の文字は受信している様である。
      問題は未だ処理しきっていないのに描画が実施されているという事である。
      コールスタックを見るとちゃんと EPILOGUE から呼び出されている。
      つまり、ちゃんと文字を処理してからという事になっている筈である。

      と此処で理由が分かった。入力した文字を表示する為に配色を計算しているのだから、
      配色を計算している間は未だ文字が描画されないというのは道理である。
      やはり timeout を入れないと変である。

      conditional-sync に timeout 機能も付ける事にする。

    * done: 着色せずに抜けた場合にはその事を記録に残す (progcolor_dirty)。
      これは ble/syntax/progcolor/word:default に対して実行すれば良い。
      或いは idle に bgworker を登録するだけでも良い?
      と思ったが、それだと沢山の bgworker が生成されてしまう気がする。
      idle に bgworker を登録するとしても、
      未着色単語がある事の情報は何処かに記録する必要がある。

      実は未着色範囲を管理した方が自然な実装になる気もする。
      例えば _ble_syntax_word_async_u{min,max} 等の変数に記録する。
      bgworker ではこれを _ble_syntax_word_u{min,max} に反映させて
      その上で着色を実行する…と思ったが shift 等の取り扱いがどうなるのか分からない。
      _ble_syntax_word_u{min,max} の場合にはどの様にしていただろうか。
      というより、_ble_syntax_word_u{min,max} が設定されるのはどのタイミングだろうか。

      % うーん。ble/syntax/parse/touch-updated-word で変更している。そしてこれは
      % ble/syntax/parse の中で呼び出される物である。一方で、ble/syntax/parse は
      % ble-edit/content/update-syntax から単体で呼び出される事もある。という事を
      % 考えると、此処で設定された _ble_syntax_word_u{min,max} は処理される事なく
      % 次の ble/syntax/parse に伝播する可能性があるという事。その時に必要になる
      % と考えられる shift が実行されていない。
      %
      % _ble_syntax_attr_u{min,max} についても同様である。これらもちゃんと shift
      % する必要がある。
      %
      % →と思ったら、ble/syntax/parse/shift の中でちゃんと shift されていた。
      % _ble_syntax_word_ 及び _ble_syntax_attr_ が接頭辞になっていたのだった。


    * done: 着色せずに残っている部分を着色する bgworker を実装する。
      最後まで完了した時に progcolor_dirty を clear する。

    * done: highlight_timeout_background: bg で着色している時の timeout は長めに取る。

    x fixed: 実際に試してみると相変わらず止まってしまう。CPUがぶんぶん回っている。

      調べてみると eval が stop_check なしで呼び出されている。
      stackdump してみると以下の様な呼び出しになっている。
      どうやら simple-word/eval の呼び出し元のチェックに漏れがあった様だ。

      stackdump:
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:27 (ble/syntax:bash/simple-word/eval)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:17 (ble/syntax/progcolor/eval-word)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:5 (ble/syntax/progcolor/word:default/.is-option-context)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:26 (ble/syntax/progcolor/word:default/.impl)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:3 (ble/syntax/progcolor/word:default)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:7 (ble/syntax/progcolor/default)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:31 (ble/syntax/progcolor)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:8 (ble/highlight/layer:syntax/word/.update-attributes/.proc)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:12 (ble/syntax/tree-enumerate-in-range)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:2 (ble/highlight/layer:syntax/word/.update-attributes)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:4 (ble/highlight/layer:syntax/update-word-table)
        @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:32 (ble/highlight/layer:syntax/update)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:12 (ble/highlight/layer/update)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:9 (ble/textarea#update-text-buffer)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:75 (ble/textarea#render)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:2 (ble-edit/bind/.tail)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:17 (ble-decode/EPILOGUE)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:78 (ble-decode/.hook)

      取り敢えずこれについては修正した。

    x ok: 次におかしいのは、既に着色済みの筈単語も改めて毎回着色されている様な気がするという事。

      と思ったらやはり気の所為だろうか。。。今度はちゃんと新しい単語に対しての
      み処理が行われている様な気がする。と思ったが、どうも word:default 自体は
      新しい単語に対してのみ呼び出されているが、simple-word/eval は何度も呼び
      出されているという事の様である。呼び出し履歴を探ると以下の様になっている。

        ble/syntax:bash/simple-word/eval
        ble/syntax/progcolor/eval-word
        ble/syntax/progcolor/word:default/.is-option-context
        ble/syntax/progcolor/word:default/.impl
        ble/syntax/progcolor/word:default
        ble/syntax/progcolor/default
        ble/syntax/progcolor
        ble/highlight/layer:syntax/word/.update-attributes/.proc
        ble/syntax/tree-enumerate-in-range
        ble/highlight/layer:syntax/word/.update-attributes
        ble/highlight/layer:syntax/update-word-table
        ble/highlight/layer:syntax/update
        ble/highlight/layer/update
        ble/textarea#update-text-buffer
        ble/textarea#render
        ble-edit/bind/.tail
        ble-decode/EPILOGUE
        ble-decode/.hook

      うーん。分かった。ble/syntax/progcolor/word:default/.is-option-context で
      全ての引数に対して評価を行っている。ble/syntax/progcolor/eval-word で一応
      キャッシュはしているが、これは一回の着色の内部でのキャッシュであって、着
      色を跨いだキャッシュは行っていない。これはまた別の箇所で対策するべきの気がする。

    x fixed: 展開が timeout した時にエラー着色になっている。
      timeout の時には d で削除する事にしてみたが、
      d ではなく 0 になってしまって黒で塗潰されている。

      どうやら #setattr は g を設定するのであって、
      wattr の指定を行える物ではない様だ。

    * reject: 実は pathname expansion に限らずユーザー入力がある時には単語着色
      は中断して良いのではないだろうか。

      うーん。これは様子見。早く着色が終わる物から順に着色して行かないと、一番
      遅い着色によって他の着色がブロックされてしまう。なので、軽い物は先に処理
      するべき。何段階にも分けるのは現実的でないので、現状は重い単語だけ処理を
      後回しにする事にする。

    x fixed: ble/util/assign の混線に関連して発生していた様々な問題

      x "bash: 予期しないトークン `(' 周辺に構文エラーがあります" というエラー
        メッセージが出る。何処かにバグが有るという事。background で実行している
        時に発生している気がする。先ずは再現性。

      x うーん。操作していると突然 hang して暫くして emacs が起動した

        何やら操作していたら "# reached line_limit_length=10000" に抵触して、そ
        の後に emacs が起動した。2500項目の要素を含んだ "ret=(......) fdsa1
        aaaa" と言った感じの内容が入力されている。これが意味する所は何
        か。_ble_edit_str に内容が展開されているのが原因と考えられるが何が起こっ
        ているのだろうか。

        a ble-decode-char に紛れ込むとは考えにくい。

        b terminal の echo back に引っかかっているとも考えにくい。そもそもその為
          にはそれ専用の escape sequence で囲まなければならないし、それを出力する
          ような事が起こるとも思えない。

        c _ble_edit_str を直接編集している箇所もないだろうし、

        d 一つの可能性は ble/util/assign の混線である。然し、そうだとしても
          ble/util/assign で挿入内容を決定する様な機会があるだろうか。

        TAB は入力していなかったと思う。従って補完が関係している可能性は取り敢
        えず除外する事にする。

        →あー。分かった。ble/util/assign の混線である。conditional-sync で
        timeout した時に動かしていたプロセスを kill するのを忘れていた為に、遅
        延して ble/util/assign の一時ファイルに様々な情報が書き込まれて変な事が
        起こっていたという事。一つ前の問題もこれに関連して発生していた現象であ
        ろうと推測される。取り敢えず再びいろいろ試して問題が再現しないか確認す
        る必要がある。

      x fixed: failglob が発生する様な状況で failglob にならなくなっている。何
        故だろうか。これは瞬間的に timeout になっている所為で、failglob で失敗
        するよりも先に timeout 142 を返して、その為に着色が無効化されているのが
        原因だった。

    * done: glob が有効な場合でも実は最初に noglob で展開を行って、其処に
      rex='[*?]|\[.*\]|[@+!]\(.*\)' が含まれている時に限り改めて
      subshell で実行するという形式にしても良いのではないだろうか。

      これに関してはわざわざ noglob で展開を行わなくても、
      変数代入を実行すれば良いのではないだろうか。
      builtin eval -- "tmp=$word"

    * done: bash3 では globstar を一時的に off にする事も考える。

      然し、そうするとユーザに対して嘘の情報を提供する事になる。本来は一致する
      筈なのに failglob して赤色に着色される等の可能性。そういう事を考えるとや
      はり時間がかかっても良いから着色するか、或いは着色自体を諦めるか。簡単な
      内容の場合には着色を諦めても良いのではという気がする。

      或いは、** が含まれる場合に限って着色を諦めるという手もある。即座に 142
      を出力する様にすれば良い。これで OK

    * done: 変数展開の中まで参照して noglob かどうかを判定する前に、
      先に extract-parameter-names & 変数内容の復元をするべき。

      再び eval の構造を大きく書き換えたが取り敢えずは動作している模様である。
      取り敢えず conditional-sync を経由した展開も動いている様子だ。OK

    x 別項目: 全く同じ内容で eval を連続して2回試すという事が頻繁に起こっている。
      これは何だろうか。やはり eval-word による呼び出しと、それから本当の着色用
      の呼び出しが混ざっているという事だろうか。これに関しては、eval の呼び出し
      をキャッシュする事で対応できる気がする。

      但し呼び出しをキャッシュすると言っても、bash3 でどの様に対処するべきかは
      微妙である。やはり汎用の hash 辞書のインターフェイスを準備するべきかもし
      れない。

      これは調べてみた所、ble/syntax:bash/simple-word/detect-separated-path と
      ble/syntax:bash/simple-word/evaluate-path-spec の二箇所で発生していれう事
      の様である。これは eval の内容をキャッシュする様にすれば解決する話である。
      独立項目で取り扱う事にする。

2021-01-25

  * edit: change default behavior of "C-w" and "M-w" to operate on backward words (reported by 3ximus) [#D1448]

    ? done: C-w の振る舞いを readline に合わせる?

      後、やはりここまで来ると普通の bash との振る舞いの違いが俄然気になってくる。
      やはり C-w は kill-uword ではなくて kill-backward-uword であるべきなのではないか。
      やはり既定で kill-backward-uword にする様に変更する。
      M-w による copy-backward-word についてはどうするか。
      どうも readline の copy-backward-word は widget copy-uword と同じ振る舞いの様である。
      しかし、M-w は元の readline では使われていないし、
      ble.sh の M-w でどの様に振る舞っても問題はない気がする。

    ? ok: C-w で kill-uword する現在の振る舞いに何か理由があっただろうか。
      何か理由があって敢えて現在の振る舞いにしている可能性もある。

      bbbd155f src/edit.sh (Koichi Murase     2019-03-22 07:28:24 +0900 6763)   ble-decode/keymap:safe/.bind 'C-w'       'kill-region-or kill-uword'
      1fc7cbaf ble-edit.sh (Koichi Murase 2017-12-04 20:48:17 +0900 6185)   ble-decode/keymap:safe/.bind 'C-w'       'kill-region-or uword'
      f18485f0 (Koichi Murase 2017-12-04 14:36:52 +0900 4442)   ble-bind -f 'C-w'       'kill-region-or uword'
      3aa7fa66 (Koichi Murase 2017-12-03 18:31:00 +0900 4461)   ble-bind -f 'C-w'      'kill-region-or uword'
      6ca737d2 (Koichi Murase 2015-02-28 12:48:55 +0900  54)   ble-bind -f 'C-w'      'kill-region-or uword'
      ^c68412b (Koichi Murase 2015-02-09 03:13:19 +0900 3381)   ble-bind -f 'C-w'      'kill-region-or uword'

      どうやら一番最初に commit した時から現在の振る舞いだった様だ。
      ここから分かる事は現在の振る舞いに根拠はないという事。
      実装初期に kill-backward-uword がなかったか不完全だった時からこうである可能性がある。
      なので、振る舞いを現時点で変更しても何の問題もない。

      copy-uword vs copy-backward-uword についても全く同じだった。
      最初から M-w は copy-uword になっていた。

    これは他の ble versions にも適用した方が良いと思われるので独立した commit にする事にした。

  * edit ({kill,copy}-region-or): fix unconditionally combined kills/copies (reported by 3ximus) [#D1447]
    https://github.com/akinomyoga/ble.sh/issues/83#issuecomment-766831785

    C-w で無限に文字列が追加されてしまうという事を指摘された。

    % 何故だろう。手許で確認した時には動いている様に見えたのに。と思ったが手許で
    % 試した時は C-k や C-u を使っていたために気づかなかったという事の気がする。
    % →と思ったら分かった。テストのために自分で ble-bind していたが、
    %   その時に kill-region-or を使っていなかった。

    kill-region-or または copy-region-or の中で
    ble/decode/widget/call を用いて widget を呼び出した時に
    LASTWIDGET が {kill,copy}-region-or に書き換わる為に、
    無条件に前回のコマンドが切り取りコマンドであったと判定されてしまうのが原因。
    取り敢えず修正した。ble/decode/widget/* の関数がまた増えてしまったが仕方がない。

  * mandb: man のオプションの情報が文字化けしている [#D1446]

    % キャッシュが全然使われていない。毎回再生成されている様に見える
    % と思ったが、これは単に core-complete.sh が更新されたから、
    % それに応じて更新されているというだけの事だった。

    データを再生成してもやはり同様に文字化けしてしまう。

    調べると nroff は UTF-8 には対応していない様だ。groff は groff -k にて
    UTF-8 に対応する様だ。更に -k に加えて -Tutf8 も必要だった。

    groff ではなくて nroff の時にはどうするのかという問題は残るが、まあ groff
    のないシステムでは UTF-8 の man は存在しないと思って良い気がする。なので取
    り敢えずは気にしない事にする。

  * 2020-11-02 complete: support complete_limit{,_auto} (contributed by timjrd) [#D1445]
    https://github.com/akinomyoga/ble.sh/issues/64
    https://github.com/akinomyoga/ble.sh/issues/65

    これは時間はかかったが無事に merge まで行った。

    * done: source:file において substr を実装する。
    * done: filter を自前で実行する場合には cand/yield 内部での filter は不要。
      これは flag_source_filter=1 を設定して実行する事にした。
    * done: timjrd を README/acknowledgement に追加する。
    * done: complete_limit_reached にリークが存在している。
      ちゃんと source:* や candidates/generate などのコメントに使う変数を記述して、
      それから auto-complete の中で candidates/generate を呼び出す前に local で宣言する。

  * main: nfs の上に _ble_base_run があると問題になるのでは [#D1444]
    取り敢えずローカルに runtime directory を作る時には $HOSTNAME も含める事にした。
    XDG_RUNTIME_DIR 及び /tmp を使う場合には host specific であると期待してその儘にする。

2021-01-22

  * edit: C-w で kill-ring への追加を実装するという事 (suggested by 3ximus) [#D1443]
    https://github.com/akinomyoga/ble.sh/issues/83#issuecomment-764893198

    これについては先ず初めに仕様を確定しなければならない。

    例えば前方を切り取るコマンドの場合には必ず左に挿入する事にする? と思ったが、
    そうすると C-k を連続で使用した時に、切り取られる行の順序が逆になってしまう。

    ? というよりどの様なコマンドが存在しているだろうか。

      | 調べると C-k, C-u, C-w, M-d, M-h で kill-... を実行している。
      |
      | widget 名で言うと
      | - kill-{forward,backward}-{?word,{graphical-,logical-,}line,text}
      |   これの対応は簡単。backward に削除する場合には prepend し、
      |   forward に削除する場合には append すれば良い。
      | - kill-{?word,{graphical-,logical-,}line}
      |   これは微妙。emacs でどの様に振る舞っているだろうかと考えたが、
      |   よく考えてみたらその様に振る舞う物は存在しない気がする。
      |
      |   emacs.rlfunc.txt で対応表を見てみたが、kill-line に対応する
      |   rlfunc kill-whole-line しか振る舞いを確認できる物が存在しない。そして、
      |   この rlfunc kill-whole-line は kill-line と違って、
      |   コマンドライン全体を切り取ってしまうのでやはり振る舞いとして異なる。
      |
      |   と思ったが、実際に readline で実行してみると kill-whole-line は
      |   前回の内容に append する様である。取り敢えず ble.sh でもその様に振る舞う事にする。
      |
      | - kill-region
      |   これは前回の内容は完全に忘れるという振る舞いで良い。
      |
      | - vi_imap/delete-backward-word
      |   これは実は kill-ring には何も影響を与えない様だ。取り敢えず無視する事にする。
      |   readline の vi mode の時には kill するが combine はしない様だ。

      →結論としては、kill-region,kill-region-or 以外の kill-* は全て対象という事。
      kill-backward-* に関しては prepend で、それ以外については append という事。

    ? ok: append/prepend をした時に元々あった内容を上書きするのか、
      新しく項目が追加されるのか。
      →試して見た所、上書きする様である。

    ? done: /.*-range の allow_empty という引数は必要なのだろうか。
      kill,copy,delete に関しては決して指定される事はない。
      replace に関しては大体指定されている。
      指定されていない物は意図的な物かどうか確認する必要がある。

      - ./keymap/vi.sh:3995:    ble/widget/.replace-range "$eol1" "$eol2" "$text"
      - ./keymap/vi.sh:4016:    ble/widget/.replace-range "$eol1" "$bol2" "$text"
        上記二つに関しては eol1<eol2 が保証されているのでどちらでも良い。
      - ./lib/core-complete.sh:5832:    ble/widget/.replace-range "$pos" "$comp_index" "$value"
      - ./lib/core-complete.sh:5865:      ble/widget/.replace-range "$pos" "$comp_index" "$value"
      - ./lib/core-complete.sh:5871:    ble/widget/.replace-range "$pos" "$comp_index" ''
        上記3つに関しても同様に pos<comp_index が保証されている。
      - ./lib/vim-surround.sh:509:  ble/widget/.replace-range "$beg" "$end" "$content"
        operator なので幅0になる事は余りない気がするが、例えば編集文字列が空の時?
        →うーん。その様な場合であっても cs 経由でしかこの operator は呼び出されないので、
        結局、delimiter を使って範囲を切り出そうとする段階で失敗してしまう。
        結局、この operator が空文字列に対して呼び出される事はない気がする。

        もし仮に呼び出される事があったとしても、allow_empty を指定する方が自然。

      replace-range については常に allow_empty という事にする。
      kill,copy,delete については常に not allow_empty という事にする。
      →書き換えた。

    ? done: copy でも同様に振る舞う必要があるだろうか。
      →実際に試してみた所、同様に振る舞う様である。。。

    動かしていて気づいたが、C-k で行末の改行を削除できていない…。
    これは別 commit での bugfix にする事にする。

  * edit: support "bleopt edit_line_type" (motivated by 3ximus) [#D1442]
    https://github.com/akinomyoga/ble.sh/issues/83

    手で一つ一つ logical-line を明示的に指定するよりは、
    一つのオプションで一括で切り替えられる様にした方が良い。
    更に、今まで既定で graphical line を使っていたのを、
    logical line を使う様に変更する事にする。

  * edit (sword): fix definition of sword (motivated by 3ximus) [#D1441]
    https://github.com/akinomyoga/ble.sh/issues/83#issuecomment-764893198

    この質問で具体的に各単語がどのような定義になっているのか説明しようとして
    コードを参照した時に気づいた。sed によって & が置換前の文字列に展開されて、
    変な事になっていたのが原因。

2021-01-17

  * LC_CTYPE の切り替えエラーが出る (reported by 3ximus) [#D1440]
    https://github.com/akinomyoga/ble.sh/issues/81

    実際に確かめてみたら確かにエラーメッセージが出る。
    過去に対策したつもりだったが対策の仕方が間違っていた。
    色々実験した所、結局余計に一つ関数呼び出しをしなければ駄目な様だ。
    自動で stderr を抑制するように書き換える汎関数を作って対応する事にした。

2021-01-01

  * decode (ble-decode-kbd): support various keyseq specifications [#D1439]
    https://github.com/urbainvaes/fzf-marks/pull/41
    https://github.com/urbainvaes/fzf-marks/pull/43

    上記で ble.sh 特有の binding を追加してもらったが、ble-bind がユーザーが自
    由に対応キーを指定できる様に公開されている変数 FZF_MARKS_JUMP の形式に合わ
    ない為に C-g 決め打ちになってしまっている。ble-bind でも bind と同様の形式
    で keyseq を指定できる様にしたい。


2020-12-25

  * edit: f1 で関数定義を表示する時に LESS=-r が効いていない [#D1438]
    これは bash のバグの様である。バグ報告は bug-report でする事にして、
    ここでは簡単に修正してしまう。

  * edit: 2020-12-09 READLINE_MARK, etc. の値が残ってしまっている [#D1437]

    これは ble/textarea#adjust-for-bash-bind によって設定されている値である。
    コマンドを実行する時に復元・保存する様にするのが良いのではないだろうか。

    * 何故か READLINE_LINE, READLINE_POINT が export されている。
      と思ったが、これは ble.sh を bind -x の内部で動かしているからであった。
      READLINE_LINE 及び READLINE_POINT が

    * 普通の bash で実行するとどうなるのかと思ったが、どうやら自分で設定した
      READLINE_LINE 及び READILNE_POINT があっても bind -x の実行と共に削除され
      てしまう様である。

    取り敢えず adjust/restore する様にした。コマンドの実行の間で値が保存される
    様にした。bind -x が実行されても値がクリアされる事はない。

2020-12-20

  * [解消] 2020-09-27 SIGWINCH で job メッセージが出る [#D1436]
    2020-12-20 これは #D1435 と同一の問題であろう。直ったと見て良い。

    SIGWINCH に対して次の様な job メッセージが表示される様になっている。
    [1] 終了 [[ -n $_dotfiles_blesh_manual_attach ]] | [[ -n $_dotfiles_blesh_manual_attach ]]
    これは .bashrc で設定されている関数の一部である。何故?

    調べてみるとそもそも関数ですらなくて、
    これは ble-attach を呼び出す条件の中に含まれているコマンドだと分かった。
    つまり SIGWINCH に際して ble-attach 関連の何かが呼び出されて、
    そして最後に呼び出された ble-attach の呼び出し時のコマンド文字列が何処かに保持されている?
    もしくは再び .bashrc が source されている可能性もあるがやはりそれは変だ。

    2020-10-10 今試してみると再現しない。


  * edit: WINCH 後に偽のジョブ情報が表示される (reported by 3ximus) [#D1435]
    https://github.com/akinomyoga/ble.sh/issues/78

    前回報告を受けていた謎のジョブ終了メッセージについて。
    これは端末のサイズを変えた直後に起こるという新情報を得た。
    3ximus/dotfiles の .bashrc を確認して再現を試みた所、
    git-prompt.sh, prompt_7.sh, ble.sh の組み合わせで再現できた。

    更に設定を最小化していく。どうやら fork があると
    jobs にメッセージが乗る様になってしまうらしい。

    これの回避方法としてどの様な方法があるか。

    a jobs で得た新しいイベントを除去する?
      然し、これの問題点は唯の fork と、
      本当にジョブとして起動したコマンドの区別が付かないという事。

      振る舞いの違いとしては trap handler の中で発生したfork に対応するジョブの
      情報は trap handler を抜けた時に消滅しているという事である。

      但し、バックグラウンドとして起動したコマンドのジョブ情報もtrap handler を
      抜けると消えてしまうのかもしれない。試せば分かるが面倒なので必要になった
      ら確認する事にする。

    b もう一つの方法はシグナルを処理している時は
      jobs の更新は行わないという物。これが妥当な気がする。

      ? この現象が起こるのは WINCH だけなのか、或いは別のシグナルでも発生するのか。
        →確認した所、INT でも同様にジョブ情報に fork が乗る様である。

        trap '(true); jobs' INT

      ? 現在シグナルの中にいるかどうかを判定する方法は存在するだろうか。
        或いは ble.sh の枠組みの中で trap-handler 経由で呼び出されたか
        どうかの情報を用いて判定する?

        trap-handler の中にいるかどうかの判定方法。一つは return を
        使って関数を抜けた時に、直前の exit status を返すか、
        或いは固定の exit status を返すかを見るという方法。
        よく考えたらこれは bash-4.4 以降でしか使えない。
        Bash はこの部分について振る舞いを変更したのだった。

    % 取り敢えず b の方向で実装する事にする。
    % ble.sh の中での jobs の仕様実態について確認する。
    %
    % どうやら指定した名称に対応する jobs が存在するかどうかの確認にも
    % jobs -- "$value" を使用している様である。これについては、偶々
    % value に一致する終了したジョブ名が存在すると jobs -- "$value" を実行する事によって
    % その情報がジョブ情報のリストから削除されてしまう。この問題を回避する為に
    % jobs -- "$value" を実行する為に ble/util/joblist.check を実行しているが、
    % trap handler の中で joblist.check をスキップしてしまうと、
    % そのジョブ情報が正しく拾われずに消滅してしまう可能性が残る。
    % trap handler の内部では jobs はサブシェルで実行するのが良い気がする。
    %
    % 1 done: 何れにしても最初に trap handler の中で実行しているかどうかを確認す
    %   る必要がある。特に ble.sh の実装が原因で発生する変なメッセージを防げれば
    %   良いので、trap/.handler の中でローカル変数を定義する事にする。
    %
    % 2 done: jobs を使っている箇所を確認する。
    %
    %   * util.sh は ble/util/joblist だけでしか jobs を呼び出していない。修正した。
    %   * core-syntax.sh も ble/syntax/highlight/cmdtype/.is-job-name だけで使っ
    %     ている。対策した。
    %   * edit.sh では ble/builtin/exit で終了する時にユーザに確認を求める所で実
    %     行しているが、exit する時には何れにしてもジョブ一覧を出力するので敢えて
    %     直接実行する。変なジョブ情報が出力される事になってしまうがこれは仕方が
    %     ない。
    %   * 他に ble/widget/command-help/.type で jobs -- "" を実行している。これに
    %     ついても修正を行った。
    %
    % 3 動作確認: さて、実際に修正して見た所直っていない。どうも trap を抜けた後
    %   も変なジョブ情報は残っている様である。ユーザのコマンドとして jobs を実行
    %   すれば変なジョブは消えてなくなっているが、bind -x の中から jobs を呼び出
    %   すと全て出力されてしまうという事だろうか。
    %
    %   サブシェルの中で jobs を実行する様にした結果か、余計に大量の偽ジョブが登
    %   録されてしまっている。
    %
    % 改めて bind -x を組み合わせた時の動作についても確認する→うーん。再現した…。
    % WINCH の直後の bind -x の中で jobs を実行すると偽情報が出る。
    % 別の bind -x を一回実行してから次の bind -x で jobs を実行しても再現する。
    % bind -x 以外の入力を行った後でも、bind -x の中で jobs を実行すると再現する。
    % 一回でもユーザコマンドを (空でも良いので) 実行すると、偽情報は出なくなる。
    %
    % こうなって来ると変なジョブ情報が消えるのを待つ作戦に頼るのは困難である。
    % 今までの変更は取り敢えずなかった事にする。

    うーん。trap/.handler の中で jobs を敢えて実行して結果が描画に回る前に
    偽情報をクリアしてしまう事にする。blehook WINCH を実行する前に joblist 更新をして、
    更に実行した直後にも joblist の更新を行う。二回目の joblist の更新では、
    一時的に現れてそれで直ぐに消滅したイベントはイベントとして登録しない事にした。

    これだと blehook WINCH を実行している最中に終了した本当のジョブ終了の情報が
    消滅すrことになるが、実際に blehook を実行している途中に jobs の状態変化を
    Bash が受信するのか不明だし、もしそうだとしても blehook WINCH の処理のよう
    なごく短時間でその様な事が起こる確率は低いと考えられる。なので、気にしない
    事にする。

    取り敢えず動いてはいる様子である。

2020-12-14

  * progcomp: : や = の quote の取り扱い (reported by 3ximus) [#D1434]
    https://github.com/akinomyoga/ble.sh/issues/77

    ? そもそも \=, \: の様にエスケープしていたのは何故だったか。

    ? bash-completion の提供した補完に対して \= や \: の様にエスケープを実施す
      る必要はあっただろうか。その辺りの実装はどの様になっていたのだったか。

    関連しそうな物を探す。ble-0.3 では = のエスケープはしていない。

    #D1133 でコマンド名に関しては =, : の quote はしない様にしている。
    #D1098 6c6bae56 で = や : のエスケープが導入されている。
    #D1094 では = や : による候補の分割を議論している。

    うーん。元々エスケープは #D1098 で導入された物の様だが深くは考察していない。
    改めてどの様に振る舞うのが自然か考察する必要がある。

    * そもそも ble.sh の補完は展開後の結果を生成して貰う前提になっている。
      一方で bash の補完は展開前の結果を生成する事を許容している。
      例えば abc$(echo hello) の様な文字列を補完で生成する事すら可能なのである。
      それどころか複数単語からなる展開結果にする事も可能の筈である。

    * それでは progcomp の結果はそのまま挿入する事にすれば良いのではないか
      とも思われるが此処で問題になるのは、ble.sh の側で適当に展開を実行してから
      COMP_LINE を構築して progcomp に渡しているという事である。

      これは途中に $var 等の単純な展開等が含まれている場合でも
      progcomp で補完を実行できる様にする為に必要。

      この時、progcomp が展開前の補完結果を生成した時に、
      それを如何に元のコマンドライン文字列に反映させるのかが問題になる。

    x [OK] 手許では再現していないが scp chat\:down[TAB] で chat\: が消滅してしまう?

      notepc の方は bash_completion が入っていないので今試せない。
      * chat は port を変えているので localhost: から試そうとしてもできない。
        localhost や chat を .ssh/config に登録してパスワード無しで補完できる様にしたが、
        補完候補は出してくれない様である。
      * hp2019 -> chat を試してみたが再現しない。local にも mkdir downloads したが再現しない。

      うーん。取り敢えずそもそも何故失敗するのか考える?
      plain bash で実行したところ failglob で失敗している。
      shopt -u failglob にしたら ble.sh の中でも補完が動く様になった。

      そして chat\: が消滅してしまう問題に関しては、
      plain bash でも再現する事ができた。
      これは bash-completion の問題である。

      特にローカルのカレントディレクトリに "host:..." というファイルが存在する時に、
      host\:... と入力している可能性があって、この時に host: の部分が消滅してしまう
      という問題が発生する。

      https://github.com/scop/bash-completion/issues で報告をしようかと考えたが、
      もしかすると最新版で直っている可能性もあるので、
      最新版の bash-completion を試してみても良い。

    うーん。progcomp による展開結果が空白などを含んでいる時にどのように振る舞うのか。
    plain bash はそのまま何も加工を行わずに展開してしまう。うーん。
    blesh ではどの様に取り扱うべきか。

    * できるだけ progcomp が提供した quote を保持する様にしたい。
      然し、これは現実的には難しいのではないか。

      a = 及び : についてだけ quote しているかそうでないか保持する? それ以外の
        文字については自分で quote し直す。

        その為には progcomp が生成した単語について = や : で分割を試して、その
        上でそれぞれ quote してから再結合する? これだといかにも処理量が大きい。
        非効率的である。

        これは処理方法として複雑でありユーザから見たら不自然で予測不能に見える
        かもしれない。処理の重さとしては次に述べる方法よりは現実的である。

      b 入力済みの部分に一致する部分を除去してそのまま挿入。

        ここで問題になっているのは既に入力済みの部分に対応する文字列を
        どの様に取り除くのかという事であった。二分法を用いる等して
        これについて既に入力済みの部分を除去する方法はないだろうか。

        どの様にしたら良いのかを調べる必要がある。二分探索で調べるという方法と、
        1 unit ずつ読み取って行くという方法の二種類を考える事ができる。

        * 二分探索で調べるというのは複雑な気がする。元の文字列について途中で切
          断して二分探索していくという手も考えられるが、変数名の途中など変な所
          で切断すると内容が空になるなどして意図しない結果になってしまう。

        * 取り敢えず 1 unit (simple word element) ずつ読み取って行って、切断す
          るという方法? 然し、'...' 等の様に一気に読み取る事ができるliteral 等
          になっているとすると、実装が複雑になる。面倒である。そもそも処理が複
          雑になる。面倒である。

      c 今まで通り基本的に progcomp が生成した物は展開毎と見做して quote を行う。
        = 及び : は基本的には quote を加えない。compopt -o filename で quote が
        明示的に指定された時にのみ =, : の quote を行う。

        これは progcomp が quote を自前で行って候補を生成した時に問題になる。つ
        まり quote が二重に為される事になり、意図しない結果になってしまう。然し、
        この問題は今までにも存在していた問題の筈である。取り敢えずの修正として
        は妥当である。

    取り敢えず今までも quote を勝手にする事による問題はあった。
    全てを一度に解決するのは難しいししなくても良い。
    此処は c の方針で修正する事にする。

2020-12-13

  * README: ((_ble_bash)) && ble-attach だと set -u の時駄目 [#D1433]
    ble.sh ロードに失敗した時や ble.sh を意図的に読み込まなかった時に
    _ble_bash が存在しないので内容をチェックする前にエラーになってしまう。

    [[ ${BLE_VERSION-} ]] && ble-attach にするべき。

2020-12-10

  * complete/mandb: FreeBSD 上で man 情報の抽出に失敗している [#D1432]

    | freebsd には roff, nroff, troff 等が存在していない。
    | それでも man が動作している事を考えると、
    | 何らかの方法で man pages を変換しているという事の筈。
    | それについて調べて対応する。

    対応した。FreeBSD では mandoc というコマンドを使って変換を行っている。
    nroff と同様に -man 等を指定する事ができる様だが、
    どうやら FreeBSD は -man ではなくて -mdoc を想定して man pages を書いている様だ。
    という訳なので -mdoc を前提として抽出をする様に書き換えた。

    ちゃんと nroff を使う版も動いている。OK

  * highlight: command \^J-a とした時に -a がオプションとして着色されない (reported by cmplstofB) [#D1431]
    https://github.com/akinomyoga/ble.sh/issues/76

    現在の着色では \-a や ''-a 等の様に quote がある場合には、
    意図的にオプションとしての着色を避けている。
    そういう意味に於いて \^J-a もやはりオプションの前に quote が
    ある物として取り扱ってオプションとしての着色が無効になっている。

    a 然し意味的に考えるとやはり \^J は単語の一部に含まれない様にするのが自然に
      も思われる。

      ? その様に構文解析を変更する事は恐らく簡単だろうが、単語の一部として解析
        しない部分文字列がコマンドラインに含まれる事による副作用などはあるだろ
        うか。思うにリダイレクションなども単語の一部として登録していないので、
        特にこの事で問題が発生する事はない気がする。

      また sabbrev の単語判定でもやはり語頭の \^J は含まれない様にしたい。

    語頭の \^J は skip する事にする。これはどの様に実装すれば良いか?
    ^J や空白を処理している箇所で一緒に処理すれば良いだろうか。

    取り敢えず構文解析は修正した。多分大丈夫。副作用が起こるかもしれないが、
    それは実際に何かが起こってから見るという事で良いだろう。
    うーん。問題が起こるとすれば二次的に起こる問題ではなくて、
    構文解析自体が変になる可能性が高い気がするが多分大丈夫。

  * color: italic が描画できていないという (by rlanore) [#D1430]
    https://github.com/akinomyoga/ble.sh/issues/73

    試してみると手許では動いている。対応していない端末で使おうとしているのではないか。
    この Issue には返信がないがもう一つの新しい Issue に対して Terminal 情報を載せている。
    Terminator 1.92 を使っている様である。

    Cygwin 付属の Terminator 0.98 は italic に対応していない。
    Cygwin 附属の GNOME terminal は対応している。
    vte のソースコードを見ると 2012 には italic 関連のコードが存在している様だ。
    2014 にまた別のフォント初期化コードが追加されている。然し一方で pango も呼び出している。
    これが実際に X11 環境で使われるのかどうかはよく分からない。

    →これは結局向こうの tmux の設定が問題であった。手許で試して見たところに依
    るとどうも tmux は default-terminal の値に応じて自身の振る舞いも変更する様
    である。これについて wiki の manual にも書いておく必要があるのではないか。
    →wiki に説明を追加した。

  * complete/mandb: ^H が大量に挿入される (reported by rlanore) [#D1429]
    https://github.com/akinomyoga/ble.sh/issues/75

    これは nroff で太字を表現するのに <CHAR>^H<CHAR> を出力する物がある為。
    なので、単に .\b を削除すれば良い。

    取り敢えず修正してみたが本当に動くか微妙。複数の OS で試す必要があるのではないか。
    freebsd で試して見たところ、troff がないので動いていない。
    これについては後で対応する事にする。

2020-12-09

  * complete: 補完候補が更新されない問題 (reported by 3ximus) [#D1428]
    https://github.com/akinomyoga/ble.sh/issues/74

    これは明らかに menu-filter で候補がなくなった時に、
    元の候補を全て表示する様に変更したのが原因である。
    やはり一致しなくなった時点で候補は表示しない様に変更する事にした。

    b 或いは別の変更方法として、候補再生成のフラグを設定して、
      この時にはメニューから候補を拾う事はしない様にする?

      x と思ったが、そうすると結局候補を全て表示する意味がない? 候補を表示する
        のはメニューから選択させる為であるが、メニューから候補を拾わない様にし
        た時点でそれが使えない?

        % x と思ったが連続 TAB や、明示的な menu-complete の bind の時には、候
        % 補の再生成をせずに menu に入る事が可能になる。

        でも連続 TAB の場合は最初の TAB の時点で候補再生成が起こるので、表示し
        ている候補が使われる事はない。明示的な menu-complete の bind についても
        既定では C-TAB 等余り使われなさそうな物になっているので設計に考慮に入れ
        なくて良い気がする。

      此処まで処理を複雑にしても余り有用ではなさそう。次の TAB で候補一覧はすぐ
      に消えてしまうので、絞り込み前の候補一覧を表示しても却って混乱を生むだけ
      である。この選択肢は却下である。

2020-12-08

  * util/term: lxterminal, gnome-terminal で vte の検出に失敗している [#D1427]
    これはソースコードを確認してみた所、xterm の version 抽出コードを追加した時
    に動かなくなった物の様に見える。修正した。

2020-12-01

  * prompt: PROMPT_COMMAND で変更した PS1 がその場で反映されない (reported by 3ximus) [#D1426]
    https://github.com/akinomyoga/ble.sh/issues/72

    確認した。これは書き換えミスである。prompt_ps1_final 等の書き換えの時に、
    更新の必要性があるかどうかの判定を PROMPT_COMMAND よりも前に持ってきたのが行けない。

    これはどの様に修正したら良いだろうか。PROMPT_COMMAND は更新の必要がある時に
    のみ実行したい。或いは :leave: の時にも実行するべきだろうか。leave の時に
    PROMPT_COMMAND は実行しなくても良い気がしてきた。うん。その様に変更する。

  * complete: 単語補完で = の右辺の . で始まるファイル名が補完されない (reported by cmplstofB) [#D1425]
    https://github.com/akinomyoga/ble.sh/issues/71

    これは試してみた所、a= で補完してから . を入力して絞り込みをすると、最初の
    a= の時に . で始まる候補が列挙されていなかった為に、絞り込みモードに入って
    も . で始まる候補が列挙されないままになるという問題。a=. まで入力してから初
    めて補完を開始する様にしたらちゃんと . で始まるファイル名でも補完できる。

    修正の方向性として二つ考えられる。

    a 一つは最初から . で始まるファイルも列挙しておくという事。

      つまり dotglob を有効にして補完を実行すれば良い。

      この方法だと . から始まるファイル名も全部表示されて煩い様な気もするが、よ
      く考えれば一文字でも入力していればこれらの候補は表示されないのだし、. を
      含めて候補生成しても特に問題ない気がする。

    b もう一つの方向性は a=. まで入力した後に先頭一致する候補が見つからないと分
      かった時点で候補を再生成するという事。

      x この方法だと BS で巻き戻して再度候補を表示しようと思ってももう戻ってこ
        ないという問題がある。改めてその場所から補完を実行しなければならなくな
        る。

      x また . が部分一致している場合には、先頭の . が部分一致を意図した物なの
      か、或いは . で始まるファイルを改めて生成するべきかの判断が付かない。安全
      側に倒すとすれば . から始まるファイルを再生成すれば良い気もするが、そうす
      ると部分一致を意図していた時に位置文字入力する度に候補が再生成される事に
      なり重くなる。或いは、本当に特定のコマンドの時にだけ再生性を行うという事
      になり不自然な気がする。

    x a の方針で実装してみたが実際に動かしてみると動かない。というよりユーザが
      dotglob を有効にしても勝手に dotglob が off になってしまう。何故だろうか。
      うーん。

      * ble.sh だけしか読み込んでいなくても勝手に dotglob が off になってしまう。
      * 補完を試みない限りは dotglob に変化はない。
      * dotglob という文字列を含むコードを全てコメントアウトしても dotglob が
        off になってしまう。

      どうやら GLOBIGNORE= : を実行しただけで dotglob の設定が変わってしまう様
      だ。そしてこの振る舞いは bash のマニュアルに書かれている。

      現在の実装で GLOBIGNORE を設定しているのは core-complete.sh だけである。
      glob 展開を抑制して split を実行する箇所では GLOBIGNORE=* ではなくて set
      +f を用いる様に変更を行った。その他の eval-pathname-expansion は現在の
      GLOBIGNORE の設定に忠実に展開を実行するので GLOBIGNORE には触らない。

      改めて GLOBIGNORE の取り扱いについて考え直す必要がある。local GLOBIGNORE
      とすると bash-3.0, 3.1 で影響が残ってしまう問題があった。ここでは何処かに
      値を保存しておいてそれを復元するという形にするべきか。

      →その様に書き直した。dotglob はこれで勝手に書き換わらない。. で始まる候
        補もちゃんと出力される様になった。

  * highlight: ~+ 等のチルダ展開が着色されない (reported by cmplstofB) [#D1424]
    https://github.com/akinomyoga/ble.sh/issues/71

    Cygwin 上では再現しなかったが Linux 上では再現した。調べてみると
    ble/syntax:bash/simple-word/locate-filename/.exists を呼び出した時点で単語
    が ''~+ の様に書き換えられていて意図的にチルダ展開が無効になっている。

    調べてみると構文解析の段階で ~ に tilde 属性が設定されていない時には
    notilde が指定される様になっていた。実際に構文解析の結果を見ると何故か ~+
    の時には ~ にチルダ展開の着色が為されていない。これは構文解析の問題である。

    どうも分かった。shopt -s extglob になっていると +() の可能性が考えられるの
    で、~+ が来ても ~ 迄で構文解析が一旦切れる。これでチルダ展開の可能性を判定
    しようとすると、後ろに余分な文字が存在するという理由でチルダ展開が無効化さ
    れる。なので tilde が構文着色されない。結果として単語着色でチルダ展開が無効
    化されている。

    そもそも extglob が有効になっている時に + が含まれている単語は単純単語なの
    だろうかという疑問もある→実際に試して見るとちゃんと単純単語として認識され
    ている。+() が含まれている場合には単純単語ではない。よく考えたら当たり前と
    いえば当たり前。() が含まれているかどうかだけ判定すれば良いのだから。

    a reject: うーん。現在の文字集合ベースの判定ではなくて simple-word で判定し
      てしまうというのが自然な気がしてきた。但し、/: 等は含まれない様にする。と
      思ってその様に書き換えてみた。

      x しかし、よく考えてみたらこの場所に於ける判定は構文解析の 1 step である。
        なので、simple-word の様に複数の解析ステップを跨ぐ様な先読みを実行する
        と変な事になる。なので、やはり元の実装のように chars ベースで判定しなけ
        ればならないのである。

    b reject: 一回の解析で読みきれない様なチルダ展開は着色しなくても良いのでは
      ないかという説。例えばユーザー名として a~b~c の様な変な物を選んだ時に、果
      たして ble.sh が ~a~b~c の様なチルダ展開に対して正しく処理を行う必要があ
      るのかという話。

      そうは言ってもユーザー名の場合には変なユーザー名にするのが悪いという事に
      なるが (ble.sh に限らず様々な場所で問題が起こるだろう)、~+ に関しては標準
      で存在する特別な指定なので、やはりちゃんと処理したい。

    c + を特別扱いする? 結局これが現実的な解になるのだろう。

      ~+ の時にはこれ全体をチルダ展開として抽出する? と思ったがそうすると ~+ ま
      でが解析終了点と判定されて、~+(echo hello) 等を正しく構文解析できなくなる。

      或いは ~+ で始まる時だけ完全に独立に実装し直す事にする?

      色々試行錯誤したが、既存のコードと同じ処理にして但し、~+ がチルダ展開でな
      かった時に ~ まで後退するという実装方法にする事にした。

    d ~ の直後で切れても良いがその直後が + の時には特別にチルダ展開を許容する?
      と思ったが、これだと ~+aaa 等の時にもチルダ展開として着色されてしまう。駄
      目。

    x 結局 c の方針で実装したが今度は ~+(echo) が動かなくなった。ちゃんと解析位
      置を後退する様にした筈なのに。というより ~+ がチルダ展開として着色されて
      いる。

      →分かった。 ~+( となっていて "(" が delimiter として登録されているので、~+
      と ( の間で単語が切れていると判定されてしまっている。これは駄目。"(" は
      delimiter として登録しなくても良い気がする。→そのように直した。

    動いている気がする。

2020-11-27

  * complete: dynamic sabbrev が動かなくなっていた (reported by darrSonik) [#D1423]
    これは cand/yield を sabbrev/expand の中で使っていたが、
    cand/yield に対する要求が増えていたのが原因だった。修正した。
    他の ble/complete/cand/yield の箇所で問題がないかも確認した。
    本来は積極的にテストを追加するべきなのである。
    然し、対話的な昨日に対してテストを追加するのは面倒である。

2020-11-26

  * 2020-03-22 syntax: { echo $fd; } {fd}>&0 の着色が変 [#D1422]
    これは単語着色の除去ができていない問題であろう。

    →これは #D1421 と全く同じ問題で、#D1421 に伴って自然解消した。

  * 2017-11-26 highlight: 配列代入の解析の不整合? [#D1421]

    最初から arr[index まで入力した時の着色と
    arr[index] まで入力してから一文字削除した時の着色が異なる。

    | _ble_syntax_attr/tree/nest/stat?
    |  7 aw   000 'a'  stat=(CTX_CMDX w=- n=- t=-:-)
    |  8 a e  001 '['  nest=(CTX_VRHS w=ATTR_VAR:0- n=- t=-:-)
    |  8*a    002 'a'  stat=(CTX_EXPR w=- n=@1 t=-:-)
    |  6*a e  003 'b'
    |  |    s 004 ^@  stat=(CTX_EXPR w=- n=@1 t=-:-)
    | \_ 'a[ab'
    |     \_ '[ab'
    |
    | _ble_syntax_attr/tree/nest/stat?
    |  7 aw   000 'a' |  stat=(CTX_CMDX w=- n=- t=-:-)
    |  8 aw   001 '[' || nest=(CTX_VRHS w=ATTR_VAR:0- n=- t=-:-)
    |  8*aw   002 'a' || stat=(CTX_EXPR w=- n=@1 t=-:-)
    |  |*aw   003 'b' ||
    |  8*aw   004 ']' ++ word=CTX_CMDI:0-5>@4 word="a[":1-5 stat=(CTX_EXPR w=- n=@1 t=-:-)
    |  |    s 005 ^@    stat=(CTX_ARGX w=- n=- t=$5:-)
    | \_ 'a[ab]'
    |     \_ '[ab]'
    |
    | _ble_syntax_attr/tree/nest/stat?
    |  7 a    000 'a'  stat=(CTX_CMDX w=- n=- t=-:-)
    |  8 a e  001 '['  nest=(CTX_VRHS w=ATTR_VAR:0- n=- t=-:-)
    |  8*aw   002 'a'  stat=(CTX_EXPR w=- n=@1 t=-:-)
    |  6*awe  003 'b'
    |  |    s 004 ^@  stat=(CTX_EXPR w=- n=@1 t=-:-)
    | \_ 'a[ab'
    |     \_ '[ab'

    どうも構文の状態は同じだ。単語の着色が異なる。
    しかしそもそも何故単語着色が起こっているのだったか。
    単語着色は CTX_CMDI としての着色が残っているということ。
    これは単語着色の側の問題であって、解析の問題ではない。

    2019-02-13 "{ echo; } 3>&1" と入力した時にも
    似たような事になる。"{ echo; } 3" まで入力した時の単語エラー着色が
    最後まで残ってしまう。#D0930

    2020-11-26 改めて振る舞いを確認してみる。a[a とすると単語が消滅している。
    また、a の場所に単語着色が残っている。消滅した単語に対する処理がない事が原因。

    消滅単語に関する処理は今どうしているのだったか。note.txt の中を検索してみた
    がよく分からない。消滅単語の範囲にある単語について再度着色を実行するという
    事が書かれているが…。

    うーん。ble/highlight/layer:syntax/update-word-table の内部で消滅した単語の範囲を
    _ble_syntax_word_u{min,max} 及び color_u{min,max} に反映させている。
    更に ble/highlight/layer:syntax/word/.apply-attribute 0 "$iN" d を実行して、
    color_u{min,max} の内部にある属性を全て消去している。
    その後で漸く各単語の属性に基づく着色を計算している。
    つまり、消滅単語の範囲が狭すぎる。恐らく単語登録位置の範囲であって、
    単語が実際に横たわっていた範囲ではないのである。

    然し実際に ble/syntax/vanishing-word/register の実装を見てみると、
    ちゃんと wbeg, wend を得てそれに基づいて範囲を更新している。
    これが意味する所は何か。消滅した単語がちゃんと登録されていないという事か?
    vanishing-word の中で変数を出力してみたが、どうやら lbeg,lend が狭く設定されている所為で
    wbeg,wend が狭められてゼロ幅になっている様である。lbeg,lend とは何か。何を目的とした引数か。

    確認してみるとどうやら 0:i1 に更新範囲を制限している。
    つまり、解析開始点よりも前に位置する消滅単語についてしか消去していない。
    これを 0:i2 に拡張したらどうなるだろうか…。もしかすると、
    既存の消去しては行けない単語についても消去してしまう可能性もある。
    実装について確認する必要がある。

    確認すると実際に単語終端が i1:i2 の外にある単語が残っていると、この単語につ
    いての着色が消されてしまう気がする。と思ったが、単語終端が外側にあってもそ
    の一部が i1:i2 の内側にあるのであれば、必ずその単語は属性再計算の対象になる
    のだからちゃんと更新されて然るべきである。うーん。0:i1 で vanishing-word を
    制限していたのは単に最初の clear を最小限にするのが目的というだけの気がする。
    というか color_u{min,max} を広げれば良いだけの話では? と思ったがどう広げる
    のが良いのかという事を考えると結局 vanishiing-word を見て最小限の広げ方に留
    めるのが良い気がする。という訳で、やはり vanishing-word の方を広げる事にする。

    取り敢えず修正した。効率化する為に syntax:layer/fill も
    新しく ble/dense-array#fill-range という関数を作って置き換えた。
    動いている。上記の a[a] の着色も { echo; } 3>&1 の着色も直った。
    取り敢えずはこれで様子見という事で良い気がする。

  * 2020-11-07 highlight: declare 等に指定したオプションの着色についても対応する [#D1420]
    →declare の着床は特別にしていると考えていたが実際に見てみると、
    通常の引数と同じ仕組みを通じて処理していた。特に CTX_ARGVI も
    オプションの判定に含めるだけで対応する事ができた。

2020-11-20

  * highlight: bin が存在しないディレクトリで bin/ とした時にエラー着色されなくなっている [#D1419]

    どの様に変更して動かなくなったのか調べようとしたが、
    逆に今までの実装で何故動いていたのかよく分からなくなった。
    今までの実装を見る限りはディレクトリ名でなければやはり着色されない気がする。

  * highlight: option を cut/paste すると何故か着色されない [#D1418]
    ファイル名に関しても同様に着色されなくなってしまっている。
    何が起こっているのかについて調べる必要がある。

    そもそも以前の version ではちゃんと動いていただろうか。
    やっぱり前の version では動いている。
    犯人は一番最後の commit である事も確定した。
    そんなに変な変更はしていない筈なので簡単なミスではないか。
    然し、何が原因か思い当たる節もない。
    同じ単語でも着色される時とされない時があるから、
    単語着色の決定自体に問題がある訳ではない気がする。

    うーん。どうも comp_words の時点で単語が一つ少なくなってしまっている。
    調べると実は別に単語が減っている訳ではない。
    ループに戻って確認してみると途中で i が書き換わっている。
    変数リークだった。修正した。

2020-11-16

  * complete: echo ~ TAB としてメニューを表示した後 [#D1417]
    存在しないチルダ展開を試みると ~ が重複して挿入されてしまう問題。

    これは何が起こっているのだろうか。
    メニューを表示していない時には何も起こらない。

    ~x が空の文字列に展開されてその後に文字列が挿入されている可能性?
    menu 経由の候補に対する曖昧補完かもしれない。
    然し、~x となっている物は展開されない筈だし何かが変。
    具体的に何が起こっているのか確かめる必要がある。

    メニューから初期化した cand_cand 及び cand_word は特に変な事にはなっていない。
    そもそも既存の文字列を保持したまま挿入されるという点が何か変である。
    ~1234 が ~~1234 になる。1234 が何処から来たのかという事を考えると、
    これは候補から生成された文字列ではない?

    調べてみると ble/complete/candidates/determine-common-prefix が既に
    ~~1234 という文字列を返している。

    * 調べていくと count-match-chars が 0 を返してそのまま結合している。
      何故 ~ を共有しているのに count-match-chars が 0 になる?
      と思って comp_filter_pattern を確認してみたが何故か空である。

      →単に count-match-chars は comp_filter_pattern を使わないからだった。
      なので init を実行する必要はない。確認するべきは COMPV でった。

    * それから common0 を展開した結果が /home/murase になってしまっている。
      うーん。後に何か文字列が続く事によってそこまでの展開結果が変化してしまう、
      という状況を今まで考慮に入れていなかった。この場合にどの様に取り扱うのかは微妙。

      取り敢えず COMPS で見た時の共通部分は縮約する?
      或いはチルダに関しては何らかの特別な取り扱いを行う?
      よく考えたらグロブ展開でも同様の事は起こるのではないか。
      という事を考えるとチルダに関してだけ特別扱いしても仕方がない。

    結局、既存の文字列 ~1234 と共通部分 ~ を比較したい所が、
    ~1234 と ~ の比較になってしまっていて、
    それが展開されて ~1234 と /home/murase の比較になってしまっている。

    うーん。明確な解決方法はない気がするが COMPS を通じて縮約する事にする?
    或いは * や ~ などを特別扱いして縮約するか…。
    glob を off にして ~ 展開も off にして見る?

    →取り敢えず noglob, notilde で展開した結果を用いて挿入を行う事にした。
    得られた結果に含まれる *?[ などの glob は全て glob として quote せずに挿入してしまう。
    これが意味する所は 'a*b' となっていたとしても、a*b になってしまうという事。
    これは実装の制限である。

  * complete: source:file の実装で ~+ 等の特別なチルダ展開の候補が列挙されない [#D1416]

    これについては一度考察した様な気もするが忘れた。と思って改めて実装を確認し
    てみるとチルダ展開による候補生成は ~ 単体でも発生するので、実は ~ だけでも
    起動する筈である。しかし実際には動いていない。

    x fixed: 動く筈のチルダ展開による候補生成が動いていない。調べてみると
      yield-filenames の中で消滅している様だ。更に調べると cand/yield の中で消
      滅している。filter:head/test で除外されている様だ。head は実際には何の制
      限も行わないという物なので head/test の実装を true に置き換える事にした。

      と思ったがそれで良いのだろうか…。現在の実装だと取り敢えず可能な候補を全
      て列挙しているので、filter をしない様にすると全て列挙されてしまう。

      一方で filter を実行する様にすると filter 側は $COMPV (/home/user) でフィ
      ルタしようとしているのに、こちら側は ~user を渡そうとするので常に除去され
      てしまう。ちゃんと filter する為には COMPS を用いて filter する必要がある。
      →その様に実装した。OK。動いている。

    ? ok: head/test を true に置き換える事による影響は? 他の箇所で従来から直接
      filter:head/test を呼び出していた箇所での振る舞いが変化してしまわないか確
      認する必要がある。

      →やはり filter:head を書き換えるのは止めた。filter:none を新しく追加して
      最初の候補生成の時にだけ filter:none を指定して、それ以外の filter では
      既定で head を使用する事にした。

      また、今まで menu-filter は head に一致する物のみを絞り込んでいたが、候補
      が全て現在入力済み単語に一致しない場合は、最初に生成された候補を全て表示
      する事にした。遡って書き換わる様な候補を補完器が生成したかもしれないし、
      もしそうでなくても生成された候補の中から選べる様にするのは一つの手であるから。

      もしかすると候補が全く生成されない時には再度補完器を呼び出す様になってい
      るかもしれないと思って確認したが、特にそういう事はしていない様だ。よく考
      えたらその様に実装すると本当に一致しない文字列を入力した時に、文字を入力
      する度に補完器を呼び出す事になって効率が悪い。なのでその様な実装になって
      いるとは考えにくい。なので、この可能性は考えなくて良い。(もしそうなってい
      たら勝手に全候補を返すという様に振る舞いを変える訳には行かなくなる。)

  * complete: CDPATH を設定していると候補が重複して生成される (reported by Lennart00) [#D1415]
    https://github.com/ohmybash/oh-my-bash/pull/183
    oh-my-bash の Issue を見ていたら偶然発見した。

    確かにそうだ。そして . を CDPATH に指定する意味があるのかと思ったが、色々試
    してみると、どうやら CDPATH を指定していると現在のディレクトリよりも CDPATH
    で見つかったディレクトリの方が優先される。これを防ぐために . を CDPATH に含
    めるという方法が使える様である。

    後、action:file にして候補を登録しているがこれだとディレクトリが見つからな
    いのでエラー着色になってしまう。新しい action を定義する事にする。

    * うーん。現在、カレントディレクトリ以下のディレクトリ名については
      source:dir を通じて列挙しているが、CDPATH で既に見つかった物と同じファイ
      ル名を持つディレクトリについては yield しない様にする必要がある。

      どの様に処理するべきだろうか。source:dir で何らかの除外条件を外部から指定
      できる様に書き換えるか、或いは source:dir の実装を真似て自前で実装するか。

      →改めて自前で complete:cd 内部で source:dir と同様の事を実行する事にした。
      一部の共通処理は source:tilde として括りだす。実装した。動いている気がする。

    動作確認する。

    x fixed: "[[ ${$1[x\$2]+set} ]]: 誤った代入です" というエラーメッセージ。
      これは ble/set#contains の内部でのクォート忘れ。

    x fixed: cdhist 候補の背景色が濃すぎる気がする→変更した。

    x fixed: 現在のディレクトリ由来のファイル名も cdhist 着色になっている。
      これはディレクトリ名に付加した / を除去するのを忘れて . と比較していた為。

    x fixed: bleopt complete_menu_style=desc にして見た所 segfault した。無限再帰だろうか
      →action:cdpath/get-desc を定義する所を action:file/get-desc を上書きしていた。
      そして、内部では action:file/get-desc を呼び出していた。

    x fixed: やはりg値を合成すると見にくい色になってしまう。
      ディレクトリの種類に応じた色は desc の方で着色するべきでは。

  * complete (source:file): tilde expansion の補完が filter されずに登録される気がする [#D1414]

    際にコードを調べてみると他にも filter されずに登録されてしまう箇所があった
    ので一緒に修正した。

    flag_source_filter に対する修正はyield-filenames の中ではなくて、
    yield-filenames に渡すファイル名を生成している側である呼び出し元で行うべき
    である。その様に書き換えた。

2020-11-15

  * 2020-11-13 complete: cd の曖昧補完で意図せず遡って書き換わる (reported by cmplstofB) [#D1413]
    https://github.com/akinomyoga/ble.sh/issues/67

    これは yield で filter する様にした結果である。progcomp は実行する前に
    compvを reduce する。一方で source:dir は compv が reduce されていないとい
    う前提の下で、maA フラグに従って候補を生成する。その時に filtering は意図的
    に offにしている。ここで progcomp の中から source:dir を呼び出すと reduce
    されたcompv で生成された候補が全て filter なしで登録されてしまう。

    この問題に対する正しい対処法は何だろうか。bash progcomp の枠組みにおける呼
    び出しでは、曖昧補完には対応していないので現状通り reduce して良い。
    complete:cd に関しては曖昧補完を認識しているので、勝手に reduce しない様に
    するべきだろうか。

    * complete:* で個別に曖昧補完に対応する?

      o ble.sh native な補完設定という事であればそれが自然な気がする。

      x 全ての complete:* の実装は曖昧補完に対応する必要がある。ユーザーが補完
        を実装するのが面倒になってしまう。

        →然し現状ではドキュメントも整備していないし実際に自分で定義しているユー
          ザもいないから、破壊的変更は気にせずできる。

        →ユーザが真面目に実装していなかった場合には head に対応する候補が毎回
          生成されるだけなので 2回目以降の呼び出しでは filter されて何も生成さ
          れない。処理時間が無駄に増えるだけである。ユーザの入力があれば候補生
          成を停止している様にしているので見た目の動作としては何も問題は発生し
          ない。

      取り敢えずその様に書き換える事にしたい。この時、reduce はもっと後で実行する必要がある。

      →実装を確認してみた所、実は progcomp は COMPS, COMPV を全く参照していな
      い? つまり、単純に COMPS, COMPV に対する補正をしない様に変更すればOK?

    色々書き換えた。結局、COMPS, COMPV はそのままにして、comp_* の方を適当に
    reduce した物に書き換える事にした。これで問題は起こらない筈。元のデータを書
    き換えていないし、bash progcomp と blesh progcomp で同じ変数を見ているので、
    両者で曖昧補完に対応した補完実装もできるし、対応していない補完実装もできる。

    以下デバグに使った .bashrc の設定

    | # bashrc
    |
    | blehook/eval-after-load complete debug1
    | debug1() {
    |   ble/cmdinfo/complete:cd() {
    |     local ret
    |     ble/complete/source:file/.construct-pathname-pattern "$COMPV"; local pattern=$ret
    |     ble/debug/print-variables COMPS COMPV pattern
    |     ble/complete/util/eval-pathname-expansion "$pattern/"
    |     ble/debug/print-variables ret
    |     ble/complete/util/eval-pathname-expansion "$pattern"
    |     ble/debug/print-variables ret
    |   } >> a.txt 2>&1
    | }
    |
    | comp1() {
    |   ble/debug/print-variables COMP1 COMP2 comp_type
    |   ble/debug/print-variables comp_cword comp_words
    |   ble/debug/print-variables COMP_CWORD COMP_WORDS
    | } &>/dev/tty
    | complete -F comp1 comp1

  * complete: 一旦 option の補完を実行すると bleopt complete_menu_style が書き換わる [#D1412]

    local bleopt_complete_menu_style として書き換わらない様にしている筈なのに。
    これは auto_complete 経由で書き換わっている?
     →やはり auto-complete であった。修正した。

  * syntax: simple-word でない時にエラー着色になってしまう (reported by cmplstofB) [#D1411]
    https://github.com/akinomyoga/ble.sh/issues/68

    #D1409 の書き換えに伴うバグだろう。

    これは簡単なミスだった。is-simple のチェックが抜けていた。locate-filename
    を使う場合は内部で is-simple に相当するチェックを行っていたが、それ以外の単
    語全体をファイル名として判定する場合には is-simple チェックがなくなっていた。
    直した。

2020-11-12

  * syntax: オプションの単語着色にも対応したい [#D1410]

    コードを少し確認してみたが複雑になりそう。- で始まる物については強制的にオプ
    ションと見做す様にする。但し、-- が途中にある場合には着色しない様にする。

    と思ったがその様に実装する為には、コマンド抽出をして -- がないかどうか確認す
    る必要が出てくる。つまり、処理が重くなる可能性があるという事? と思ったが現在
    の実装ではコマンド抽出はどうなっていたのだったか。独自の着色を許すのだとした
    ら何れにしてもコマンド抽出を始めに実行しなければならない。そして各単語につい
    て毎回コマンド抽出をしていると非効率である事から、普通に考えて単語情報はちゃ
    んと既にあると考えるのが自然。現在の実装を確認。

    呼び出し元で -- の確認をしてオプションを付加するのが良い気がする? 実装を確認
    してみたが、単に各単語について word:default を呼び出しているだけであった。つ
    まり、つまり単語について調べる必要がある。

    実装してみたが微妙。途中に = や : がある場合は除外している。本来は = の左側
    と右側で独立に着色を決定したい。右側も着色する為には右側に対してパス名の着色
    を適用できる様にしなければならない。

    パス名については =, : で区切って着色を与えているが最後のパスしか着色していな
    い。パス名の着色について再考してから対応する必要がある気がする。

    → #D1409 で一緒に実装した。

    * -- という引数が指定された後はオプションとして解釈しないという処置が未実装。
      →対応した。

    * mandb による補完候補の着色にも同じ色を用いる。

  * highlight: =, : で区切られたパス名の着色について再考 [#D1409]

    現在の実装では locate-filename で最初に全体に一致を試みて、それから次に先頭
    から順に削っていくという方法になっている。この様になっているのは
    https://... 等の形式の URL または C:\... の形式のファイル名を認識する為であ
    る。これを拡張して任意の場所で切れる様にするにはどうしたら良いか?

    例えば A:B:C となっていたとする。できるだけ長く一致させたいので A:B:C から順
    に試していく? A:B, A と試して、駄目であれば B:C, B, C という順に試していく。
    途中で一致した場合にはそれで確定して、未処理の文字列についてまた続きから試す。

    現在の実装では =, : を等価に取り扱っているが、= は最初の一つだけ処理する様に
    したい。或いは、最初に = で分割して、その後で : で分割する? 何だかよく分から
    ない。。。というより、= については左辺の形に制限を加えるべき。変数代入形式か、
    或いは -[-[:alnum:]_]+ で一致させる事にする。

    a. ^-[-[:alnum:]_]+= に一致する場合には、= 以前を強制的にオプション着色にす
      る。この場合には右辺の中の = は分割に寄与しない。右辺は : で分割しても良い。
    b. ^[[:alnum:]_]+= に一致する場合には全体をファイル名と見做しても良いし、或
      いは、右辺をファイル名と見做しても良い。右辺は : で分割しても良い。
    c. それ以外の場合には = は分割でない。: で分割しても良い。

    1 先ず初めにオプションに一致するか確認して、もし一致したら其処までを処理済みにする。
    2 オプションに一致しない場合には変数代入の形式になっているか確認して、
      もし変数代入の形式であれば = を可能な分割点の候補として登録する。
    3 残りの部分は : を分割点の候補として登録する。
    4 分割点の候補を元にしてできるだけ長く一致させる。

    eval の戦略についても考える必要がある? 分割点が決まったら先に各要素を eval
    してしまうか、或いは、試行の度に eval を実行するか。うーん。各要素を eval し
    てから繋ぐ事を考えていたが、実は試行の度に eval しても良いのではないかという
    気がしてきた。OK

    * done: ble/syntax/progcolor/wattr#* の整備

      次に考えるべき事。各パス要素毎に着色をするとすると、前のパス要素の結果を明
      示的に処理しなくても自動で構築できる様な方法で登録する必要がある。

      wattr を動的に構築できる様に枠組み (ble/syntax/progcolor/wattr#*) を整えた。
      先ずは既存の振る舞いを壊さない様に wattr#* に移行する。以前よりもコードが
      すっきりした。

      更に progcolor/word:default についても全体に wattr#* を使う様に書き換えた。
      前より少しぐちゃっとしている気がしないでもないが、恐らく慣れの問題だろう。
      客観的に考えれば変数の変な取り回しも除かれて前よりも整理されている筈。

    オプションの着色は後回しにして、取り敢えずパス名の着色について再度。

    取り敢えず = による分割は確定という事にして、探索は : 区切りだけにする。或い
    は , も区切り文字として解釈しても良いかもしれない。というのも、
    -Wl,-rpath,... 等の様なオプションの指定の仕方をする事がある為。

    * done: locate-filename を複数のパスを抽出する様に書き換える。
      →書き換えた。ret は配列になり第一要素は今迄と同じく範囲の開始である。
      但し、最後の範囲ではなくて最初の範囲の開始である事には違いがある。
      これだと範囲の開始点以降全てをファイル名とみなす実装に於いて問題が出るが、
      関数の意味的にはそんなに変な拡張ではないので良しとする。

    * done: locate-filename を用いて新しく各パス要素を着色する様に変更した。動い
      ている。古い実装はもう削除しても良い様な気がしている。オプションに関しても
      ちゃんと動いている。

    * ok: highlight: echo hello:~ において ~ の着色が行われない。と思ったが、こ
      れは恐らく意図した振る舞いである。と思ってコードを確認したが、やはりちゃん
      と処理していない気がする。変数代入形式の時には ~ を有効にしたい。と思って
      実際に試してみるとちゃんと変数代入形式の場合には ~ の着色が有効になってい
      る。これについてはどうやって実現されているのか改めて確認が必要である。

      →これについては分かった。文法解釈を参照して tilde がチルダ展開の物かどうか
      判定している。この実装で良い。

    x fixed: パス要素が誤っている場合に locate-filename でファイル名と検出されず
      に着色されない。この場合には途中の正しいディレクトリ名までは着色したいが、
      全体が無効な文字列となってしまっているので全く着色されない。

      認識できないパスに関してはどの様に取り扱うか。: で強制的に区切って着色する
      か、或いは greedy に探索して駄目だった所からまた : を見つけて着色するか。
      自然な振る舞いになる様にしようとすると後者になるが、実装が複雑になる。もし
      その様に実装するのであれば、: で区切ってから着色するのではなくて、最初から
      / と : で区切りながらパスを着色して行く実装にするべきだった。

      うーん。再実装するべきだろうか。再実装するとするとファイルが存在しない時の
      取り扱いについて確認が必要。コマンド名の時にはエラー着色にしていた。然しコ
      マンド名は : による分割の対象ではないので問題ない。

      うーん。どうするのが良いか。: で区切るという規則の引数の場合には何れにして
      も : で分割する。ファイルが存在するかしないかで : で区切るかそうでないかが
      変わるという事はありえない。一方で URL を受け付ける様な引数の場合には : で
      区切るという事はない。色々考えると、URL 判定は : で区切った後に実行するの
      ではなくて、最初に実行するべきなのでは。URL に一致しない時に指定された引数
      が : で区切ったパスなのかそうでないのかの判定が現在の問題である。

      うーん。結局全体が一致しなければ即座に : 区切りであると判断して良いのでは
      ないだろうか。と思ったが新しい未だ存在していないファイルを指定する場合で、
      ディレクトリ名に : が含まれている場合には全体を path として取り扱っても良
      いのではないだろうか。つまり、先ず初めに / で切りながら存在するディレクト
      リまで取得を行う。ディレクトリが存在しなくなってそれ以降に : が含まれてい
      たら : で区切られる物と見做す。ディレクトリ名に : が含まれていた場合には強
      制的に : は無効で良いのではないか。整理すると以下の様になる。

      1 最初に全体に対して URL 判定 / C:\... 判定を行う。
      2 / で切りながら存在するディレクトリまで読んでいく。
      3 (2) のディレクトリ名に : が含まれていれば : 区切りではない。
      4 (2) の残り部分に : が含まれていれば : 区切りである。
        つまり存在するパスに : が含まれず存在しない部分に
        : が含まれる時にのみ : 区切りである。
        どちらにも : が含まれない時にはどう取り扱っても良いので、
        実際の所は、存在するパスに : が含まれていれば : 区切りではない。
        : が含まれていなければ : 区切りである。という判定で良い。

    x ok: 実装してみたがかなり遅い。と思ったが、これは eval の中でグローバル変数
      の復元等の複雑な処理を行っている為である。$HOME などのパラメータ展開が存在
      する場合にはそんなには遅くならない。

      これに関してはまた別の課題として後で考える事にするのが良い。

    x detect-separated-path を実装したら動かなくなっている。常に単一パスと判定さ
      れている。調べたら detect-separated-path の中でファイルが存在しているかど
      うかの判定をするのを忘れていた。常に存在する取り扱いになっていた。修正した。

      しかし、未だ動かない。今度は locate-filename が動いていない気がする。丁寧
      に見てみると実は wtxt を更新するのを忘れていた。直した。今度は動いている。

      うーん。PATH=... の場合にはこれで動く様になったが、今度は通常の引数の場合
      に全く動いていない。prefix が存在しない場合でも動かなくなっている。何故だ
      ろう。

  * syntax: [:alnum:] 等を使ってしまったが [#D1408]

    良く考えたら locale 依存で変な文字も含むのでやはり直接 a-zA-Z0-9 等と指定す
    る必要がある。

    →これは全体的に書き直した。vi.sh の [:alnum:] は vim の単語の判定に似せた物
    なので [:alnum:] で良い。decode.sh に残っている [:alnum:] に関しても、通常文
    字でない事の判定なのでそのままで良い。

2020-11-11

  * global: 改めて ble/bin/* の使用について確認する [#D1407]

    core-syntax.sh に関しては #D1406 により完全に ble/bin/* は排除した。

    edit.sh に関しては

    - bash-4.3 以下で ttyname を取得する為に tty を使用している
    - command-help を表示する為に awk, man を使用している。
    - removed: suppress_bash_output の終了処理で rm を使用している。
      実はこれは _ble_base_run の一括の削除に任せれば良いのではないか。
      →うーん。やっぱりそうだ。$_ble_base_run で削除されるのだから
      わざわざここで rm を呼び出す必要はない。
      ファイルの存在・非存在が振る舞いに影響を与える物でもない。
      一応中身をクリアしておく事にする。
    - bash-3.2 以下では C-d を捉える為に色々していて、その為に
      grep, rm, mkfifo を使っている。これは仕方がない。

    ble.pp

    - rm, mkdir, chmod, readlink: ble.sh のディレクトリの初期化・終了処理

    def.sh

    - blehook/.compatibility-ble-0.3/check: cat (ユーザーにメッセージを表示する)

    util.sh

    - ble/util/declare-print-definitions: awk
      declare -p の出力結果のバグを修正する為に用いている。
    - ble/util/strftime (bash-4.1 以下): date
    - ble/util/msleep (bash-4.3 以下): rm, mkfifo, sleep, sleepenh, usleep, etc.
    - ble/util/getmtime: date, stat (この関数自体使われていない)
    - ble/term/stty: stty ユーザーコマンドを実行する時の環境の調整

    decode.sh

    - ble/decode/nonblocking-read: od (大量の入力があった時の処理の為)
    - ble/decode/cmap/initialize: awk (cmap キャッシュ初期化)
    - ble/decode/bind/.generate-source-to-unbind-default: (初期化)
    - ble-bind -L: sed
    - ble/builtin/bind/.reconstruct-user-settings: sed, cat, mv, awk

    benchmark.sh

    - (diagnose) ble-measure: awk (小数の計算)

    history.sh

    - awk, mv, sed, wc

    core-complete.sh

    - (performance) grep, sed, awk, sort
    - (mandb) man, gzip, nroff, mkdir

    取り敢えず wiki/Note.md にまとめた。

    * 他に > でリダイレクトしている箇所がまた現れていたのでこれを >| に修正する。

  * syntax: enable -p | grep で builtin を判定しているのは何故か [#D1406]

    core-syntax.sh 及び edit.sh (command-help) で以下の様な判定をしている。

    enable -p | ble/bin/grep -q -F -x "enable $cmd" &>/dev/null

    何故単に type -t $cmd を用いなかったのか。或いは初期からあったコードの可能性
    もある。と思ったが 3 forks + 2 exec と書いている事から速度については意識して
    いた筈の気もする。どの時点でこのコードになったのか経緯を調べる必要がある。

    変更履歴を辿ると以下の様になっている。

    9aa1e267 (Koichi Murase 2015-02-16 03:55:37 +0900 2396)     elif enable -p | fgrep -xq "enable $cmd" &>/dev/null; then
    a4f89a71 (Koichi Murase 2015-12-03 08:10:41 +0900 4425)     elif enable -p | command grep -q -F -x "enable $cmd" &>/dev/null; then
    1649187a (Koichi Murase 2018-02-12 13:52:39 +0900 5832)     elif enable -p | ble/bin/grep -q -F -x "enable $cmd" &>/dev/null; then

    9aa1e267 は一番最初に ble-syntax.sh を repository に追加した commit である。
    つまり、enable -p の使用は一番最初期のコードの名残である。
    これは type -t $cmd を用いた実装に切り替えて良い気がする。

    と思ったが微妙。どうも keyword が quote されていてコマンドとして取り扱う必要
    がある時に、どうやってそのコマンドの種類を特定するのかという話の様だ。
    loadable builtin で keyword と同名のコマンドをロードしていた時にどの様に取り
    扱うのかという事。type -tは "keyword" を返すので使えない。

    * 実際にダミーの builtin を作成して試してみる? Cygwin で builtin をコンパイ
      ルしようとしたらできない。昔コンパイルした様な気がする。その時にはどうした
      のだったか。libbash.dll 的な何かを作った様な気がする。

      ? と思ったが bash の既定の loadale builtin ではどの様にコンパイルしている
        のだろうか。或いは、実は cygwin 上では loadable builtin はコンパイルしな
        い?  →実際に確認した所コンパイルされていない。Makefile は生成されている
        のでディレクトリに入って make して見るが、そうするとやはり同様のエラーが
        出てコンパイルできない様だ。

      bash の Makefile に ($(Program) に対するルールを弄って) 以下を追加して libbash.dll を得た。

      libbash: libbash-5.0.11.dll
      libbash-5.0.11.dll:  .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP)
          $(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -shared -o $@ $(OBJECTS) $(LIBS)

      これに対してリンクしてビルドすると一応ビルドはできた。然し実際に実行してみ
      ようとすると先ず libbash-5.0.11.dll が存在しないとロードに失敗する。そして
      実際に実行してみると libbash-5.0.11 の内部の変数に対して処理を実行している
      様で、本体の bash に対して変数に対するアクセスが反映されていない。駄目だ。

      唯、keyword と同名の物が存在する時にどう振る舞うのかについての実験はできる
      だろう。これで実際に簡単なコマンドを作成して実行してみる事にした。hello と
      いう名前の builtin コマンドは無事に作成して呼び出す事ができたが、time や
      while と言った名前のコマンドについては駄目。enable -f でロードする所までは
      できるが、実際に呼び出そうとするとコマンドが見つかりませんでしたというメッ
      セージが出て実行されない。

      これは cygwin 特有の問題だろうか。chat でも試してみたが駄目だった。
      bash-3.0 でも振る舞いは同じである。つまり、enable -p で確認するとちゃんと
      出力されていたとしても keyword と同名のコマンドは定義しても使えない。

      % 結局、enable -p は実際にその builtin が使えるかどうかの判定には使えない。
      % 表示されていても keyword に一致するコマンドは実行する事ができないからで
      % ある。

      と、思ったら 'while' を上書きするとコマンドが見つかりません、という状態に
      なるが、'time' というコマンドを上書きするとちゃんと動く。'while' を続けて
      ロードすると 'time' までも使えなくなってしまう。Cygwin でも再現した。

    試してみて分かった事は enable -p はコマンドを実際に使えても使えなくても表示
    してしまうが、enable "$cmd" はコマンドが有効でないと失敗するという事。

    うーん。分かった。type -a -t $cmd を実行すれば良い。実際に使える時に2番目以
    降にちゃんと候補が表示される。ちゃんと 'while' をロードすると他も使えなくな
    るという振る舞いも type -a に反映されている。どうせなので ble/util/type で
    -a を指定して全ての候補について取得してしまう事にした。

2020-11-06

  * complete: コマンドラインオプションの説明を表示する機能 [#D1405]
    https://www.reddit.com/r/bash/comments/joafpu/is_it_possible_to_achieve_zsh_like_completion_in/

    やはりそういった要望は存在する物である。

    x 然し、問題は man から抽出するにしても --help から抽出するにしても、別にこ
      れらのファイルは文法が決まっている訳でもないので、抽出ミスが生じる可能性が
      あるという事である。

      man (roff) の形式の方が未だ信頼性はある。然し、サブコマンドのオプションを
      拾う可能性や諸々がある。更に -- の後に続く引数がオプションとして取り扱われ
      るかそうでないかというのもコマンドに依存して色々だろうと考えられる。これら
      に対する完全な解は存在しないと思われる。或る程度の間違いをユーザに許容して
      もらわなければならない。これに関してはオプションでユーザに有効化してもらう
      事にするのが良い気がする。

    x 更に言うと --help を認識しないコマンドで勝手に実行すると困るものだって存在
      するかもしれない。例えばユーザーが作った command.sh 等のような物は引数を水
      に既定の処理を実行する物だって存在する。という事を考えると勝手に知らないコ
      マンドに対して --help をつけて呼び出す訳には行かない。

    zsh でどうなっているのか調べてみる。autoload -U compinit; compinit とすると
    初期化される? オプションを補完している時にはオプション名と説明が表示されるが、
    ファイル名が表示されている時にはファイル名だけが表示される。何を補完している
    かに応じて表示の形式を変更している様である。そもそも引数が - で始まらない場
    合にはオプション名は補完候補に出さない。また - で始まる引数の場合には通常の
    ファイル名は補完候補に出さない。という具合に排他的になっているからである。

    ble.sh の argument でもその様に実装して良いのかもしれない。現在の実装だと -
    で始まる引数であってもファイル名に曖昧補完してしまって使いにくい。- で始まる
    場合には専らにオプションとして補完するのが自然だろう。

    zsh のオプションの説明は grep で確認した所 man でも --help でもない。どうも、
    自前で用意した説明を表示している可能性?

    * man の解析
      取り敢えず ble.sh では man を解析するという具合にしても良い気がする。
      man の解析は…awk を使っても良いだろうという気がする。
      然しその前に man の文法についてちゃんと調べておく必要がある気がする。

      - .XX は特別に処理する必要がある。
      - \- は - に置換する。
      - \^ は空文字列に置換する。
        (grep の man で -- が \-\^\- とエスケープされている。\-\- だと駄目な理由が存在する?)
        groff を見ると \^ はとても小さな空白 (1/12em よりも小さい)という事になっている。
      - [ や ] の周辺の空白は除去する。
      - "..." はそのまま表示する。

      groff のマニュアルを見ても .TP 等は載っていない。
      https://man7.org/linux/man-pages/man7/roff.7.html に載っている .XX には
      結構 man で使われている物が載っているがそれでも .TP は載っていない。

      - https://linuxjm.osdn.jp/html/LDP_man-pages/man7/man.7.html に .TP が載っている。
        https://linuxjm.osdn.jp/html/GNU_groff/man7/groff_man.7.html にも説明が載っている。
        どうやら -mNAME でマクロ定義ファイル NAME.tmac を読み込む事ができて、
        man の指定は an.tmac というマクロファイルにあるので roff のオプションに
        -man と指定できるという仕組みになっている様である。

      - 様々の複雑な指定が存在している事を考えると man のソースではなくて、
        man の出力を見るべきだろうか。うーん。或いは、
        自前で色々弄った後に groff に食わせる。groff -Tascii -man file.1 で行ける。
        試しに適当な内容を作って groff に食わせたが何も起こらない。
        どうも .TH で最初にページ名などを初期化しなければならない様だ。
        groff がない場合はどうするのか。troff と nroff を試してみたが、
        troff はよく分からない出力結果になった。nroff は groff と同じ結果。
        調べると troff は印刷専用のようである。

      うーん。候補と表示内容を変更したい時にはどうすれば良いか。
      既存の物でそれを実行していた物があったような気もするし、
      なかった様な気もする。表示内容を勝手に変更した時の問題は、
      部分一致の太文字を表示できなくなるという事。
      という事を考えるとやはり候補と表示内容は一致させている気がする。

      →と思ったら init-menu-item で prefix と suffix を指定する事ができる。
      ここで [=WHEN] だとかその他諸々を記録すれば良い。

      取り敢えず補完の表示に必要な情報は抽出できた様な気がする。
      然し問題点はこれをどのように bash の配列に記録するのかという事。
      例えば抽出した情報はファイルに保存しておく。
      補完を実行する時にその情報を読み取り候補生成する。
      全てのデータを DATA に保存してしまう事にすれば良い気がする。

    * 指定したコマンドに対応する man を探し当てる方法?
      MANPATH 及び /usr/share/man を探す?
      man1, man8 の辺りを探索すれば良い気がする。
      : で区切られたパスからファイルを探す関数は既にあっただろうか。
      ない気がする。新しく実装して良い気がする。

      manpath は /etc/manpath.config), ~/.manpath, MANPATH
      /usr/local/etc/man_db.conf など様々な場所に保存されている?
      どうやら man -w で manpath 一覧が出力される様だ。
      更に man -w grep 等で実際のファイルの場所が出力される様だ。
      然し、これは POSIX ではない様である。

      従って、(1) man -w grep を試す (2) man -w を試す (3) /etc/* を読み取る (4)
      MANPATH を参照する…。と思ったが、/etc/* の中身は結構複雑である。そもそも
      /etc/* の設定に対応している man 実装は高機能なので -w ぐらい対応していても
      良い気がする。殊更に独自実装をする必要はないのではないか。単に
      /usr/share/man:/usr/local/share/man:/usr/local/man を探索すれば良いのでは
      ないだろうか。→その様に実装した。実は簡単だった。わざわざパス検索用の関数
      を用意する程でもない?

    これ以降の変更は core-complete.sh に対する変更が必要なので取り敢えずここまで。

    * 実際に得られた結果を用いて実装した所、呆気なく動いている様な気がする。

    x done: 但し、説明を表示する為には bleopt を desc-raw に設定していなければな
      らない。という事を考えると menu_style を動的に変更できる仕組みを整えるべき
      かもしれない。然し、menu_style が動的に変わってしまうと問題になるので、
      menu の何処かに記録しておく必要がある…と思ったがそれは既にその様にしてい
      る筈。これも簡単に対応できた。

  * complete: filter を cand/yield の中で実行する枠組みを整える (motivated by timjrd) [#D1404]

    filter:substr に対して source:file がより緩い条件で候補を生成したとしても、
    後の filter:substr/filter で除外されてしまう。そもそも後で一括して filter す
    る事自体が物事を複雑にしている。cand/yield で cand_cand その他に登録する時点
    で filter してしまって良い様な気がする。

    更に、source:file でフィルタを実行しても良いという事を確かめる必要がある。

    先ずその様に書き換えても問題が起こらないかを確認する。

    * 先ず filter でやっている事を確認する。

      filter-by-regex は cand_cand に対してフィルターを実行している。
      filter-word-by-prefix は cand_word に対してフィルターを実行している。
      →これは別の filtering で使っている物であって関係ない。
      cand_cand は補完単語を格納していて、cand_word が実際に挿入される文字列を格納している。
      filter-by-command はコマンドを指定できる物である。
      実際に使っているのは filter:substr

    * 問題がある。独自に filter すると filter:substr/match の実装が乖離してしまう。
      つまり、メニュー選択で太字の着色がなされなくなってしまう。
      候補ごとにフィルターを記録する様にするとまた面倒になる。

      或いは始めから一致位置を計算して記録する事にする? 然し実際には使われない事
      の方が多いのでやはり重さを考えると一致位置を一緒に計算するのは避けたい。
      action に処理を紐付ける事にする? 然し filter の種類の情報も記録しなければならない。

    取り敢えず独自にフィルターを実行するかどうかはさておき、
    cand/yield の内部でフィルタを実行するという実装にはする。
    そちらの方が自然だからである。

    * done: comp_filter_type と comp_filter_pattern の宣言されている場所、
      代入されている場所、使用している箇所を確認する。
      現状では別々の場所で宣言・代入しているが、
      両者の取り扱いを統一できればしたい。

      comp_filter_type について先ず調べる。

      宣言 ble/complete/candidates/generate-with-filter
        ここで宣言したものは以下で使用されている。
        使用 ble/complete/source:*

        通常の補完の場合にはどうだったかと思ったが、
        調べてみると head フィルタを使っていたので、
        ちゃんと ble/complete/candidates/generate-with-filter
        を経由して呼び出されていた。

        ble/complete/source:* の呼び出し元は他には存在していない。

      宣言 ble/complete/menu-complete.class/render-item
        ここでの宣言・設定はこの関数の中で閉じている気がする。
        ややこしいのでこれは単に filter_type 等に変更するのが良い気がする。
      宣言 ble/widget/auto_complete/self-insert
        ここでの宣言・設定もこの関数の中で閉じてはいるが、
        comp_filter_pattern については共有している。
        対称性を考えるとこのまま comp_filter_type で良い気がする。

      comp_filter_pattern について次に調べる。

      宣言 ble/widget/complete
      宣言 ble/complete/menu-filter/.filter-candidates
      宣言 ble/complete/auto-complete/.check-context
      宣言 ble/widget/auto_complete/self-insert
      宣言 ble/complete/source:sabbrev

        どうやら兎に角 filter を呼び出している箇所で全て宣言している様である。

      設定 ble/complete/candidates/filter:*/init
      使用 ble/complete/candidates/filter:*/filter
      使用 ble/complete/candidates/filter:*/test

        実際の値の設定などに関しては filter 内部で閉じている。

      filter の関数を呼び出している箇所は多岐に渡る。

      ble/widget/complete
        ble/complete/insert-common
          ble/complete/candidates/determine-common-prefix
            ble/complete/cndidates/filter:*/count-match-chars [OK]
        ble/complete/insert-braces
          ble/complete/insert-common..

      ble/complete/menu-complete.class/render-item
        ble/complete/cndidates/filter:*/match [OK]

      ble/complete/menu-filter/.filter-candidates
        これは内部で宣言・使用する事にした。

      ble/widget/auto_complete/self-insert
        これも内部で宣言・使用する事にした。

      関数 ble/complete/menu/generate-candidates-from-menu

        ここで comp_filter_pattern の値を復元しようとしているが、実際には空の値
        を設定している。source の内部でしか使わないからというコメントが書かれて
        いるが、実際には insert-common の内部でcount-match-chars を使っている。
        と思ったが、count-match-chars は実は comp_filter_pattern は使っていなかっ
        た。従って comp_filter_type も comp_filter_pattern も使っていない。代わ
        りに、自分で filter_type も自分で明示して呼び出す必要がある。

        実は全く使っていないのであればそもそも comp_filter_pattern を設定する必
        要はないのでは。というより ble/widget/complete の内部で宣言する必要はな
        いのではないか。

      うーん。ble/complete/candidate/filter:*/init 等の呼び出しを実行する
      関数を追加してしまう? comp_filter_type はその時に pattern と一緒に宣言する。

        ble/complete/candidates/filter#init head "$COMPS"
        ble/complete/candidates/filter#apply
        ble/complete/candidates/filter#test "$cand"

      match, count-match-chars は stateless なので直接呼び出して使う事にする。

    * done: 現在 comp_filter_pattern は ble/widget/complete の内部で宣言しているが、
      これは実際に filter を使う箇所で宣言するだけで良いのではないか。
      改めて filter#* が使われている箇所を確認する。

      - ble/complete/candidates/generate-with-filter
        comp_filter_type, comp_filter_pattern は ble/widget/complete ではなく
        generate-with-filter の内部で宣言する事にした。
      - ble/complete/menu-filter/.filter-candidates
        これは既にその場で宣言している。
      - ble/widget/auto_complete/self-insert
        これも既にその場で宣言している。
      - ble/complete/source:sabbrev
        これは source の内部なので comp_filter_type,
        comp_filter_pattern は既に宣言されている。

    次に cand/yield の内部で filter を実行する様に変更する。

    * done: その様に変更した。というより一行追加しただけである。
      同時に複数の関数が不要になった気がする。
      大分コードが綺麗になった気がする。

    ? cand/yield で filter するとしても、menu-filter では結局 filter されてしま
      う。従って menu-filter でも filter 方法を変更する必要があるのではないか。

      或いは substr では候補を何も生成せずに hsubseq まで行ってから substr に相
      当する候補を生成して、もし何もなければ本来の subseq や hsubseq を生成する
      という方針も考えられる…。と思ったが、そうすると別の source による結果が
      存在する時に substr でそちらの候補だけが表示される事になり不自然な結果に
      なる。

      そもそも曖昧補完の substr で path component 毎に substr にして生成する必
      要性があるだろうか。考えてみたが余り複雑な事をしてもユーザがついて行けな
      い。という事を考えると、やはり *dir1/dir2/file* の形式だけを取り敢えず許
      すというので良いのではないか。或いは何も生成しない。

    % source 側で(既定と異なる) filter するに当たっての現状の問題点は以下の二つ
    %
    % * menu-filter で結局通常の filter 動作で除外されてしまうという事
    % * menu の着色でどのように一致したのかの着色が正しく反映されない事
    %
    % * 共通部分の何処までを挿入するかの決定。
    %
    %   これは実は各候補毎に決定しているのではなくて共通の設定として決定しているの
    %   で、単純に source:file に合わせて計算するという事はできない。これは遡った
    %   書き換えが起こった時に今までの候補生成ができなくなる事を防ぐ為のものなので
    %   特別な処理はしなくて大丈夫な気がする。しかし source:file の様に足並みを外
    %   すような物があった場合に本当に正しく動くのかに関しては注意が必要である。
    %
    %   そもそも共通部分の挿入によって候補生成が破壊されるのはどのような時だったか。
    %   うーん。分かった。まず最初に通常の common-prefix を求めているが、曖昧補完
    %   の場合には必ずしも common-prefix が元々の COMPV の文字を全て含んでいるとは
    %   限らない。(本来は common-prefix ではなくて common subseq に対応する何かを
    %   求める必要があるが、展開などを考えると難しいという事か)。
    %
    % DATA 経由で特別な動作を実装する?
    %
    % * source:file は action:file 及び action:tilde を生成している。
    %   と思ってよく見てみると action:tilde の場合にはチルダ展開のみしか
    %   候補生成していないので、実際には action:file を気にすれば良い。
    %
    %   一方で source:glob も action:file を生成している。
    %   source:glob については曖昧補完の時には候補を生成していない。
    %
    %   何れにしても action:file に対して DATA を指定している物は存在していないので、
    %   気にせずに DATA に新しく filter_type 等指定しても良い気がする。
    %   と思ったら source:argument も file を生成している。
    %
    % 自前の filter を実行しているかどうかに関しては、
    % cand/yield の時点で判定可能なので、内部で処理する?
    % と思ったが自前でフィルタしていても元のフィルタの振る舞いに準拠している可能性もある。
    % その場合には自分で処理するのではなくてやはり既定の filter に処理してもらいたい。
    %
    % うーん。改めて確認すると construct-pathname-pattern を使用している箇所は複数存在する。
    %
    % source:file,directory でファイル名を列挙している箇所 (action:file)。
    % source:argumet で = の右側のファイルを生成している箇所 (action:file_rhs)。
    % source:command でディレクトリ名を列挙している箇所 (action:command)。

    うーん。色々考えると substr を source:file に対して特別に実装する必要がある
    のか疑問である。実のところ同等の候補が subseq, hsubseq で生成されるのだから
    substr の段階で候補を生成しなくても良い気がする。

    特別な実装はしないという事に決めた。

  * syntax: [!...] が常にエラー着色になっている問題 [#D1403]

    うーん。これは ble/syntax:bash/simple-word/is-simple が成功しているのに、
    ble/syntax:bash/simple-word/evaluate-path-spec が失敗しているのが行けない。
    正規表現の構築で ! を含めるのを忘れているという事だろうか。

    is-simple で使っている正規表現は以下の通り。
      local letter='\[[!^]|[^'${_ble_syntax_bashc_simple}']'
      _ble_syntax_bash_simple_rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter')'
      _ble_syntax_bash_simple_rex_word='^'$_ble_syntax_bash_simple_rex_element'+$'

    evaluate-path-spec で使っている正規表現は以下の通り。
      local letter1='[^'$sep$_ble_syntax_bashc_simple']'
      rex_element='('$bquot'|'$squot'|'$dquot'|'$param'|'$letter1')+'

      あー。分かった。letter で特別扱いしている物を入れるのを忘れている。

    他にも同様の違いがある物が色々ある。これは #D1303 の cmplstofB さんの報告が
    あった時の修正で中途半端な修正になっていたのが原因。合わせて関連する letter
    の正規表現も一括して修正する。

  * syntax: glob bracket expression で POSIX [...] に対応していない (reported by alvinseville7cf) [#D1402]
    https://github.com/akinomyoga/ble.sh/issues/66

    これは簡単に対応できると思ったが動いていない。何故?
    どうも [...] の2文字目は既に特別に処理してしまっている様子。
    と思ったがそうではなかった。条件コマンドの [[ を判定する為に、
    [[ の連なりは連続して読み取るという事にしていたのである。

    これをどうにかして防ぐ?  [[= [[. [[: の時には 1 文字だけしか読まない様にする?
    これだと余分に先読みしている事になるが仕方がない。

    またそれとは別の問題として [![:lower:]] が何故か常にエラー着色になる。
    failglob かどうかに関わらず。履歴展開が関係している可能性?
    というより [!x].txt としてもエラー着色になっている。
    もう ! が存在しているだけでエラーという事なのだろうか。
    うーん。然し glob でなければ問題は起こっていない気がする。
    [^x].txt でもエラー着色になる。

    更に [[:lower:]] が simple words ではない事になっている?

2020-10-10

  * 2020-09-07 prompt: rps1 の内容が長くなった時に表示が乱れる [#D1401]
    次の行に改行してしまう。これは表示している内容に依存せずに長さだけで決まる様だ。

    入力部分に未だ 10 文字程度の余裕がある段階で問題が発生している。
    これはもしかするとプロンプトを表示しなくする条件と関連している可能性?
    或いはプロンプトの範囲を制限する事に失敗している可能性?
    スペースが限られている時に rprompt をどの様に処理しているか確認する必要がある。

    変なのは長さが足りなくなると一番最後の列から表示し始める様に変化してしまう
    という事。謎。或いは本当は全く表示しない様にした筈なのに表示されてしまって
    いるという事なのだろうか。

    →分かった。修正した。rps1_show の時にだけ表示するべき所が常に表示される様
      になっていた。

    * 然し、rps1_clear と rps1_show というのがあって、これの違いは何だろうか。
      rps1_clear は前回は表示されていたけれども新しく消す事になったという事を表
      すのだろうか。だとすると、動的に rps1 の内容が変化した時に残像の様な物が
      残ってしまうのではないだろうか。と思ったが、残像が残ってしまうのはどの様
      にしてもやはりそうなのではないかという気がする。

      % →取り敢えず rprompt を描画する場合には先ず消去を行う事にした。(本来は
      % rprompt の前回の表示内容を管理してそれに応じて消去・更新をするべきなの
      % だとは思われる。)

      と思ったら、消去に関しては既にその様になっていた。然し、消去の判定は単に
      rps1_transient によって、次の行に移る時に削除するという処理だけの様である。
      rps1 の内容が変更された時には前の描画を削除するという様な処理は行わない様
      である。というより、rps1 の内容が変更されたという事が分かる時には既に前回
      の rps1 の内容についての情報は喪われているので現在の実装では消去する事が
      できない。

      現在の実装では transient によって rps1 が消去された時に、改めて
      ble/textarea#render/.cleanup-trailing-spaces-after-newlineを呼び出してい
      る。これが何だったかというと…。端末に無駄な空白が記録されるのを防ぐ為だっ
      た。rps1 が表示されている時にその間に空白が埋められるのは仕方がないとして、
      rps1 がない時には空白ではなくて NUL がそこにあるという状態にしたい。

      - rps1_clear=1 rps1_show= → 消去
      - rps1_clear= rps1_show=1 → 描画or再描画
      - rps1_clear= rps1_show= → 前回表示した物のまま

      前回表示していなくて今回新しく表示する場合はどうなるか?
      →大丈夫。消去して新しく描画する事になる。
      前回表示していて今回表示しない場合にはどうなるか。
      →表示したままになってしまう。これだと表示を取り消す筈なのにそのまま
        前回の内容が残ってしまう。

      問題は前回表示していたのか表示していなかったのかの情報が記録されていない
      という事。前回表示していたかどうかに関わらず動作する方法は存在するだろう
      か。前回表示していても表示していなくても、今回表示するのであれば
      $_ble_edit_rprompt_dirty に委ねれば良い。では今回表示しない場合にどうする
      か。前回表示していれば消去するし、前回表示していなければそのままで良い。
      取り敢えず毎回消去すれば良いだろうか。然し、そうすると表示していない状態
      の時には更新がある度に毎回消去が発生する事になり非効率的であ
      る。_ble_edit_rprompt_dirty を参照しても表示を実行していないので常に 1 に
      設定されている。そういう事を考えるとやはり新しい変数を作って現在非表示か
      どうかを管理した方が良いのではないだろうか。

      →取り敢えずコードを整理した。rps1_{enabled,clear,show} 等の様々な変数が
      あったが、整理して rps1_enabled だけを用いる事にした。

  * prompt: 丁度折返しの起こる場所の直後が全角文字の時に空白文字が余分に入る [#D1400]
    screen の中でも発生しているし contra の中でも発生している。
    →確認したら普通に padding 文字の幅の計算をみすしていた。修正した。

  * ble_debug 配列の表示が冗長なのを改善できないか [#D1399]
    多少コンパクトになる様にして quote を着色する様にした。

  * ble_debug 改名 [#D1398]
    bleopt syntax_debug に改名した。

  * complete: shopt progcomp_alias とは何だろう [#D1397]
    progcomp の補完関数の探索に alias 展開も考慮に入れるという物。
    この機能自体は ble.sh にもある様な気がするが、
    実際に progcomp に対して有効になっていたかは分からない。
    →これは実際に確かめてみた所、実装済みだった。
    単に shopt -q progcomp_alias を見て機能を無効化できる様にした。

  * menu: やはり上下移動は一番最初の列を覚えておくべき [#D1396]
    実装した。逆方向の探索の実装は非効率的な気がする。
    現在の実装では最初から全ての要素を見ていって調べる事になっている。

    a 一つの方法は二分探索して同じ行の始まりに移動するという事。
    b もう一つの方法は逆方向から要素を参照するという事。最近の実験によれば実は
      配列を逆方向に触るのは最近の bash ではそんなに遅くない。何より大量の要素
      を抱えた配列でなければ問題は起こらない。今の場合は探索対称の配列は現在の
      ページに含まれている要素しか含んでいないので、要素数が物凄く沢山という事
      もないし、逆方向に探索する事による速度の問題はないと考えられる。

    取り敢えず逆方向から一つずつ見ていく方式で再実装した。
    速度は改善した気がする。ちゃんと動いている。

2020-09-26

  * edit: 行末まで色が残ってしまう問題を修正したと思ったが直っていない [#D1395]

    % どうやら contra & ble.sh のバグが組み合わさって
    % screen の内部でも再現しなくなっていただけで未だ問題は直っていない様だ。

    否、rps1 が表示されている時には問題ないが、rps1 がない時に問題が生じるという事の様だ。

  * 2020-09-01 color: 24bit color を使うと背景色がおかしくなる [#D1394]

    これは contra の方で修正した。

    | $ ble-color-setface command_builtin 'fg=#4bd'
    | $ echo hello
    | $ echo
    | $
    |
    | auto_complete の背景色がクリアされないまま残ってしまっている?
    | printf '\e[m' してもそのままになってしまう。
    | C-l しても背景色がクリアされないまま残っている。
    | layer のキャッシュに削除しきれない物が残っている?
    | と思ったがそうでもないようだ。
    |
    | どうも contra の方のバグの様な気がする。ED 等の塗りつぶしに使う属性が
    | 書き換えられてしまっているか或いは描画時のブラシの管理が狂っている。
    | contra x11 でも再現する。xterm, mintty では再現しない。
    | やはり contra のバグだろう。

  * edit: mc の対策として sgr0 を省略する様にしたら着色が残ってしまう様になった [#D1393]

    何故だろうか。うーん。contra の中だと発生しない。
    screen の中だと発生する。mintty や cygwin/ConPTY でも発生する。

    contra の中で発生していないし rps1 がなくても発生している事を考えると、
    別に空白文字が実際に大量に出力されているという訳でもないのだろう。
    具体的にどの様な出力がされているのかについて調べてみる事にする。

    →調べると ECH(113) が出力されている。成程、これで contra と他の terminal の
    振る舞いの違いが説明できる。ECH の出どころは何処か。put-ech.draw を見張って
    見たが此処は通過しない様だ。_ble_term_ech で調べると、

    * reject: もう一つは textmap#update にある。eraser という所で行のそれ以降の
      文字列を消去している。取り敢えずここに _ble_term_sgr0 を入れる事にする。
      →と思ったが此処を修正しても何も変化がない。此処は関係ない?

      ? 懸念: SGR を復元する必要があるのではないか?

        _ble_textmap_ichg は関係あるだろうか。
        _ble_textmap_ichg は改行について登録している。
        というかこれは #T0005 で議論している内容である。
        #T0005 の内容は改行にエラー着色がある時にそれをどう表示するかという話。
        改行の "SGR が行末まで反映されるのを防ぐ" のではなくて、
        "一文字だけ着色" などの細かい制御をどうするかという話である。
        確かに、全く表示しないというのでも良いのかなど色々単純ではない。
        今回は textmap#update に対しては変更は行わない事にする。

    * ok: もう一つの箇所は ble/textarea#render/.erase-forward-line.draw である。
      ここにも _ble_term_sgr0 を入れる事にした。
      →これにより動く様になった。

    * ok: rps がない場合には EL が使われている。
      この時にもちゃんと対策する必要があるのでは。
      →これも上と同じ箇所での処理である。同様に _ble_term_sgr0 を入れる。

    * ok: contra が ECH に対して現在の背景色を適用しないのは意図的だったか。
      うーん。変だ。既定では mode_bce が true なので現在の背景色で ECH する筈。
      然し、実際には反映されていない。何故だろうか。うーん。これはバグである。
      →これは contra を修正した。

  * edit: mc と一緒に使うと mc が固まる (reported by onelittlehope) [#D1392]
    https://github.com/akinomyoga/ble.sh/issues/62

    報告した症状は起動時に 10s の delay が入るということ。
    これは自分の手許でも再現する。

    | 何故だろうか。取り敢えず実行してみると mc は新しく PTY を作って、その中で
    | bash を interactive に起動する様子である。
    |
    | というか mc はどういう言語で書かれているんだ?  PTY を生成しているという事は
    | bash という事はなかろう。何のために bash を起動している? 不思議なのは実際に
    | コマンドを実行する場合にはnon-interactive の bash が使われているということ。
    | 或いは、ble.sh がロードされていなければ interactive になるのか。fallback と
    | して non-intarcive の bash になっているのか。
    | →どうやらその様である。
    |   ble.sh なしで起動した時には interactive mode になっている。

    * mc はコマンドを受け取る為に PTY を開いて中で bash を interactive mode で起動する。
      然し、ble.sh が有効の時には何らかの timeout により non-interactive bash に fallback する。

    | prompt-attach をしない様にすればOK? と思ったが実際に attach するとやはり動かない。
    | うーん。mc は一体何を期待しているのだろうか。或いは… C-q 等の状態になっている可能性?
    | 或いは stty の状態を ble.sh が変更しようとするのがいけない可能性?
    |
    | もしかして mc はプロンプトが表示されるのを待っている可能性?
    | そして PS1= を設定している。と思ったが、vi モードの時には -- INSERT -- を表示するから
    | それを prompt だと判定しても良いのではないかという気がする。
    | 実際に一回起動してから source ble.sh すると -- INSERT -- をプロンプトだと思う様である。
    | それに PS1= を設定するのにプロンプトが表示されるのを待つというのは変である。

    mc の中にいる事を判定できる方法はあるだろうか。例えば環境変数が設定されているかなど。
    調べてみると以下の変数が設定されているので検出する事は可能である。
    そもそも mc は自身の line editor を使っている様なので、
    ble.sh が使えなくても特に問題はない。
    なので基本的には mc の内部では ble.sh を無効にするという方法で良い筈。

    declare -x MC_SID="30814"
    declare -x MC_TMPDIR="/var/tmp/mc-murase"

    一方で何故この様な振る舞いになるのか調べておく必要はある。
    ソースコードは以下にある。C言語で書かれている。
    https://github.com/MidnightCommander/mc

    | ソースコードを検索してみたが特に bind を使って bash と交信しているという事はない気がする。
    |
    | * TERM も別に mc の物を設定しているという訳ではない。
    | * ble-0.1 でも同様に問題は発生する。
    | * PS1 に変な物が指定されているという事もない。
    | * PS1='\$ ' として見ても問題は変わらない。
    | * bleopt_internal_suppress_bash_output= を試したがやはり振る舞いは変わらない。
    |
    | mc は一体何を待っているのだろうか。エラーメッセージもないので分からない。
    | mc のソースコードの何処かに non-interactive で起動するのと
    | interactive で起動するのの二種類が存在する筈である。
    | 或いは PTY ありとなしで起動しているだけの可能性もあるが。
    | うーん。grantpt で検索したら subshell/common.c に init_subshell という関数があって、
    | 其処で色々と初期化している様に見える。
    |
    | mc をコンパイルした。試してみる。確かに init_subshell の中で 10s 過ごしている。
    |
    | どうも PROMPT_COMMAND に pwd >&XXX を設定していて、
    | これが実行されるのを待っている様だ。
    | と思ったが、もしそうならば --noattach & attach でちゃんと動く筈なのでは。
    | 実際に試してみると PROMPT_COMMAND は ble-attach 時には空になっている。
    | →PROMPT_COMMAND を何処で設定しているのかと思ったら一回起動した後に、
    |   PROMPT_COMMAND=... というコマンドを pty 経由で入力している。
    |
    | ble.sh はコマンド履歴を受け取っていない気がする?
    | それなのに .bash_history にはちゃんと文字列が追加されている。
    | これは一体どういう事なのだろうか。別の経路で bash 本体がコマンドを受信している?
    | と思ったが分からない。それは考えにくいという気がする。
    | 或いは単に見落としだろうか→見落としだった。
    | ちゃんと実行されていた。然し問題はコマンドの途中の改行で分割されて実行されているという事。
    | 多分 syntax が初期化される前なので文法チェックがなされずに直接コマンド実行されているという事?

    状況をまとめると。mc は bash に対して 'PROMPT_COMMAND=云々' というコマンドを送信する。
    そして次のプロンプトが表示される時に PROMPT_COMMAND に設定した pwd >&15 というコマンドを経由して
    現在のディレクトリを受信する。現在のディレクトリを受信する迄待ち 10s で timeout すると失敗と見做す。

    ble.sh は最初のコマンドを受信するが受信した文字列を、
    途中の改行で分割して個別に実行しようとする為、PROMPT_COMMAND の設定に失敗する。
    従って pwd >&15 がいつまでも実行されないのでブロックされる事になる。

    syntax.sh がロードされていない状態でもちゃんと
    文法チェックをする様にした方が良いのかもしれない。

    うーん。分かった。何故効かないのかというと \n (C-j) を使って改行を入力しているからだ。
    一方で ble.sh では C-j を強制実行に割り当てている。

    % 取り敢えず ble-bind -s C-j $'\r' 等としておけば問題は発生しない様だ。
    % 報告されているもう一つの問題もこれで一緒に解決する。
    % 対策としては MC の中にいる時には既定で上記の設定に切り替える。
    % もしくは最初のコマンド実行迄は C-j を強制的に C-m に読み替える様にする。
    % MC の中にいるかどうかをより正確に判定するにはどうすれば良いか。
    % MC_SID の有無だと更に subshell の中に入った時にも対策が起動してしまう。
    %
    % * 強制的に attach している筈なのに ble-detach 状態になっている。何故か。
    %   と思ったらそもそも ble-attach していなかった。そしてble-bind で解決したかに見えたのも、
    %   単に ble-attach していなかったからである。

    改めて回避方法について考える。ble-bind -f C-j nop とすると、
    ごみの bash_history すら追加されなくなる事を見ると、
    ちゃんと ble-bind は効果を持っている。然し、反応がなくなってしまう。

    とここで分かった。先ず ble.sh の C-m は文法構造に関係なく、
    続きに何か入力がある時には改行挿入と見做す。
    そして一旦改行がコマンドラインに入ると以降は multiline mode になって
    以降どんなに改行が現れても改行挿入にしかならない。

    つまり ble.sh の C-m でも C-j でもない振る舞いにしなければならない。
    うーん。accept-line でも文法チェックを行う?
    →結局 accept-line に syntax という引数を与えるか、
    或いは $$MC_SID == $$ 且つ LINENO == 0 の時に文法的に完全かどうかをチェックする事にした。

    x fixed: 実際にコマンド履歴に妙な物が大量に出力されている。
      これについてもどうにかする必要がある。
      或いは特に問題が発生しない限りはコマンド履歴に変な物が登録される事はないのだろうか。

      というか普通に bash が起動できた場合にもこのごみが出力されるのだろうか。
      →確かにごみが .bash_history に残ってしまう。
      cd の記録程度であればまあ残っていても良い気がするが、
      PROMPT_COMMAND 云々は .bash_history に残す理由もないし消したい所である。

      うーん。ble.sh だと PROMPT_COMMAND= と PS1= の二種類のコマンドが履歴に書き
      込まれてしまって、最初の物は空白が前置されているので HISTCONTROL に
      ignorespace が入っている distro では何も起こらないが、二番目の PS1= は空白
      が前置されていないので本当に履歴に書き込まれてしまう。所が bash の中で実行
      すると PROMPT_COMMAND しか設定されない。この違いは何処から来るのだろうか。
      或いは何かのエラーが起こった時に fallback として PS1 を設定している?

      ソースコードを見るとちゃんと PROMPT_COMMAND と共に PS1= が送信される様になっている。
      然し実際に起動した物を見ると PS1 は設定されていない様に見える。何故。
      うーん。どうもこれは kill -STOP $$ がどの時点で発動するかという問題の様だ。
      元の bash では \n が来た時にコマンドの解釈が途切れるので、
      その時点で SIGSTOP が来て bash が取り敢えず動作を停止する?
      一方で、ble.sh では kill -STOP をしてもお構いなく入力されたコマンドを全て実行する。
      結果として後に続く PS1= も一緒に実行されるという事である。

      これは意図的にその様に動作する様にしているのだと思われるが何故かはよくわからない。
      取り敢えず現状のままに ble.sh の中では PS1= も実行してしまうという振る舞いのままにする。
      cd に関してはユーザの設定で HISTCONTROL=ignorespace でも追加してもらう事にする。

    x fixed: プロンプトが消滅している。これは rps1 やその他の特別なプロンプトを
      $MC_SID == $$ の時には表示しない様にすれば良い気がする。
      と思ってその様に対策したがそれでもプロンプトが消滅したままである。

      明示的にプロンプトの設定を全て削除してもやはりプロンプトは消滅したままである。
      というかそもそもプロンプトが食われてしまって何も表示されない。
      という事はプロンプトを抽出するコードで何か問題が生じているという事。

      調べると正に read_subshell_prompt という関数が存在している。
      うーん。というかもしかして kill -STOP を用いて区切れを判定している?
      そして kill -STOP のタイミングが変なのでプロンプトではなくコマンドの出力と思われている可能性。
      然し、実際にはプロンプトが消滅してしまっているという事を考えるとやはり違うのだろうか。
      或いはプロンプトが消滅してしまっているのは単に \r\e[K して現在行を消去しているからという可能性もある。
      それにテストしている最中に -- INSERT -- をプロンプトと認識してしまう事もあったので、
      恐らく kill -STOP のタイミングによる問題ではないのではないか。

      * 改めて read_subshell_prompt の動作について確認する必要がある。

        read_subshell_prompt の呼び出しを見てみると通常の bash では一回しか呼び出
        されていないのに、ble.sh の中ではコマンドを実行する度に 3 回呼び出されてい
        る。最初の呼び出しでは空文字列が読み取られ、二回目の呼び出しでちゃんと内容
        が読み取られる。最後の呼び出しで \e[m が読み取られて終わる。
        どうして呼び出しの回数が異なるのか。

        何処から呼び出されているのか。filemanager/layout.c の do_load_prompt から
        呼び出されている。そして do_load_prompt は更に load_prompt から呼び出され
        ている。呼び出し経路を調べてみると、

        bash (1) do_load_prompt -> read_subshell_prompt (有限)
        ble.sh (1) do_load_prompt -> read_subshell_prompt (空)
        ble.sh (2) load_prompt -> do_load_prompt -> read_subshell_prompt (有限)
        ble.sh (3) load_prompt -> do_load_prompt -> read_subshell_prompt (sgr0)

        の様になっている。ble.sh では load_prompt 経由の読み取りが余分にある。
        そして load_prompt は filemanager/midnight.c の初期化時に

          add_select_channel (mc_global.tty.subshell_pty, load_prompt, NULL);

        の様にして登録されている以外は使われていない。要するに pty で何か受け取っ
        た時に load_prompt が呼び出されるという事の様に思われる。それにしても何を
        trigger にして呼び出されるのだろうか。

      * 3回目の read_subshell_prompt の呼び出しで sgr0 を読み取ってしまうのが原因に思われる。
        この3回目の read_subshell_prompt が起こらない様にすればよいのではないか。
        その為にはこの sgr0 の出どころを調べる必要がある。

        何が起こっているのか分かった。ble/textarea#render を実行すると、
        特に更新の必要がない場合には ble/textarea#focus が呼び出され、
        カーソル位置を ble/textarea#render の現在位置に移動する。
        この時に sgr0 を出力してから移動しようとするのである。

        もう一つの疑問は何故二つに分けて出力されているのかという事。
        うーん。分かった。ble/textarea#render -> ble/util/idle.do
        -> ble/textarea#render の順に呼び出されている。従って、
        ble/textarea#render が二回呼び出されるのである。

      うーん。goto しても移動がない場合には _ble_term_sgr0 は出力しない事にする?
      他に影響があるかどうか分からないが多分大丈夫だろう。
      →これでちゃんと動くようになった。実は set -o vi でもちゃんと動いている。
      -- INSERT -- を表示するタイミングとプロンプトを表示するタイミングが偶々
      良い感じになっていたからだと思われる。

      それでも C-o の画面に戻るとプロンプトが消滅してしまってはいる。これは画面
      の一番下にいる時に発生している。どうも mc はコマンドを実行する時に画面の一
      番下の行にカーソルを持ってくる様である。ble.sh の canvas は行を全て管理で
      きていると思っているから、消去したい panel に普通に CUD で移動して削除しよ
      うとする。然し、実際には CUD で移動するのに失敗して誤って現在の行を削除し
      てしまうという事。これは対策できる気がする。対策した。

  * widget: keymap による自動的な振る舞いの切り替えの仕組みを作る [#D1391]

    うーん。何だか面倒になってきた。そもそも vi_imap の時にだけ振る舞いが変わる
    物が多過ぎて widget が色々異なるのが面倒である。ble/widget/newline を呼び出すだけで
    現在の keymap に応じて適切に振る舞いを変更する様に変更したらどうだろうか。
    edit.sh に全ての実装を書き込むと edit.sh が肥大化してしまうので、
    動作を自動的に切り替える仕組みを作るというのでも良い。

    と思ったが ble/widget/newline に関してはユーザの好みで振る舞いを変えたい事もあるかもしれない。
    等と考えると、keymap で固定してしまうのではなくやはり自分で設定できる様にするべきだろうか。
    うーん。然し、それはオプションで制御できる様にしても良い気がする。
    或いは、もしユーザが自前で widget を作るのだとしたらそれは備え付けの ble/widget/newline とは
    関係がないのだから気にしなくても良い。

    というか今その対策をする必要はあるだろうか。
    うーん。この対策をせずに実装しようとすると、
    accept-line についても vi_imap 云々という keymap 判定をしなければならなくなる。
    取り敢えず暫定の実装として accept-line の内部で keymap 判定を実行する様にするか、
    或いは先に keymap 判定を自動的に実行する仕組みを作って整理してから accept-line
    に対する対策を実行するか。

    先に ble/widget/newline 等の実装を自動で切り替える仕組みを実装する事にする。
    対象は newline, accept-single-line-or, accept-line である。

    accept-single-line に関しては vi-command 版もある。
    vi-command/accept-single-line-or は vi_nmap でしか使われていないが、
    名称的には vi_[onx]map で使っても問題がない様に設計されている気がする。

    これらにちゃんと対応する為には vi_omap, vi_xmap についても機能を追加するか、
    或いは vi_nmap しか対応しないか、或いは vi_[onx]map の時には特別に
    vi_command も一緒に探索する事にするか。取り敢えずは vi_nmap だけの対応で良い
    気がしてきた。

    * dispatch 先の関数名をどうするか。

      a 取り敢えずの実装としては ble/widget/NAME に対して ble/widget/KEYMAP/NAME
        を試行する事にした。このルールは既存の緩やかなルールに合致しているので既
        存のコードを大きく書き換える必要はないだろう。

      b また ble/widget/NAME/.keymap:KEYMAP 等の名称よりはわかりやすい気がする。
        と思ったが、: が含まれる場合も widget として列挙されない様な気がする。と
        いう事は ble/widget/NAME/keymap:default でも良い様な気もする。

        うーん。keymap 特有の accept-line を呼び出す時に内部的に accept-line を
        呼び出したい時にble/widget/accept-line ではなくて
        ble/widget/default/accept-line を呼び出さなければならないという事を思う
        と、ble/widget/accept-line/keymap:default の方が良い? と思ったが、何れに
        しても ble/widget/accept-line/keymap:default と書いて呼び出さなければな
        らない。ble/widget/accept-line の儘で呼び出せる方法はないのである。なの
        で、やはり名称は ble/widget/default/accept-line でも変わらない。

      c この観点だと ble/widget/accept-line.default や
        ble/widget/accept-line.vi_imap 等だったら分かりやすかったかもしれないが、
        ble/widget/*.* の形式の補助関数は沢山あるのでそれと被ってしまう問題があ
        る。

      やはり取り敢えずは dispatch 先の関数名は a の方針で行く事にする。

    [変更]

    - done: newline 対応した。
    - done: accept-single-line-or

      実はこれは今対応する必要はない? というのも accept-line から newline を呼び
      出した時にもう既に自動的に keymap に対応する関数が呼び出される様になっている。
      従って特別に実装する必要はないのではないか。

      一方でコードの綺麗さという観点で考えるとやはり此処は統一した枠組みの上で実
      装したい。うーん。やっぱり accept-single-line-or についても keymap dispatch
      に対応する事にする。

    - done: accept-line
      これも既に vi-command/accept-line という物があるので keymap dispatch にする。
      vi-command/accept-line は vi_nmap/accept-line に名称を変更。
      実は vi_nmap/accept-single-line-or はこれで不要になる。

    他にも vi_imap/... 等は存在している気がするが、これらは互いに呼び出す等の事
    をして複雑になっている訳でもないので、追々置き換えていけば問題ない。
    取り敢えず動いている気がするので気にしない事にする。

2020-09-15

  * [解消] 2020-09-07 complete: 空白を含むファイル名の補完候補が増殖する [#D1390]
    Note: #D1389 で解決した。

    更にファイル名のパターンによって同じ候補が沢山表示されることもある。
    これは一般の引数で発生する。complete -r しても同様。
    どうもファイル名に含まれている空白の数だけ候補が増殖する様子である。

    これは bash_completion では発生しない。
    自前の補完を用いた時に発生する問題である。

    先ずは再現させなければならないが再現できない。新しい ble.sh で自然
    に直ったのかとも思ったが古いセッションでやっても再現しない。
    →再現できた。少なくともファイル名に完全一致している状態で<TAB>すると起こる。
    然し新しい ble.sh では再現できていない。

    一応何が原因で発生していたのか調べる必要がある。OK。発生は確かめた。
    次に確認するべき事は何かというと、…候補生成で何が起こっているのかという事。

    分かった。これも glob pattern が単語分割されているのが原因だった。
    echo 'a b c' に対してパターンが以下の様になり、
    結果として3つに展開されていたという事である。

      pattern: ret='*a* *b* *c*'
      expanded: ret=('a b c' 'a b c' 'a b c')

    これは #D1389 で自然に解決したと見て良い。

  * 2020-09-10 complete: mkdir aaaaaaaaaaa. とすると無限ループになる [#D1389]
    →aの数が少ないと問題が起きない。という事を考えるとこれは曖昧補完で使っている
    正規表現またはパス名展開による物と思われる。
    実際には無限ループになっているという訳ではなくて指数関数的に処理量が大きくなっている。
    これに対する対策はしておかなければならない。

    同じ文字数でも abcdefg.... という文字列だと問題は起こらない。
    つまりこれは同じ文字が連続で存在している時に発生する問題である。

    一つの対策方法は同じ文字が複数並んでいる時の曖昧文字列生成について。
    然しそれでも abababababa というパターンに対しては脆弱になるのではないか。

    というよりそもそも、a*a となっている時に最初の * の中に
    a が含まれる事を禁止すれば良いのではないか。
    a*b の場合には b を禁止する。その様にすれば必ず literal b match は、
    a の後に現れる最初の b という事になるので曖昧さはなくなり、
    様々な種類のパターン一致を試す必要もなくなるのではないか。
    そしてそれはグロブパターンならば *([!b]) 等とすれば良い。
    正規表現ならば [^b]* とすれば良い。

    然し、本当にこれで問題ないだろうか。実はこれによって一致しなくなっ
    てしまうパターンなどがあったりするのではないか? と思ったが…。多分
    大丈夫である。元のパターンで一致する文字列であれば必ず制限をかけた
    パターンでも一致するという事を示せば良い。そしてそれは自明の事のよ
    うに思われる。

    chatoyancy 上で再現できないと思ったらどうやら bash-4.4 では問題が
    起きるが bash-5.0 では問題は起きない様子だ。何れにしても再現できる
    様になったので修正できる。

    取り敢えず *([!b]) に変換する様にしてみたがこれでちゃんと動作するかは分からない。
    先ずはちゃんと ambiguous expansion が働くかどうか。動く。
    そして bash-4.4 で遅くなってしまう問題も解決している。
    取り敢えずこれで様子見する事にする。

  * 2020-09-10 最初に起動した時に bleopt prompt_screen_title が反映されていない [#D1388]

    これは分かった。ble.sh は _ble_term_TERM を見て
    prompt_screen_title を出力するかどうか決めている。然し
    _ble_term_TERM は DA2 応答があるまでは代入されない。
    最初は空なのである。

    _ble_term_TERM が空の時には TERM も確認する事にした。
    流石に screen, screen.* に設定しているのは screen か tmux だけだろう。
    screen が xterm に設定している場合には判定できないが仕方がない。

  * 2020-09-07 complete: メニュー補完で引用符が消える [#D1387]

    引用符で囲んでいる状態でメニュー補完すると引用符が消える。何故だろう
    試していた所メニュー補完でなくても問題が生じる事が分かった。
    これは cd の引数でだけ発生する? →どうもその様である。

    然しディレクトリ名のパターンによって発生したりしなかったりする。
    OK. 再現する。

    $ mkdir 'a b'
    $ cd 'a b       <--この状態で TAB を押すと引用符が消える。

    実は bash_completion を有効にしている場合は cd だけでなく mkdir でも起こる。
    原因が同じかどうかは分からない。

    ble/cmdinfo/complete:cd を削除すると再現しない。
    ble/cmdinfo/complete:cd で直接 ble/complete/source:file,dir 等を実
    行する様にしている場合は再現する。

    →普通にquote-insert も呼び出している…と思ったが、調べてみると、
    COMPS も COMPV も設定されていないということが判明した。何故。

    →調べると一回目の呼び出しではちゃんと有限の文字列になっていて引用符も含ま
    れている。然し、それに対しては候補生成に失敗して、更に 曖昧補完として
    COMPS, COMPV を空にして再度呼び出された時に候補が生成されるという事である。
    ここで二つの問題がある。

    x fixed: 何故最初の引用符ありの補完に失敗しているのか

      これは分かった。glob で "$COMPV"*/ に等価な物を生成しようとしているが、

      % $COMPV の部分をエスケープする時に空白文字のエスケープをしていないのが原
      % 因。然し、実際に一文字ずつエスケープする必要があっただろうか。実は
      % '...'*/ としたり、或いは最早 "$COMPV"*/ でも良かったのではないだろうか。
      % 然し、それはどの様にパス名展開を引き起こしているのかに依存する。もし
      % eval "a=($pattern)" としているのであれば良いが、もし a=($pattern) とし
      % ているのであれば quote 除去や変数展開は使えない。展開は実際に
      % ble/complete/util/eval-pathname-expansion で行われていて、その中では以
      % 下の様にして展開が実行されている。
      %
      % IFS= GLOBIGNORE= builtin eval 'ret=(); ret=($pattern)' 2>/dev/null
      %
      % つまり後者なので quote 除去や変数展開は使えないのである。
      %
      % ? 然しここで疑問が生じる。もしこの様にしているのであれば、何故空白をファ
      %   イル名の一部としてパス名展開が行われないのか。と思ったが、それよりも
      %   先に単語分割が先に行われてしまう。
      %
      % ? もう一つの可能性として eval "ret=(); ret=($pattern)" の様に書き換える
      %   という事。こちらの方が融通が効くのではないかという気がする。然し、
      %   "$COMPV" の様な特定の変数の値が保持されている事を前提とする物は使いた
      %   くない。だとすると '...' による quote に頼る事になる。実は \ に対する
      %   グロブ自体の quote と対して変わらないのではないかという気がする。
      %
      %   然し、もしちゃんと \ によるエスケープで動作できる様にするのであれば、
      %   その儘の形で意図した物にちゃんと一致する様にパターンを構築した方が自
      %   然の気がする。という事を色々考えるとやはり現状の方針を変えずにエスケー
      %   プを修正するという方向で直す。
      %
      % ? ファイル名に改行が含まれている場合にはどうなるのか?
      %
      %   この場合は単純に pattern=$'a\\\nb*' 等としても一致しない気がする。
      %   実験してみる事にする。動かない。というより気づいてしまったが、
      %   実は通常の空白であっても \ を前置しても単語分割を防ぐ事はできない様だ。
      %
      % ? ok: bash-5.0 pathname expansion quirk の問題はあるか
      %
      %   一方で bash-5.0 の特別な振る舞いとして \ が含まれているか含まれていな
      %   いかで、ret=($PATTERN) とした時に PATTERN がグロブパターンとして取り
      %   扱われるかどうかが切り替わるという話がある。これは bash-5.1 でまた昔
      %   の動作に戻った。これに関しては、ble.sh で使う時には必ず * 等のパター
      %   ンを含んでいるから常に意図的にパス名展開の対象であるので"意図せずパス
      %   名展開が起こった" という事態にはならない。

      →変数に含まれるグロブパターンに於いて空白をエスケープする手段は存在しな
      いという事が判明した。つまり ret=($pattern) という展開自体が駄目という事。
      代わりに pattern を適切にエスケープした上で eval "ret=($pattern)" とする
      必要がある。

      先ず ble/complete/util/eval-pathname-expansion の呼び出し元を確認する。
      全て ble/complete/source:file/.construct-pathname-pattern の結果を使っている。
      なので、両方を書き換えれば問題ない。

      ? util: 実は ble/util/eval-pathname-expansion でも同様に注意が必要なのでは?
        と思ったが、調べてみると ble/util/eval-pathname-expansion では始めから
        eval "ret=($1)" の形式を採用していたのでこの手の問題は発生しない。

      * 単に pattern='"$COMPV"*' とすれば良いのではないかと考えたが、
        それだと is-cygwin-slow-glob の判定をすり抜けてしまうので、
        やはり自分で展開して quote する形にするのが良い気がする。

      どの様に quote するか。単純に考えれば '...' で良いが特別の文字を含む時に
      限って'...' の形式に移行するというのでも良い気がする。
      →これに対しては新しく ble/string#quote-command という関数を作った。
      取り敢えずこの問題に関しては修正された気がする。

    x 二回目の補完で COMPS が消滅しているのにも関わらず、COMPS が存在していると
      いう前提での文脈に応じた escape をしている。これは単に COMPS に応じて
      escape の種類を変えるという事で対処できる。

      quote-insert から呼び出している escape では comps_flags を参照している。

      こちらについては修正されていない。先に前者の方を修正してしまったので、
      改めてこれを再現させる方法を考えなければならない。と思ったが、
      単に head による候補列挙を一時的に停止すれば良いだけの気がする。

      と思ったら空白を含むファイルの補完候補が増殖する問題が邪魔をして再現でき
      ない。取り敢えずそちらを先に解決する事にする。と思ったが勘違いだった。中
      途半端に head による候補列挙をスキップした為に候補が重複して生成されてい
      ただけだった。取り敢えず問題を再現させる所までは行った。原因は明らかであ
      る。問題はどの様にしてこれを実装するべきかという事である。

      元々の quote では元々存在している文字列を置換しないという事を前提としてい
      た。なので quote 状態は破壊されないという前提であった。或いは COMPV がちゃ
      んと quote 状態に対応しているという前提があったのである。然し、曖昧補完の
      時には COMPV を強制的に置換してしまっているので、quote 状態と COMPV が対
      応していない状態になっているのが元々の問題点である。

      COMPV を置換せずに曖昧補完であるという事を伝達するか、或いは曖昧補完の時
      には quote 状態のフラグも一緒に変化させてしまうか。後者の場合には、元々の
      quote の種類が補完によって変わってしまうという事を意味する。やはりできる
      だけ quote の種類は保持する様に置換を実行したい。或いは現状のままで
      COMPV= が特別に曖昧補完であるという事にして、quote を処理するという方針?
      この方が良い様な気がしてきた。

      念の為 COMPV= を設定している箇所について確認する。調べるとどうやら各
      source に於いて独自の判断で COMPV を空にしている様である。これは本来は内
      部の変数にコピーしてから改変するべきなのではないかという事。COMPV はその
      儘にしておく事で quote の側ではこれにより補完で遡った書き換えが起こったか
      どうかを正しく判定する事ができる。

      | a 例えば COMPV から compv にコピーして処理するという事。この時に何らかの
      |   問題が生じる可能性があるだろうか。COMPV を使用している箇所について確認
      |   する。結果分かった事は COMPV は候補生成の時にしか使われていなくて、寧ろ
      |   元の文字列を参照する必要があるのは quote をする時だけの様であるという事。
      |   つまり、逆に COMPV は現状の様に処理して、代わりに別の変数に本来の COMPV
      |   を保持するべきではないか、という事。もしくは COMP_POINT か何かの変数を
      |   用いて自前で COMPV に対応する文字列を抽出する?
      |
      |   と思ったが、COMPV は eval 後の値である為そう単純ではない。というか、本
      |   当に COMPV による判定だったろうか?
      |
      |   判定は [[ $comps_flags == *v* && $CAND == "$COMPV"* ]] で行われている。
      |
      |   この時に一致している部分までを COMPS に置き換えてそれ以降をエスケープし
      |   て追記している。うーん。或いは、COMPS= COMPV= としたのが行けなくて、
      |   COMPS に引用符などを保持して置くべきだったのかもしれない。それは一つの
      |   解決方法である。
      |
      |   x compv の使用箇所について確認を行う。ほとんど使われていない。使われて
      |     いるのは filter を実施する関数内で icasematch を実行する為に内部で
      |     lower case に変換して差し替える為に置き換えている所のみである。
      |
      |   x 然し一方で小文字の compv を特殊変数名とするのには抵抗がある。やはりで
      |     きるだけ特殊な関数の間で共有して動的スコープでアクセスする変数は
      |     prefix をつけるか大文字にするかして区別する様にしたい。
      |
      | b COMPV= とする時に COMPS の方にちゃんと引用符等の quote も含めた値を設定
      |   する。もしくは、quote 状態のフラグを修正する。
      |
      | c 或いは COMPS が空で quote 状態が設定されている時には曖昧補完として
      |   COMPS/COMPV が上書きされたと判定する?

      うーん。b の方法が現在のところ一番良い様な気がする。取り敢えず COMPS=
      COMPV= を実行している箇所を関数に置き換える事にする。と思ったが微妙な事が
      残る…。COMPS=${COMPS::1} 及び COMPV=${COMPV::1} しているのは駄目である。
      例えば COMPS が 'hello' だった場合に、COMPS=\' COMPV=h という状態になって
      しまう。これだと h が補完後に消滅してしまう事になる。現状でも問題になるの
      ではないだろうか。今まで問題が起こらなかったのは何故だろうか…。

      実際に試してみると確かに問題が発生している。

      $ touch hello
      $ echo 'hll <-- ここで TAB を押すと補完結果が 'ello' になってしまう。

      COMPS=${COMPS::1} としている部分も含めてちゃんと対応する必要がある。一方
      でどの様に切り出すのが正しいのかというのはかなり謎。うーん。COMPS は別に
      自分で勝手に作り出しても良いのではないだろうか。どうせ曖昧補完なので遡っ
      て書き換わってしまうのは仕方がない。それに実際に置換する時には、呼び出し
      元の関数で処理するので書き換わった COMPS の影響はない。飽くまで候補生成に
      影響を与えるだけなので気にしなくても良い。

      という訳で何れにしても COMPS として適当な物を合成する方針にする。これだと
      例えば abc"def<TAB> とした時に "abcdef... になるという動作になるが、まあ
      それで良いだろうという気がする。

      x 取り敢えず実装した…と思って動作確認したら全く直っていない。どういう事
        だろうか。確認したら簡単なミスだった。コードの整理もした。

    ? ok: source:command を見ると command の曖昧補完は起こらない様になっている?
      と思ったが実際にやってみると動いている。何故だろうか。確認する必要がある。

      改めて確認すると source:command/gen を呼び出して更にその中の
      source:command/gen.1 に於いて曖昧補完の設定をして実際の展開を行っている。
      これについてはOK

    ? comps_fixed がある時 (ブレース展開がある時) 曖昧補完を実行しようとすると何が起こるのか?

      | 例えばブレース展開がある所までは展開結果が一致していたとしても、引用符
      | 関連で書き換えが起こるとすると補完できないという事になるのでは。以下を
      | 試したら補完できなかった。これについては他を修正してから改めて確認する。
      |
      |
      | $ touch hello
      | $ echo h{'ll<TAB>
      |
      | これに関しては曖昧補完の場合でも comps_fixed に対応する部分まではそのまま
      | にして補完を実行するのが良い気がする。問題は、h{xxx,ll<TAB> とした時に何
      | 処までが fixed_part なのかという事。"h{xxx," が fixed part になって展開結
      | 果が h になるのであればOK。何れにしても取り敢えず実装して様子を見る。

      →これは次のテスト項目で一緒に取り扱う事にする。

    以下の動作確認を行う。

    | $ touch hello
    | $ echo 'hll<TAB>
    | $ echo 'hello'
    | これは動いた。
    |
    | $ echo h"ll<TAB>
    | $ echo "hello"
    |
    | これは動かない。何故だろうか。うーん。もしかして h"ll は単純単語ではない?
    | 実際に呼び出してみると別に単純単語でないという事はない。ちゃんと h"ll" に
    | 変換してその上で hll に変換される。一応 h'll の場合には期待通りに全体が
    | '...' で囲まれた形で補完されるので当初期待した機能はちゃんと実装できてい
    | る。問題は何故 ' で動いて " で動かないのかという事。これはまた独立に調べ
    | る必要がある。
    |
    | $ echo h{'ll<TAB>
    | $ echo h{'ello',
    |
    | これも動かない。echo h{ello', になってしまう。ブレース展開の場合には
    | quote が外されてしまうので、末端の ' をつけてはいけないという事。ブレース
    | 展開があっても適当な所で始まりの quote を挿入する様にしなければならないの
    | である。と思ったが、分からない。
    |
    | 調べてみると先ず $CAND == "$COMPV"* のテストには失敗する。曖昧補完先頭一
    | 致の場合には COMPV=hl という具合に最初の一文字を含んでいるからである。
    |
    | * うーん。実は COMPV に既に文字が含まれている場合には先頭一致でも COMPV
    |   に新しい文字を追加する必要はない。そうしないと CAND == COMPV のフィルタ
    |   リングで無駄に候補が削られてしまうから。というよりそもそも hl から始ま
    |   る単語しか生成されなくなってしまう。と思ったが、それは或る意味期待した
    |   事なのでは? うーん。然し、やはり h から始まる単語にした方が直感的な気が
    |   する。その点に関してはまた後で修正する。
    |
    | x ok: もう一つの問題は何故か COMPV に文字列を設定しているのにも関わらず、
    |   関係ない候補が沢山生成されているという事である。後でフィルタリングされ
    |   るとは言え無駄である。これは bash_completion だろうか。或いは ble.sh 自
    |   体の問題だろうか。→ complete -r したら生成されなく鳴ったのでこれは
    |   bash_completion である。無視して良い。
    |
    | x pinned: 何故か quote-insert の時に COMPS/COMPV が変化してしまっている。
    |   quote-insert は source:* の中で呼び出されているのではないのか。実際に確
    |   かめてみると source:argument の中で呼び出されている。つまりちゃんと
    |   COMPS/COMPV は補正されている筈である? やはり内部で書き換わってしまって
    |   いる。代入している箇所は他にはない気がする。一体何が起こっているのか改
    |   めて確認する。先ず何処で書き換わっているのかを特定する。
    |
    |   うーん。どうやら分かった。 COMPS/COMPV を補正しているのは
    |   .generate-user-defined-completion の中であるが、実際に yield しているの
    |   はそれよりも外側の関数という事の様である。何故だろう。
    |
    |   分かった…。source:file がそもそも曖昧補完に対応していないか壊れている?
    |   調べてみると source:file はパス名展開を用いて曖昧候補を生成する仕組みに
    |   なっている。つまり別の枠組みで生成している。
    |
    |   これは今までにもあったバグだろうかと思って調べてみるとやはり以前から存
    |   在していたバグの様である。これも別に修正しなければならない。と思ったが、
    |   これの前に修正したバグで再現していただけかもしれない。何だか分からない。
    |   少なくとも新しく問題が起こる様になった訳ではない。
    |
    | * comps_fixed が quote を含んでいないという点には注意する。この時何処かに
    |   は quote を入れる必要があるのである。これについては改めて考察する必要が
    |   ある。

    問題がまた絡み合ってきたので改めて現状について整理する。以下のテストケース
    を考える。

      $ touch hello
      $ echo 'hll<TAB>

      $ echo h"ll<TAB>

      $ complete -r
      $ echo 'hll<TAB>

      $ echo h{'ll<TAB>

    上記が全て動くようにならなければならない。既知の問題は、

    x fixed: source:file の実装で曖昧補完の時の quote 再現に対応できていない。
      これに対応する為にはどうしたら良いか。うーん。単純に開始 quote を
      quote-insert の側で挿入してしまうという事? まあそれで良い気がする。これは
      "曖昧補完による特別処置 COMPV= の時の特別な振る舞い" ではなくて、一般に
      "COMPV にも comps_fixed にも一致しなかった時の振る舞い" として適当な物で
      あるから ad hoc な処置ではない。

    x fixed: ブレース展開がある時 comps_fixed は "h{" になるのであって、quote
      の開始 "'" を含む訳ではない。comps_fixed に続いて quote 文脈に応じた
      quote 開始を挿入する必要がある。

      これに関しても comps_flags に応じて勝手に引用符を挿入するというので良い気がする。
      comps_fixed に入る文字列はちゃんと quote を閉じていると期待したい。
      因みに h{aaa,'ll となっている場合は comps_fixed は一体どうなるのか?
      と思って調べた所、

    * done: [[ $compv ]] のチェック in reduce。COMPV から compv_fixed を取り除
      いた後 compv= (空文字列) になっている時に、"最初の一文字を切り出す" 処理
      をするのは変である。見た感じ問題が起こりそうな気配もないがちゃんとチェッ
      クしておく。

    o echo 'hll<TAB>
    o echo 'hll<TAB> (complete -r)
    o echo h{'ll<TAB> (complete -r)
    o echo h{aaaa,'ll<TAB> (complete -r)

  * complete: bash_completion の autoload が初回に失敗する問題 [#D1386]

    [まとめ] これは echo h"ll 中に見つかった不自然な振る舞いから。結局、
    autoload した後再度補完を実施する事を要求する 124 の終了ステータス
    を受け取った時、改めて補完関数の探索からやり直す所で、default opts
    が残っていた所為で、新しい補完設定ではなくて再び complete -D の補
    完設定を使って読み取りを行おうとしていた事が原因だった。これは 124
    を受け取った時に default opts を削除して再度補完を実行する様に変更
    して解決した。

    | 不思議な事に最初の一回はちゃんと補完されて、二回目以降からは補完
    | 候補が一致しない物も含めて全て表示される様になる。
    |
    | 最初の呼び出しではプログラム補完が見つからずにデフォル
    | トの補完が走って、それが失敗する事によって次の曖昧補完に移行し
    | ている。二回目以降の補完ではプログラム補完が呼び出されてそれが
    | 成功するので曖昧補完が走らない。
    |
    | プログラム補完が見つからないとご判定されているのかと考えたが、
    | 実際に補完は見つかっておらず complete -p echo しても補完指定が
    | 見つかりませんでしたと表示される。という事は別の箇所で echo に
    | 対する補完指定が設定されているという事になる。何処だろうか。
    |
    | 恐らく default を使って compgen を呼び出したタイミングだろう。
    | 中を覗くとちゃんとデフォルトの補完が読み込まれて 124 を返して、
    | 結果として再度補完が走って、最終的にちゃんと補完が呼び出される。
    |
    | % ここで気づいた事…。何故か compgen に渡されている compv が空
    | % になっている。124 で再ロードした後にのみちゃんと値が設定され
    | % ている。と思ったらこれは勘違いだった。
    |
    | 一回目と二回目を比較してみると…どうも compopt の内容が違う。ど
    | うして前者では候補が生成されず (期待通り)、後者では合致しない候
    | 補が生成されてしまうのか。
    |
    | H2332:builtin compgen -o bashdefault -o de
    | fault -F ble/complete/progcomp/.compgen-he
    | lper-func -- 'hll' 2>/dev/null
    | comp_func=_python_argcomplete_global
    |
    | H2332:builtin compgen -F ble/complete/prog
    | comp/.compgen-helper-func -- 'hll' 2>/dev/
    | null
    | comp_func=_minimal
    |
    | 補間関数も含めて比較してみると両者が異なっている。何故? というよ
    | りリロードして評価した筈なのに何故再度同じ関数が呼び出されている
    | のか?? 漸く分かった。compgen の引数に "default" が入っているので、
    | 124 で再ロードしても default 用の補間関数が呼び出されてしまうと
    | いう問題であった。

  * complete: echo h"ll<TAB> で bash_completion が全ファイル名を列挙する [#D1385]

    [まとめ] これは extract-command で閉じていない単語を回収するのに失
    敗していたのが原因だった。閉じていない単語を仮に実体化していたがそ
    の時の単語の種類 wtype が CTX_ARGX になっていた。然し、
    extract-command は CTX_ARGI しか回収していなかった。単語を仮に実体
    化する時に、ctx-word-end で実際にやっているのと同様に wtype を補正
    する事にした。

    | これはどうも bash_completion が入っていると駄目のようである。
    | bash_completion の生成する候補に問題がある?
    | もしくは、progcomp による yield に問題がある?
    | うーん。実は bash_completion による候補は filtering で全て消える?
    |
    | 一回どのような候補が生成されているのか確認する必要がある? 取り敢
    | えず bash_completion は全てのファイル名を列挙する。filter:head
    | は何もしていない様に見える。実際に動作を見てみると何もしていない。
    | つまり、progcomp が生成した物をそのまま使うという作戦になってい
    | る。これはまあ理解できる。一方で bash_completion が遡って書き換
    | えの起こる候補を全て出すのも理解できる。
    |
    | これに完全に対応する為には bash_completion の生成した候補に対し
    | てフィルタをかける必要があるが…うーん。フィルタをかけて有限個の
    | 候補が残ればOK、そうでなければそのまま沢山の候補を保持するという
    | 作戦? でもよくわからないのは最初の補完ではちゃんと補完ができると
    | いう事。何故だろう。
    |
    | 改めて bash_completion の振る舞いについて確認する。ble.sh なしで
    | 実行すると h"ll に対してエラーメッセージが出るが最終的にはちゃん
    | と何も候補を生成せずに終わる。然し、経由だと全ての候補が列挙され
    | てしまっている。つまり、ble.sh の時と bash の時でやはり何らかの
    | 違いがあるという事だろうか。具体的に ble.sh による呼び出しの時と、
    | bash による呼び出しの時でどのような違いがあるのかについて調べる
    | 事にする。
    |
    | * 取り敢えず今までに埋め込んだデバグ用の出力は全て削除する。
    | * _minimal に対して advice を仕掛ける。
    |
    | | ble.sh の下では、
    | | -----------------
    | |
    | | COMP_CWORD='1' COMP_KEY='67108969' COMP_LINE='echo '
    | | COMP_POINT='5' COMP_TYPE='9'
    | | COMP_WORDS=('echo' '')
    | | COMPREPLY=('a b' 'a b' 'a' 'bc' 'a xyz' 'h ello')
    | |
    | | bash の下では
    | | -------------
    | |
    | | COMP_CWORD='1' COMP_KEY='9' COMP_LINE='echo h"ll'
    | | COMP_POINT='9' COMP_TYPE='9'
    | | COMP_WORDS=('echo' 'h"ll') COMPREPLY=()
    |
    | 成程、これは ble.sh が悪い。COMP_WORDS の復元に失敗している。空
    | の単語になってしまっている。COMPV 等に基づく候補生成はちゃんと動
    | いているという事を考えると、extract-command か或いは COMP_WORDS
    | の構築に失敗している。
    |
    | 確かめた所、extract-command の時点で失敗しているという事が判明し
    | た。問題は h'll の時にはちゃんと成功しているのに何故 h"ll の時に
    | はうまく行かないのかという事。" が中に構造を持つ事ができるという
    | 事に関係しているだろうか。
    |
    | 実際に構文木を見てみると確かに nest が設置されていて単語が構築で
    | きていない状態になっている。本来は擬似的に文法構造を閉じてその上
    | で解析するのではなかったか。覚えていないがその様な処理が何処かに
    | あった筈。これである。
    |
    | ble/syntax/tree-enumerate/.initialize で TE_root を
    | ${_ble_syntax_tree[iN-1]} の補正版として初期化している。本来はこ
    | れによって nest が閉じられて単語になって欲しいのだが、実際にはそ
    | うはなっていない。然し、f11 による画面でも文法構造が確定せずエラー
    | の様な状態になっている。と思ったが f11 による画面では文法構造を
    | 閉じていないので当然といえば当然である。具体的に問題の起こる状況
    | で TE_root がどの様に復元されているかを確認すると以下の様になっ
    | ている。
    |
    | TE_root='3 4 0 5 -- none 3 -1 -1 -- '
    |
    | 3 は wtype で 4 は現在の単語の長さである。此処までは正しい。0 は
    | 子単語までの offset であり、実は同じ位置に子単語が存在している。
    | 子ノードは wtype=none (nest 構造) であり、長さは 3 である。子や
    | 兄要素は存在しない。実際にこれに問題があるのかどうかの判定は分か
    | らない。見た感じは明らかな異常はない様に見える。特に長さが "4"
    | となっている以上は長さ4の単語を抜き出せて良いのではないだろうか。
    |
    | 何故正しく単語を抜き出せないのかについては、実際にどの様に
    | tree-enumerate が走るのか確認するしかない。
    |
    | * 色々分かった。TE_root の復元によって生成された単語は CTX_ARGX
    |   になっている。一方で通常の単語は CTX_ARGI である。
    |   extract-command では ARGI な単語しか収集していない。つまり
    |   ARGX による単語は register-word が呼び出されず登録されない事に
    |   なる。
    |
    |   一方で、一番最初に見つかった単語の終端がが現在の起点の位置より
    |   も前にある場合には、現在の起点の位置に長さ 0 の単語が存在して
    |   いると見做して、"" の単語を挿入する。この空単語は ARGX になっ
    |   てスキップされた単語とは何の関係もない。
    |
    | この状況に於いてどのように修正するのが正しいか。TE_root を構築す
    | る時に ARGX → ARGI の規則を適用するのが良い気がする。その様にし
    | たらあっさりと動く様になった。

2020-09-05

  * ln23.para.bscc が何故か SM(?1004) Any event mouse を設定する [#D1384]
    これにより focus/blur で SS3 I, SS3 O が送信される様になって
    ble.sh が混乱している。SS3 I は TAB になっている。
    SS3 O は何のキーにも束縛していないので ESC O O という入力になってしまう。
    取り敢えず SS3 O を認識する様に修正する。

2020-09-03

  * 2020-08-31 util: is-global の実装はちゃんとしているのだろうか [#D1383]
    つまり変数が unset 状態にある場合等に対しても予想通りに動作するのだろうか。
    また、現在の実装ではヘルパー関数を用いているがこれは本当に必要だろうか。

    →試してみると global に declare だけしている変数を local と勘違いする様である。
    global に declare だけしている時に readonly すると local でも変数を作れるという事?
    と思ったらテストの問題だった。テストは恐らく関数の中で実行しているので、
    トップレベルに declare v1u 等としているつもりでも関数内に変数が作成されている。
    declare -g を使って明示的にグローバルに unset 変数を作成してテストした所ちゃんと動くことを確かめられた。

  * 2020-08-03 ble.sh ロード方法と attach 戦略に対する考察 [#D1382]
    関連 (attach=prompt): #D0940, #D0737, #D1124

    そろそろ .bashrc の設定方法を変更しても良いのではないだろうか。
    特に、 .bashrc の末尾に記述するのが良い気がする。
    或いは未だ先頭に . ble.sh を記述する必要性があっただろうか。

    ユーザーが ble.sh の有無で bashrc の中の設定を切り替える場合がある。
    この場合には最初に source して BLE_VERSION を用いて判定するのが良い。
    然し、ble.sh の有無はユーザが独自に判定している場合も多いので、
    わざわざこれの為に二箇所に ble.sh のコードを書くのはやはり変かもしれない。

    * BLE_VERSION を使って判定する為にはちゃんと読み込みに失敗した時に
      unset されていなければならない。ちゃんとその様になっているか。

      * _ble_bash と BLE_VERSION の初期化されている位置をまとめた。
      * また、_ble_bash 初期化前に値を参照している箇所があったので使わない様に修正した。
      * BLE_VERSINFO についても同様に unset する様にした。
      * ble/base/unload で _ble_bash, BLE_VERSION, BLE_VERSINFO を削除する様にした。

    以下の attach 戦略に対する考察は #T0004 に纏め直した

    | 初に記述すると他のフレームワークが勝手に PROMPT_COMMAND を書き換えた時に動かない。
    | 後に記述すると他の設定で ble.sh の有無で切り替えを行いたい時に不便である。
    | うに、どの場所に記述しても動く様にするのが本当は良いのだろう。
    | 状の問題点としては PROMPT_COMMAND を上書きされると動かないという事だけである。
    |
    | 或いは、その場で attach してしまう方向で改良する手もあるのかもしれない。
    | と思ったがそれだと PS1 の設定などが反映される前にプロンプトを表示してしまう?
    | その直後に PS1 が設定されて次のキーボード入力の際に更新されるのだろうが、
    | それだとちらついたりしてよくない。
    |
    | 或いは、その場で attach した時には最低限の処理を行って、
    | それでユーザの入力を受け付ける様にする。
    | PROPMT_COMMAND が生きていれば続きの処理を行って、
    | もし上書きされて動いていない場合でもできるだけ問題が起こらない様に処理する。
    |
    | ble-attach して最初は出力抑制しない作戦
    |
    | もっと具体的に考える。その場で attach した時の問題点は何かというと、
    | attach してプロンプトを表示して、然しその後で bashrc の中から何か
    | メッセージが画面に表示しようとしても出力が抑制されているので
    | 内容が消えてしまうという事である。
    |
    | 然し、ble-attach の時は出力を抑制しないでその次のユーザの入力の
    | 時に初めて抑制をするという手もある。
    |
    | x この時には最初のユーザ入力の際に一瞬だけちらつきが発生してしま
    |   う。
    |
    | x もう一つの問題点は ble-attach した後に、bashrc の別のシェル設
    |   定が画面に何か出力すると表示が乱れてしまうという事である。
    |
    | 後者の問題を解決する為に、プロンプトの表示は PROMPT_COMMAND まで
    | 遅延するという可能性もある。
    |
    | x しかし、そうすると起動までの時間が気になる。ble-attach すると
    |   いう事は bind するという事で、bind するという事は keymap の初
    |   期化を行うという事である。つまり時間がかかる。本来はそれより前
    |   にプロンプトは表示しておきたい。まあ、これはそれ程気にしなくて
    |   も良いかもしれない。
    |
    | 前者のちらつきの問題に関しては、PROMPT_COMMAND が正しく機能すれ
    | ば特に問題ない筈である。
    |
    | ble-attach して出力抑制もする。後で出力内容を dump する作戦
    |
    | 或いは ble-attach してから次のユーザ入力を得るまでの間に bashrc
    | から出力された内容は適当なタイミングで画面に出力する様にする?
    | これは一つの手であるような気がする。PROMPT_COMMAND が有効であれば、
    | その瞬間にそれまでに出力された内容を dump すれば良い。
    |
    | x ただし、時間のかかる処理やプログレスバー等の表示があると最後に
    |   一気に表示するので期待はずれの動作になる
    |
    | x 更にユーザの入力を求める処理があると何も表示されない状態になっ
    |   て困る。いざ /dev/tty に対して読み書きするプログラムがあったとし
    |   ても、今度は逆に画面の表示が乱れてしまう。
    |
    | 等などの事を考えるとやはり ble-attach してから、後の bashrc の処
    | 理を適当に流すというのは難しいのではないか。或いは本格的に bash
    | の出力を別のプロセスに繋げて、そのプロセスで出力内容を選別しなが
    | ら適当に描画を乱さない様に調整する? と思ったがそれだと本格的に端
    | 末を実装する様な物だし、/dev/tty を使われたら結局調整もできなく
    | なる。駄目。
    |
    | 或いは trap RETURN もしくは trap DEBUG を用いて PROMPT_COMMAND
    | を監視する? 上書きされたり破壊されたりしたら復元する。
    |
    | 関連する議論が #D1124 及び D#0737 にある。然しこれも微妙である。
    |
    | x trap DEBUG はコマンドの実行直前に実行されるので、bashrc の一番
    |   最後の行で PROMPT_COMMAND が書き換えられると駄目。それに trap
    |   DEBUG 自体を上書きされてしまうと動かなくなってしまう。それに
    |   trap DEBUG は結構面倒である。
    |
    | x trap RETURN は bashrc の末尾では発生しないようなのでこれは全然
    |   使えない。
    |
    | れ以外に不定期で呼び出される hook の類は存在しただろうか。本当は
    | OMPT_COMMAND が変更された時にそれを検出できたら良い。或いは
    | OMPT_COMMAND に対する読み書きを全て hook できたら良い。然し、ス
    | リプトだけでそれを実現する方法はないのだろうという気がする。
    |
    | EXIT はプロセスが終了する時にしか呼び出されないし、ERR もコマン
    | ドが失敗した時にしか発生しない。bashrc の最後に自動的に失敗する
    | コマンドを呼び出させる方法もない。
    |
    | command_not_found_handle はコマンドが見つからない場合にしか呼び
    | 出されない。それにディストリビューションによって何か処理が設定さ
    | れるだろうから PROMPT_COMMAND と同様の問題がある。寧ろ、処理の追
    | 加という事ができないので PROMPT_COMMAND にも増して使いづらい。
    |
    | bashrc の処理を見たら bashrc の最後に介入する方法が見つかったり
    | しないか。と思ったが eval の最後に何もないように bashrc の最後に
    | も特別な物は何もないだろうという気がしてならない。
    |
    | bash は maybe_execute_file という関数を用いて bashrc を呼び出す
    | 様である。調べてみるとどうもファイルの中身を丸ごと文字列 string
    | に読み込んで、更にそれを parse_and_execute で一気に実行する様で
    | ある。第三引数のフラグには SEVAL_RESETLINE を設定している。然し、
    | parse_and_execute の中には介入できそうな場所はやはりない。
    |
    | 或いは execute_prompt_command を見たら何かないだろうか。またはそ
    | の呼び出し元。execute_prompt_command を見たら単に PROMPT_COMMAND
    | を見ているだけである。呼び出し元は parse_command であり、その冒
    | 頭で run_pending_command を呼び出している。うーん。これが使える?
    |
    | kill -USR2 $$ をしたら trap handler が実行されるのはどのタイミン
    | グだろうか。もし bashrc が終わってから一括で実行されるのであれば
    | kill -USR2 $$ で bashrc 直後の処理を予約できる。
    |
    | うーん。駄目だった。その場で実行される。kill -USR2 $$ & として見
    | ても駄目だった。USR2 が届いてから次のコマンドを実行する直前に実
    | 行されるという事の様である。
    |
    | PROMPT_COMMAND の代わりに PS1 に $(kill -USR2 $$) をしかける等の
    | 手もあるかもしれないが、これは PROMPT_COMMAND と同じ問題が在る。
    | というより、PS1 は追記ではなく置き換えて使う物なので
    | PROMPT_COMMAND よりも信頼性は低い。
    |
    | もし PROMPT_COMMAND を上書きした犯人がいるのだとしたら、上書き後
    | のコマンドを必ず実行する筈で、だとすればそれを trap DEBUG で判定
    | できるのではないか。
    |
    | | そして bashrc の中か外かの判定ができれば OK. と思ったが #D1124
    | | を見ると 4.3 以降で動く微妙な方法しかない様だ。
    | |
    | | * reject: 或いは bashrc の中で declare などしておけばそれが消滅
    | |   した事を見れば bashrc の外に来たと分かる? と思ったが実際に試し
    | |   てみるとbashrc の中で設定した declare はそのままグローバルスコー
    | |   プになる様だ。なのでこれは使えない。
    | |
    | | どうやら関数の中で ${BASH_SOURCE[-1]} を参照してそれが bashrc と
    | | 一致しているかを確かめれば良さそうだ。と思ったが…。現在の
    | | bashrc が何かを知る方法がない。BASH_ENV に入っているのは別の変数
    | | の様子だ。grep して確かめると BASH_ARGV の末端には bashrc の名称
    | | が格納されている様だが、これは関数の中では何れにしてもトップレベ
    | | ルの関数名が入っているので区別できないのでは。
    | |
    | | 唯、一つ明らかなのは、bashrc の中にいる間は BASH_SOURCE に何か設
    | | 定されていて、PROMPT_COMMAND を実行しようとした瞬間には何も設定
    | | されていないという状態になるという事。なので原理的に可能である。
    | |
    | | x PROMPT_COMMAND に関数定義だけ設定されている等の時、DEBUG は呼
    | |   び出されないのでは。まあその様な特殊な場合には仕方がない。
    | |
    | | * 重大な問題として bashrc の中で source ble.sh したのと、普通の
    | |   対話コマンドの一部として source bashrc して間接的に source
    | |   ble.sh したのをどう区別するのかという事。後者の場合には、
    | |   source bashrc; echo hello 等としていた時のためにトップレベルま
    | |   で戻ったとしても即座に PROMPT_COMMAND になったと判定して発火す
    | |   るのではなくて、本当の PROMPT_COMMAND が現れるまで待たなければ
    | |   ならないのでは無いか。
    | |
    | |   LINENO を参照すれば判定できる? と思ったが LINENO は対話コマン
    | |   ドではコマンドの番号であるが、bashrc の中ではファイル内の行番
    | |   号という事になっている。使えない。
    | |
    | |   うーん。もしかして BASH_LINENO[-1] が常に0?
    |
    | PROMPT_COMMAND など外部のコマンドの実行直前に発火したい。bashrc
    | の外に出た事を検出する必要がある。
    |
    | * DEBUG で [[ ${FUNCNAME[-1]} == source ]] である事を監視して最
    |   初にそれが破れた瞬間を PROMPT_COMMAND もしくは別のコマンドと考
    |   えれば良い気がする。
    |
    | * [[ $BASH_COMMAND == $PROMPT_COMMAND ]] は使えない。何故なら
    |   PROMPT_COMMAND が単一のコマンドとは限らないから。それに古い
    |   version の bash だと BASH_COMMAND は本当に今のコマンド [[
    |   ... ]] になってしまうので当てにできない。
    |
    | x PROMPT_COMMAND が空に設定されてしまった時や、PROMPT_COMMAND に
    |   関数定義だけが記述された場合には検出ができなくなってしまうが、
    |   その様な場合は稀であるし、それで逃したとしても次の別のコマンド
    |   の実行時に attach が発火するので問題ない気がする。
    |
    | * 現在 rcfile の実行中である場合には ${BASH_LINENO[-1]} == 0 に
    |   なっている。
    |
    |   然しよく考えたら rcfile かどうかを区別する必要はあるのだろうか。
    |   対話コマンドで source .bashrc と入力した場合を考えると、この場
    |   合にも .bashrc の中で PROMPT_COMMAND を上書きされる可能性を考
    |   えると同様に対策が必要になるのではないだろうか。
    |
    |   * rcfile で実行している時には rcfile の外に出た瞬間に attach
    |     して良い。何故ならば rcfile の外に出たら次は PROMPT_COMMAND
    |     の実行以降であり既に attach のタイミングになっているから。
    |
    |   * 対話コマンドで実行している時には top level の source を抜け
    |     たとしてもすぐに attach して良いとは限らない。何故ならその後
    |     に直接また別のコマンドを記述しているかもしれないから。ここで
    |     出来るのは PROMPT_COMMAND に別の値が設定されていた時にそれを
    |     ble.sh のそれに修正する事である。然し、現在 PROMPT_COMMAND
    |     が実行されている時に限れば、その場で attach しなければならな
    |     い。その為には現在実行しているのが PROMPT_COMMAND なのか或い
    |     は通常のコマンドなのかを判定する必要がある。それは
    |     BASH_LINENO が増えたかどうかで判定できるだろうか? と思ったが
    |     多分難しい。
    |
    |   * どうやら HISTCMD / ${_histcmd@P} の結果で判定できる気がする。
    |     対話コマンドの実行中は HISTCMD には履歴項目の個数が入ってい
    |     るが、PROMPT_COMMAND の実行中は 1 に展開される。HISTCMD が
    |     unset されていたとしても ${_histcmd@P} (_histcmd='\!') は 1
    |     に展開される。HISTCMD が unset されているかどうかは
    |     ((HISTCMD++)) して数が変化するかどうかを確認すれば良い。
    |
    |   * ソースコードも確認したがやはり PROMPT_COMMAND を区別するのは
    |     本質的に難しい? PROMPT_COMMAND は parse_and_execute 経由で実
    |     行していて、この時フラグに SEVAL_NONINT|SEVAL_NOHIST を指定
    |     している。つまり $- を見たら違いが分かるかもしれない? と思っ
    |     て確認したら通常コマンドも PROMPT_COMMAND も himBHs だった。
    |
    |     別に分かった事は rcfile の処理中は $- に s が存在していなく
    |     て、PROMPT_COMMAND の時には s が存在しているという事。s は何
    |     か。man によると bash の起動時の -s は位置パラメータの指定が
    |     あるかどうか? いや、標準入力から読み取るモードになっている時
    |     に s が入るのである。
    |
    |     類似の変数として $BASHOPTS があるが、こちらは rcfile とそれ
    |     以降で違いは見られない。
    |
    |     bash の変数 "interactive" で振る舞いが変わる物を使って
    |     interactive の状態を検出できるだろうか。ソースコードを検索す
    |     ると取り敢えず alias は non-interactive の時にだけ有効になっ
    |     ている気がする。
    |
    | * DEBUG trap の取り扱いが難しいという事に注意する。これについて
    |   は未解決の task が存在した筈である。


2020-08-29

  * 2020-08-24 auto-menu を有効にしていると vbell がずっと鳴っている状態になる [#D1381]
    auto-menu は大々的には告知していないし manual にあるだけなので
    使っている人はいないのだろうという気がするが修正する必要がある。

  * 2020-08-23 main: bash-5.1 で PROMPT_COMMANDS が定義されている時 --attach=prompt が効かない [#D1380]

    PROMPT_COMMANDS 経由で attach する様にしなければならない。
    また PRPOMPT_COMMANDS 経由で attach した場合は、
    attach した後に自身を消去する必要がある。

    書いている内に分からなくなった。PROMPT_COMMAND と共存する為にどう
    したら良いのか。結局 bug-bash で議論を呼びかけてみたが良い解決方法
    は存在しないし、Chet はこれに対する対策はする気がない様である。

    * Chet は distro が PROMPT_COMMANDS と PROMPT_COMMAND の両方に設定
      を行うと主張しているが謎である。もし両方有効になるという具合に宣
      伝したらちゃんとバージョンを見て一方だけに設定するに違いない。そ
      の場の思いつきで適当な事を書いているのではないかと疑わしい。

    * 結局、不完全な対策方法しかない。或いは PROMPT_COMMAND を
      readonly unset するか。と思ったがそうした所で警告が発生されるだ
      けで問題が解決する訳ではない。

    取り敢えず不完全な解ではあるが、PROMPT_COMMAND に値が設定されてい
    て、かつ PROMPT_COMMANDS に何も設定されていない時に限り、
    PROMPT_COMMAND を PROMPT_COMMANDS に変換して、その上で値を設定する
    事にした。まあ、これが妥当な妥協点であろう。

    2020-08-31 attach した後に PROMPT_COMMANDS から項目を削除するのを忘れていた。
    と思って気づいたが PROMPT_COMMANDS を実行中に PROMPT_COMMANDS を編集すると何が起こるのか。
    →実際に試してみると PROMPT_COMMANDS を再代入した時に後続の処理が実行されなくなる。
    なので ble/array#remove を使うのではなくて空文字列で上書きするか unset するかする必要がある。

    - 新しく ble/array#replace を実装してそれを使う様にするか。
      然しもしこの bash の振る舞いが修正されるのだとしたら、
      わざわざ新しく変な関数を追加する必要もないのではないか。

    - 問題は現在の bash-dev の振る舞いが変更される見込みはあるのかという事である。
      これが意図的な振る舞いだとしたらそうなる可能性はない。
      もしこれが意図的な振る舞いでないとしたら、
      現在の振る舞いが直感的であるとは思われないので変更の余地はある。
      もしこれにより実際に変な事 (メモリ破壊など) が起こる可能性があるのであれば、
      明らかに問題であるのでパッチを受け入れて貰える可能性がある。

      % 従って何れにしても先ずは bash の実装を調べるという事である。
      bash の振る舞いに関してはまた別に議論する事にした。

    2020-08-31 と改めて確認してみたら PROMPT_COMMANDS は PROMPT_COMMAND に改名されていた。
    コードを書き換えなければならない。書き換えた。
    面倒なので取り敢えずは bash の将来的な修正はさておくとして ble/array#replace を使った。

2020-08-25

  * syntax: syntax-highlighting を無効にする機能 (requested by pjmp) [#D1379]
    https://github.com/akinomyoga/ble.sh/issues/61

    #58 に関連して実装しようかと思っていたが丁度 request が来た。実装する

    * done: 取り敢えず三種類のオプションを実装した。
    * done: wiki と blerc にも説明を書いた。

    * 完全に着色を消滅させるには以下を実行すれば良い筈だが、
      自動補完やメニュー補完による一次挿入などが見えなくなるので余り有用性はないだろう。

      $ _ble_term_color=1
      $ bleopt term_true_colors=none

      これはコメントで書くだけに留める。

    * done: 動作テストも実施した。幾つか修正した。

2020-08-22

  * prompt: bleopt prompt_screen_title や prompt_xterm_title 等を用意しても良い [#D1378]

    * done: 自動的に screen/tmux を判定してこれらを有効にする。
      どちらも異なる TERM を設定している事があるので DA2R によって判定したい。

      https://qiita.com/kefir_/items/0bda5e55f43392420d66 によると tmux の DA2 は
      0;95;0 という事になっているが実際に確かめてみると 84;0;0 になっている。
      0:95:0 だと xterm と区別がつかないので無視する事にする。

    * done: ASCII 以外の文字を自動的に # 等に置換する機能も考えられる。

    * done: tsl, fsl で囲む様にする。と思ったが微妙な気がする。
      tsl, fsl は status line の内容を指定する物で、
      tmux の terminfo は OSC 0 と同一視しているが、
      xterm 等他の terminfo は OSC 0 とは考えていない。
      tmux は確かに OSC 0 の内容をステータスに表示するからそれで正しいのだろう。
      然し、端末によってはステータスバーが別個にある場合もあり必ずしも
      tsl/fsl が OSC 0 に対応している訳ではない。

      →新しく独立した設定を作成する事にした。

    結果として
    - bleopt prompt_xterm_title
    - bleopt prompt_screen_title
    - bleopt prompt_status_line
    の三種類の設定を追加する事になった。

    * done: wiki.en, wiki.ja, blerc

  * prompt: bleopt prompt_rps1= を clear しても内容が残り続けて表示が乱れる [#D1377]
    prompt_rps1 に別の有限の大きさの文字列を指定した時には問題は起こらない。
    これは prompt_rps1= の時に rprompt の情報が全く更新されないのが問題だった。
    クリアすらされなくなってしまう。修正した。

  * contrib: prompt-git で適当にキャッシュを行うようにしたい [#D1376]
    ble.sh の側からは cache の更新を管理するために、
    _ble_prompt_update という変数を提供する事にした。
    contrib/prompt-git でキャッシュする様にした。

    これは mshex で screen の window-title にリポジトリ名を表示するため。
    取り敢えず mshex にこれを利用して git name を PS1 screen title から
    表示する様に実装してみた。動いている。

  * complete: menu に高さ制限を加えるオプションを追加する [#D1375]

    menu に高さ制限を加えた方が良いかもしれない。
    自動的に表示される物で画面がクリアされてしまうのは不便といえば不便である。
    自動で表示する場合には menu に高さ制限を加えるのも一つの手である。
    然し、自動でメニューを表示した後に手動のメニューに移行する場合にどのようにするのか。
    例えば、メニューの項目に入る時に再配置が起こるのは問題がある気がする。
    然し、だからと言って TAB で表示したメニューと自動で表示したメニューで
    高さが異なるままメニュー選択に入るのも一貫性がない様な気がする。

    実は、通常の場合でも高さ制限を加えたいという需要はあるかもしれない。
    ユーザが高さ制限を指定してそれを TAB 補完でも自動メニューの共通の設定とするのが自然。

    どの様に高さを決定しているのかを調べようとしたが、
    どうも cols lines の変数の初期化が怪しい。
    複雑になりそうなので先に auto_menu だけでも commit する事にする。

    | - "$menu_class"/render-item
    |   - ble/complete/menu#render-item
    |     - ble/complete/menu-style:align/construct/.measure-candidates-in-page
    |       - "$menu_style"/construct-page
    |         - ble/complete/menu#construct (init)
    |     - "$menu_style"/construct-page (done)
    |     - ble/complete/menu#select (init)
    |
    | - "$menu_style"/guess
    |   - ble/complete/menu#construct (done)
    |
    | - [fixed] ble/complete/menu#construct
    |   これは中で使っている様に見えるが呼び出し元を確認しても設定している様子がない。
    |   更に、同じ関数内の後で local cols lines として初期化を行っている。
    |   これは書き換えのミスではないだろうか。
    |
    |   少なくとも一つのケースで cols= lines= と空である事を確認した。つまりこれはミスである。
    |
    | - [fixed] ble/complete/menu#select (1)
    |   内部で cols lines を初期化しているがどの関数が使っているのか不明。
    |   ble/complete/menu/show しか使っていない様に見えるが、
    |   ble/complete/menu/show は cols lines を外から受け付けたりはしない筈である。
    |   後で再確認する→やはり ble/complete/menu/show は cols lines を外から受け付けない。
    |   この初期化は削除する事にする。
    |
    | - ble/complete/menu#select (2)
    |   もう一箇所では cols lines を初期化した後に
    |   ble/complete/menu#render-item を呼び出している。
    |   これは必要な初期化である。

    既存の cols lines の仕様については整理した。OK
    新しく行数を制限する様に実装した。動いている。OK

  * prompt: \q{...} で存在しない物を指定した時 [#D1374]
    文字を入力するたびにエラーメッセージが表示される。
    これが意味する所は実はキー入力をする度にプロンプトの計算を
    再実行しているのではないかという事。
    確認する必要がある。

    先ず再現する事を確認する→再現する。つまり毎回 instantiate しているという事。
    分かった…。強制的に更新する場合に force=1 を設定する所が、最初から force=1 になっていた。
    06381c96 (2020-05-21 12:32:58 +0900) で埋め込まれたバグである。
    修正したら毎回 instantiate するという事はなくなった。

    然しこれが速度に大きな影響を与えているとは思われない。
    と思ったら…何と毎回シェル展開まで実行していた。
    つまり $() 等のコマンドもキー入力が起こる度に呼び出されていた事になる。

  * 2020-08-05: complete: auto-complete で menu も出してしまう? [#D1373]

    * bleopt complete_auto_menu=DELAY で設定する。
      ble/complete/auto-complete.idle の中で
      ble/complete/auto-complete.impl の直後に
      local delay=$((bleopt_complete_auto_menu))
      ble/util/idle.push -S"$delay" "show-menu" を呼び出して
      遅延でメニューを表示させる。

      と思ったがよく考えたら自動補完候補とメニュー補完では候補が異なる。
      特に履歴項目から自動補完を実行している時。
      というか自動補完を実行している時は候補一覧を保存していない気がする。

      或いは別に自動補完とメニュー補完の内容が一致していなくても良い気がする。
      →取り敢えず独立な内容を提示する様にする事にする。

    適当に実装してみたら微妙な事になっている。
    これらはゆっくり修正すれば良い気がする。

    x fixed: コマンドラインが空でもメニューが表示されてしまう。
      空白の文字列からは補完が開始しない様にするべきかもしれない。
      ble/widget/complete に non-empty 的な opt を追加する。

      →今度は二文字以上入力しないと show_menu されない様になってしまった。
      何故だろうか。とにかくまた後で調べる事にする。
      →これは以下の問題を解決したら一緒に直った。

    x fixed: menu が表示される場合と表示されない場合がある。
      auto-complete で self-insert した時に起動しない様になっていた。
      auto_complete/self-insert の直後でも起動する様に修正した。

    x fixed: 最後のユーザー入力からの経過時間で起動するべきところが、
      最初の auto-complete からの経過時間で起動している。
      これは auto-complete と同様の方法で起動するべきではないだろうか。

    x fixed: menu が表示されている状態で一文字でも入力するとメニューが閉じてしまう。
      これは menu-filter 状態になっていないから?
      勝手に menu-filter 状態に移行するのも考え物だが…。

      どうやら menu-filter が無効になっている様子だ。
      _ble_complete_menu_active= になっている。
      調べてみると一旦は _ble_complete_menu_active=1 になるが、
      直後に get-active-range に失敗して menu/clear が呼び出される様だ。

      分かった。auto-complete の中から menu に入っている為に、
      記録される left,right の中身が auto-complete によって
      一時的に挿入されている物を含む様になっている。
      menu 表示次の状態記録で keymap が auto_complete の時には、
      一時的に挿入されている文字列を除去する事にした。

    * todo: complete_auto_menu の説明
      * done: blerc
      * done: wiki 英語
      * done: wiki 日本語

2020-08-06

  * fzf の設定でエラーが発生する (reported by tigger04) [#D1372]
    https://github.com/akinomyoga/ble.sh/issues/60

    bind '"...": fzf-file-widget' の様に -x を
    指定し忘れたかの様なエラーメッセージが出ている。
    更に、_fzf_setup_completion というコマンドが
    存在しないというメッセージも出ている。
    然し、fzf のソースを見る限りはその様な事はあり得ない。変だ。

    | fzf を最新版に更新してもらったが変化はない。
    | 実際に使われている completions.bash, key-bindings.bash を貼って貰ったが
    | やはり勝手に編集しているという事はなくて
    |
    | ? bash 5.0.18 が悪い?
    |   コンパイルし直してみたが別に問題は発生していない。
    |
    | ? 或いは ble.sh が bind を上書きする前に fzf が bind を実行して、
    |   その後で ble.sh が bind -X の設定を読み取る時に失敗している?
    |
    |   然し、そうだとしても _fzf_setup_completion の問題の説明が付かない。
    |   というより、_fzf_setup_completion のエラーが
    |   どう ble.sh と関わってくるのか謎である。
    |
    |   x fixed: .fzf.bash を先に実行すると設定が反映されていない?
    |     →試しに先に .fzf.bash を source する様にしてみたが機能していない。
    |     というより、そもそも bind -x の結果がちゃんと呼び出されていない気がする。
    |     或いは、bind の出力結果から設定を復元する機能が有効になっていない?
    |
    |     調べると ble/builtin/bind/read-user-settings で復元する機能が有効になる筈。
    |     ここでちゃんとユーザ設定として fzf の設定が残っているか確認する。
    |     →何とユーザー設定は空である。
    |
    |     うーん。どうも途中でクラッシュしている様だ。
    |     振る舞いを見ると標準出力に何か出力しようとすると終了する。
    |     SIGPIPE が怪しい。という事は後段の awk が勝手に終了してしまっている。
    |     →分かった。ble/bin/awk を呼び出すべき所を /ble/bin/awk を呼び出そうとしていた。
    |     つまり、そもそも後段のプログラムが正しく起動していなかったのが原因。
    |     これを修正した所、ちゃんと fzf の設定が反映される様になった。
    |
    |   そして .fzf.bash を先に読み込んでも
    |   報告されているエラーメッセージは特に表示されない。
    |
    | うーん。やはり謎である。取り敢えず確実である。
    |
    |   shopt -s extdebug
    |   ble/function#advice before bind \
    |     '[[ ${ADVICE_WORDS[*]} == *fzf* ]] && ble-stackdump'
    |
    | これを試してもらおうと思ったがそもそも contrib 経由で呼び出している時には、
    | bind を封じている筈なので bind からエラーメッセージが出てくる筈がない。
    | これが示唆する事は何かというと @tigger04 は別の箇所で .fzf.bash も呼び出している。
    |
    | 恐らく Option 2 で出ているエラーメッセージは .fzf.bash を
    | 他の場所で source しない様にお願いすれば解決する。
    | 一方で _fzf_setup_completion が見つからないというエラーメッセージの方は謎である。
    |
    | どうやって調べたら良いのか。
    | そもそも問題のメッセージは本当に completions.bash の中で発生しているのか。

    bashrc の内容を教えてくれた。

    * どうも _fzf_setup_completion は bashrc の中から直接呼び出している様だ。
      ble.sh を設定していると何が問題になるのかというと、
      fzf の設定の初期化が遅延されるので、
      .fzf.bash を読み込んだ直後に _fzf_setup_completion を実行しても
      設定が未定義になっているという事である。

      これは .fzf.bash の中の ble-import で -d を指定しない様にすれば良い。

    * うーん。次の報告が来た。
      やはり ble.sh (bind) のエラーは bind の中で発生しているらしい。
      もしかすると shopt によって変な振る舞いをしている可能性?

      あー。分かった nocaseglob が悪いんだ。
      改めて bashrc を見ると nocasematch が設定されている。

    ? では何故自分の手元で実行した時には問題が発生していなかったのか。
      調べてみるとやはり問題は起こらない。
      何故かと言うと、blerc は nocasematch の設定よりも先に呼び出されるからである。
      @tigger04 が option 2 をどの様に構成したのかは分からないが、
      或いは option 2 を設定した上で更に .fzf.bash も source したという可能性がある。
      これは option 2 の使い方として予期したものではないのでこちらでは再現できなかった。


    何れにしても問題は明らかになったのでそれの対策をする。
    この nocasematch の問題に対してはどの様に対処すれば良いだろうか。
    先ず nocasematch の設定について動作を確認する。
    どうも nocasematch が入っていると [[ a == A ]] すら一致してしまう。
    これは問題になるのではないか。特に opts で一文字の物は変な事が起こる可能性がある。

    と思って調べてみると ble/base/adjust-bash-options で
    ちゃんと nocasematch の調整は行っている。
    うーん。では何故ちゃんと nocasematch の状態になっていないのか。
    と思ったが、分かった気がする。そう、builtin bind はユーザの側から呼び出されるので、
    nocasematch によって調整されていない文脈で呼び出される可能性があるのである。

    core-complete.sh の nocasematch は実は不要なのではないか、
    と思ったが、この部分は逆に敢えて一時的に nocasematch を有効にして、
    大文字・小文字に関係ない補完を実現するのに使われているのだった。
    これはこのままで良い。

    取り敢えず bind については nocasematch を一時的に保存復元する事にする。

2020-08-04

  * textarea: vi-mode strings がある時の計算がおかしい (reported by tigger04) [#D1371]
    https://github.com/akinomyoga/ble.sh/issues/60

    先ず、再現するかどうかを確認する必要がある。
    再現する。どうも、プロンプトを更新する度に vi-ins-mode-string が
    有効になったり無効になったりしてるようである。

    * 呼び出し元を調べる必要がある?
      呼び出し経路を調べると殆ど同じだが、
      ble-edit/bind/.tail の中での行番号が 3 だと有効で 4 だと無効になっている?
      然し、両方とも更に呼び出しているのは ble/textarea#render である。
      調べてみると、3行目は idle.do の前で、
      4行目は idle.do で何らかの処理が走った後である。
      然し、これだけで振る舞いが変化するというのも不思議である。

    * fixed: 分かった。_ble_decode_keymap が原因だった。
      と思ったが、別に表示が乱れる訳ではない…。
      もしかすると別の原因かもしれないが取り敢えず直した。

      以下はデバグに使ったコード。

      > #ble-stackdump "$(cat -A <<< "$expanded")" >> a.txt
      > echo "opts=$opts" >> a.txt
      > echo "processed: $(cat -A <<< "$processed")" >> a.txt
      > echo "expanded: $(cat -A <<< "$expanded")" >> a.txt
      > bind -v | grep -E 'show-mode|mode-string' >> a.txt
      > echo ---------------------- >> a.txt

    * もう一つの問題がある。auto_complete から抜けて prompt の内容が変化しても、
      prompt の再描画が実行されていない。prompt の再計算はちゃんとできている。
      prompt が変化したらそれを検出できる様にしているのではなかったか。
      prompt の再計算と描画がどの様に呼び出されているか改めて確認する。

      prompt の再描画は _ble_textarea_invalidated が設定されている時にのみ発生する。
      ここで prompt が変更された時に全体を再描画するか、もしくは
      部分更新でも特定の条件で prompt の再描画を実施するかという選択肢がある。
      部分更新でも prompt の再描画を実行するのが良い気がする。

      ble/prompt/.instantiate はプロンプトに変更があったかどうかを終了ステータスで知らせる。

2020-07-18

  * TERM=xterm-direct で一部の色が正しく表示されない [#D1370]
    どうも TERM=xterm-direct の時には 256 色を terminfo から使う事ができない様である。
    という事を考えると xterm-direct の時には init-term.sh で特別に処理する必要がある?
    2:r:g:b の形式で 16 色を決め打ちで設定してしまう事も考えたが、
    それだとユーザが好みで設定した 16 色の色を使わない事になってしまって良くない。
    やはり、ユーザの設定した 16 色を利用する様にする必要がある気がする。

  * color: xterm の最新版の既定の TERM が xterm-direct になっていた [#D1369]
    xterm は 24bit color を direct color という呼ぶ事にした様だ。

    当初 xterm の version 判定を使おうとしたが、もしかするとユーザが
    24bit color を使いたくなくて敢えてversion を使うという事もあるかも
    しれないと考えて、取り敢えずは TERM だけで判定する事にする。

2020-06-04

  * bash-5.1 のその他の変更。ble.sh に修正が必要かもしれない項目 [#D1368]

    > 3. New Features in Bash
    >
    > j. shell-transpose-words: a new bindable readline command that uses the same
    >    definition of word as shell-forward-word, etc.
    >
    > p. BASH_REMATCH is no longer readonly.
    >
    > 4. New Features in Readline
    >
    > c. Readline automatically switches to horizontal scrolling if the terminal has
    >    only one line.
    >
    > e. rl-clear-display: new bindable command that clears the screen and, if
    >    possible, the scrollback buffer (bound to emacs mode M-C-l by default).

    新しい readline bindable に関しては自動的に検出する枠組みを作っても良いのではないか。
    一応、以下のコマンドで列挙できる:

    $ join -v1 <(bash-dev -c 'bind -l' 2>/dev/null | sort) <(sort keymap/emacs.rlfunc.txt)

    現在の所は clear-display, shell-transpose-words が新しい bindable である。
    shell-transpose-words は良い。

    clear-display は clear-screen と何が違うのだろう。
    というより scroll buffer まで clear するという事が果たして可能なのだろうか。
    →よく分からないので実際に実装を調べてみると termcap E3 を用いて scroll を clear している様だ。
      https://www.man7.org/linux/man-pages/man5/user_caps.5.html によるとこれは ncurses の拡張?
      tput clear で出力されるのはこれであると書かれている。
      また、infocmp -x | grep E3 としても何も出てこない。
    →一方で通常の clear は clear_screen/clear/cl だそうだ。うーん。変だ。
    →https://invisible-island.net/xterm/terminfo.html によると E3=\E[3J らしい。
    つまり、\E[2J が clear_screen で、\E[3J が clear_display という事だ。
    取り敢えず現状は \e[3J を直接その場で出力する事にした。

    横スクロールに関しては複雑ですぐには実装できそうにないので別項目で議論する。

  * syntax: bash-5.1 では time -- が許される (from Bash-4.1 CHANGES) [#D1367]
    以前は time -p -- echo は OK だったが、
    time -- echo は -- がコマンド名と解釈されてしまって駄目だった。

2020-05-20

  * prompt: transient prompt (suggested by Dave-Elec) [#D1366]
    https://github.com/akinomyoga/ble.sh/issues/57#issuecomment-631648877

    powerline10k に transient prompt という設定があるそうだ。
    しかし、README には機能の存在は紹介されているが設定の仕方が書かれていない。
    https://github.com/romkatv/powerlevel10k#transient-prompt
    Reddit に使い方が投稿されている。
    https://www.reddit.com/r/zsh/comments/dsh1g3/new_powerlevel10k_feature_transient_prompt/
    trim するらしい。使い方が良く分からない。

    AndyChuがプロンプトを書き換えてコマンド開始時刻を表示する話について言及していた。
    https://github.com/oilshell/oil/issues/719
    https://redandblack.io/blog/2020/bash-prompt-with-updating-time/
    https://news.ycombinator.com/item?id=22912226

    zsh の "setopt transient_rprompt" に関しては二値の設定なので余り参考にならない。

    実装に関しては簡単そうである。既に rps1_transient を実装している。
    単に opts == *:leave:* を見てプロンプトを切り替えれば良い様に見える。
    trim するのは実は非効率的である気がする。
    (或いは .newline 等の別のレベルで trim しても良い。)
    どの様な機能を実装するかについて考察してから実装するのが良い。

    bleopt ps1_transient=same-dir:trim
    bleopt ps1_transient=

    * これを機にプロンプト設定の名前も整理するのが良い。

      bleopt prompt_ps1_preexec=
      bleopt prompt_ps1_transient=
      bleopt prompt_rps1=
      bleopt prompt_rps1_preexec=
      bleopt prompt_rps1_transient=

      bash を終了する時にも置き換えるのだとしたら、preexec は変ではないか。
      と思ったが、プロンプトの再描画は .newline の時に実行されるのであって、
      Bash を終了する時には置き換えられない。という事を考えるとやはり preexec
      という名前が適切な気がする。"exit" で抜ける場合にはちゃんと消える。
      C-d 等、widget 経由で抜ける時には消えない。取り敢えずそれで問題ない気がする。

      transient には same-dir を指定できる様にする。
      と思ったが preexec との相互作用が変な気もする。
      "same-dir を指定すると preexec が使われない" という動作である。変である。
      更に、transient になにか指定しないと ps1_preexec が表示されないというのも変だ。

      思うに ps1_preexec だけで良いのではないか。
      これが有限の文字列であればそれに置き換える。
      ps1_transient=trim が設定されていれば更に trim する。
      それ以外の場合には ps1_preexec も ps1 も表示しない。

      名前については preexec よりも final の方が良い気がしてきた。

    実装

    * done: 取り敢えず prompt_{ps1_{final,preexec},rps1_final} を追加した。
    * done: 古い設定名も書き換える。
    * done: 古い設定名に対する警告を表示する。

    * done: trim の対応? → 対応した。
      然しやはり ps1_transient を指定した時に trim でなければ
      プロンプトを完全に消すというのは変な気がする。
      然しだからと言って既定で trim というのは rps1_transient と振る舞いが違う。
      →やはり対称性を重視して完全にプロンプトを消す事にした。

    x fixed: 動かしてみると keep-info の時に info が消滅している→直した。

    * done: blerc, Manual を更新する。新しい設定の追加と名称変更についての注記。
      これらについてはちゃんと更新した。

  * prompt: プロンプトに vim mode を表示できる様にする (suggested by Dave-Elec) [#D1365]
    https://github.com/akinomyoga/ble.sh/issues/57

    keymap_vi_nmap_name 以外のモード名の設定。

    [関連情報]

    * readline には以下の変数が存在する。
      set show-mode-in-prompt on
      set vi-cmd-mode-string "(cmd)"
      set vi-ins-mode-string "(ins)"

      ble.sh ではいきなり独立行にこれを表示するので、
      この設定が使えなくなってもそれ程迄に気にする人はいないだろう。

    * prompt に新しい設定を追加するには。
      特に \p{name} 的な形式で指定できる様にしたい。
      p の代わりにもっとましな文字を使いたい。例えば、

      a 正規表現の参照的には \k<name> \k'name' \k{name}
        \'name' 或いは \'{name} \{name} \"{name}

      b printf %()T 的には、\(name)N 等? でも分かりにくい。

      c zsh prompt は %D{strftime format} に対応している。
        zsh では以下の特殊文字について既に % が定義されている。
        %% %# %! %? %_ %^ %/ %~ %. %{..%} %(...)
        %<...< %>...> %[>...] %[<...]

      d 良く考えたら既に Bash も \D{format} に対応している。
        この様に考えると \X{...} の形式にするのは確定。
        \! \# \$ \[ \] は既に使われている。
        この雰囲気だと \' \" 等は今後も使われる事が無さそうな気がする。
        \'{name} 等でどうだろうか。取り敢えず \'{name} で対応する事にする。

    [変更]

    * done: ble-edit/prompt/backslash:name は
      ble/prompt/backslash:name に変更する事にする。
      Recipe から以前の名前を使っている人がいるかもしれないので、
      関数が見つからない場合には古い名前を使用する。

    * fixed: 実際に動かしてみて気付いたが \'{name} だと、
      PS1 を指定する時のエスケープと被ってしまって良くない。
      別の文字にするか或いは \{name} にする?
      \{name} は余り使いたくない。やはり \D{name} が存在する以上は
      それに従うのが自然だろうと思われる。

      アルファベットは今後使われる可能性がある。
      従ってやはり記号の類が良い気がする。
      \?{name} は正規表現の名前に似ているが、
      \? が別の目的で使われないとも限らない。
      うーん。\:{name} にしようか。lisp 的に \,{name} でも良い?
      或いはやはりアルファベットを使うか。\q にするのが良い気がしてきた。

      OK 動いている。\q{name} というのも分かりやすい気がしている。

    * done: mode名を表示しない設定を作るのも良い気がしている。
      bleopt keymap_vi_mode_show=
      取り敢えず対応した。動作確認をして修正もした。

    * done: 次にモードが変化した時にプロンプトを invalidate することについて考える。
      これはもう全体を invalidate してしまっても良い気がする。
      更にそれと同時に prompt のキャッシュも強制的に更新させる必要がある。
      →実はこれは単に ble/prompt/clear を呼び出せば良いという事だろうか。
      そんな気がする。取り敢えず動いているという事を確認した。

    * done: readline の設定に対応するべきだろうか?

      取り敢えず振る舞いについて確認する。

      set show-mode-in-prompt on
      set emacs-mode-string "@"
      set vi-cmd-mode-string "(cmd)"
      set vi-ins-mode-string "(ins)"

      bind で設定する時に "\1\2" 等とした場合に、
      bind -v ではどの様に出力されるのだろうか。
      →何と直接表示された。つまりこれは ble/prompt/print で追加するべき。

      * モードが変化した時に ble/prompt/notify-readline-mode-change
        を呼び出して強制的に prompt を再計算させる事にする。

      vi 内部でのモードの変更は update-mode で実行すれば良い。
      emacs, vi の切り替えに関しては現状の枠組みでは必ず
      reset-default-keymap 経由で実行される。そしてその際には __attach__ が呼び出される。
      従って __attach__ でモードをチェックして set show-mode-in-prompt になっていたら
      prompt を強制更新するという具合にするので良い。

      動作確認を実行する。以下の設定で期待通りに動く事を確認した。OK

      bind 'set show-mode-in-prompt on'
      ble-bind -m vi_imap -f C-t emacs-editing-mode
      ble-bind -m emacs   -f C-t vi-editing-mode

    * done: Manual を更新する。新しい bleopt を追記した。
    * done: vi guide も更新する
    * done: blerc も更新する。新しい bleopt を追記

    * done: Manual: プロンプト文字列に関する説明
      プロンプトの改造の仕方の説明
      これらは rps1 付近に追記すれば良いだろう。
      或いはプロンプトに関する独立した章を設ける。
      readline variable の解釈についてもちゃんと書きたい。

    [返答の準備]

    取り敢えずサンプルを提示する?
    或いは、contrib にサンプルを追加してしまっても良い気がする。
    →contrib に追加した。

2020-05-18

  * 複数行履歴中の \ が q に化けてしまう (reported by cmplstofB) [#D1364]
    https://github.com/akinomyoga/ble.sh/issues/56

    これは 4bcbd71 support timestamp で導入されたバグである。簡単な修正だった。

    一方の複数行コマンドの復元ができていない問題に関しては謎。
    一回再現できたが、もう二度と再現しない。何故だろう。
    再現できた時には eval -- $'a q\nb q\nc' の形になっていた。
    履歴ファイルには eval -- $'a \\\nb \\\nc' で登録されているので、
    つまり、mlfix が走った後で history/load が走って、その時になにかに失敗している。
    然し、何をどう失敗するとこうなるのか謎。取り敢えず様子見。

2020-05-16

  * 元のリポジトリが消滅している時にも update を可能にする [#D1363]
    https://github.com/rux616/init/blob/7e1a5d2e0dbaa792f4a0a4830ea2f8b92b433b44/install#L422
    →その様に修正した。

  * util: escape 単語先頭の ~ や # は escape しなくて良いのか [#D1362]
    ble/string#escape-for-bash-specialchars

    調べてみると core-complete.sh が使っている。

    * そして試しに touch '#hello' '~hello' で調べてみると正しく escape されない。
      →これについては修正した。
      x 単語先頭以外でも \# \~ に修正されてしまう。
        単語先頭かどうかを判定する事は可能だろうか。

    * fixed: 更に \~hello に至ってはチルダ展開が起こって補完候補にも現れない。
      '~hello' の場合にはちゃんと候補が列挙される。
      →どうもこれは bash-completion が悪い様である。
      然し、'~' の場合にはちゃんと生成できている。何が悪いのだろうか。
      具体的にどの様な情報が渡されているのか確かめる必要がある。

      調べるとシェル関数の引数である cur prev に渡されている情報が悪い。
      cur="'~" の時には bash-completion は何も生成できない。
      cur="\\~" の場合には bash-completion は何故かユーザー名を列挙する。
      然し、よく考えてみるとそもそも COMP_WORDS の方も対応する様に
      エスケープしなければならないのではないか。
      その上で COMP_WORDS に一致する様に cur prev を用意するべきなのではないか。
      もっと振る舞いを調べると bash-completion は引数と COMP_WORDS の両方の情報を使っている。

      * 先ず COMP_WORDS の値を修正する必要がある。修正した。
      * 更に、cur prev として渡している値も COMP_WORDS に変更したら動く様になった。

      ? no: 然し、この部分は過去に何らかの議論があってこの様に修正した気がする。

        | 改めてこの部分について調べる必要がある。調べると c8433971 43bb0749 が怪しい。
        |
        | 2018-08-05 09:15:39 c8433971
        | 2019-03-23 21:41:19 43bb0749
        |
        | と思ったが、 c8433971 は quote を変更しただけである。更に遡る。
        |
        | 2015-11-24 04:05:14 1929132b (complete.sh) ここで導入されている。
        |
        | 更にその前のコードはどうなっていたかと言うと、以下の様な具合になっていて、
        | そもそも COMP_WORDS と comp_words の区別がなかったし、更に関数に引数を渡していなかった。
        | というより上の commit の僅か 4 時間前の事である。要するに実装してすぐに
        | cur=${comp_words[comp_cword]} だったという事である。
        |
        | | 2015-11-23 23:58:01 cdd38598 (complete.sh)
        | | function ble-complete/source/argument/.compgen-helper-vars {
        | |   COMP_WORDS=("${comp_words[@]}")
        | |   COMP_LINE="$comp_line"
        | |   COMP_POINT="$comp_point"
        | |   COMP_CWORD="$comp_cword"
        | |   COMP_TYPE=9
        | |   COMP_KEY="${KEYS[${#KEYS[@]}-1]:-9}" # KEYS defined in .ble-decode-key/invoke-command
        | | }
        | | function ble-complete/source/argument/.compgen-helper-func {
        | |   local -a COMP_WORDS
        | |   local COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY
        | |   ble-complete/source/argument/.compgen-helper-vars
        | |   [[ $comp_func ]] && eval "$comp_func"
        | | }

        結論: COMP_WORDS ではなくて comp_words を使っているのに特に意味はない。
        未だ COMP_WORDS と comp_words に区別のなかった一番最初の実装の時からこうだった。
        従って気兼ねなく変更する事ができる。変更した。

    * ~ は ble.sh が勝手に展開してから bash_completion に渡しているが、
      ~ の儘にして渡した方が良いのではないだろうか。
      特に ~ という単独の単語の時にのみ特別扱いとするのである。

      →対応した。候補はちゃんと生成される様になったが、
      quote されてしまう。\~murase という具合に。これは期待する動作ではない。
      実際に bash の場合には勝手に quote されるという事はなかった。
      complete -p echo しても特に -o noquote が指定されている訳でもないし、
      また、compopt の呼び出しを確認しても compopt -o filenames が呼び出されるだけで
      compopt -o noquote が呼び出されるわけでもない。

      元の Bash の振る舞いについても確認しておく必要がある。
      →どうやら元々の Bash は ~ に関しては quote しない様だ。
      そう思って quote しない様にしてみたら
      今度は \~hello の様なファイル名で期待通りに動かない。
      候補としては ~hello が生成されている。

      不思議な事が起きている。bash_completion 経由だとメニューの表示には
      \ 無しで表示されているのにも拘らず実際に補完される時には \ 付きで挿入される。
      自分で作った補完関数で試してみるとどちらも COMPREPLY に格納した通りにしかならない。
      或いは文脈に応じて bash_completion は quote の仕方を変えるという事なのだろうか。
      →分かった。bash は compopt -o filenames が指定されている時、
      ローカルファイル名に "~..." が一致する時に限り tilde の quote を実施する。

      →Bash の振る舞いの通りに実装してみたがこれで良いのか分からない。
      本来はいつでも先頭の ~ は quote するべきの気もするがまあこれで大丈夫だろう。

2020-05-14

  * loadable builtins を積極的に使うという可能性について [#D1361]

    | builtin mkdir, rmdir, rm, mktemp -d 等を積極的に使っても良いのではないか。
    | 然し問題点はユーザが /usr/bin/mkdir を使いたい時に
    | 勝手に builtin の方が呼び出されるという事。
    | という事を考えると enable を使って一時的に有効にして使う?
    |
    | 然し、元から有効だったかどうかをどの様に判定するのか。
    | 調べてみたが type コマンドを使うぐらいしか方法がない気がする。
    | enable の終了ステータスを使って判定する方法はあるだろうか。
    | やはりない気がする。やはり勝手に enable/disable するのは良くない気がする。
    |
    | といってサブシェルで実行するというのだと fork は結局する。
    | でも fork/exec よりは効率が良い様な気もする。

    * というより、sleep の場合でも問題が起きるのではないだろうか。
      調べてみると coreutils sleep は 1s や 1m 等の指定を受け付けるが、
      builtin sleep は整数と小数にしか対応していない。
      これの対策については真面目に考える必要がある。

      a 例えば sleep は関数で上書きしてしまって内部では command sleep を呼び出す。
        然し、msleep からは builtin sleep を使う様にする。
        然し、これはこれでユーザが sleep 関数を定義したい場合や、
        ユーザが enable -f ./sleep を実行したい場合に不都合が起きる。

        うーん。builtin と明示的に指定した時にのみ builtin として使える、
        という感じの仕組みがあると良いのだが、難しい。

      b 或いは、いっその事 ble.sh 専用の builtin を作ってしまうというのも手なのである。
        x loadable builtin に手を出したらもう ble.sh の存在意義が失われる気がする。
          それだったら初めから loadable builtins だけで全部実装すれば良かったのである。
        x 一応コンパイラの存在しない環境の為に loadable builtin を使わない
          場合も用意する事ができるが、頻度が低くなるとテストが十分にできな
          くなり問題を起こす可能性がある。然し、その為の単体テストではない
          のだろうか。という事を考えるとそういう意味では問題はない。

      取り敢えずこれはそれ程深刻ではない気がするので放置で良いのではないか?
      或いは 1m や 1s 等の表記にシェル関数を使って対応してしまうという可能性。
      どうせならその方が良いという気がする。

      取り敢えず coreutils 的な sleep をシェル関数で実装する事にした。
      この様にすればユーザが普通の sleep の機能を使いたい場合でも大丈夫だし、
      或いは enable -f sleep で sleep を有効にして組み込み sleep を使いたい場合でも
      どちらでも大丈夫。

      他に現実的な解もない気がするのでこれで良しとする。

    [結論]

    色々考えた結果 sleep 以外に関しては builtin を読み込むのは却って管
    理が複雑になるという事。また、それ程迄に必要という訳でもないという
    事。それよりは stty を builtin にするべきという事。

    loadable builtins には既定で mkfifo, mkdir 等、システムのユーティ
    リティと同名の物が提供されている。loadable builtins を読み込むとシ
    ステムのユーティリティが上書きされてしまう。loadable builtin の方
    が一般的にシステムが提供するコマンドよりも機能が少ないので問題にな
    る。

    mkdir() { /usr/bin/mkdir "$@"; } とすれば単に mkdir と呼び出した時
    には必ずシステムのユーティリティを呼び出して、builtin mkdir とした
    時にだけ読み込んだ物を使う様にできる。然し、この様にすると逆にユー
    ザが意図的に loadable builtin の mkdir を読み込んだ時に、builtin
    を読み込んでいるのにも拘らず builtin が使われないという状況になっ
    てしまう。

    sleep は他に良い代替手段がないという事と、coreutils sleep の振る舞
    いをシェル関数でも実現できるという事から、load してシェル関数によ
    る実装で上書きする事にした。一方で mkfifo, mktemp, mkdir は
    SELinux の context 等の対応が難しい。rm は更に様々な機能がある。

    [まとめ]

    ユーザが file コマンドを使いたい場合と builtin を使いたい場合があ
    る。それに干渉したくないので基本的に同名の loadable builtins は使
    わない。代わりに ble 的な builtin を作成して其処から様々な関数を呼
    び出すという可能性はある。

  * syntax: 何故か {aa}> はちゃんと認識されるが {a}>&1 は認識されない [#D1360]
    文字数が1文字だと駄目になっているようだ。
    これは簡単な修正だった。

  * main: ble-update で新しい commit が fetch できなかったとしても [#D1359]
    現在の ble.sh repo の状態が、現在ロードされている version と違えば
    その場で reload するべきなのではないか。

    序でに一時ファイルを全て $_ble_base_run/$$/ という
    ディレクトリに移動することを考えたが、これだとディレクトリを作る為に
    fork が必要になるので初期化時間が伸びてしまう。
    これは取り敢えずは現状の儘にしておくという事で良い。

2020-05-13

  * complete: 変数代入の中で変数名の補完が効かない [#D1358]
    例えば var=1234 が存在している時に x=$va に対して補完が効かない。

    実際に試してみると v=$B に対して "rhs 2" という候補しか生成されていない。
    うーん。"variable 3" という物が生成されても良いのではないか。
    以前、変数代入を代入の右辺からの候補を生成する様にした。
    この時に元々ある候補が生成されなくなってしまったという事。

    調べると .check-prefix から直接 .check-prefix/ctx:rhs に移動している。
    そして其処で rhs の開始点まで遡るという事をしている。
    確かに $B となっている時の懐石再開点は $ の直前であり、其処での文脈は VRHS である。
    逆に通常の文脈ではどの様に処理していたのだったか。
    例えば ARGI の時には inside-argument を呼び出している。
    更にその中で ble/syntax/completion-context/.check/parameter-expansion を呼び出しているのだった。

    他にも似たような物はないか確認したが > file$BASH や
    time $BASH でもパラメータ展開の補完ができなかった。


  * prompt: PS0 という物が Bash 4.4+ には存在する様である [#D1357]
    何故か http://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html には反映されていない。
    もしかするとこのマニュアルは更新が Bash 4.3 で止まっているのかもしれない。
    https://github.com/rcaloras/bash-preexec/issues/28
    http://superuser.com/a/1052132
    https://stackoverflow.com/questions/43201274
    これは対応した。簡単だった。

2020-05-12

  * history: "bleopt history_share=1" でエラーメッセージが発生する (reported by rux616) [#D1356]
    https://github.com/akinomyoga/ble.sh/issues/50#issuecomment-627061087

    これは新しく埋め込んだバグだろう。エラーメッセージを見ると、
    ble/history:bash/resolve-multiline/readfile であろう。
    要するに新しい履歴項目がない場合にそもそも TMPBASE.part が作られないという事では?
    調べると reason=resolve の時には作られるけれども、reason=read の時には作られない。

    然し、ble/history:bash/resolve-multiline/readfile の呼び出し元を確認した時に不思議なのは、
    ちゃんと呼び出し元ではファイルが空でないという事を確認しているという事。
    #%s の行しか存在していない時にはこういう事が起こるのかもしれないが、
    それも何だか変である。実際に何が起こっているのか再現させて調べるしかない。

    →再現させる事ができた。然し、ファイルの中身はちゃんと存在している。awk が悪い?
    これは単純なミスであった。修正した。

  * LC_COLLATE=C で検索すると未だ LC_COLLATE=C func の形式の物が残っている [#D1355]
    これは問題が起こるので避ける様にした筈。調べると
    LC_XXX=C external_cmd の場合には問題は起こらない様子である。
    従って、組み込み機能で処理を行う場合には全て local に入れる必要がある。

    その他、わざわざ bash-4.1 で処理を切り替えている物を
    新旧 bash のどちらでも動く方法を使う様に統一した。

2020-05-11

  * main: bashrc で source ble.sh を2回実行すると固まる (reported by GavinRay97) [#D1354]
    https://github.com/akinomyoga/ble.sh/issues/51

    bashrc に設定したら ble-reload というメッセージが表示されて操作できなくなる。
    ble 0.3.2 で source ble.sh を2回実行すると発生する。
    ble-0.4 でも ble-attach を手で実行すると発生する。

    また ble-0.4 で同じ事を --attach=prompt で実行すると
    リダイレクトエラーが沢山発生する。文字列を入力する度に発生する。
    これはつまり stdout.on, off で問題が発生しているという事だろう。
    (too many open files とは一体どういう事だろうか。)

    bashrc の中で2回以上 source ble.sh するとエラーが発生する。

    $ bash --rcfile bashrc.1.bash
    bash: リダイレクトエラー: ファイル記述子を複製できません: Too many open files
    bash: /dev/null: Too many open files
    bash: リダイレクトエラー: ファイル記述子を複製できません: Too many open files
    bash: /dev/null: Too many open files
    bash: リダイレクトエラー: ファイル記述子を複製できません: Too many open files
    bash: /dev/null: Too many open files
    bash: リダイレクトエラー: ファイル記述子を複製できません: Too many open files
    bash: /dev/null: Too many open files

    これはどうも単に stdout.off の状態でロードすると駄目という問題の気がする。

    ? と思ったが --attach=prompt でも問題が起こるという事はそんなに簡単ではない。
      →ソースコードを確認した所、別に attach しなくても ble.sh を読み込んだ時点で
      ble/fd#alloc _ble_edit_io_stdout '>&1'
      ble/fd#alloc _ble_edit_io_stderr '>&2'
      を使ってリダイレクト先を設定している。
      というよりこれらは実は明示的に /dev/tty に繋ぐべきなのでは?

      * 取り敢えず修正としては /dev/tty に繋ぐという事。
      * unload の際に stdout.on を実行するという事。
        実際に確認してみた所、ちゃんと stdout.on が呼び出される様に実装してある気がする。

      またもう一つ変なのは --attach=prompt を使っているという事は、
      二回目の ble.sh の時点では未だ stdout.off の状態になっていない筈という事。
      それでも問題が発生するというのは何か別の事が起こっている?
      →実際に確認してみた所 1 も 2 も /dev/null に繋がっている。
      stdout.off の状態になっているという事を意味する?

      何処で stdout.off が呼び出されているのか調べようとしたが、
      実は stdout.off は呼び出されていない?
      何らかの別の場所で 1,2 が /dev/null に繋がれている?
      そもそも本当に 1,2 は /dev/null に繋がっているのだろうか。

      また、ls -la /proc/$$/fd を見た感じだと _ble_edit_io_stdout 等はちゃんと
      tty に繋がっている。変な物に繋がっているという事はない様である。

    x fixed: PROMPT_COMMAND 無限ループ

      % ? too many open files というエラーメッセージは恐らく間違ったメッセージの気がする。
      %   →これについては確認してみた所、別に沢山の file descriptors を開いている訳ではない。
      %   という事はつまりこれは単にエラーメッセージが間違っているだけである。

      うーん。stdout.off で実際に確かめてみた所、
      実は本当にファイルディスクリプタを使い果たしている様だった。
      というか PROMPT_COMMAND で無限ループになっているという事の様だ。

      これは一体どの様にして回避したら良いのか。
      PROMPT_COMMAND が ble/base/attach-from-PROMPT_COMMAND なら
      _ble_base_attach_PROMPT_COMMAND を上書きしないというのが愚直な対策だが、
      ユーザが PROMPT_COMMAND="$PROMPT_COMMAND;..." 等と変更していた場合を考えると、
      コンポ天気な対策になっていない。

      % fixed: 先ず ble/base/attach-from-PROMPT_COMMAND の最初で
      % _ble_base_attach_from_prompt= を設定して何度も実行されない様にする?
      % と思ったが違う気がする。_ble_base_attach_from_prompt= は
      % 何度も attach を実行してしまわない為の物であって、
      % PROMPT_COMMAND の呼び出しを抑制する為の物ではない。
      %
      % 実際に attach しているかどうかに関わらず
      % PROMPT_COMMAND を入れ子で実行してしまわない為の物である。
      %
      % →lambda を使って実装し直したので結局この修正は不要になった。

      * 問題は何処にあるのか。

        更に元々ユーザが設定していたコマンドは何処に退避するのか?
        現状の設定だと _ble_base_attach_PROMPT_COMMAND= に待避されていた
        ユーザのコマンドは消滅してしまう。うーん。
        実は unload する時に復元するべきなのではないだろうか。
        と思ったが更にユーザが PROMPT_COMMAND を変更していた場合、
        勝手に復元する訳には行かなくなる。

        二回実行した時に既に退避していたコマンドを実行するのか、
        或いは完全に削除してしまうのかどうするべきか。

        | そもそも ble.sh を reload する事を許しているのはユーザが source ~/.bashrc
        | した時に改めて初期化する事を可能にする為。そういう事を考えると、
        | PROMPT_COMMAND が累積して行くというのは変といえば変な話である。
        | 本来は bashrc の先頭でクリアしてしまうべきなのではないかという気がする。
        |
        | 然し、現実にはわざわざその様にする事はない。
        | というか重複して実行されても良いのではないだろうか。
        | その様になってしまうのはユーザが何度も実行するから。
        | と思ったがユーザが登録する時には PROMPT_COMMAND に既に
        | 自分の設定した文字列が含まれているかどうかを確認してからという事もある。
        | そういう事を考えると、やはり何度も実行してしまうのは変な気がする。
        |
        | というか同じ問題が普通に reload した時にも起こる。
        | _ble_base_attach_PROMPT_COMMAND= に指定していた設定が消滅するという事。
        | これに対してどう処理するのが正しいのか。。
        |
        | 本来は ble.sh の設定した PROMPT_COMMAND は一時的な物なので跡形もなく消したい。
        | 然し、実際にはユーザの別の設定に取り込まれたりするので後で消し去れない事もある。
        | その時に如何に透明になる事ができるかというのが問題である。
        |
        | _ble_base_attach_PROMPT_COMMAND を配列にして上書きする?
        | 或いは _ble_base_attach_PROMPT_COMMAND に既に値が設定されていた場合には、
        | それを更に別の変数に退避して、ble/base/attach-from-PROMPT_COMMAND が
        | 二重に呼び出された時にそれを実行するという事にする?
        |
        | うーん。ble/base/attach-from-PROMPT_COMMAND という名前ではなくて、
        | 適当にラムダ関数として重複の無いようにその場で関数を生成する?
        | そうすればちゃんとそれに紐付いた関数として呼び出す事ができる。
        | うーん。それが良い気がしてきた。

      * lambda で実装するのが良い気がしてきた。

        改めて方針について整理する。
        実際に登録するのはラムダ関数にする。
        そのラムダ関数から ble/base/attach-from-PROMPT_COMMAND を呼び出す。
        古い PROMPT_COMMAND は変数に保存するのではなくて、ラムダの本体に埋め込む。
        また、ラムダを削除する為に、ble/base/attach-from-PROMPT_COMMAND にラムダの関数名を渡す様にする。

        ble/base/attach-from-PROMPT_COMMAND 'old-prompt-command' "$FUNCNAME"

        ble/function#lambda 変数名 'function-body' というインターフェイスにする。

      * ok: lambda を使って実装した時に再帰呼び出しが発生する可能性はあるだろうか。
        考えてみる。

        一回目の source で PROMPT_COMMAND=lambda/1 になる。
        元の PROMPT_COMMAND は lambda/1 から呼び出される。
        二回目の source で PROMPT_COMMAND=lambda/2 になって
        此処から lambda/1 が呼び出される。

        実際に PROMPT_COMMAND が評価されるとどうなるか。

        | - lambda/2
        |   - ble/base/attach-from-PROMPT_COMMAND lambda/1 lambda/2
        |     1 PROMPT_COMMAND=lambda/1
        |     2 lambda/1
        |     | - ble/base/attach-from-PROMPT_COMMAND 元々の値 lambda/1
        |     |   1 PROMPT_COMMAND=元々の値
        |     |   2 元々の値
        |     |   3 PRECMD-=lambda/1
        |     |   4 _ble_base_attach_from_prompt=
        |     |   5 ble-attach
        |     3 PRECMD-=lambda/2
        |     4 [[ $_ble_base_attach_from_prompt ]] || return

        の様になって無限ループは防げる。

        PRECMD が重複して登録されてしまっているのは気になるが、
        まあ大丈夫だろうという気がする。
        PROMPT_COMMAND が複数回実行される程度の気がする。うーん。本当だろうか。
        PRECMD 経由だと何が起こるかというと…。
        登録した順に呼び出されるという事を考えると変な事になる。

        | - lambda/1
        |   - ble/base/attach-from-PROMPT_COMMAND 元々の値 lambda/1
        |     1 local PROMPT_COMMAND=元々の値 (PROMPT_COMMAND (lambda/2) != 元々の値なので local)
        |     2 元々の値
        |     3 PRECMD-=lambda/1
        |     4 _ble_base_attach_from_prompt=
        |     5 ble-attach
        | - lambda/2
        |   - ble/base/attach-from-PROMPT_COMMAND lambda/1 lambda/2
        |     1 PROMPT_COMMAND=lambda/1
        |     2 lambda/1
        |     |   ble/base/attach-from-PROMPT_COMMAND 元々の値 lambda/1
        |     |   1 PROMPT_COMMAND=元々の値
        |     |   2 元々の値
        |     |   3 PRECMD-=lambda/1
        |     3 PRECMD-=lambda/2
        |     4 [[ $_ble_base_attach_from_prompt ]] || return

        この様に考えてみると単に "元々の値" が二回実行されるだけである。
        或る意味これは自然と言えば自然な気もする。
        ユーザが二回初期化を実行したのだから。
        そして各 source ble.sh 毎に1回ずつプロンプトの計算が走る。
        また、最終的には PROMPT_COMMAND も PRECMD も解除される。

        次の場合はユーザが後になって PROMPT_COMMAND を修正した時に何が起こるかという事。
        これについては PROMPT_COMMAND の復元が行われないというだけで PRECMD は削除される。
        PROMPT_COMMAND の復元に関しては実は行われなくてもそう大きな問題にはならない気がする。
        attach も二度は起こらないし単に無駄に関数呼び出しが実行されるだけである。

      * ok: ble.sh が PROMPT_COMMAND を設置した後にユーザが更に何か追加する可能性がある。
        →これに関しても lambda を使って実装すれば大した問題にはならない。

      x fixed: これで --prompt=attach に対しては動くかと思いきやプロンプトが表示されない。
        これは /dev/null にリダイレクトしているのが原因である。
        と思ったがよく見るとちゃんと PROMPT_COMMAND の標準エラーは外に伝わる様になっている。
        という事はこれが原因ではないという事? ble-attach がそう何度も実行されるとは考えにくい。

        然し、実際のこのリダイレクトを修正したら問題が発生しなくなった。
        何が起こっているのだろうか。番号を指定してリダイレクトしている事によって
        何らかのファイルディスクリプタが上書きされてしまっている?

        或いは、2>/dev/null によって ble-attach の内部で実行した恒久的な exec redirection
        が復元されてしまっているのが原因だろうか。何か違いが生まれるとすればこれしかない。
        然し、何故これによってその様な症状になるのかというのは謎である。

        →何だか分からないがやはり attach は一番最後に行うべき気もするし、
        そういう意味でも一番外側で実行するべきである。その様に修正した。

    結局、--attach=prompt の時のファイルディスクリプタの問題と、
    ble-attach を強制的に実行した時に何も表示されなくなる問題は独立の問題だった。
    それがはっきりした今改めて状況について整理する。

    * ble-attach を実行したあとで source ble.sh を実行した時に、
      本来であれば stdout.off が unload で呼び出される筈で、
      結果として stdout.off, on が破壊されるという事はない筈である。

      という事は起こっている問題は stdout.on, off の問題ではない?
      或いは stdout.off に失敗している所為でこれが起こっている?
      まずはこれがどちらなのかを確認する必要がある。

      →確認した。二回目の初期化に於いて stdout.off 状態になっている。
      ここでの謎は何故 unload で stdout.on が実行されなかったのかという事。

      実際に調べてみるとちゃんと stdout.on は呼び出されていて
      状態は復元されている。と思ったら分かった。
      ble/base/unload-for-reload &>/dev/null として呼び出していたので、
      ble/base/unload-for-reload の実行が終わった後に
      1,2 が呼び出し前の状態に復元されてしまうのだった。

      そもそもこの &>/dev/null は何の為の物だったろうか。
      これを削除してしまっても特に問題はないのではないだろうか。
      或いは set -x 等の状態復元に関係があるだろうか。
      実は set -x の状態復元は此処では行っていない様に見える。
      →実際に set -x を実行してみたが特に何か出力されるという事もない様だ。

      念の為この部分の変更を履歴を調べておく。

      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 226) if [[ $_ble_base ]]; then
      | fc45be68 (Koichi Murase 2019-01-11 20:38:38 +0900 227)   if ! ble/base/unload-for-reload &>/dev/null; then
      | fc45be68 (Koichi Murase 2019-01-11 20:38:38 +0900 228)     echo "ble.sh: ble.sh seems to be already loaded." >&2
      | fc45be68 (Koichi Murase 2019-01-11 20:38:38 +0900 229)     return 1
      | fc45be68 (Koichi Murase 2019-01-11 20:38:38 +0900 230)   fi
      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 231) fi
      |
      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 226) if [[ $_ble_base ]]; then
      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 227)   echo "ble.sh: ble.sh seems to be already loaded." >&2
      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 228)   return 1
      | 59995c62 (Koichi Murase 2015-08-11 19:42:02 +0900 229) fi
      |
      | commit fc45be6841be364d152cb2228e662ca842bf4fc3
      | Author: Koichi Murase <myoga.murase@gmail.com>
      | Date:   Fri Jan 11 20:38:38 2019 +0900
      |
      |     main: support "ble-update"

      対応する項目は #D0874 の様である。
      ちゃんとは読んでいないが特に >/dev/null の処置についての言及はない様である。
      取り敢えず何も起こっていない様なのでそのままで良い事にする。bash-3.0 でも大丈夫。

  * [別要因] menu: bleopt complete_menu_style=dense の座標計算が間違っている? [#D1353]

    | dense-nowrap では問題が起きていない事を見ると wrap で問題が発生しているという事か。
    |
    | 初め trace-text に渡している nonewline オプションが悪いのではないかと思ったが関係ない?
    | nonewline は confine 等とは関係なくて、単に改行文字を出力しないという事らしい。
    | 勝手に wrap するのは許す実装になっている気がする。
    |
    | そもそも何故座標計算がずれてしまうのか。どういう座標になっているのか?
    |
    | dense-nowrap で問題が発生しないということは
    | やはり右端で折り返す候補が来た時の処理が問題になっている。
    |
    | 幅は174 である。x0=169 で始まって x=19 で終わっている。
    | 出力している文字列は generate-release-note.sh である。
    | gener 折返し ate-release-note.sh という具合になる筈である。
    | 何も間違う所はない気がする。
    |
    | うーん。更に実際に描画している物を見ると複数行ある筈の所が同じ行に出力されている。
    | 最終的に行がカーソル位置が上に移動してしまっている。
    |
    | 何だかわからないので実際に表示を行っている部分を確認する。
    | construct-page が実際に出力するシーケンスを esc に格納している。
    | これを出力して確認してみるのが良いという気がする。
    |
    | かなり謎の振る舞いをしている。というか cat して表示した内容と、
    | Emacs で開いてみてみた内容が対応していないこれはどういう事か。
    | 暫く観察してこれは screen が悪いのではないかという事に思い至る…。
    | echo {1..100} を実行してみると改行せずに途中までしか表示されない。
    | 試しに新しい画面を C-a C-c で開いてみると直る。
    | DECAWM が変な状態になっているという事?
    | echo $'\e[?7h' としたら直る? 7l を何処かで間違って実行してしまったという事だろうか。
    | ble.sh の中には少なくとも 7l という文字列はない。
    | ble.sh の変数の中にも 7l が含まれている物はない。
    | という事はこれは恐らく何か別のプログラムが変な設定をして抜けたか、
    | 或いは別のプログラムがクラッシュした時に残したなにかである。
    | この pty では ssh はしていないと思うので途中で接続が切れて中途半端になったという事ではないと思う。
    |
    | 或いは履歴を探すとそういうコマンドが残っている様だ。
    | このセッションで実行した物ではない様に思われるが、
    | 子 bash で試してそのままになっているという事の様な気もする。
    | と思ったがこの bash を起動したのは 2020-04-26 23:43:05 JST だし、
    | この bash 自体が別の bash の子供という訳でもない。不思議である。

    結局これは端末の状態が変になっていただけであった。DECAWM が無効になっていた。
    然し、何故この様な状態になってしまったのかは終に分からない。
    ble.sh 自体には CSI ? 7 l を実行しそうな物は含まれていないので、木にしなくて良さそう。

  * complete: blerc で bleopt complete_menu_style を設定できない (reported by rux616) [#D1352]
    https://github.com/akinomyoga/ble.sh/issues/54

    指定した設定が存在しているかどうかのチェックをその場で行っている。
    core-complete.sh の初期化前なのでその設定が存在している事を確認できないのが原因。
    core-complete-def.sh に complete_menu_style 用の autoload を追加する事にした。
    これは単純な修正なのでテストしなくても良いだろうという気がする。

  * history: HISTTIMEFORMAT によるタイムスタンプが記録されない (reported by rux616) [#D1351]
    https://github.com/akinomyoga/ble.sh/issues/50

    まずは bash の振る舞いについて調べる必要がある。

    | というかそもそも HISTTIMEFORMAT がどの様に動作するか理解していない…。
    | 後、自分で HISTTIMEFORMAT を実装するとしてもコマンドの時刻をどの様に取得すれば良いのだろうか。
    |
    | HISTTIMEFORMAT を設定している時には history コマンドで表示する時に timestamp が表示されるそうだ。
    | それとは別に HISTTIMEFORMAT が表示される様だ。
    |
    | というか今気づいたが history -s で読み込ませた場合は時刻情報が欠落してしまうのではないか。
    | と思ったがそもそもファイルに出力された時刻情報を bash は読み取るのだろうか?
    | 何だか変な time format で記録した場合には復元できないし、
    | そもそもデフォルトでは出力していないので時刻情報は復元できない。
    |
    | ? ファイルに保存された時刻を読み取るのか?
    |   ファイルに記録されるのは unixtime 値である。
    |   そしてちゃんと読み取る様になっている様だ。
    |
    | ? 時刻が記録されていない場合には時刻はどうなるのか。
    |   history -w で書き出すとどうなるのか。
    |
    |   →何と HISTTIMEFORMAT が設定されているかどうかによって、
    |   bash の複数行履歴の記録の on/off が変化する様である。
    |   うーん。つまり? どうすれば良いのかというと?
    |
    |   例えば、ble.sh が使う場合には常に HISTTIMEFORMAT=%s を指定する?
    |   そうすれば常に複数行履歴が有効になった状態で
    |   履歴に対して特別な処理をせずにファイルを読み取る事ができる。
    |
    |   もう少し振る舞いは異なる様である。
    |
    |   HISTTIMEFORMAT が設定されていてかつ
    |   読み取るファイルの一番最初の行が #%s の形式である場合に、
    |   bash は複数行履歴モードに移行する。
    |   この時 #%s の形式の行が現れるまでを次のコマンドとする。
    |
    |   それ以外の場合にはそれぞれの行を履歴項目として取り扱う。
    |
    |   どちらの振る舞いの場合でも履歴の時刻は読み取られる。
    |   HISTTIMEFORMAT が設定されていてもされていなくても。
    |   直前に時刻が記録されていないコマンドに関しては、
    |   bash を起動した時の時刻が用いられる。
    |
    | ? HISTTIMEFORMAT は空かどうかで判定されるのか、
    |   それとも変数が存在しているかしていないかで判定されるのか?
    |
    |   ファイルの書き出し、ファイルの読み取り(複数行モード)、
    |   history による出力のそれぞれに対する影響を調べる必要がある。
    |
    |   ファイルの読み取りに関しては変数が存在していれば複数行モードに為る (bash 5.0)。
    |   ファイルの書き出しに関しても変数が存在していれば書き出される。
    |   history による出力に関しては空文字列と変数が存在していないという状況は
    |   動作に違いを与えないので調べても仕方がない。
    |
    | ? HISTTIMEFORMAT が設定されていない時でもコマンドの時刻は記録されているか。
    |   確認したがちゃんと記録されている様に見える。
    |   後で HISTTIMEFORMAT を設定しても history コマンドで時刻が表示されるし、
    |   ファイルにもちゃんと時刻が書き出される様になる。
    |
    | ? HISTTIMEFORMAT が設定されていない時でも #%s の行は読み取られるか?
    |   →ちゃんと読み取られている。
    |
    | ? HISTTIMEFORMAT が設定されている時に ble.sh の履歴の初期化が壊れるのではないか。
    |   つまり、全ての履歴が結合した状態で初期化されてしまうのではないだろうか。
    |   これは動作を後で確認する必要がある。
    |
    |   →履歴ファイルの先頭行 #%s が存在しているとこれが発生する。
    |   ble.sh の初期化で読み取る際に使うファイルは ble.sh が生成する物なので、
    |   #%s を全てに出力するか、或いは一個も出力しないかは自分で決められる。
    |
    | ? #%s の形式以外のコメント行はどう取り扱われるのか。
    |
    |   "#%s hello" でも認識された。"#X%s" だと駄目で "#%sX" だと認識される。
    |   " #%s" だと駄目。"# %s" でも駄目。"#1.5..." としたら 1 と読み取られた。
    |   という事は、bash は行が "#数字" で始まっているかどうかを見ている。
    |   もし当てはまれば整数を読み取る。読み取れない部分が残っていても無視する。
    |   "#-1" としても時刻行とは認識されなかった。
    |
    |   "#001" とすると 1 になった。 "#010" にすると 10 になった。8進数表記にはならない。
    |
    |   "#0x10" としてみたら "0x10: 無効なタイムスタンプです" になった。
    |   どうやら文字列として記録している? そして history コマンドで出力しようとすると、
    |   標準出力にこれが出力される。つまり、history の出力に混入する。
    |   HISTTIMEFORMAT= の時にはエラーメッセージは出力されない。
    |   HISTTIMEFORMAT=A の時にはエラーメッセージが出力される。
    |   恐らく HISTTIMEFORMAT が非空の文字列の時にのみ文字列を整数に変換して
    |   strftime を呼び出す等しているのだろう。
    |
    |   更に、"#0x10hello" とするとエラーメッセージも "0x10hello" に変わる。
    |   つまり、16進数表記の場合には文字列全体を時刻として読み取るという事?
    |
    |   どうやら試してみると先頭が 0 の時だけ振る舞いが異なる様である。
    |   なにか特別な解釈なのかもしれないと考えて 00:11:11 や 00-09-20 等として見たが
    |   別に時刻や日付として読み取ってくれそうな気配はない。
    |
    | ? 時刻行の先頭の # は常に # だろうか。或いはユーザの設定で変わりうる?
    |   何だかそういう設定が bash に存在した気がする。と思って調べたがなかった。
    |   恐らく記憶にあったのは readline variable comment-begin '#' であろう。
    |   然しこれは履歴ファイルに使われるものではなくて insert-command rlfunc
    |   で使われる物である。
    |
    | ? history -s で $'#123\necho hello' とすると何が起こるか?
    |   →そのまま "#12345 改行 echo WORLD" 等の様なコマンドが登録された。
    |   つまり「自動的に切り離して時刻として解釈する」というような機能は実装されていない。

    Bash の HISTTIMEFORMAT についてまとめた結果は #M0017 に書いた。

    ここで、何に対応しなければならないか。
    __ble_ext__ に unixtime 値を含める様に拡張するのは簡単である。
    然し、どういう風に振る舞うべきかというのについて考える必要がある。

    * done: 履歴ファイルに時刻を記録するという事。
      それから履歴ファイルに記録された時刻を読み取るという事。

      取り敢えず順番に対応する事にする。
      取り敢えず対応してみたがそもそも振る舞いは bash-3.2 でも同じなのだろうか。
      確認する必要がある→OK bash-3.2 でも HISTTIMEFORMAT= で出力される。
      bash-3.0 でも同様に振る舞う事を確認した。
      bash-3.0 でも HISTTIMEFORMAT='__ble_time_%s__' は有効である。

      試しに多少動かしてみたら動かなかった。修正した。
      取り敢えず書き出しはできている様子である。
      但し、時刻の読み取りはできていないので起動時の時刻になっている。

    * done: 履歴ファイルに書き込まれた時刻を正しく読み取るようにしたい。

      history -r とそれから最初の履歴の初期化について。
      そもそも最初の履歴の初期化はどの様に行っているか。確認する。

      ble/history:bash/load で実行しているのは
      Bash のコマンド履歴を ble.sh の配列に読み出す作業である。
      Bash のコマンド履歴自体には何も手を加えていないので此処では時刻について考えなくて良い。

      ble/history:bash/resolve-multiline に関しては実装の方法について再考しなければならない。
      先ず、古い bash の version でも先頭行が #%s である時に複数行モードが有効になるのかという事。
      →どうもこれは bash-4.4 以降の機能の様である。従って、#%s を利用して複数行読み取りに対応したとしても、
      その実装は bash-4.4 以降でしか使えない。history -s による実装は依然として削除できない。

      1. 取り敢えず現在の方針としては history -s 及び history -r による実装を修正する。
        ファイルに出力してそれを読み取らせる場合には、
        #%s という行を出力する様にすれば良いだけの気がする。
        history -s で複数行を読み込ませている部分に関してはどうしようもないので諦める。

      2. その後で bash-4.4 以降で #%s を用いて複数行を読み取らせる実装を用意する。
        これは後で実装する。

      取り敢えず実装した。意図通りに動くかを試す必要がある。
      取り敢えずは動いている様な気がする。

    x fixed: mlfix.0.part の1行目に空白行が出力されている。
      元のファイルには存在しない筈だし、builtin history もこれを出力しているとは考えにくい。
      これは一体何だろうか→分かった。
      存在していなかった変数 scalar_array[scalar_count] = ... と代入していた。
      以前は scalar_array[scalar_count++] としていたので 0 に評価されてちゃんと 0 番目の要素に代入されていた。
      今回 ++ を独立した行で実行する様に変更したので本来 0 に格納されるべきデータが "" に格納されていた。
      scalar_count を明示的に初期化する様に変更して修正した。

    * done: builtin history -a file で履歴をファイルに書き出している箇所では、
      意図せず #%s が出力されない様に HISTTIMEFORMAT を unset しておく。

      * local && unset でちゃんと出力されなく為るという事を確認する必要がある。
        →確認した所駄目だった。どうも HISTTIMEFORMAT の変数の place holder
        が存在するだけで有効になるという事の様である。

      どうも local で unset しても変数が存在している限りは #%s が出力される様だ。
      仕方がないので後の処理で削除するという事にする。

      これに関しては builtin history -aw 等の出力を ble.sh が利用している箇所は
      一箇所しかなかったので其処を修正するだけで済んだ。

    * done: 残っている __ble_ext__ があればそれについて対応が必要か確認する。
      残っているのは load だけである。そしてこれは
      _ble_history etc にデータをロードするのに使っているだけなので、
      日付の情報は関係ない。此処も修正するかどうか?
      不要といえば不要であるが、複数の箇所で異なる方法を用いているのも変な気がする。
      一方で使いもしない出力をさせるとそれはそれでややこしい。
      取り敢えずここは __ble_ext__ のまま残して置く事にする。

    * done: mlfix で bash-4.4 以降では #%s を用いて複数行を読み取らせる様にする。
      ファイルの最初の行に '#%s' を指定すれば複数行として読み取ってくれる筈である。

      | history -s の代わりに HISTTIMEFORMAT=%s history -r file として、
      | 複数行モードで履歴を読み取らせるという手がある気がする。
      | その場合には自分で $'' を decode してファイルに書き込む必要がある。
      |
      | この振る舞いは bash のどの version でも同じだろうか。
      | またどの shopt の集合でも同じだろうか。
      | これについては確認する必要がある。
      | →bash-4.4 以降で複数行として読み取る様になった様である。
      |
      | 何れにしても awk で #%s を出力する様に加工すれば良いという事の気がする。

      その他の箇所で複数行コマンドを初期化するのに
      history -s を使っている箇所はあっただろうか。ない気がする。

      うーん。これは実装してしまう事にする。

      と思ったが eval -- $'...' の形式を復号しなければならない。
      どうやって復号するのが良いだろうか。
      実際にこの形に加工している部分を探す。awk で加工している。
      以下のコードである。

        gsub(/['$apos'\\]/, "\\\\&", text);
        gsub(/\n/, "\\n", text);
        gsub(/\t/, "\\t", text);
        text = "eval -- $'$apos'" text "'$apos'"

      基本的にはこの操作の逆手順を実行すれば良い筈。だが。
      ユーザがこれと同様のコマンドを実行していて、
      其処に \e 等の別の種類のコマンドを混入させていたらどうなるのか。
      すると復号しきれない文字が残ってしまう。

      或いは全種類のエスケープシーケンスに対応する?
      と思ったが上記のエスケープで生成できない様な
      コマンド文字列の場合には復号しない様に修正すれば良いのである。
      そしてその検出は正規表現で十分にできる。

      実装した。ちゃんと動いている気がする。

    * ok: 特定の条件で history のHISTTIMESTAMPの出力は ?? になってしまった筈。
      この場合にどの様に振る舞うかはちゃんと考えておく必要がある。

      bash 4.0 以降では履歴の初期化は idle で実行しているので問題はない筈。
      つまり、もし問題が起こるとしたら bash-3.2 である。
      →うーん。複数行コマンドの日時が起動時に置き換わってしまっているという事以外は大丈夫。
      prompt attach を採用しているからだろうか→特に問題は起こっていない。

      元々 \?\? は何処で導入されたのか。調べると ble-0.1 の時点で __ble_ext__ がある。blame した。
      4e97b41a (Koichi Murase 2015-02-19 00:41:20 +0900 3327)     /^ *[0-9]+\*? +(__ble_ext__|\?\?)/{
      e7606868 (Koichi Murase 2015-02-12 02:55:39 +0900 2131)       /^ *[0-9]+\*? +(__ble_ext__|\?\?)/{

      | commit e7606868bbbb04ed7087a180317bd56446460304
      | Author: Koichi Murase <myoga.murase@gmail.com>
      | Date:   Thu Feb 12 02:55:39 2015 +0900
      |
      |     - ble-decode.sh, ble-edit.sh: ble の detach 機能の実装
      |     - ble-decode.sh: exit 後に stty が壊れているのを修正
      |     - ble-color.sh: 色の付け方を修正・追加

      うーん。大した記録は残っていない。
      一応 #D0129 が対応する項目の様だが単に rcfile 内部での履歴の読み取りに対応したというだけ。
      或いはサブシェルで実行していたりすると発生するのだろうか。
      そもそも bash-3.2 で ble-attach した時に mlfix は呼び出されているのだろうか。
      見ると複数行の履歴項目が復元されているのでちゃんと処理はされている筈。
      と思ったが、よく考えたら初めて必要になった時まで遅延させているのだった。

    * fixed: bash-3.2 で history_lazyload= にして初期化時に読み込ませると、
      '#%s' の行もコマンドの行として読み込まれてしまっている。
      何が起こっているのだろうか。つまり、builtin history が '#%s' もコマンドとして出力している?

      % これはその後の bash の初期化で修正される様だ。
      →修正されるというよりは、サブシェルで builtin history -n で履歴を読み込んだ結果であり、
      本体のシェルには影響を与えない様になっているという事の様だ。
      一方で直接に bashrc に history -n を書き込んで実行してみると、
      確かに履歴に #%s の行が混入して面倒な事になってしまっている。

      と思ったら ble/history:bash/load/.generate-source のコメントに rcfile として
      実行すると HISTTIMEFORMAT を指定しても ?? になるという旨が書かれている。
      然し、現在ではこれは再現していない。うーん。
      親シェルで実行していた時にだけ発生していたのだろうか。
      然し、実際に history -n history を直接実行した場合でも問題は発生していなかった。謎。

    * ok: bash-3.2 で mlfix が実行されているのは確かの様に思われるが、
      一体何処で実行されているのだろうか。そもそも本当に実行されているのか。
      実際にソースコードを観察するとどこでも呼び出していない気がする。
      然し、実際に複数行 escape が外されている。
      Bash が勝手にコマンドの内容を書き換えるのは不可能である。
      或いは load で書き換えられているのか、と思ったが、load は
      _ble_history シェル変数にロードするだけで Bash のコマンド履歴を編集したりはしない。

      結局、ble-stackdump して分かった事は、
      コマンドを実行するタイミングで history -p が呼び出されて、
      その結果として resolve-multiline が呼び出されるという事らしい。
      というか実際に ble/builtin/history/option:p のコメントにその様に書かれていた。

      @ out/ble.sh:4 (ble/history:bash/resolve-multiline/.worker)
      @ out/ble.sh:13084 (ble/history:bash/resolve-multiline.impl)
      @ out/ble.sh:660 (ble/history:bash/resolve-multiline)
      @ out/ble.sh:7 (ble/builtin/history/option:p)
      @ out/ble.sh:1 (ble/edit/hist_expanded/.core)
      @ out/ble.sh:1 (ble-edit/hist_expanded/.expand)
      @ out/ble.sh:-2169 (ble/util/assign)
      @ out/ble.sh:5 (ble-edit/hist_expanded.update)
      @ out/ble.sh:3433 (ble/widget/accept-line)
      @ /home/murase/.mwg/src/ble.sh/out/keymap/vi.sh:7352 (ble/widget/vi_imap/accept-single-line-or)
      @ out/ble.sh:5089 (ble-decode/widget/.call-keyseq)
      @ out/ble.sh:48 (ble-decode-key)
      @ out/ble.sh:51 (ble-decode-char/.send-modified-key)
      @ out/ble.sh:156 (ble-decode-char)
      @ out/ble.sh:11 (ble/encoding:UTF-8/decode)
      @ out/ble.sh:4927 (ble-decode/.hook)

      という事はつまり、bashrc の中で history -p を呼び出すと変な事になる?
      一応履歴が空の時には mlfix を呼び出さない様に修正した。

      確かにこの様に history -p に伴って遅延して mlfix を実行する様にすれば、
      HISTTIMEFORMAT が変な値になる事もないし、
      また時刻が history -n によって読み込んだ変な値になっているという事もない。
      特に問題はないだろうという気がする。

2020-05-06

  * bash-4.4 trap return の work around はあるか [#D1350]

    現在の Bash の振る舞いでは関数内でも無引数 return なら
    外側の終了ステータスになってしまうが、もしこれは解釈Aに修正してもらうと、
    ユーザートラップが無引数 return を実行したのか有引数 return を実行したのかを
    正しく判定しなければならなく為る。

    a 実は return() { builtin return $?; } とすれば問題を解決できる?
      と一瞬思ったがこれだと return できなくなるので駄目である。

      a 或いは alias return='ble/builtin/return; return' とでもして
        何とかなる? と思ったが、引数は結局取れない。

      b RETURN トラップで何とか検出できないか。
        つまり function return を実行したらなにか変数に記録して、
        次の RETURN で実際に RETURN を実行させる事にする。

        そして検出したらその場で RETURN する。
        と思ったが trap を実行している途中には RETURN トラップは無効なのでは。
        trap の中で trap を呼び出せるのかについて確認する必要がある。

        →確認した所、RETURN trap の中では RETURN は発火しない。
        DEBUG trap の中では RETURN が発火する。
        つまり RETURN 以外の trap handler の中では RETURN が発火するという事。

    % 例えば RETURN と return() { _return_status=${1:-$?}; } を組み合わせて何とかする。
    % もし呼び出されたフレームが trap のフレームであれば
    %
    % return() {
    %   local status=$?
    %   _return_arg=$1
    %   if ((_trap_level==${#FUNCNAME[@]}+1)); then
    %     _return_status=${1:-$status}
    %   else
    %     _return_status=${1:-$_trap_preceding_status}
    %   fi
    % }
    % builtin trap '[[ $_return_status ]] || builtin return' RETURN
    %
    % ? trap の中で RETURN trap は有効か?
    %
    % うーん。色々面倒である。取り敢えず ble/builtin/trap で
    % return を実行できる様に修正してから調整するべきである。

    →そもそもの問題として RETURN は関数の内部で実行される様なので、
    return() { ... } で return の機能を再現する事はできない。

    或いは DEBUG/RETURN の両方を trap してどちらか最初に呼び出された方を用いて
    "return xxx" を実行するという手がある。何れにしても込み入った方法になる。

    これは困難である。取り敢えず保留という事にする。

  * trap: bash handler の継承が一体どうなっているのかは謎 [#D1349]
    bash の場合サブシェルの中で見ると handler が継承されていたりいなかったりするのでは。
    どういう規則になっているのか。どのハンドラーが継承されてどのハンドラーが継承されないのか。
    RETURN DEBUG と -o functrace, declare -tf との関係。
    ERR と -o errtrace の関係。RETURN, DEBUG では今から実行しようとしているコマンドを知る事ができるのか。
    ソースコードと行番号は知ることができそうな気がする。実行が eval string で定義された関数の場合には、
    行番号を知ったとしてもよく分からないのでは。そもそも BASH_SOURCE は何になるのか。

    →取り敢えず #M0016 にまとめた。

  * trap: 現在の実装だとユーザが INT に何か設定していても無視されてしまうのでは [#D1348]
    というより何が起こるのか不明である。
    然し、C-c を禁止するというのも変な気がする。
    後で可能な設計について考える。

    →これは取り敢えず新しい枠組みを使ってユーザの設定した物を実行し、
    ユーザが return/break/continue を実行した場合にはそれを実行する様にした。
    然し、ble.sh 自体が設定している DEBUG trap による中止もそのままである。

  * trap: ユーザ trap handler 内部で return を実行した時の振る舞い [#D1347]
    ユーザが DEBUG トラップに return を設定した場合には何が起こるのか
    というより全般にユーザが return を設定した時にその場で関数を抜ける、
    という振る舞いが再現できていない。

    全ての hook は 'hook; if [[ $_ble_trap_return ]]; then return; fi'
    の様な形にするか或いは 'hook; builtin eval -- "$_ble_util_trap_hook"'
    の様な形にする必要があるのである。

    因みにユーザが return で抜けたかどうかを判定するのは簡単である。
    というのも eval ''; _ble_builtin_trap_done=$? 的な感じにすれば良い為。
    もし _ble_builtin_trap_done が設定されていなければ return で抜けたという事。

    (取り敢えずは Bash 4.4 無引数 return の問題は後回しにする。)

    * 現状の設計について確認する。

      _ble_builtin_trap_reserved に登録されているシグナルは特別な処理を実行する。
      それ以外のシグナルについては Bash の builtin trap をそのまま使う。
      reserved への登録は必ず ble/builtin/trap/reserve で行う。
      EXIT, INT, WINCH, DEBUG, USR1 を reserve している。

      その他のシグナルについては大丈夫だが
      これらのシグナルについてはちゃんと処理する必要がある。

      問題は reserve したシグナルに対する本当の trap を何処で設置しているのかという事。

    取り敢えず先に DEBUG から対応しようと考えたが微妙である。
    現在の実装では DEBUG は INT を受信した時にだけ ble.sh で設定する事になっている。
    そしてユーザーが設定したとしても取り消される仕組みになっている。

    DEBUG は特に全てのコマンドの前で設定されるので不要であれば外しておきたい。
    ユーザの設定した trap か ble.sh の設定した trap のどちらかがある時に有効になる様に実装したい。
    取り敢えず USR2 辺りで試験的に実装してみて枠組みを確定させるのが良い気がする。
    →取り敢えず USR2 で実験してみた結果は成功である。
      trap handler 内部での return も再現できている。
      勿論 FUNCNAME 等は異なる値になっているがそれは仕方ない。
      その他に振る舞いを左右する別の物があったりするだろうか。

      実は、continue や break 等も本来は正しく処理したいのである。

    | * DEBUG trap の性質について調べる事にする。
    |
    |   * 取り敢えず return, continue, break は DEBUG trap で検出できる。
    |     →実は bash-3.0 では BASH_COMMAND には trap handler
    |     の文字列自体が入ってしまっているので、
    |     この方法では return/continue/break は検出できない。
    |
    |     continue, break に引数が指定された時にどのように検出するかに関係する。
    |
    |   ? declare -ft を設定した関数では DEBUG が継承されるというが、
    |     間に普通の関数が挟まっていても活性化するのか?
    |     →駄目。活性化しない。やはり飽くまでも "継承" という事の様である。
    |     つまり、signal handler を呼び出す際に改めて trap DEBUG し直す必要がある。
    |
    |   ? debug trap が有効でない関数の中で trap を呼び出して出力した時に、
    |     DEBUG trap は列挙されないのか、それとも列挙されるけれども不活性という事なのか。
    |     →列挙されない。
    |
    |   ? 関数内部で trap DEBUG した時に、外側の trap が破壊されたりしないか。
    |     →trap DEBUG で削除した場合には外側の trap DEBUG に影響はない。
    |     →trap cmd DEBUG で登録した場合には、bash-4.3 以下では外側の trap DEBUG に影響はない。
    |     然し、bash-4.4 以降では外側の trap DEBUG も書き換わってしまう。
    |
    |     ユーザの設定した trap DEBUG の有効・無効を管理するのは実は大変である。
    |     現在の関数の位置と一緒に覚えておく必要がある。
    |     関数の終端で解除するという事をしなければならない。
    |     その為には RETURN 等にも仕掛けなければならないだろうか。
    |
    |   ? 関数内部で trap DEBUG した時に、
    |     全く同じ trap DEBUG の内容でもちゃんと有効になるだろうか。
    |
    |     →全く同じ内容で定義した時にそれが有効になったかどうかをどうやって判定するのか。
    |     もし判定する事ができないのだとすればそれは実質動作に変化がないという事なので、
    |     有効になっても有効にならなくても何の問題もない。
    |
    |     或いは、関数内部で無効にになっている状態で改めて trap DEBUG を設定した時に
    |     有効になるのかどうかという疑問だとすれば、それは当然有効になる筈である。
    |     念の為に確かめる事にする→ちゃんと無効から有効に変化するという事を確認した。
    |
    |   うーん。色々考えるとやはり別の trap を使うというのは
    |   その trap の元々の機能も保持しなければならないので大変である。
    |   更に RETURN や DEBUG 自体の return/continue/break はどうやって検出するのか等、
    |   色々複雑になってしまう。
    |
    |   ? DEBUG trap の中で DEBUG trap は有効か?
    |     実際に試してみると trap で設定する事はできるが発火しない。
    |     BASH_COMMAND は書き換わらない。
    |
    |     つまり DEBUG trap 自体を再現する為に DEBUG は使えないという事。
    |
    | * RETURN trap の性質について調べる。
    |
    |   ? declare -ft, set -T の効果について。
    |     これは DEBUG と同様に継承が決まる。
    |
    |   ? 関数を抜けるコマンドが実行された後に呼び出される。
    |     BASH_COMMAND は一番最後に実行したコマンドが入っている。
    |     return を使った時には return コマンドである。
    |
    |   ? 関数内で発火するのか、それとも関数外で発火するのか。
    |     関数内で発火する気がする→実際に試してみたらそうだった。
    |     内部で更に return を実行すると無限ループになる。
    |     勿論、条件付きで return すれば無限ループにはならない。
    |     その場合には終了ステータスを書き換える事が可能になる。
    |
    |   さて、この RETURN トラップの性質を考えると、
    |   continue/break を関数で上書きするという作戦は使えない事になる。

    a もしくは DEBUG trap を使えば面倒な事をしなくても
      実際に実行したコマンド (continue/break 等) を検出できるだろうか。
      実はその方が良いという気がする。

    うーん。結構面倒な気がするので DEBUG trap による continue/break の
    引数の検出は実装しなくても良いという気がする。これは制限である。
    或いは完全に異なる方法で検出する方法はあるだろうか。

    b 行番号とファイル名からソースコードを割り出してそこから読み取る?
      然し、continue break の引数に指定されている単語が複雑な物の場合、
      特に副作用がある物やコマンド置換等の場合にはそれを実行する訳には行かない。

    c やはり RETURN trap を犠牲にして continue, break を emulate する方法を考える?
      因みに builtin continue, builtin break をユーザが使っている場合には不可能。

    ? continue/break で実際に抜けられるのよりも大きな値を指定した時にどうなるか。
      →全てのループを抜ける。失敗するという事はない。
      呼び出し元関数のループには影響を与えない。

    色々の事を考えると continue/break の引数に対応するのは複雑になりすぎる。
    そもそも trap を ble.sh の枠組みの上で完全に再現するのは難しそうである。

    取り敢えずの実装 (break/continue の引数には対応しない) については
    以下のコマンドを用いてちゃんと動くかを確認した。

    $ ble/builtin/trap/.set-signal-handler USR2
    $ trap 'echo world; return 123' USR2
    $ f1() { local i; echo BEGIN; while :; do sleep 0.01; done; echo END; }
    $ (sleep 1; kill -USR2 $$) & { f1; echo $?; }
    $ trap 'echo world; break' USR2
    $ (sleep 1; kill -USR2 $$) & { f1; echo $?; }

2020-05-02

  * .s AAA と入力すると表示が乱れる [#D1346]

    | 更にシグナルハンドラ関連の配列添字エラーが発生する。
    | これは一体どういう事だろうか。eba9b92 で再現している。
    | bash --rcfile out/ble.sh では発生しない。
    |
    | →どうやらこれは PS1= を internal_suppress_bash_output=1
    | の時に実行しない様に変更した事と関係している。この PS1 の出力は
    | bash によって出力されている物だろうか。
    | suppress してリダイレクトしているのに表示されてしまっている理由は何だろう。
    | stdout.on, stdout.off がちゃんと動いていないという事なのだろうか。
    |
    | PS1 と _ble_edit_PS1 に別の値を設定して確かめた所、
    | 確かに bash が勝手にプロンプトを出力しているのだという事が判明した。
    | 特に文字が先頭に移動するという事から、bash はプロンプトを出力した後に
    | \r 等を出力しているという事だろうか。或いは、ble.sh の枠組みに於いて、
    | \r を出力するタイミングと文字を出力するタイミングの間に
    | bash が介入してしまうという事だろうか。
    |
    | 或いは、bash-5.0 では実は suppress の効果がないという可能性。
    | 確かめてみた所 bash-4.1 以降で問題が発生する様子である。
    | どのタイミングで bash のプロンプトが表示されるのか確かめる。
    | うーん。どうも .s が含まれる場合に処理がクラッシュして off が呼び出されていない?
    | →その様だ。stdout.off が消滅している。何故? bashrc の設定と何か関係ある?
    | failglob で終了してしまっている可能性が濃厚である。
    | と思って shopt -u failglob で試してみたが問題は解決しない。
    |
    | 調べると idle.do の中で起こっている。更に auto-complete.idle の中で起こっている。
    | どんどん掘っていくと ble/complete/source:argument の中で発生している。
    |
    | →結局これは bash-completion の __load_completion の実装で
    | xspecs[$cmd] の $cmd に .s 等を渡すとエラーになってその場で実行が終わる為の様だ。
    | eval で囲んでみたがそれでも実行が停止してしまう様だ。
    |
    | もし仮にクラッシュを防げたとしても根本的な問題として
    | xspecs の定義が消滅してしまうという問題は関数内で source している限り残る。
    | 然し、これはどうしようもない。うーん。或いは xspecs が連想配列でない場合には
    | __load_completion を呼び出さないという事にする?
    |
    | 然し問題はそもそも bash-completion の呼び出し方にある。
    | その時点で何が起こっても仕方がないと諦めるしかないのではないか。

    * まとめるとこれは bash_completion が内部で declare -A _xspecs で連想配列を宣言しているが
      関数内で bash_completion を source している為にこの宣言が環境に残らない。
      連想配列以外について _xspecs[.s] の様な参照を行うとエラーになってその場で色々の実行が終了してしまう。
      internal_suppress_bash_output の設定の処理についても行われずに終了してしまう。

    * ok: 然し、直接 source する様にしても問題が解決しない
      何故だろうと思っていたら、実は . と source で振る舞いが違う?
      と思ったらこれは function#advice で remove しても関数として残留する事が原因だった。

      つまり、関数内で実行しているので source 内の declare の類は
      その関数のスコープの中に作成されてしまう。
      同様の問題が function#advice remove unset でも起こるのではないか。
      常に dynamic unset になってしまう。
      従って、advice する物がなくなったら元に戻すというのが正しい筈。

      →これはその様に修正した。OK

    bash-completion については自分で直接 source してもらうしか解決方法はない。
    従ってこれについては諦める事にする。

    或いは bind -x の exec 経由で bash-completion を
    実行するという手がない訳ではない。
    然し、何れにしてもその他の枠組みを用いた場合でも autoload すると、
    bash-completion は正しく初期化する事ができないという事になる。
    まあ取り敢えずは気にしない事にする。

2020-04-27

  * SIGWINCH でちゃんとプロンプトの計算が更新されていない [#D1345]

    要約: builtin trap WINCH 後に readline でコマンドを実行しないと、
      readline が COLUMNS/LINES の更新に使っている handler が設置されない。

    というより、空コマンドで RET を押しても更新されない。
    そもそもプロンプトのキャッシュで COLUMNS:LINES を参照していなかったのか。
    →うーん。確認すると COLUMNS が入っている。

    という事はつまりそもそも ble-edit/prompt/update まで到達していない?
    然し、それも変な気がする。何しろ RET を押しても更新されないのだから。
    →実は更にその次の部分でのキャッシュにより更新が抑えられている?

    うーん。trace_hash にもちゃんと COLUMNS が記録されている。
    というか rps1 ですら再計算されていない。という事は、やはり
    ble-edit/prompt/update にまで到達していないと見るべきか。

    不思議だ。手許で新しく実行してみると症状が再現しない。
    然し、ble-reload した場合には再現している。
    何らかの条件で発生したりしなかったりするのだろうか。
    振る舞いを調べるとやはりそもそも SIGWINCH を受信していない?
    と思ったがそれも変である。そうだとしたら再描画されていない筈。

    取り敢えず reload では再現するので其処を手がかりに調べていく事にする。
    →分かった。新しいセッションでも reload すると再現する様になる。
    然し、cygwin では常に再現する。
    →分かった。COLUMNS, LINES が更新されていない様だ。
      それから SIGWINCH もその場では実行されなくなっている。
      ユーザが何かを入力したタイミングで初めて SIGWINCH が発火する。

    問題は何故最初は動いていたのに reload すると動かなくなるのかという事。
    何らかの操作が関係しているのだろうか。或いは、二回以上 SIGWINCH すると
    振る舞いが変わってしまうという事なのだろうか。

    更に stty の状態やリダイレクトの構造も関係してくるのかもしれない。
    確認したがリダイレクトの構造については変化はない。
    stty についても stty 自体が悪さをしているという事はないだろう。
    何かあるとしても特定の stty の時に何かをすると再現するという事だろう。

    →再現した。或いは builtin trap を実行する環境に問題があるのかもしれない。
      ble-detach して builtin trap して ble-attach しても問題は発生しない。
      問題が発生している時に ble-detach; ble-attach すると直る。

    今までの振る舞いを整理すると。

    * ble-reload すると問題が発生する様になる。
    * builtin trap -- ...　WINCH するだけで発生する。
    * ble-attach; ble-detach すると直る。
    ? 他の bash version は?
      bash-4.1 以下では常に問題が発生している。
      bash-4.2 以降は bash-5.0 と同じ振る舞いである。
      つまり、この振る舞いは特に最近導入された物ではないし、
      寧ろ古い bash の方が振る舞いが酷いという事である。
    ? WINCH 以外の builtin trap でも問題は発生するか?
      →しない。WINCH を設定したときにだけ振る舞いが変化する。

    問題は何処に在るのか。そしてどの様に避ける事ができるのか。
    ble-attach; ble-detach で直るのは何故なのか。
    一旦 readline に戻すと良くなるという事なのか、
    或いは、何らかの設定 (stty) 等が変更されてしまうという事なのか。
    然し、stty の問題であれば何か一つでもコマンドを実行すれば
    変な振る舞いにはならずに元と同じ様になる筈である。

    ? bleopt_internal_suppress_bash_output= bash でも再現するのか。
      →bleopt_internal_suppress_bash_output= では発生しない。
      つまり勝手に標準入出力を繋ぎ変えているつけである。
      これは単純なスクリプトで再現するのは難しそうだし、
      再現できたとしてもそんな変な事をしているのが悪いという事になる。

      然し、それでは何故普通に attach した時には問題がなくて、
      biltin trap -- し直した時にだけ問題が発生するのだろうか。

    ? ble-detach; ble-attach をその場で実行したら直るだろうか。
      (振る舞いを見ると治らない様な気もする。
      一回通常の状態で bind -x から抜ける必要がある気がする。)

      ble-detach/impl と ble-attach を呼び出せば良いだろうか。
      →これだと直らない。

      或いは、edit.sh の ble/widget/.change-editing-mode では
      次の操作を実行している。
      ble/decode/reset-default-keymap
      ble/decode/detach
      ble/decode/attach
      →これでも直らない (reset-default-keymap は試していないが関係ないだろう)。

    % と思ったら builtin trap しても再現しなくなってしまった。
    % と思ったら分かった。 WINCH ではなくて USR2 に対して実行していた。

    ? 子bashで問題が発生している状態で終了したら、
      親bashでも問題が発生したままだろうか。
      →親bashでは問題は発生していない。
      つまり、これは tty の状態というよりは
      やはり bash のプロセスの中で起こっている問題である。
      bash のプロセスの側で修正されるべき物である。

    ? internal_suppress_bash_outputを一瞬だけ有効にするという手もなくはない?

      追記: 原因は別の所にあったのでこの方法では何も解決しない。

      % 本当に可能だろうか。そしてそれで本当に解決するのか。
      %
      % builtin trap で上書きが実行される瞬間、または、
      % ble-reload が行われた後に対策を実行する必要がある。
      % そもそも ble-reload はどのタイミングで再ロードを実施しているのか。
      % 現在の実装だと prompt で再ロードを実行している。
      %
      % * 棄却: Bash の PROMPT_COMMAND で ble-attach すれば問題は解決するのでは?
      %   この prompt command の表示は何処で実行されるのか。
      %   Bash による物なのか或いは ble.sh 自身による物なのか。
      %   →確認した所、ble.sh 自身の eval-prompt の中から実行されている。
      %   --attach=prompt と同様の状態に持っていく事はできないのだろうか。
      %
      %   ここでの問題は PROMPT_COMMAND が実際に呼び出されるのかという事。
      %   →試してみたが bind -x の関数の呼び出しの直後には呼び出されない。
      %   WINCH の後でも呼び出されない。
      %   PROMPT_COMMAND から ble-attach するのはできない。
      %
      % ここでの問題は其処ではない。suppress_bash_output を無効にするという事。
      % 一時的に無効にすることは果たして可能だろうか。
      % 確認してみた所、internal_suppress_bash_output は元々有効なのを
      % 一時的に無効にするのは可能である様に見える。有効な時にだけ行う初期化がある。
      % 無効な時には何も初期化はしない。
      %
      % と思ったが無効な時の stdout.on stdout.off を上書きしていた。
      % stdout.on と stdout.off に internal_suppress_bash_output= の時に
      % 処理を動的に切り替える様にすれば良い様な気がする。
      %
      % 然し一時的に切り替えたとして誰が復元するのか。
      % うーん。それよりは internal_suppress_bash_output=tmpoff 等の様に
      % 特別な値を設定して、その特別な値の時にだけ対策を実行する?
      % そして一回特別な処理をしたら後はまた普通の値 (1) に戻す。
      %
      % * PS1 の保存・復元方法の変更
      %
      %   | ここで問題になる可能性があるのは PS1= にする対処を
      %   | bash_completion の為に諦めた事である。
      %   | PS1= に有限の文字列が含まれている為、初期化スクリプトが勘違いする。
      %   | 実際の所 bash_completion は二度以上初期化しないのでここでは関係ない。
      %   | 然し、その他のスクリプトで二度以上実行する必要のあるものがあるかもしれない。
      %   | そして、最初のプロンプトを表示してユーザ待ち状態になっている時に
      %   | ble-import を実行する可能性は高い。
      %   |
      %   | というより、本当に PS1= を諦める必要があったのだろうか、という疑問が残る。
      %   | PS1= のタイミングを本当に一番最後にしていれば問題は起こらなかったのではないか。
      %   | →調べると PS1 は殆ど常に待避した状態になっていて
      %   | コマンドを実行する直前と直後にだけ復元するという事になっている。
      %   | 実は単に stdout.{on,off} のタイミングで保存・復元すれば良いのでは。
      %
      %   もし一時的に internal_suppress_bash_output を無効化するのであれば、
      %   同時に PS1 の待避の方法も変更する必要がある。現在はユーザコマンドを実行する度に
      %   PS1 を復元するという方策を取っているが、実は stdout.{on,off} を呼び出す度に
      %   保存・復元を実行するという形にすれば良い。その場合には _ble_edit_PS1 の代わりに
      %   PS1 を直接編集する様に変更する必要がある。もしくは PS1 を _ble_edit_PS1 にコピーする。
      %   read 等を実行する際に一時的に _ble_edit_PS1 を変更しているが、
      %   これはどうなのだろう。。と思ったが、これは save/restore-vars で復元されるのだった。
      %   なので実は PS1 を直接上書きする方法でも良い気がして来た。

    原因について調べればもっと良い回避方法が見つかる可能性もある。

    * そもそも RET でコマンドを実行すると一時的に直るのは何故だろうか。

      要約: stty を実行するとその場で COLUMNS/LINES が更新される。
        WINCH によって更新される訳ではないし、WINCH handler が修正される訳でもない。

      | 特に echo を実行しただけで直るというのは不思議である。
      | 或いは、もっと早くに COLUMNS が修正されているが、
      | 単にプロンプトが更新されていないだけ?
      |
      | →確認すると確かに echo を実行した直後に初めて COLUMNS が更新されている。
      | これが意味する所は何だろうか。epilogue/prologue で何かが起こっている?
      |
      | →分かった。term/enter,leave を省略すると
      | コマンドを実行しても COLUMNS が更新されない。
      | これは stty を実行すると直るという事だろうか。
      | →その様だ。特に stty sane でも良いので実行すると COLUMNS が更新される。
      |
      | 或いは bash で何か操作したら直るかもしれない。
      | shopt -u checkwinsize; shopt -s checkwinsize を stdout.on に入れてみたが
      | 特に何も変化はない。COLUMNS も更新されない。

    * bind -x で再現する事は可能だろうか。
      例えば。trap WINSIZE を実行してから一度でも
      stdout.on で制御を bash に戻せば状態は元に戻るのである。

      逆に言えば、生の bash でこの状態を再現する為には
      全ての bind -x に bind しなければならない?
      と思ったがユーザが特定のキーしか押さないという事にすれば十分再現できる?

      取り敢えず C-t で bash suppress に入って C-y で抜ける様な bashrc を作った。
      更にここで builtin trap -- WINCH を実行するのである。
      取り敢えず手許のスクリプトでは問題を再現する事ができた。

      不思議なのはこのスクリプトだと最初から winch を trap していたとしても、
      suppress している時に WINCH が呼び出されず、COLUMNS も更新されない事。
      ble.sh の場合には bash-4.2 以降では既定では suppress していても
      ちゃんと WINCH が更新されているという事なのである。

      ここでの疑問は何故 "bind -x" 外で trap を設定した時に
      ble.sh でちゃんと動いている様に見えるのかという事である。

    [問題]

    * bash-4.2 以降では reload すると問題が発生する。
    * bash-4.1 では常に問題が発生している。
    * Cygwin でも常に問題が発生している。

    bash-4.2 以降の初期状態の様に振る舞わせる事が可能であればそれで良いが、
    現状の様子を見ると bash-4.1, Cygwin では問題が発生している。
    従って可能であれば bash-4.1, Cygwin でも常に動くような対策が欲しい。

    a 一つの可能性は毎 bind -x で stty sane を実行するという事。これは
      重い。或いは空コマンドを実行する場合 (newline) でも stty sane を
      実行するという事。これもある程度の重さが残ってしまう気がする。

      stty sane 以外の方法で COLUMNS を更新させる事は可能だろうか。

    b 例えば winsize の通知を要求する terminal sequence はあるのだろう
      か。端末エミュレータ側では termios で端末サイズなど設定してしま
      うので、端末自体がこれに対応しているという話は効いたことがない。
      端末ハンドラ経由で要求するしかないのだろうか。簡単な terminal
      sequence でサイズを要求できないのか。

    c 或いは現在の端末のサイズを変更するシーケンスを送れば強制的に
      WINCH をその場で発生させる事ができるだろうか。然し、その為には端
      末のサイズを知っていなければならない。或いは端末のサイズを実質的
      に変更しないシーケンスを送る事ができたとしても、端末側がサイズが
      変更なかった場合に termios に設定しないのだとしたら、或いは端末
      ハンドラが変更チェックを行っていたとしたらこれは効果がない。

    bash のソースを確認すると値の設定を行っているのは恐らく
    sh_set_lines_and_columns である。そして呼び出し元は lib/sh/winsize と
    readline である。lib/sh/winsize は get_new_window_size を提供している。
    get_new_window_size は第一引数に from_sig というのがあるが、
    これは使われていないし、また、呼び出し元でも 0 しか指定していない。
    readline 側での呼び出し元は _rl_get_screen_size である。
    また readline 内部にも sh_set_lines_and_columns の実装がある。
    lib/readline/shell.c である。でもこれは readline を standalone で
    コンパイルした時に使われる物ではないかとの疑惑がある。

    [未解決の謎]

    * 何故 bash-4.2 以降 / linux では WINCH を検出できているのか。
      というかそのまま bash を抜けると親 bash はちゃんと動くので、
      端末ハンドラの設定ではない。やはり bash 自体が何だか変な事になっている。

    Bash の実装について確認する

    | bash の振る舞いについて調べている。どうも biltin trap で WINCH に登録すると
    | bash は別のシグナルハンドラを signal で登録し直す様である。
    | builtin trap -- WINCH していると sig.c sigwinch_sighandler が呼び出されない。
    | 何も実行していないと呼び出される。他に検索してみたが直接に trap handler を
    | 設定している箇所は見つからなかった。だとすると普通の siginal の一つとして
    | signal handler が登録されているという事になる。本当だろうか??
    | signal 関数の呼び出しを検索してみると readline の他には sig.c しか存在しない。
    | 結局 set_signal_handler 関数で全て設定しているという事だろうか。
    |
    | 実装を見るとどうも sigaction という sycall を使っている。
    | 直接に signal を使っているという訳ではない様である。
    | 一応、実際にこの関数が本当に呼び出されているか確認する。
    | →何と物凄い勢いで呼び出されている。SIGWINCH だけを拾う。
    | →調べてみると fork する度に呼び出されている様である。
    |   サブシェルの起動時にも呼び出されている。
    |   これだと余り参考にならない気がする。
    |
    | うーん。0x480040 というアドレスの関数を設定している。
    | それ以外の関数は設定していない様だ。
    | そしてこの 0x480040 とは何だろう。
    | どうやら sigwinch_sighandler の様である。
    | 然しこれは呼び出されていなかった筈である。
    |
    | どうやら trap_handler が登録されてはいるけれども、
    | サブシェルを起動する時にはそれをキャンセルする為に
    | sigwinch_sighandler が登録されているということの様である。
    |
    | | なのでここで観察するべきは trap_handler の方である気がする。
    | | 調べてみると変な状態になった後でもちゃんと trap_handler は起動されている。
    | | という事はその後の処理の流れが変だという事になる。
    | | trap_handler の中では実はシグナルハンドラは処理しない。
    | | 単に pending_traps 配列に情報を記録するだけである。
    | | interrupt_immediately は試した範囲では 0 である。
    | | すると run_pending_traps の中で何か変な事が起こっている?
    | |
    | | run_pending_traps が呼ばれるタイミングを調べようとしたが呼び出されない。。。
    | | 一度 run_pending_traps が呼び出されれば大量に run_pending_traps が呼び出される。
    | | 然し、trap -- を実行した後だと何も実行されない。不思議である。
    | | run_pending_traps の呼び出し元は沢山ある。builtin trap を実行すると
    | | 何処かの呼び出し元で何かが変化するという事。
    | |
    | | run_pending_trapsの振る舞いを調べる必要がある。
    | | 正常に動作している時に run_pending_traps が一回だけ処理される。
    | | 呼び出し元は check_signals_and_traps で更に
    | | 呼び出し元は bash_event_hook である。
    | | この関数は実は rl_signal_event_hook に対して関数ポインタとして設定される。
    | | 有効・無効が bashline_{set,reset}_event_hook で切り替えられる様になっている。
    | |
    | | 振る舞いを見ると以下の様になっている。
    | |
    | |   - trap_handler
    | |     - bashline_set_event_hook
    | |     - (interrupt が設定されていないので
    | |       その場では run_pending_traps は実行しない)
    | |   - _rl_signal_handler
    | |     - bashline_reset_event_hook
    | |     - bash_event_hook
    | |       - check_signals_and_traps
    | |         - run_pending_traps
    | |
    | | bashline_{set,reset}_event_hook は毎回設定・解除する様である。
    | | 一方で builtin trap した場合にも bashline_set_event_hook が呼び出されている。
    | | 2回目以降には呼び出される事は無いようである。
    | |
    | | そして、問題が起こっている時にはそもそも
    | | _rl_signal_handler も呼び出されない様だ。
    | | RL_CHECK_SIGNALS というマクロの中で呼び出されている。
    | | そしてこのマクロは色々なところから呼び出されている。
    | | 取り敢えず一番怪しい signals.c から見る。
    | | rl_check_signals という関数から呼び出されている。
    | | 然しこの関数は誰も使っていない様に見える。
    | | RL_CHECK_SIGNALS マクロ自体に __FILE__, __LINE__ を出力する様に細工を入れた。
    | | 結果として呼び出し元は input.c:625 である様だ。
    | |
    | | _rl_caught_signal と errno == EINTR をチェックしている。
    | |
    | | 漸く違いを見つけた。getc で EINTR を受け取った時に、
    | | 問題が発生していない時には _rl_caught_signal = 28 (WINCH) なのに、
    | | 問題が起こっている時には _rl_caught_signal = 0 になっている。
    | | これを強制的に 28 に書き換えたらどうなるだろうか。
    | | →うーん。一段階深くまで行くようにはなったが結局止まっている。
    | | bashline_set_event_hook が呼び出されていないからの気がする。
    | |
    | | 先に bashline_set_event_hook の呼び出し箇所について確認するのが良い気がする。
    | | 確認すると trap_handler の中に説明が書かれている。
    | | EINTR で反応をする事ができる、とその様に書かれている。
    | | 此処で bashline_set_event_hook を呼び出している。
    | | その様にする条件は RL_ISSTATE (RL_STATE_SIGHANDLER) だそうである。
    | | これは何だろうか。
    | | #define RL_ISSTATE(x) (rl_readline_state & (x)) のように定義されている。
    | | rl_readline_state の状態が異なるという事なのだろう。
    | | 実際に rl_readline_state を出力してみると 4800e が 4000e に変化している。
    | | この 8 というのが丁度 している。
    | | その様にする条件は RL_STATE_SIGHANDLER なのだろう。
    | | ではこの RL_STATE_SIGHANDLER というのは何処で設定or解除されるのか?
    |
    | ここで問題が2種類ある (1) SIGWINCH までは受信している。
    | しかし trap handler が何故か実行されない。(2) COLUMNS が更新されない。
    | それぞれ何故なのだろうか。
    |
    | うーん。どうやらやはり rl_sigwinch_handler が呼び出されるか
    | trap_handler が呼び出されるかの違いらしい?
    | 両方とも trap_handler が呼び出されている様に見えたが、
    | 実際には通常時は rl_sigwinch_handler 経由で trap_handler が呼び出されて、
    | それ以外の場合には rl_sigwinch_handler が呼び出されるという仕組みになっている様だ。
    |
    | そして builtin trap を実行すると sigwinch_handler が消滅する。
    | 何らかのタイミングで再度設置されるというだけの様な気がする。
    |
    | うーん。sig.c の set_signal_handler を見る限りでは trap_handler しか設定していない。
    | 実は他に rl_set_sighandler という関数が存在して其処で rl_sigwinch_handler が設定される様だ。
    | また、普通の readline 環境で builtin trap -- WINCH を実行するとこの
    | trap_handler の呼び出しと rl_set_sighandler の呼び出しが両方実行される。
    |
    | [set_signal_handler (sig.c)] SIGWINCH trap_handler (25353)
    | [rl_set_sighandler (signals.c)] SIGWINCH rl_sigwinch_handler (25353)
    |
    | $ builtin trap -- 'ble-edit/attach/TRAPWINCH' WINCH; sleep 5
    | を実行してみて判明したのは rl_set_sighandler は builtin trap に対して発生しているのではなくて、
    | readline に制御が戻ってきた時に改めて設定する物である様だ。
    |
    | うーん。rl_maybe_set_sighandler という関数から呼び出されていて、
    | この関数自体は普通の readline で毎回コマンドを呼び出す度に呼び出される。
    | そしてこの関数は rl_set_signals という関数から呼び出される。
    |
    | rl_set_signals という関数がコマンドを呼び出す度に呼び出されるという事の様だ。
    | 然し不思議なのは ble/term/enter, leave を実行すると回復するという事である。何故?
    | 実は WINCH は呼び出されていないけれども何らかの理由で COLUMNS, LINES が更新されるという事だろう。
    | →実際に WINCH handler が呼び出されていないという事を確認した。

    今までに分かった Bash の振る舞いについて以下にまとめる。

    1. builtin trap は trap_handler という関数を登録する。
      これは SIGWINCH に対しても同様である。

    2. readline はユーザがコマンドを実行し終わったタイミングで
      rl_set_signals - rl_maybe_set_sighandler - rl_set_sighandler(SIGWINCH) として、
      rl_sigwinch_handler を SIGWINCH に登録し直す。
      この rl_sigwinch_handler が COLUMNS, LINES を更新してくれるのである。
      そして元々登録されていた関数も呼び出してくれる。

    然し、ble.sh では bind -x でユーザのコマンドを処理しているので、
    readline の rl_set_signals が呼び出される機会がない。
    そうすると壊れたままという事になる。

    # * なので PROMPT_COMMAND で attach したとしても解決はしない。
    #
    # * ble-detach してから ble-attach すると問題が解決して見えたのは、
    #   単に readline としてコマンドを実行したからであった。
    #   つまり、コマンドであれば何でも良かった。
    #
    # * ble/term/enter, leave で解決した様に見えたのも少し違った。
    #   ble/term/enter, leave を実行すると stty が呼び出されて
    #   その場で COLUMNS, LINES は修正されるが、
    #   実はもう一度 winsize を変更するとまた変な状態になる。
    #   これは一時的に COLUMNS の状態が正しくなるというだけで、
    #   trap 関連で変な状態になっているというのを修正する事にはなっていない。
    #
    # ? ok: suppress をしていないと問題が起こらないのは何故か。
    #   →問題が起こっていない様に見えたのは勘違いだった。
    #   今試してみると suppress しない場合でもちゃんと問題が発生している。
    #
    # * Cygwin で bash-4.2 以降でも問題が起こっている原因は分からない。
    #   Cygwin ではまた別のタイミングで rl_set_signals 等を実行しているのかもしれない。
    #   或いは、単に trap_handler が別の理由で中断しているというだけかもしれない。
    #   これはまた別の機会に考える事にする。
    #
    # ? 保留: bashline_set_event_hook が builtin trap で呼び出されているのは何故か。
    #   これについては未だ調べていないが、全体について大体分かったし、
    #   この部分は余り関係無さそうなので今は調べなくて良い。


    ここで考えるべき事は何か。

    a rl_set_signals を誘起する別の手法について考える。
    b builtin trap を二度としない様にする。

    b の方が現実的かもしれない。が、ble-update で違う値になる場合に為る時は
    もう一度実行せざるを得ない。しかし、そういう事はめったに起きないし、
    そもそもこの問題はそんなに大きな問題ではない。一時的に表示が乱れる程度なのだ。
    という事を考えると、取り敢えずは b の方で良い気がする。

    * [棄却] rl_set_signals を誘起させる方法について
      少し試してみたがうまく行かないので諦める事にする。

      もし a が可能であればそちらの方が良いので少し確認しておく事にする。
      rl_reset_after_signal という関数が呼び出している。
      _rl_callback_newline, rl_callback_read_char という関数も特定の条件の元で呼び出している。
      後は readline 関数が一番最初の最初の初期化で呼び出している。
      可能性があるとすれば rl_reset_after_signal である。

      →然し、これが呼び出されるのは INT, TSTP, TTIN, TTOU, TERM, HUP, ALRM, QUIT である。
      例えば INT を上書きして invoke するというのもありなのかもしれない。
      試しに実装してみる事にする。

      TSTP, TTIN, TTOU, INT, TERM, HUP, QUIT, WINCH は全て再設定の対象の様である。
      という事は INT を上書きするのも問題が発生するという事。うーん。

      もっと具体的に見る事にする。rl_reset_after_signal は _rl_handle_signal から呼び出される。
      更にこれは _rl_signal_handler から呼び出される。更に SIGHANDLER_RETURN から呼び出され、
      これは rl_signal_handler から呼び出される。つまり。rl_signal_handler が設定されている
      シグナルを使わなければならない。その場で trap すると trap_handler が設定されてしまうので、
      その様な handler をその場で生成する事はできない。とすれば。うーん。分からない。
      原理的にはどれか一つに何か無害な物が設定されていれば特に問題は起こらない筈。

      取り敢えず TSTP, TTIN, TTOU は特に何も起こらない様である。
      これらに特に何も設定されていなかったらそれを使うという事で良いのだろうか。
      取り敢えず試してみる事にする。
      →実際に試してみた所全く呼び出されない。どういう事だろう。
      何か trap に登録していないと駄目という事だろうか。

      # Induce "rl_reset_after_signal" to set up rlhook
      for sig in TTOU TERM QUIT; do
        ble/util/assign trap "builtin trap -p $sig" || continue
        [[ ! $trap ]] || continue
        kill -"$sig" "$$"
        return 0
      done

      うーん。駄目だ。動かない。諦める事にする。

      調べてみると TTOU に確かにハンドラが設定されている気がするが実際には呼び出されない。
      もっと別の仕組みによってもみ消されているのか、或いは、
      単に別の場所で handler が上書きされてしまっているのか。
      どうしたら上書きされているか分かるだろうか。
      signal を2回呼び出す? 或いはもしそもそも全く呼び出されないのだとすれば。
      signal SIG_DFL を呼び出して中身を出力して抜ければ良い気もする。

      うーん。やはり呼び出されない。そして TTOU を再設定する時に確認したが、
      やはり rl_signal_handler が設定されている。別のものは設定されていない。
      どうも自分で kill を呼び出すと何も起こらない様だ。
      子プロセスから呼び出しても何も起こらない。
      別の通信方法を使っているとしても不思議である。
      時間の無駄なので深追いするのはやめる事にする。

2020-04-26

  * bash-completion が有効になっていない→ PS1= の影響だった [#D1344]
    何かと思っていたが、分かった。
    bash-completion は PS1='' かどうかで対話シェルかどうかを判定している。
    本来対話シェルかどうかの判定には $- を使うべきである。

    * bash-completion が何故 PS1 を使っているのか

      良く分からない。

      * bash の振る舞い
        動作を調べてみると (PS1= bash) として起動すると PS1 は空になる。
        (unset -v PS1; bash) として起動すると PS1 にはデフォルト値が設定される。
        bash-1.14 の時点でその様に振る舞っている。
        然し、bash-completion はその様に実装されていない気がする。

        また $- についても bash-1.14 の時点でちゃんと i を含んでいる。

        うーん。改めてソースコードを見ると shellcheck=sh としているので、
        その他のシェルの場合を考慮に入れていると解釈できる。
        BASH_VERSION をチェックしている時点で bash と確定しているので、
        $- を使わない理由は "${-%%i*}" != "$-" が構文エラーになる処理系があるという事か。
        少なくとも dash は対応している。

      * The Bourne sh で試してみたら ${var%i*} に対応していない様だ。
        結局 $- に i が含まれているかどうかを判定する為には case..esac が必要という事?
        →と思ったが [ -n "$BASH_VERSION" ] && [ $- == ${-%i*} ] で普通に動いている。

      多分、the Bourne sh などどのシェルでもエラーにならなくて、
      簡単で分かりやすいからである。

    何れにしても PS1 を使って対話環境かどうかを判定しているスクリプトは他にもありそうである。

    a という事を考えると PS1= の上書きはしない様にしても良いのかもしれない。
      元々 PS1= にしているのは Bash の出力を抑制する為だった。
      然し、現在の stdout.on, off を実装してからは実は必要ないはず。

      記録を辿ったが PS1= にする理由については殆ど書かれていない。
      一番最初のメモである #D0002 によると C-d を受け取る為に必要らしい。
      当初は stty を実行していなかったからそれと関係するかもしれない。
      現在は stty で調整しているが bash-3.2 ではそれも動かない。

      取り敢えず bash-3.2 で PS1= にしなくても動くか確認する。
      →問題なく動いている。internal_suppress_bash_output を有効にしていない
      時に PS1 が空になって設定が誤作動するのは仕方がない。
      そもそも internal_suppress_bash_output はデバグ用の設定だから気にしなくて良い。

    b 或いは或る程度はシェルの状態を復元して ble-import する方が良いのかもしれないと考えたが、
      ble-import の中で実行している以上は set -e だとかのユーザ環境に対して適用する
      事を意図した様な設定は off にしておきたい気もする。

      飽くまで ble-import は blesh 空間で実行するという仕様という事にする。
      但し PS1 等の変数は多くのスクリプトが使う物という事で空欄にするのはやめる。

    取り敢えず a の方針で変更した。

    結局これは外部のスクリプトを ble-import で初期化した時に起こる問題なので
    影響範囲は少ないだろう。唯一 fzf は ble-import で読み取る設定を紹介しているが、
    fzf は $- を使って判定していた筈なので影響はないのである。

  * OK: preexec の振る舞いについての調査 [#D1343]
    preexec は全てのコマンドの前に実行する物なのか、
    或いは、ユーザコマンドの開始前に実行する物なのか。
    zsh での振る舞いと bash-exec での振る舞いを調べる必要がある。

    * zsh で試してみた所、ユーザのコマンドを実行しようとした時に実行される。
      各コマンドの前で毎回実行するという事はない。

      % autoload -Uz add-zsh-hook
      % preexec_func1() { echo "[$LINENO]"; }
      % add-zsh-hook preexec preexec_func1
      % echo
      % for i in {0..10}; do echo hello; done

    * 一方で Bash の DEBUG は全てのコマンドの前に実行される。
      特に "for i in {0..10}" という部分に対しても毎回呼び出される様だ。

      $ trap 'echo "[DEBUG] $BASH_COMMAND"' DEBUG
      [DEBUG]
      $ for i in {0..10}; do echo hello; done
      [DEBUG] for i in {0..10}
      [DEBUG] echo hello
      hello
      ...

    * bash-preexec はどうだろうか。試してみた所、
      ちゃんとユーザコマンドの実行前に一回だけ実行される。

      $ bash --norc
      $ . bash-preexec.sh
      $ preexec() { echo "[preexec] $BASH_COMMAND"; }
      $ echo hello
      [preexec] echo hello
      hello
      $ for i in {0..10}; do echo hello; done
      [preexec] for i in {0..10}
      hello
      hello
      ...

    従って、現状の動作で問題ない。

2020-04-24

  * [棄却] LC_ALL= LC_COLLATE=C 等の指定をしているが、 [#D1342]
    もしユーザーが LC_ALL に自分の言語情報を指定していた時にはどうなるのか。
    そういう事を考えると LANG に LC_ALL:LANG から導出した値を指定する必要があるのではないか。

    うーん。然し勝手に LC_ALL を空にしてそれから LANG に値を設定すると、
    LC_ALL で上書きしていた他の locale (LC_CTYPE) は一体どうなるのだろうか。
    例えば LC_CTYPE を LC_ALL で上書きしていたとする。
    ここで LC_ALL をクリアしてそれを LANG に設定したとする。
    LANG よりも LC_CTYPE の方が優先される事から、
    上書きされていた筈の LC_CTYPE が有効になってしまう。

    x そういう事を考えると完全に対応する為には
      全ての locale 項目に対して値を再計算する必要がある。非効率である。
    x 更に locale 項目に値を設定する度に内部で locale の構築が行われる。
      locale の構築はファイルの読み取りなども発生し重い処理になるので、
      できるだけ少なくしたい。
    x 更に、ユーザが LC_CTYPE などを指定したとしてもそれが有効になってはならない。
      LC_ALL で強制している筈だからである。
      然し個別に locale を指定する場合にその振る舞いは再現できない。

    などなどという事を考えるとユーザが指定した LC_ALL の効果を正しく保持するというのは難しい。
    飽くまで LC_ALL は特別な場合の回避方法であるという事を考えると、
    ble.sh の特別の関数の中では LC_ALL の効果がなかった事にしても良い様に思う。

  * util: LANG=en_US.utf8 の時の bash-3.2 の振る舞いが変である [#D1341]
    ref memo/D1341.locale-and-casematch.sh

    c2s のテストで見つかった。ble/string#toupper で問題が発生していた。
    調べると LC_ALL= LC_COLLATE=C func と指定しても bash-4.1 以下では効果が出ない。

      local LC_ALL= LC_COLLATE=C
      func

    等の様にして実行しないと駄目の様である。

    LC_ALL= LC_CTYPE=C については大丈夫なのだろうか。
    と思って試すと大丈夫に見えたが良く見たら既に対策されていた。
    つまりこの問題は或る意味で既知の問題だったのである。

  * test: ble.sh --test でテストを実行する? [#D1340]
    interactive session に入らずに色々実行する機能?

    * というより複数の bash version でテストする機能も作りたい気がする。
      然し、毎回全ての version でテストするのも大変である。
      →と思ったがユーザの環境によって異なるし、

      呼び出す時には結局何れかの version の bash から
      更に様々な bash の version に ble.sh を読み込ませなければならない。
      親の bash では実は ble.sh を読み込む必要は全く無い。
      という事を考えると、実は make_command.sh 辺りに実装するべきなのではないか。

      m check には既にソースコードのパターン検出によるチェックがある。
      然し、m check と言えば普通はテストである。
      現在の check は別の名前に変更したい。名前は何が良いか。
      lint という程でもないし、check-pattern は長い。
      check-all で全部チェックするというのでも良いのかもしれない。

      うーん。取り敢えず scan という事にする。

    * test を実行する時に version を表示したい。
      表示する様に変更した。

2020-04-19

  * 後、READLINE_MARK に対応したがちゃんと範囲チェックを忘れていないか確認する [#D1339]
    →確認した所、これについては READLINE_POINT ですらチェックしていなかった。
    チェックする様に修正した。

  * PROMPT_COMMANDS の判定を declare -p で行っているが、 [#D1338]
    これだと "配列として宣言したが unset である" という状況で
    PROMPT_COMMAND に fallback しないという問題があるのではないか。
    というより bash ではどの様に振る舞っているか確認する必要がある。
    →bash-dev で振る舞いを確認した所、配列要素が 1 つ以上あるかどうかで決まっている様だ。

    →然し bash-3.2 以下では declare a123 としただけで要素が 1 になってしまう。
    という事を考えると set/unset も一緒に使って判定するのが良い?
    と思ったが a123[1]=hello 等の時に判定できなくなってしまう。
    或いは declare a123 は a123=('') と等価なのだからその様に取り扱うというので良い気もする。
    というか本質的に declare a123 は declare a123= と等価なので区別してはならない。OK

  * ble-stackdump の開始フレームがずれている [#D1337]
    ble/util/stackdump という内部実装に分けた為である。
    分ける必要があっただろうか。或いは、開始フレームを外から変更できる様にする?
    後、BASH_LINENO の参照を誤っている。取り敢えず修正した。

  * syntax: 変数展開で bash-5.1 で UuLK という operator が追加されている [#D1336]
    というより、bash-4.3 では operator は無効にするべきでは。
    →確かめてみた所ちゃんとその様な実装になっていた。

2020-04-16

  * fzf で複数行モードに入ってしまうという報告 (reported by Brendonk13) [#D1335]
    https://github.com/akinomyoga/ble.sh/issues/49

    もっと再現を簡単になるまで絞ってから報告して欲しい。
    fzf を入れた。再現しない。bfs を今度は入れる必要がある。
    或いは find でも再現するかどうか事前に確かめるべきなのではないか。
    というか FZF_ALT_C_COMMAND の中に tr -d だとか C-j だとか記入している時点でおかしい。
    確認してみると始めての issue 報告という事である。初心者である。
    初めての issue 報告をする人というのは結構いるようである。

    bfs を入れようとしたがコンパイルできない。
    README を参照したが各 distribution のパッケージが並んでいるだけで
    実際のコンパイル方法は make しか書かれていない。
    必要なライブラリが -lacl -lcap -lattr である。
    検索すると libacl libcap libattr で入りそうである。
    駄目だった。全て元から入っていた。
    sudo dnf install lib{acl,cap,attr}-devel としたら入った。

    取り敢えず動作は確認した。然し問題は発生していない。
    どうやらディレクトリ名を選択させて cd を実行する様だ。
    予想できるのは fzf は "cd ディレクトリ名" を入力して
    続いて決定を押しているのだろうという事。
    というか、これは bfs は関係ないのでは。

    さて、現在再現しないのは ble.sh に特別に調整した
    key-binding を実行しているからである。
    普通の fzf の bind でどう動作するのか確認する必要がある。
    うーん。fzf の設定 .fzf.bash を dotfiles に追加してしまうか。
    或いは ble.sh のディレクトリに追加してしまうというのも手である。
    何しろ ble.sh の対応の為に追加した物なのだから。

    →特別の調整を外したら再現した。絞り込みに入る。
    先ず bfs を外す。bfs の設定がなくても再現した。
    fzf の key-bindings.bash を確認すると以下の様になっている。
    確かに C-m の後に沢山の文字列が設定されている。
    恐らくこれは編集文字列とカーソル位置を保存して
    それからカーソル位置を復元する為の物であろう。
    bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'


    [contrib を整備する]

    うーん。毎回この様に説明を書くのは面倒である。

    a reject: 一つの方法は fzf に修正を入れてもらうという事。
      然し、こちらは 115 star の小さなライブラリである。
      一方であちらは 28.5k star の巨大なリポジトリである。
      このような小さなライブラリの要求をいちいち飲んでいたら大変である。
      という訳でどう考えても PR を出しても対応してくれるとは思えない。
      幾らインターフェイスが綺麗だとしても。

      もし可能性があるとしたら key-bindings.blesh 等のようなファイルを作るのが良いか。
      然し、そうすると同じ bash でも .fzf.bash と .fzf.blesh を使い分ける必要が出てくる。
      それよりは key-bindings.bash の中で自動的に振り分ける方が良いのではないか。

    b もう一つの方法は ble.sh で ble-import -d lib/fzf-key-bindings とできる様にする事。
      この方法の問題点は fzf の場所を事前に指定する必要があるという事。
      一番簡単なのは .fzf.bash を source するという事。
      然しそうすると結局 fzf の変な key-bindings が登録されてしまう。

      或いは "fzf" だけインストールしてもらって、
      fzf のパスから辿るという方法。これはユーザに特別の指定をしてもらう必要がある。

    c reject: 或いは .fzf.bash -> fzf/shell/key-bindings.bash を検出して、
      その中で実行される bind は自動的に無効にして、
      代わりに blesh の特別の binding をその場で実行するという方針?

      これは何が問題かというといざユーザが key-bindings.bash を編集しても反映されないという事。
      更にユーザが何が起こっているのか理解するのに時間がかかるという事。
      というか何が起こっているのかを解明するのは物凄く難しいという気がする。
      これはかなり大変な書き換えである。

    d 或いは、.fzf.bash の中で source "..." となっている部分を自分で書き換えてもらう。
      然し、沢山設定を書くのは面倒なので設定に関しては以下のファイルを用意する。

      lib/fzf-key-bindings.sh
      lib/fzf-completions.sh
      lib/fzf-git.sh

    まあ、これぐらいが妥当な気がする。然し、問題はどうやって _fzf_base を伝えるかという事。
    .fzf.bash にこれを設定する項目はあるだろうか→うーん。無いような気がする。
    結局何かは source しなければならない。まあ、自分で source すれば良いという気がする。

    うーん。contrib というディレクトリでも作る事にしようか。
    或いは、blesh-contrib というリポジトリを作る事にする?
    そうした方が他の人が設定を追加しやすくなるという気がするのである。
    contrib の中に theme 等のサブディレクトリを更に作る?
    或いは単に contrib/theme-*.sh 等の様にするか。
    その方が良い気がする。
    blesh-contrib というリポジトリを作成する事に決めた。

    * 作成した設定をテストする。

    * ble.sh からどの様にリンクするのが良いだろうか。

      # さて、問題はどの様に git submodule を追加するかという事。
      # 相対パスで設定できるという話だった気がする。
      # うーん。該当する記事が見つからないが試してみる事にする。
      # と思ったら空の repository は追加できないそうだ。
      # 仕方がないので取り敢えず簡単な内容で作成する。

      submodule contrib を使う?
      というより他に思い浮かばない。
      或いは、別 repository として管理するのは OK としても
      明示的に link はしないという様にする?
      だとしても結局何処かで download しなければならないのだから、
      submodule を使ってしまっても問題ないという気がするのである。

      x ok: submodule を使った時の問題は同期が面倒という事。
        然し、install 先に直接 repository を作成するとしても同期が面倒なのは変わりない。
        寧ろその方が ble-update 等の処理が複雑になって面倒である。
        という事を考えると、やはり中で submodule を管理するのが良い。

      * submodule の同期をする必要があるという観点に関しては、
        contrib/.git が存在しない時には
        git submodule update --init --recursive を make の中で呼び出せば良い。
        ble-update に対してもこれを実行する。

    * done: 試しに相対パスでもちゃんと GitHub から同期できるか確認した。
      →できた。これで大丈夫。

    * done: Makefile の設定も行った。
      2回実行しなければならない気がするが、まあ大丈夫だろう。
      と思ったが make して out/ble.sh を source している場合は微妙。

    * done: ble-update で更新する様にする。これは pull --recursive で良いのでは。
      と思ったが実際にそういう物はあるのだろうか。
      $ git pull --recurse-submodules という物があるらしいが、
      これを実行すると .gitmodules を書き換えて最新の物に更新してしまうらしい。
      という事で必要なのは以下のコマンドの様である。
      $ git submodule update --recursive --remote
      --remote の意味はよく分からない。うーん。--help で観察すると、
      sha1 hash ではなくて branch に基づいて同期する様である。
      考え直してみるとその方が都合が良い。という訳で取り敢えずこれを使う事にする。
      不整合が起こるのではないかという心配もあるが、まあ使ってみて問題が起こってから考える。

    * done: 次に追加した fzf-*.sh がちゃんと動くかをテストする必要がある。
      動作確認した。

    * done: 次は contrib の README に説明を書く事にする。説明を書いた。

  * resize で hang するとの事 (reported by killermoehre) [#D1334]
    https://github.com/akinomyoga/ble.sh/issues/48

    PS1 について尋ねたら以下の結果になった。

    > ^A^[]133;D;0^G^B^A^[]0;cXXXXXXX@apfelkuchen:~^G^B^A^[]133;A^G^B$ ^A^[]133;B^G^B

    これは以下の設定に対応する。

    PS1='\[\e]133;D;0\a\]\[\e]0;cXXXXXXX@apfelkuchen:~\a\]\[\e]133;A\a\]$ \[\e]133;B\a\]'

    | Additional questions.
    |
    | **Question 3**: Does the problem reproduce with `PROMPT_COMMAND=''`?
    | For example, please add the line `PROMPT_COMMAND=` before the line of
    | `ble-attach` in `.bashrc` as follows:
    |
    | ```bash
    | # bashrc
    |
    | [[ $- == *i* ]] && source /path/to/blesh/ble.sh --noattach
    |
    | # ...
    |
    | PROMPT_COMMAND= # <-- This line
    | ((_ble_bash)) && ble-attach
    | ```
    |
    | **Question 4**: Does the problem reproduce with `source ble.sh` in
    | interactive sessions? To try this, please follow the following steps:
    |
    | 1. Open terminal
    | 2. Type the following commands
    |
    | ```bash
    | $ bash --norc
    | $ PS1='\$ '
    | $ PROMPT_COMMAND=
    | $ source /path/to/ble.sh
    | ```
    |
    | 3. Resize before input anything
    |
    |
    |  --attach=attach
    |
    | $ trap 'ble-stackdump > /dev/tty' USR1


    再現できたので原因を解明する。
    結局、read -r aaa bbb を builtin read -r aaa bbb に変更したら動く様になった。
    或いは以下の変更で治る。おかしい。これは bash のバグなのではあるまいか。

    | +++ b/src/edit.sh
    | @@ -6998,8 +6998,8 @@ function ble/builtin/read {
    |    [[ $__ble_command ]] || return "$__ble_ext"
    |
    |    # 局所変数により被覆されないように外側で評価
    | -  builtin eval -- "$__ble_command"
    | -  return
    | +  builtin eval -- "$__ble_command"; local ext=$?
    | +  return "$ext"
    |  }
    |  function read { ble/builtin/read "$@"; }

    return "$ext" の代わりに 'ble/util/setexit "$ext"; return' としても問題が発生する。
    %または return を完全に削除しても問題が発生する
    →勘違いだった。return を実行した場合には問題は発生しない。
    他の version でも発生するのかを確かめてみた。

    [Bash 用最小再現コード]

    Bash のバグの可能性があるので Bash だけで再現できるか試みる。

    | bash-4.4 でも再現する。
    |
    | * bash-4.3 だと別のエラーが発生する。
    |   このエラーは iterm2 を読み込まない場合には発生していない気がする。
    |
    |   $ bash-4.3: history: 書き込みエラー: Broken pipe
    |   bash-4.3: history: 書き込みエラー: Broken pipe
    |   Segmentation fault (コアダンプ)
    |
    |   うーん。これは何だろうか。iterm2 の読み込みと関係がある?
    |   不思議である。history がどう関係してくるのか謎である。
    |   一応 __bp_preexec_invoke_exec が history を内部で呼び出している様だが、
    |   実際にこれが問題の原因なのかどうかについては不明である。
    |
    | * bash-4.2 では問題は発生しない。
    |   bash-4.0 でも問題は発生しない。
    |
    | * ok: bash-3.2 だと変なエラーが発生して無限ループする。
    |   これは precmd の問題の気がする。
    |
    |   | bash-3.2: branch.ab: syntax error: invalid arithmetic operator (error token is ".ab")
    |   | bash-3.2: branch.ab: syntax error: invalid arithmetic operator (error token is ".ab")
    |   | bash-3.2: branch.ab: syntax error: invalid arithmetic operator (error token is ".ab")
    |   |
    |   | stackdump は以下の通り
    |   | @ iterm2_shell_integration_local.sh:13 (iterm2_print_user_vars)
    |   | @ iterm2_shell_integration.sh:374 (iterm2_print_state_data)
    |   | @ iterm2_shell_integration.sh:-8 (__iterm2_precmd)
    |   | @ iterm2_shell_integration.sh:-471 (__bp_precmd_invoke_cmd)
    |   | ...
    |   | @ iterm2_shell_integration_local.sh:13 (iterm2_print_user_vars)
    |   | @ iterm2_shell_integration.sh:374 (iterm2_print_state_data)
    |   | @ iterm2_shell_integration.sh:-8 (__iterm2_precmd)
    |   | @ iterm2_shell_integration.sh:-471 (__bp_precmd_invoke_cmd)
    |   | @ iterm2_shell_integration.sh:-16230 (__bp_install)
    |   | @ /home/murase/.local/share/blesh/ble.sh:7 (ble-edit/prompt/update/.eval-prompt_command.1)
    |   | @ /home/murase/.local/share/blesh/ble.sh:-429 (ble-edit/prompt/update/.eval-prompt_command)
    |   | @ /home/murase/.local/share/blesh/ble.sh:33 (ble-edit/prompt/update)
    |   | @ /home/murase/.local/share/blesh/ble.sh:308 (ble/textarea#render)
    |   | @ /home/murase/.local/share/blesh/ble.sh:14091 (ble/textarea#redraw)
    |   | @ /home/murase/.local/share/blesh/ble.sh:3 (ble-attach)
    |   | @ zzz-attach-ble.sh:28 (source)
    |   | @ .bashrc:0 (source)
    |
    |   iterm2_print_user_vars の中を調べると確かに branch.ab という文字列が使われている。
    |   連想配列は bash 3.2 で存在しないのでそれが原因で問題が起きているのだろう。
    |   然し、__bp_precmd_invoke_cmd は呼び出されていない。
    |   よく考えたら bp_precmd は trap DEBUG を使っている。
    |   つまり、branch.ab によって構文エラーが発生して DEBUG か何かが発生し、
    |   その結果として無限ループが発生しているという事だろうか。
    |   まあ、bash3.2 に関しては考えない事にする。
    |
    | 取り敢えず最小再現を作成する事にする。
    | 恐らく WINCH の中では return が思うように動かないという事?
    |
    | $ function f1 { false; return; }; function f2 { f1; }
    | $ trap 'while f1; do echo hello; break; done' WINCH

    再現した。最小化する。

    $ f1() { false; return; }; trap 'f1; echo exit=$?' WINCH

    実は別のシグナルでも問題ないのではないか。

    $ f1() { false; return; }; trap 'f1; echo exit=$?' USR1; kill -USR1 0

    うーん。もしこれが Bash のバグだとしても、Bash 4.4, 5.0 が世の中に現れてしまった以上は、
    これに対する対策を ble.sh の側で実行する必要がある。もしくは、return を上書きするか…。
    と思ったが return を関数で上書きすると setexit と同じ意味になってしまって、
    元々の return の意味を失ってしまうので駄目である。という訳でやはり return を
    修正しなければならないのであった。

    取り敢えず行末にある return を全て修正していく事にする。
    修正した。これで恐らく全ての return に明示的に終了ステータスが指定されている。

2020-04-14

  * 2020-01-23 stackdump [#D1333]

    以下の様な内容。再現しない。編集手順を記録する? 後、その場で ble_debug=1 にする機能が欲しい。

    | echo 1 2 3 4 5 8 9 10 | ( read numbers; set -- $numbers; i=0 i1=0; for n; do if ((n!=i)); then if ((i==i0)); then echo $i0-$i; ; ((i++)); done )
    |
    | ble/syntax/tree-enumerate/.initialize/FATAL1
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:26 (ble/util/assert)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:4 (ble/syntax/tree-enumerate/.initialize)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:6 (ble/syntax/tree-enumerate)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:6 (ble/syntax/parse/shift.method2)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:19 (ble/syntax/parse/shift)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:7 (ble/syntax/parse)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:73 (ble-edit/content/update-syntax)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble/textarea#render)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:16 (ble-edit/bind/.tail)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:50 (ble-decode/EPILOGUE)
    |
    | 取り敢えず f11 で ble_debug を toggle して f12 で編集履歴を出力する様にした @ blerc
    | 本質的にはそんなに複雑な構造はしていないのだからすぐに再現しそうな気がしたが再現しない。
    | 或いは一時的な物で既に直ってしまった可能性もなくはない。
    | echo 1 | ( echo; for n; do if ((n!=i)); then if ((i==i0)); then echo $i0-$i; ; ((i++)); done )

    [再現] 2020-04-14 再現した。

    | echo {1..9}|(read numbers;set -- $numbers;i=0;i0=0;for n;do if((n!=i));then echo $i0-$i;i=$n;done)
    |
    | ble_debug 構造を入手した。然し何処から手をつけたら良いのか分からない。
    | 取り敢えず diff を取ってみる事にする。本質的な違いは以下の様になる。
    |
    | --- D0000.a.expected-1.txt^I2020-04-14 11:57:31.268375794 +0900
    | +++ D0000.a.error-1.txt^I2020-04-14 12:01:30.567636568 +0900
    | @@ -86,24 +86,21 @@
    |  14 a    083 '$' || stat=(ARGX w=- n=@14 t=$82:$11)
    |   7 a    084 'i' ||
    |   | a    085 '0' ||
    | - 4 a    086 '-' || stat=(ARGI w=ARGX:83- n=@14 t=-:$82)
    | -14 a    087 '$' || stat=(ARGI w=ARGX:83- n=@14 t=-:$82)
    | + 4 a    086 '-' || stat=(ARGI w=ARGX:83- n=@24 t=-:$82)
    | +14 a    087 '$' || stat=(ARGI w=ARGX:83- n=@24 t=-:$82)
    |   7 a    088 'i' |+ word=ARGI:@81>83-89/(wattr=d)
    | -12 a    089 ';' |  stat=(ARGX w=- n=@14 t=$89:$11)
    | - 7 a    090 'i' || stat=(CMDX w=- n=@14 t=$89:$11)
    | +12 a    089 ';' |  stat=(ARGX w=- n=@24 t=$89:$24)
    | + 7 a    090 'i' || stat=(CMDX w=- n=@24 t=$89:$24)
    |   8 a    091 '=' ||
    | -14 a    092 '$' || stat=(VRHS w=_ble_attr_VAR:90- n=@14 t=-:$89)
    | +14 a    092 '$' || stat=(VRHS w=_ble_attr_VAR:90- n=@24 t=-:$89)
    |  26 a    093 'n' |+ word=_ble_attr_VAR:@88>90-94/(wattr=m2:d,$:d)
    | -12 a    094 ';' |  stat=(CMDXV w=- n=@14 t=$94:$11)
    | -19 a    095 'd' || stat=(CMDX w=- n=@14 t=$94:$11)
    | +12 a    094 ';' |  stat=(CMDXV w=- n=@24 t=$94:$24)
    | +19 a    095 'd' || stat=(CMDX w=- n=@24 t=$94:$24)
    |   | a    096 'o' ||
    |   | a    097 'n' ||
    |   | a    098 'e' |+ word=CMDI:@93>95-99/(wattr=d)
    | -12 a    099 ')' +  word="(":@10>14-100>@98 stat=(CMDXE w=- n=@14 t=$99:$11)
    | - |    s 100 ^@    stat=(CMDXE w=- n=- t=$100:-)
    | + 6 a e  099 ')'    stat=(CMDXE w=- n=@24 t=$99:$24)
    | + |      100 ^@    stat=(CMDXE w=- n=@24 t=$99:$24)
    |
    | 確認すると $i0-$i の - の時点で nest の座標がずれている。
    | どうも read numbers; set -- は関係ない気がする。
    | 編集履歴を dump する機能はあっただろうか。
    | この通りに編集したら再現するかどうかを先ず確認する必要がある。
    |
    | 13:echo {1..9} |
    | 16:echo {1..9} | ()
    | 22:echo {1..9} | (read --)
    | 21:echo {1..9} | (read -)
    | 20:echo {1..9} | (read )
    | 45:echo {1..9} | (read numbers; set -- $numbers;)
    | 28:echo {1..9} | (read numbers;set -- $numbers;)
    | 57:echo {1..9} | (read numbers;set -- $numbers;for n;do done)
    | 54:echo {1..9} | (read numbers;set -- $numbers;for n;do ;done)
    | 58:echo {1..9} | (read numbers;set -- $numbers;for n;do echo ;done)
    | 48:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do echo ;done)
    | 57:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do cho ;done)
    | 57:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do ho ;done)
    | 57:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do o ;done)
    | 57:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do  ;done)
    | 74:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));then\;done)
    | 73:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));then;done)
    | 72:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));the;done)
    | 71:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));th;done)
    | 70:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));t;done)
    | 69:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));;done)
    | 68:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0));done)
    | 67:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0);done)
    | 66:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==0;done)
    | 65:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==;done)
    | 69:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==n));;done)
    | 68:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==n));done)
    | 67:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==n);done)
    | 66:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==n;done)
    | 65:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i==;done)
    | 64:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i=;done)
    | 63:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((i;done)
    | 62:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ((;done)
    | 61:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if (;done)
    | 60:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if ;done)
    | 59:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if;done)
    | 63:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if(());done)
    | 65:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if((n==i));done)
    | 62:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if((n=i));done)
    | 63:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if((n!=i));done)
    | 80:echo {1..9} | (read numbers;set -- $numbers;i=0;for n;do if((n!=i));echo $i0-$i;done)
    | 53:echo {1..9} | (read numbers;set -- $numbers;i=0;i0=0;for n;do if((n!=i));echo $i0-$i;done)
    | 78:echo {1..9} | (read numbers;set -- $numbers;i=0;i0=0;for n;do if((n!=i));then echo $i0-$i;done)
    | 94:echo {1..9} | (read numbers;set -- $numbers;i=0;i0=0;for n;do if((n!=i));then echo $i0-$i;i=$n;done)
    | 56:echo {1..9} | (read numbers;set -- $numbers;i=0;i0=0;for if((n!=i));then echo $i0-$i;i=$n;done)
    |
    | 駄目だ。再現しない。微妙な操作の違いですぐに再現しなくなるという事か、
    | 或いは、より前の履歴編集によって種が仕込まれている必要があるのか、
    | もっと別の際限条件が存在するのか。文字列の挿入位置にも関係がありそう。
    | また、paste 等を実行すると incremental な解析にならずに一気に解析するので問題が起こらないという可能性も。
    |
    | 直感としては read/set の部分は関係ない気がする。for の辺りが怪しい。
    | 再現できた。だいぶ短くできた気がする。これは実は最初の :| も関係ないのでは。
    | 内部で ;; が発生すると起こる問題ではないだろうか。
    |
    | 4::|()
    | 18::|(:;for n;do done)
    | 15::|(:;for n;do ;done)
    | 9::|(:;i=0;for n;do ;done)
    | 34::|(:;i=0;for n;do if((i==0));then\;done)
    | 33::|(:;i=0;for n;do if((i==0));then;done)
    | 32::|(:;i=0;for n;do if((i==0));the;done)
    | 31::|(:;i=0;for n;do if((i==0));th;done)
    | 30::|(:;i=0;for n;do if((i==0));t;done)
    | 29::|(:;i=0;for n;do if((i==0));;done)
    | 28::|(:;i=0;for n;do if((i==0));done)
    | 27::|(:;i=0;for n;do if((i==0);done)
    | 26::|(:;i=0;for n;do if((i==0;done)
    | 25::|(:;i=0;for n;do if((i==;done)
    | 24::|(:;i=0;for n;do if((i=;done)
    | 23::|(:;i=0;for n;do if((i;done)
    | 22::|(:;i=0;for n;do if((;done)
    | 28::|(:;i=0;for n;do if((n!=i));done)
    | 41::|(:;i=0;for n;do if((n!=i));echo $i0-$i;done)
    | 14::|(:;i=0;i0=0;for n;do if((n!=i));echo $i0-$i;done)
    | 39::|(:;i=0;i0=0;for n;do if((n!=i));then echo $i0-$i;done)
    | 55::|(:;i=0;i0=0;for n;do if((n!=i));then echo $i0-$i;i=$n;done)
    |
    | 短縮した。
    |
    | 2:()
    | 16:(:;for n;do done)
    | 12:(:;for n;do;done)
    | 7:(:;i=0;for n;do;done)
    | 34:(:;i=0;for n;do if((i));echo $i-$j;done)
    | 11:(:;i=0;i=1;for n;do if((i));echo $i-$j;done)
    | 33:(:;i=0;i=1;for n;do if((i));then echo $i-$j;done)
    | 45:(:;i=0;i=1;for n;do if((i));then echo $i-$j;i;done)
    |
    | 実は直前の状態まで大丈夫だったのではないか?
    | と思って試してみたが駄目だった。やはり編集履歴が必要。
    | 2つ前から始めたら再現した。
    |
    | 44:(:;i=0;i=1;for n;do if((i));echo $i-$j;done)
    | 33:(:;i=0;i=1;for n;do if((i));then echo $i-$j;done)
    | 45:(:;i=0;i=1;for n;do if((i));then echo $i-$j;i;done)
    |
    | 初期状態を少しずつ小さくしてみる。
    |
    | (:;for n;do if((i));echo $i-$j;done)  再現する
    | (:;for n;do if((i));echo;done)        再現しない
    | (:;for n;do if((i));: $i;done)        再現しない
    | (:;for n;do if((i));: $i-$j;done)     再現する
    | (for n;do if((i));: $i-;done)         再現する
    | (if((i));: $i-;:)                     再現する
    | (:;$i-;:)                             再現しない
    | (:;: $i-;:)                           再現する
    |
    | 結局以下で発生するという所までは突き止めた。
    |
    | 11:(:;: $i-;:)
    | 8:(:;then : $i-;:)
    | 14:(:;then : $i-;;:)
    |
    | (: $i-;:) でも再現する。更に then でなくても良い様だ。
    |
    | 9:(: $i-;:)
    | 6:(echo : $i-;:)
    | 13:(echo : $i-;i;:)

    更に (:: $i-;:) から始めても再現する。
    最初の空白挿入操作で既に変な状態になっていると考えられる。

    10:(:: $i-;:)
    3:(: : $i-;:)
    10:(: : $i-;i;:)

    初期状態
    _ble_syntax_attr/tree/nest/stat?
    12*a    000 '(' |  nest=(CMDXE w=- n=- t=-:-) stat=(CMDX w=- n=- t=-:-)
     2*aw   001 ':' || stat=(CMDX1 w=- n=@0 t=-:-)
     2*aw   002 ':' |+ word=CMDI:1-3/(wattr=216173653992204032) stat=(CMDI w=CMDX1:1- n=@0 t=-:-)
     3*a    003 ' ' |
    14*a    004 '$' || stat=(ARGX w=- n=@0 t=$3:-)
     7*a    005 'i' ||
     4*a    006 '-' |+ word=ARGI:@2>4-7/(wattr=d) stat=(ARGI w=ARGX:4- n=@0 t=-:$3)
    12*a    007 ';' |  stat=(ARGX w=- n=@0 t=$7:-)
     2*aw   008 ':' |+ word=CMDI:@6>8-9/(wattr=72057594037930241) stat=(CMDX w=- n=@0 t=$7:-)
    12*a    009 ')' +  word="(":0-10>@8 stat=(ARGX w=- n=@0 t=$9:-)
     |    s 010 ^@    stat=(CMDXE w=- n=- t=$10:-)


    空白挿入後の状態 (yが正しい状態でxが異常になった状態)
    --- D0000.b.y.txt^I2020-04-14 12:58:01.259916873 +0900
    +++ D0000.b.x.txt^I2020-04-14 12:56:49.470879943 +0900
    @@ -2,12 +2,12 @@
     12 a    000 '(' |  nest=(CMDXE w=- n=- t=-:-) stat=(CMDX w=- n=- t=-:-)
      2 aw   001 ':' |+ word=CMDI:1-2/(wattr=72057594037930241) stat=(CMDX1 w=- n=@0 t=-:-)
      3 a    002 ' ' |
    - 4 a    003 ':' |+ word=ARGI:@1>3-4/(wattr=m1:d,$:d) stat=(ARGX w=- n=@0 t=$2:-)
    - 3 a    004 ' ' |  stat=(ARGX w=- n=@0 t=$4:-)
    -14 a    005 '$' || stat=(ARGX w=- n=@0 t=$4:-)
    + 4 a  s 003 ':' |+ word=ARGI:@1>3-4/(wattr=m1:d,$:d) stat=(ARGX w=- n=@0 t=$2:-)
    + 3 a  s 004 ' ' |  stat=(ARGX w=- n=@0 t=$4:-)
    +14 a  s 005 '$' || stat=(ARGX w=- n=@0 t=$4:-)
      7 a    006 'i' ||
    - 4 a    007 '-' |+ word=ARGI:@3>5-8/(wattr=d) stat=(ARGI w=ARGX:5- n=@0 t=-:$4)
    -12 a    008 ';' |  stat=(ARGX w=- n=@0 t=$8:-)
    - 2 aw   009 ':' |+ word=CMDI:@7>9-10/(wattr=72057594037930241) stat=(CMDX w=- n=@0 t=$8:-)
    -12 a    010 ')' +  word="(":0-11>@9 stat=(ARGX w=- n=@0 t=$10:-)
    + 4 a    007 '-' |+ word=ARGI:@3>5-8/(wattr=d) stat=(ARGI w=ARGX:5- n=@1 t=-:$4)
    +12 a  s 008 ';' |  stat=(ARGX w=- n=@0 t=$8:-)
    + 2 aw s 009 ':' |+ word=CMDI:@7>9-10/(wattr=72057594037930241) stat=(CMDX w=- n=@0 t=$8:-)
    +12 a  s 010 ')' +  word="(":0-11>@9 stat=(ARGX w=- n=@0 t=$10:-)
      |    s 011 ^@    stat=(CMDXE w=- n=- t=$11:-)


    [原因]

    | 更新範囲を見てみると ": : " の4文字だけなので、
    | これは shift の失敗によって起こっている不整合である。
    | では何故 shift に失敗するのか。shift のバグは流石にもうないと思っていたのに。
    | 而も、shift が起こる条件が良くわからない。他の場合には起こっていなかった筈である。
    | 不思議なのはその他の nest の shift はちゃんとできているという事。
    | "-" に設置されている stat の nest だけ shift できていない。
    |
    | shift.stat を観察してみた。ここで stat の中にある nlen を更新している。
    | 然し、何か変である。というか shift を実行する前から既に shift 済みの気がする。
    | 一体どういう事だろうか。或いは j=7 というのは shift 前のインデックスという事か。
    | だとすると j=6 に対して shift.stat が呼び出されていないという事になる。
    | j=7:nlen=7:beg=2:end0=2:shift=1
    |
    | →確認してみた所配列の再配置は shift の後だった。つまり j は shift 前の位置である。
    | そして shift.stat が呼び出されていないという事なのだろうと思われる。
    | というのも shift.stat は全体に対して実行しているのではなくて、
    | 必要のありそうな物を tree-enumerate で列挙するという形になっている様だから。
    |
    | * shift.method2 の実装に関する記録を探す。
    |   要するにこの shift.method2 が悪いというのは明らかであるが、
    |   そもそも何故この様な複雑な事をしているのだったか。
    |   done.txt を method2 で検索しても見つからない。
    |   blame を確認すると e74c1163 と書かれている。
    |   日付は 2016-04-07 になっている。#D0321 に議論が残っている。
    |   結構複雑な変更だったのだろうか。議論がごちゃごちゃとしていて分からない。
    |   どうも tplen と tclen に関しては単語内部に対する探索を実行しているが、
    |   nlen に対しては何らかの仮定の下にスキップを行っている。
    |   そしてその仮定が崩れているのではないかというのが今回の問題点。
    |
    |   また別の shift.impl2 に関する議論は #D0223 にある。
    |   然し、こちらは単純なバグ修正なので深い事は何も書かれていない。
    |
    |   結局見つからない。結局改めて何が行われているかコードを読まなければない。
    |
    |   shift として何が必要かについて考える。
    |   wlen, nlen, tplen, tclen 等は全て相対位置で記録しているので、
    |   基本的には shift は必要ないはずである。shift が必要になるのは、
    |   wlen, nlen, tplen, tclen が変更領域に跨っている場合と考えられる。
    |   shift 対象としては stat / tree / nest の3種類がある。
    |
    | shift.stat では stat 内の情報と beg/end0 の情報だけで更新している。
    | 変更領域を超えた参照についてはそのまま shift して、
    | 変更領域内部 (inclusive) に対する参照については消滅した物として、
    | 参照点を変更領域末端まで移動する。
    | shift.tree も実質同様である。shift.nest も同様であった。
    |
    | shift.stat, nest に関しては j2 まで全て呼び出す形になっている?
    | 但し、変更領域の後の nest の内部にある物に関してはスキップできる。
    | 何故ならば参照はその中で閉じている筈だから。
    |
    | * 或いは最近の TE_nofs に関係する修正でバグが埋め込まれた可能性もあるだろうか?
    |   TE_nofs etc の様に変数名を書き換えたのは 9cb35832 である。
    |   試しに 9cb35832~ を checkout して見たが同じ問題が発生している。
    |   v0.2-master でも発生した。v0.1-master では発生していない気がする。
    |   どうやら #D0321 の e74c1163 の段階では発生していなかった様である。
    |
    |   犯人は分かった 035ad68 この commit で問題が発生する様になっている。
    |   2017-02-25 の事である。#D0364 が該当する項目である。
    |   さて、実際に修正した内容を確認すると…。うーん。
    |   _shift2_j=j の位置を変更しただけである。
    |   という事は元からあったバグがこれで発現しただけという事なのだろうか。

    但し単語内部の場合には外側の nest に対して参照がある可能性がある。
    そう考えるとスキップできる tree というのは nest に限られるのでは。
    →やはりこれが悪い様に思われる。

    取り敢えず、スキップするのは nest の時だけにする事にした。問題は発生しなくなった。

    ? 単語ごとに nest を設置しないのは何故か。
      というよりそもそも何故 nest を単語の時に更新していなかったのか。

      * nest を辿る事によって文法の解釈を変えたりという事に nest を使っている。
        然しこれは主に単語の内部での解釈についてなので
        実は単語ごとに nest を作っても大した影響はないのではないか。
        →nest-type を呼び出している箇所を確認したが、
          やはり単語でも nest を作る様にして問題は発生しない様に感じる。
      * また解析状態一致の判定にも使っている。実は解析状態一致の判定に関しては、
        寧ろ単語ごとに nest を作った方が都合が良いのかもしれない。
      * そもそも "単語" という概念と "nest" という概念を独立に管理する必要はあるのだったか。
        解析状態に wlen と nlen の両方があるがその必要は本当にあったのだろうか。
      * 解析状態の一致判定に時間がかかる様になるかもしれない。
        というのも一致を判定する為に毎回 nest 配列の中身を辿る必要が出てくるから。
        単語に対しても nest を作る様にしてしまうと毎回辿る nest が多くなってしまう。

      始めから再設計するのだとしたら nlen と wlen は統合した気がするが、
      現在の実装でそうなっている以上は敢えて変える必要もないように感じている。
      wlen/nlen をくっつけると多少効率が下がるかもしれないし、
      また解析器の部分を全体的に書き換えなければならなくなる可能性がある。
      別に其処までしなくても良いという様に感じている。


    ? 単語の場合でもその文脈に於ける nest が空であればスキップできるのではないか。
      * tree 構造に nlen は記録していただろうか。ble_debug で観察すると記録していない気がする。
        実際に確認したが記録はしていない様だ。単語の場合には wlen を nest の場合には nlen を記録している。
        つまり、単語の場合に外側の nlen を記録するという事はしていないのである。
        寧ろ、nlen は stat の側にしか記録していない。

      或いは単語と同じ位置に記録してある stat の中にある nlen を参照するという手もある。
      然し、単語の終端に必ず stat が設置されているかどうかは非自明である、
      少なくともそういう要求を意識して実装はしていない。
      見た感じは一致している様にも見えるが際どい。

      * 然し、よく考えてみればこれでスキップできる様にしたとしても、
        結局 $() 等の構造の内部では余り意味がない。
        結局 ${} 等の nest を作る構造単位で飛ばすという処理だけでしか
        本質的には高速にする事ができない。
        その様に考えると単語の時にわざわざ nest が空かどうかを判定しても仕方がない気がする。
        一方で、設計の綺麗さよりも効率を考えるのであれば、やはりトップレベルで沢山コマンドを
        入力する場合が大半であるから、そう考えると nest をチェックしても良い。

      色々考えると、単語の場合に nest の情報を無理して取得してスキップをするのは
      現在の実装を考えると余り綺麗ではない上にそんなに効率化する訳でもない気がする。
      という事から対応しない事にする。
      スキップはネストの時にだけ行う事とする。

  * edit: set +H としても次のコマンドの実行の時には履歴展開が有効になってしまう [#D1332]
    set -H についても記録・復元するべきである。

    というよりもそもそも何故 set -H が設定されているのだったか。
    D0110 によるとそもそも履歴展開が実行されないということの様だ。
    確かに自前で history -p を呼び出して履歴展開を実行している。
    という事は eval では履歴展開は発生しないという事を意味する。
    set -H は履歴展開を起こす為に念の為に設定した物であって、
    特にいま history -p を使って自前で展開しているので不要である。
    単に削除する事にする。

  * 棄却 2020-04-02 highlight: hello! () { echo; } として hello! としても関数名着色にならない [#D1331]
    と思ったがこれは履歴展開を含む単語は単純単語ではないと判断される為である。
    更に、単語の境界が必ず履歴展開の終端とも限らない。
    例えば echo hello!; は !; で履歴展開になっている。
    従って hello! の部分だけ見て ! が末端にあるからと言って、
    それが履歴展開にならないという事は保証できないのである。
    これは対応しない。

  * syntax: ${#@a} の着色 [#D1330]
    どうも $@ に修飾 # とごみ a がついていると解析している気がする。
    然し、実際には $# に修飾 @a がついていると解釈するべきである。
    他に ${##0} もエラー着色になっている。
    これは ${##} に 0 がついているという具合に解釈されている気がするが
    実際には $# に #0 という修飾がついているという様に
    解釈しなければならないのである。

    関連して現在の実装では ${-[@]} の様な物も許容されているが、
    これは実際の bash では許容されない組み合わせである。
    これらについて正しく判定する事は可能だろうか。

    可能な組み合わせについて全て列挙すれば良いのだろうか。
    特に一文字特別パラメータについては別に取り扱えば良い気がする。

    * 現在の実装では先ず初めに普通の変数名の場合には
      ${var} ${!var} ${#var} ${!var@} ${!var[@]} ${var[@]} ${var@flags} 等が存在する。
      うーん。整理すると以下の 9 の組み合わせが存在して、 ${#var@} だけが定義されていない。
      因みに ${var[0]} 等の場合の取り扱いは ${var} の時と全く同様である。

        ${var}    ${var[@]}   ${var@}   ${var[@]@}
        ${!var}   ${!var[@]}  ${!var@}  ${!var[@]@}
        ${#var}   ${#var[@]}  ${#var@}  ${#var[@]@}

      それぞれ以下の意味を持つ。
        普通の展開  配列一覧      フラグ   配列フラグ
        間接参照    配列キー一覧  変数名   間接参照*2
        文字数      配列要素数    <Error>  <Error>

        *1: 3列目に関してはフラグはなくて良いが4列目に関してはフラグ文字は1文字以上必要?
          と思ったがそうではなくて変数が定義されていない場合はフラグがなくても良い。
          変数が定義されている場合にはフラグがないとエラーになってしまう。
        *2: 何故か全要素を結合した文字列を一つの変数として扱おうとする。

      うーん。振る舞いを見ていると @Flag に関しては寧ろ [-+^,?] と同じ取扱の気がする。
      特に # の後には続けられないという点はそれに同じである。
      但し、${!var@} は特別に取り扱わなければならない。${!var@F} とするとエラーになる。

    * またパラメータの場合にはどうなっているだろうか。
      試してみると色々の気がする。取り敢えず数字パラメータから調べる。
      基本的には普通の変数と同じだが配列添字の形式が存在しない、という事が違う。

        ${1}  ${1@}
        ${!1} ${!1@}
        ${#1} ${#1@}=err

    * 特殊パラメータの場合はどうか。先ず - や ? の場合にはどうか。
      これらは特に迷う事もなく、位置パラメータと同じ取扱の気がする。

    * @ や * の場合は何だか良くわからない。
        ${@}  ... これは位置パラメータ一覧
        ${!@} ... これは "\${$*}" と取り扱われる様だ。
        ${#@} ... これは $# に等価の様である。
                  $# に @Flag がついているのかと思いきや ${#*} でも同様に動く。
                  然し ${#@Q} とすると $# に @Q という動作になる。
        ${@@} ... これはちゃんとフラグとして取り扱われる。
        ${!@@} ... これも ${!@} に対するフラグになっている様だ。
        ${#@@} ... これはエラーである。

    * # の場合
        $# ... これは位置パラメータの数
        ${!#} ... これは $# の間接参照である。つまり "\$$#" という事で最後の引数を取るのに使える。
        ${##} ... これは $# の文字数を数えている。
        ${#@} ... これは上述の解釈が優先される? そして ${#@Q} だと $# + @Q になる。
        ${!#@} ... これはエラーになるが ${!#@Q} は ${!#} + @Q という解釈に為る。
        ${##@} ... これはエラーにならない。恐らく $# + #@ という解釈になっている。

    * ! の場合
        $! ... PID
        ${!!} ... これは履歴展開になってしまう。履歴展開を off にするとエラー。
        ${#!} ... これは 0 に展開された。どういう事だろうか。
                  →sleep 1 & してからだとちゃんと有限の値、文字数に展開された。
                  つまり $! の文字数を数えている。
        ${!@} ... (上記) これは $@ の間接参照という取り扱いになっている。
        ${!!@} ... これはどうやってもエラーである。
        ${#!@} ... これもどうやってもエラーになってしまう。

    * 取り扱いを纏めると、パラメータ展開の内容は

      (1) 前置詞: !, #
      (2) パラメータ名: var var[0] var[@] 1 - @ # ! の何れかに分類できる。
      (3) 後置修飾: #... %... //... @... -... +... ?... など色々。
          但し、前置詞 # がついている時にはパラメータ名の直後で終了しなければならない。
          空白が入る事もない。

      * 例外的な形式として ${!var@} という物がある。
        これは var@ というパラメータ名という訳でもない。
        後置修飾できないし、! の前置修飾という解釈も難しい。
        つまり特別に許された形であるという様に解釈できる。
        既に現在の実装で特別に取り扱って実装する様になっているのでこれはそのまま。

      * 前置詞 # と本体 # と 後置修飾 # は紛らわしいが、
        1. 一番はじめの文字が # だった時には ${#ParamName} に一致するか確認。
        2. もしその形式で解釈できない時は 1 文字目をパラメータ名として解釈。
        という順番で処理されている様に見える。少なくともそうすれば一致する。

    ble.sh の実装ではどの様に取り扱うべきか。
    取り敢えず、@... に関しては別に取り扱う事にする。
    \[ に関しては var の形式のときにだけ許容する様に変更する。
    先に ${#param} を試して、それで駄目だった時に ${param...} 及び ${!param...} を試す。

    x fixed: ${var@} がエラー着色になっている。
      これは空のフラグとして処理されているのだろうか。
      →bash 4.3 で駄目で bash 4.4 から許容される様になっているので空のフラグという事である。

    実装した。実際に動かして試してみる事にする。

    x fixed: ${!var@Q} の着色が異なっている。${!var@} の特別扱いはすぐに } で閉じている時だけでは。
    x ${!1} がエラー着色になる。${!-} もエラー着色になる。
    - ok: ${#var[@]@Q} は実際にはエラーだが許容している。
    - ok: ${!!@} も bash ではエラーだが許容する様になっている。

2020-04-12

  * util (conditional-sync): サブシェルで実行しているのは何故か [#D1329]
    テストを書いていて気づいたが check 用のコマンドで親環境を参照・変更する事ができない。
    考えてみれば同期的なサブシェルなので
    親環境の変数は変化しないので直接親に取りに行く必要はない。
    そして cancel-check のコマンドが副作用を持つというのも変である。
    然し、変更できないというのは不便な気もする。

    * そもそもサブシェルで実行する必要はあったのだろうか。
      記録を探すと #D1080 である。然し、議論には詳しいことは何も書かれていない。
      一行 "遅くならないように修正した" としか書かれていない。
      うーん。特に問題もなかったのではないかという気がしてきた。
      サブシェルを除いてみる事にする。
      →特に変化は見られない様である。

      と思ったが分かった気がする。内部で & を使ってコマンドを起動している。
      直接対話シェルでこれを実行すると jobs の変なメッセージが表示されて邪魔になる。
      丁度 ble/util/visible-bell で同様にサブシェルの中から & を使ってコマンドを起動している。
      少し試してみた限りでは conditional-sync では問題は発生していないが、
      何らかの条件で表示される可能性がある。という事なので現状のままサブシェルで実行する事にする。

    * というか現在の実装でこれが功を奏している様に見えない。
      相変わらず c と打つと処理に時間がかかっている様な気がする?
      →実際に試してみると実は conditional-sync が使われていない様だ。
      実装を確認してみた所、補完文字列が空の時にのみ conditional-sync
      が使われるということの様である。

      一文字cだけの時でもかなり時間がかかっている。5.8s-6s かかっている。
      cに対する候補の数はそんなに多くない。279件である。
      因みに0文字の時には 20s かかっている様だ。
      2文字 'cd' の時には、0.074sである。
      総合するに、何か時間のかかるコマンドが存在している?
      →調べると cy で 4.9s かかっている。

      もっと全体的に調べてみる事にする。
      function measure-compgen { { time compgen -A command -- "$1" | wc -l >&3; } 2>&1 | head -2; } 3>&1

      a   216 real 0m0.750s  k 105 real 0m0.535s  u 150 real 0m0.614s   4 1 real 0m0.118s
      b  2270 real 0m0.518s  l 250 real 0m0.929s  v  54 real 0m0.293s   5 1 real 0m0.129s
      c   297 real 0m5.649s  m 323 real 0m0.853s  w 178 real 0m0.567s   6 1 real 0m0.116s
      d   252 real 0m0.826s  n  81 real 0m0.292s  x 336 real 0m1.249s   7 1 real 0m0.116s
      e   108 real 0m0.384s  o  53 real 0m0.299s  y   9 real 0m0.156s   8 1 real 0m0.118s
      f   178 real 0m0.669s  p 396 real 0m1.173s  z  46 real 0m0.261s   9 1 real 0m0.127s
      g   291 real 0m1.144s  q  42 real 0m0.260s  0   0 real 0m0.140s
      h    80 real 0m0.341s  r 155 real 0m0.540s  1  11 real 0m0.114s
      i   248 real 0m1.071s  s 298 real 0m0.817s  2  11 real 0m0.114s
      j    18 real 0m0.165s  t 297 real 0m1.039s  3   1 real 0m0.118s

      A  15 real 0m0.165s  K   3 real 0m0.184s  U  10 real 0m0.141s  [   4 real 0m0.141s
      B  15 real 0m0.143s  L  16 real 0m0.153s  V   6 real 0m0.137s  ]   1 real 0m0.128s
      C 134 real 0m0.204s  M  41 real 0m0.189s  W  75 real 0m0.256s  {   1 real 0m0.128s
      D  59 real 0m0.185s  N  23 real 0m0.151s  X  24 real 0m0.186s  }   1 real 0m0.127s
      E  11 real 0m0.131s  O   8 real 0m0.132s  Y   0 real 0m0.119s
      F  15 real 0m0.141s  P  34 real 0m0.159s  Z   1 real 0m0.128s
      G   7 real 0m0.125s  Q   0 real 0m0.137s  !   1 real 0m0.114s
      H  12 real 0m0.144s  R  40 real 0m0.157s  .   2 real 0m0.166s
      I  12 real 0m0.137s  S  61 real 0m0.200s  :   1 real 0m0.125s
      J   0 real 0m0.120s  T  17 real 0m0.156s  @  18 real 0m0.125s

      この結果を見ると 1 文字の時は全般に遅い。

      ca 18 real 0m0.191s ck 2  real 0m0.126s cu 5  real 0m0.140s c4 0 real 0m0.116s
      cb 0  real 0m0.125s cl 43 real 0m0.203s cv 0  real 0m0.120s c5 0 real 0m0.115s
      cc 4  real 0m0.138s cm 9  real 0m0.156s cw 2  real 0m0.125s c6 0 real 0m0.122s
      cd 2  real 0m0.163s cn 0  real 0m0.127s cx 0  real 0m0.115s c7 0 real 0m0.142s
      ce 23 real 0m0.185s co 61 real 0m0.262s cy 16 real 0m4.925s c8 2 real 0m0.120s
      cf 2  real 0m0.135s cp 12 real 0m0.145s cz 2  real 0m0.134s c9 2 real 0m0.118s
      cg 2  real 0m0.126s cq 0  real 0m0.136s c0 0  real 0m0.123s
      ch 35 real 0m0.285s cr 12 real 0m0.163s c1 0  real 0m0.150s
      ci 3  real 0m0.143s cs 9  real 0m0.144s c2 0  real 0m0.116s
      cj 2  real 0m0.119s ct 21 real 0m0.187s c3 0  real 0m0.120s

      ga   7 real 0m0.151s  gk   2 real 0m0.141s  gu   2 real 0m0.160s  g4   0 real 0m0.130s
      gb   5 real 0m0.139s  gl  18 real 0m0.203s  gv  40 real 0m0.283s  g5   0 real 0m0.120s
      gc  20 real 0m0.179s  gm   0 real 0m0.144s  gw   0 real 0m0.117s  g6   0 real 0m0.116s
      gd  22 real 0m0.229s  gn  14 real 0m0.187s  gx   0 real 0m0.130s  g7   1 real 0m0.129s
      ge  33 real 0m0.218s  go   2 real 0m0.124s  gy   0 real 0m0.137s  g8   0 real 0m0.117s
      gf   6 real 0m0.145s  gp  14 real 0m0.176s  gz   4 real 0m0.141s  g9   0 real 0m0.132s
      gg   0 real 0m0.119s  gq   0 real 0m0.141s  g0   0 real 0m0.118s
      gh   0 real 0m0.147s  gr  30 real 0m0.249s  g1   0 real 0m0.130s
      gi  14 real 0m0.221s  gs  22 real 0m0.183s  g2   0 real 0m0.113s
      gj   0 real 0m0.119s  gt  32 real 0m0.278s  g3   0 real 0m0.125s

      ia   0 real 0m0.129s  ik   0 real 0m0.126s  iu   0 real 0m0.130s  i4   0 real 0m0.131s
      ib  11 real 0m0.154s  il   0 real 0m0.117s  iv   0 real 0m0.117s  i5   0 real 0m0.116s
      ic  10 real 0m0.153s  im  19 real 0m0.196s  iw   2 real 0m0.116s  i6 126 real 0m0.722s
      id   5 real 0m0.141s  in  33 real 0m0.225s  ix   0 real 0m0.117s  i7   0 real 0m0.125s
      ie   5 real 0m0.126s  io   0 real 0m0.129s  iy   0 real 0m0.134s  i8   0 real 0m0.127s
      if   8 real 0m0.149s  ip  11 real 0m0.156s  iz   0 real 0m0.116s  i9   0 real 0m0.114s
      ig   1 real 0m0.114s  iq   0 real 0m0.116s  i0   0 real 0m0.128s
      ih   0 real 0m0.128s  ir   3 real 0m0.121s  i1   0 real 0m0.115s
      ii   0 real 0m0.118s  is  13 real 0m0.142s  i2   0 real 0m0.117s
      ij   0 real 0m0.148s  it   0 real 0m0.129s  i3   0 real 0m0.118s

      la  32 real 0m0.198s  lk   2 real 0m0.127s  lu  17 real 0m0.194s  l4   2 real 0m0.138s
      lb   0 real 0m0.150s  ll   3 real 0m0.129s  lv   0 real 0m0.125s  l5   0 real 0m0.114s
      lc   4 real 0m0.123s  lm   0 real 0m0.128s  lw  10 real 0m0.131s  l6   0 real 0m0.119s
      ld   8 real 0m0.149s  ln   4 real 0m0.142s  lx  60 real 0m0.380s  l7   0 real 0m0.115s
      le  10 real 0m0.146s  lo  22 real 0m0.197s  ly  10 real 0m0.132s  l8   0 real 0m0.126s
      lf   0 real 0m0.128s  lp   7 real 0m0.140s  lz  22 real 0m0.204s  l9   0 real 0m0.133s
      lg   0 real 0m0.133s  lq   0 real 0m0.137s  l0   0 real 0m0.123s
      lh   0 real 0m0.115s  lr   2 real 0m0.129s  l1   0 real 0m0.118s
      li  16 real 0m0.197s  ls   9 real 0m0.137s  l2   0 real 0m0.124s
      lj   0 real 0m0.132s  lt   6 real 0m0.126s  l3   2 real 0m0.117s

      pa  21 real 0m0.195s  pk  16 real 0m0.182s  pu  11 real 0m0.160s  p4   0 real 0m0.117s
      pb   2 real 0m0.138s  pl  11 real 0m0.161s  pv   0 real 0m0.124s  p5   0 real 0m0.119s
      pc  11 real 0m0.138s  pm   6 real 0m0.144s  pw   4 real 0m0.128s  p6   0 real 0m0.120s
      pd  62 real 0m0.301s  pn   3 real 0m0.125s  px   0 real 0m0.117s  p7   0 real 0m0.115s
      pe  28 real 0m0.168s  po  38 real 0m0.194s  py  38 real 0m0.248s  p8   0 real 0m0.115s
      pf  10 real 0m0.144s  pp   6 real 0m0.131s  pz   0 real 0m0.117s  p9   0 real 0m0.123s
      pg   4 real 0m0.140s  pq   0 real 0m0.116s  p0   0 real 0m0.130s
      ph   1 real 0m0.119s  pr  44 real 0m0.227s  p1   2 real 0m0.128s
      pi  12 real 0m0.185s  ps  43 real 0m0.244s  p2   2 real 0m0.126s
      pj   0 real 0m0.115s  pt  20 real 0m0.181s  p3   0 real 0m0.129s

      ta  20 real 0m0.188s  tk   2 real 0m0.126s  tu   2 real 0m0.143s  t4   2 real 0m0.135s
      tb   2 real 0m0.130s  tl   6 real 0m0.137s  tv   0 real 0m0.130s  t5   0 real 0m0.134s
      tc  23 real 0m0.201s  tm   2 real 0m0.119s  tw   2 real 0m0.125s  t6   0 real 0m0.126s
      td   5 real 0m0.135s  tn   0 real 0m0.121s  tx   0 real 0m0.115s  t7   0 real 0m0.121s
      te  92 real 0m0.390s  to   6 real 0m0.151s  ty   7 real 0m0.122s  t8   0 real 0m0.127s
      tf  12 real 0m0.187s  tp   9 real 0m0.151s  tz   6 real 0m0.147s  t9   0 real 0m0.117s
      tg   6 real 0m0.136s  tq   0 real 0m0.132s  t0   0 real 0m0.122s
      th   3 real 0m0.134s  tr  25 real 0m0.194s  t1  22 real 0m0.226s
      ti  10 real 0m0.146s  ts  14 real 0m0.164s  t2   0 real 0m0.116s
      tj   0 real 0m0.120s  tt  19 real 0m0.188s  t3   0 real 0m0.115s

      xa   6 real 0m0.143s  xk  14 real 0m0.188s  xu   0 real 0m0.119s  x4   0 real 0m0.136s
      xb   0 real 0m0.131s  xl  14 real 0m0.163s  xv   4 real 0m0.143s  x5   0 real 0m0.116s
      xc  23 real 0m0.185s  xm  28 real 0m0.215s  xw  13 real 0m0.141s  x6   0 real 0m0.129s
      xd  36 real 0m0.239s  xn   0 real 0m0.125s  xx   2 real 0m0.134s  x7   0 real 0m0.115s
      xe   8 real 0m0.153s  xo   4 real 0m0.141s  xy   0 real 0m0.126s  x8  80 real 0m0.464s
      xf  14 real 0m0.179s  xp  14 real 0m0.155s  xz  20 real 0m0.198s  x9   0 real 0m0.115s
      xg   2 real 0m0.141s  xq   0 real 0m0.119s  x0   2 real 0m0.129s
      xh   4 real 0m0.124s  xr   6 real 0m0.137s  x1   6 real 0m0.144s
      xi  10 real 0m0.147s  xs  21 real 0m0.186s  x2   0 real 0m0.128s
      xj   0 real 0m0.118s  xt   4 real 0m0.135s  x3   0 real 0m0.116s

      cy i6 lx te x8 辺りの組み合わせが重い。cy は cygwin だろう。
      i6 と x8 は i686 と x86 であろう。te は tex で lx は lx の様だ。
      3文字だと i68 0.7s x86 0.4s cyg 4.9s が重い。
      4文字だと cygg 0.7s cygc 0.5s cygp,cygf,cygk 0.4s が重い。

  * edit: bash-5.1 PROMPT_COMMANDS 及び READLINE_MARK [#D1328]
    bash 5.1 のこれらの機能にはいずれ対応しなければならない。
    簡単に対応できるのでもう対応してしまう事にする。

  * decode: ble-0.3 を使うと二回目以降の起動で ble/widget/ が見つからない [#D1327]
    というエラーが沢山発生してまともに操作する事ができなくなる。
    調べると decode table が変な事になっている。
    複数の要素からなる項目が全て分割されてしまっている。
    初期化した直後は配列の内容はちゃんとしているが、すぐに変な状態になる。
    何処か別の場所で書き換えているとは考えがたい。

    と思って書き換わっている場所を探っていった所、
    cmap/initialize の中で壊れていた。そこで分かった。
    cmap のキャッシュを記録する時に keymap のキャッシュもダンプしている。
    それによって keymap が上書きされてしまうのであった。
    特に容量を減らす為に cmap のダンプの出力から引用符を削除していたので
    cmap を再ロードした時に複数の単語からなる binding が全て分割されてしまっていたのだった。

    これについては ble-bind を実行する前に cmap/initialize を
    実行する様にして、更に cmap/initialize の中のキャッシュの記録についても
    cmap に関係のある行だけを選別して保存する様に修正した。
    取り敢えずこれで直った様である。
    0.4 の方でも安全の為に cmap に関係のある行だけを選別して記録する事にした。

  * util: has-glob-pattern の判定がサブシェルの中ではできない [#D1326]
    failglob を使って判定しているがサブシェルの中だと
    eval を用いて評価していたとしてもその場で終了してしまう。

    サブシェルの中でも failglob が発生しない様にする方法はあるのか。
    例えば nullglob を用いるという手があるのではないか?

  * util: ble/util/print-global-definitions で未定義変数と配列に対応する [#D1325]

    ble/util/print-global-definitions で定義されていない変数が
    空の変数名として抽出される様になっている。
    unset という事を検出する事は可能だろうか。

    そもそも宣言されていないという事と宣言されているけれども unset である
    という事は今回は区別しない事にする。そもそも途中でローカル変数が定義されている時、
    "宣言されていない" という状態にするのは不可能なので、
    状態を再現するとしても "宣言しているが unset" という状態にするしかない。

    unset であるという事を検出する事はできるか。試してみた所できる様子である。

    * 配列に対応できていないという事が判明した。実は現在の用途では配列要素を指定する
      という事は無いような気がするけれども、関数の設計としては配列名であっても
      正しくグローバルに於ける配列を取得できる様にしておくべきである。

      配列かどうかの判定はどうするか。配列かどうかの判定は。
      is-array を用いているが、実はこの関数は、普通の配列と連想配列を判定できない。
      is-array の実装を見直すべきだろうか。改めて is-array の実装を計測してみた。
      compgen による方法は遅い。実は ble/util/assign declare -p した方が速いのでは。
      と思って実測してみたらそうだった。これは declare -p による方法に切り替える必要がある。

      配列の場合には実装はどの様にするべきだろうか。
      値を value=("${name[@]}") でコピーする方式だと飛びの在る配列の時に中身が変化する。
      一つずつ key を抽出して保存するのも大変である。
      ということであれば declare -p の出力をそのまま使う?
      然し、declare -p の出力には様々なバグが有るという事が判明している。
      そうすると declare-print-definiitions を呼び出す事にするか。
      それはそれで計算量が大きい。然し他に手段はないのである。
      或いは新しい bash の場合には declare -p を呼び出して、
      古い問題のある bash の場合には declare-print-definitions を呼び出す?

      調べると修正が必要になるのは bash-3.2 以下の様である。

    * fixed: さて値を unset にする為には declare && unset すれば良いだろうと思っていたら
      何と思うように動いてくれないという事が判明した。変だ。
      localvar_unset が実装されたために振る舞いが変わったという事なのだろうか。

      | →何と a=1 f として呼び出した時と、a=1; f として
      | 呼び出したときで a の振る舞いが異なる? どうも a=1 f として呼び出すと、
      | f のローカル変数として定義される? いや何だか変である。よく分からない。
      |
      | 以下は全ての bash 3.0..5.0 で declare -x a=1 が表示される。
      | $ bash -c 'f1() { local a; declare -p a; }; a=1 f1'
      |
      | 以下は 4.1 以下では declare -x a= であり、
      | 4.3 では変数が見つからず、他は declare -x a である。
      | $ bash -c 'f1() { local a; declare -p a; }; export a=1; f1'
      |
      | 以下は 4.3 以下では変数が見つからず 4.4 以降では declare a である。
      | $ bash -c 'f1() { local a; unset -v; declare -p a; }; export a=1; f1'
      |
      | 以下を試しても特に振る舞いの違いは見えない。
      | bash -c 'f1(){ local a;unset -v a;declare -p a;};f2(){ local a=1;f1;};f2'
      |
      | では何故テスト環境でだけ上の変数が再び見える様になってしまっているのか。
      | 或いは対話環境では別の振る舞いをするなどの違いが在るのだろうか。試してみる。
      | →対話環境でも振る舞いは同じである。然し ble.sh をロードしていると振る舞いが違う。
      |
      | eval の中で実行すると振る舞いが変わる? →そうではなかった。
      | $ eval 'f1(){ local a;unset -v a;declare -p a;};f2(){ local a=1;f1;};f2'
      |
      | bind -x の中で実行すると振る舞いが変わる? →そうでもなかった。
      | $ text='f1(){ local a;unset -v a;declare -p a;};f2(){ local a=1;f1;};f2'
      | $ bind -x '"\C-t": eval "$text"'
      |
      | shopt の違いが効いているのだろうかと思って確かめてみたが、
      | 違いは failglob と histappend histreedit, hostcomplete しかない。
      | これらは振る舞いには関係ないだろう。
      |
      | NOBLE=1 で起動しても再現しない。其処から source ble.sh すると再現する様になる。
      | 更にその後で ble-detach しても再現したままである。不思議だ。bash-4.4 でも再現する。
      | うーん。何らかの変数が効いているのか或いは、builtin の上書きが関係しているのか、
      | それとも何らかの操作をすると不可逆的に bash の振る舞いが変化してしまうのか。
      | というか一度はテストに通過していた気もする。
      |
      | bash-3.0..5.0 の全てでこの現象が再現している。謎である。

      状況をまとめると ble.sh をロードすると current-scope unset が
      dynamic に動作する様になってしまう。と此処まで書いて分かった。
      最近 unset を関数で上書きしてユーザが変更できない様にしたのだった。
      然し、そうすると unset の振る舞いが変化してしまう事になる。

      やはり unset を関数で上書きするのは悪手である。修正する。

    * fixed: 現在の ble/variable#has-attr の実装だと変数 attr に対して正しく取得できない。
      get-attr の場合にはインターフェイスから attr が取得できないというのは分かる。
      然し、has-attr の場合には attr について動作しないというのは不自然である。
      単に真偽値を終了ステータスで変え雨だけなのであるから。
      これは実際に ble/util/print-global-definition で使いたいので対応する事にした。


    * 実は bash-4.2 未満でも現在見ている変数がグローバルかどうか判定できるのではないか。
      というのもグローバル変数に対して -r を設定すると、
      ローカル変数としても定義する事が不可能になるから。
      ローカル変数に対して -r を設定した場合には新しく上書きする変数を定義できる。

      問題はグローバル変数に対して -r 属性を関数内から付加する事ができるのかという事。
      →readonly を使うとちゃんとグローバル変数に対して -r 属性を付加できた。
      →typeset -r を使った時には同じスコープに変数が作成される。

2020-04-11

  * 解消 2019-04-29 bashbug: #D1078 の bash-5.0 のバグを報告する? [#D1324]
    一応最新版で確認はしておいた方が良いかもしれない。
    と思ったが、どうせパッチを作るのであればその時に気づく筈である。

    2020-04-11 これは既に PATCH を報告済みである。

  * decode: bind --help の終了ステータスは 2 の様だ [#D1323]
    その他の buitlin も全て --help に対しては 2 で終了する様だ。

    exit unset bind read history trap を上書きしている。
    その内で正しく 2 を返しているのは unset, history のみである。
    確認した所、何れも本来の builtin は 2 を返している。
    bind exit read trap は修正する必要がある。

2020-04-10

  * complete: bash-dev で 10# のエラーが出ている [#D1322]
    "0>10#: invalid integer constant (エラーのあるトークンは "10#")"
    →これは簡単に修正できた。一箇所しか 10# はなかった。

  * failglob: bash-4.3 で $? を入力するとエラーメッセージが出る [#D1321]
    syntax highlighting が効いているのに違いないという気がする。
    特に変数の内容を調べるコードが怪しい気がする。
    うーん。get-attr だろうか→正にそれである。
    これは直った。

  * _ble_decode_input_buffer で不正な添字というエラーが発生する [#D1320]
    bash-4.1 以下で発生する様である。
    うーん。((i=-1,i>=0&&a[i--])) が bash-4.1 以下で駄目の様である。
    うーん。これは算術式のバグである。今まで知らなかったバグだ。
    →と思って確認したら既に分岐内の配列参照は実行されるという事が書かれている。
    唯、それが配列添字の中でも起こるという事は新たな発見であった。

    一応類似の物が存在しないか確認する。
    grc '(\|\||\?|&&)[[:alnum:]_]+\['
    取り敢えずは問題無さそうである。

2020-04-09

  * ble/util/openat は関数名を変更するべきでは [#D1319]
    openat という unix の関数が存在して、
    これは指定した fd からの相対パスでファイルを開くという物である。
    恐らく readlink で読みだしたリンク先を開くようなそういう関数なのだろう。

    名前が同じで機能が全く異なるのは良くないので名称を変えたい。
    また、ble/util/is-fd-open という関数も作成した。
    そういう事を考えると、以下の様な感じに改名すると良さそうな気がする。
      ble/fd#is-open
      ble/fd#alloc
      ble/fd#close

    うーん。この際なので解明する。

  * util: 実は openat で行っている fd の生死判定は : >&fd でできるのでは [#D1318]
    現在の実装では bash 4.0 以下では自分で適当な場所に fd を開いている。
    然し、既存の fd と被る場合には 3.0 では先に fd を閉じて置かなければならない。
    また 3.1 では fd を閉じても変な事になってしまう。
    仕方がないので 3.1 の時にだけ特別に fd が開いているかどうかを
    /dev/fd/.. または /proc/self/fd/.. で判定している。

    然し、実は : >&fd で判定できるのではないかという事。
    これならば環境依存せずに高速に判定する事ができる。
    内部的には dup2 を 3 回程度実行するだけの気がする。

    * ok: fdが再利用できない?
      然し、これによって今までは再利用していた fd が再利用されなくなって
      fd を無駄に使う様になってしまうのではないか。と思ったが、
      よく考えたら bash-4.1 以降では {fd}<> を使うので何れにしても再利用されない。
      bash 4.0 以下でだけ再利用する理由もないので、毎回判定する事にする。

      或いは、O_CLOEXEC を設定する方法があれば良い。。
      が少し考えてみたがその様な裏技の様な物はない気がする。
      或いは、export _ble_util_cloexec=10:11:12 等として上書き可能な
      fd を export して知らせるという手もあるが其処までする必要があるのかは謎である。

      総じて fd は再利用しなくても良いという様に結論づける。

    * ok: これによって openat_base は不要になったのではないか、と一瞬思ったが、
      ble.sh の側で重複判定をしていたとしても別のシェルプログラムが同じ領域を
      勝手に上書きして使うという事態になっていると結局問題が起こる。
      従って wiki の openat_base の説明は更新しなくても良い。

2020-04-08

  * test: テストフレームワークの整理 [#D1317]
    幾らか実装したので実装済みのものはこちらに移動する。

    * 単体テストの機能
      * done: 複数行 stdout を指定しやすくする?
      * done: stderr のチェック
      * done: テストのタイトル→これは '# title' の形式の単語で指定する。

    * その他の細かい動作について
      * done: start-section で自動的に end-section を呼び出す
      * done: start-section で開いた fd を閉じる
      * done: 並列テストに向けて一時ファイルが被らない様に BASHPID をファイル名に含める
      * done: diff のファイル名を分かりやすくする。

    * テストに BASHPID を使っているが bash-3 で使えない。
      bash-3 以下では sh -c $PPID を使って BASHPID を更新する事にした。
      と思ったが、これだと feature-test を使っている環境で変な事になるのでは?
      まあ、テストだけで使う様にすれば問題はない様な気がする。
      それ以外の場所では version を分けて local BASHPID 等とする事にする。

  * 2020-03-11 test: oilshell に Travis でテストを自動化せよと (suggested by andychu) [#D1316]
    実のところテストらしいテストは何もないのだが。
    自動化テストについて思うところ。

    →取り敢えずのテストの枠組みは形が見えてきたのでこれは考察済みという事にする。

    # そもそも何故そういう GitHub 上のテストを設定する気が余りしないのかというと、
    #
    # 1 先ず interactive session でないと ble.sh をロードしない様になっているので、
    #   其処を弄って特別に起動できる様にしなければならないという事。
    #   つまり、そもそもローカルでテストが自動化出来ていないのである。
    #
    # 2 GitHub 上でやるという事は不完全な形で push するという事を想定しているようで嫌だ。
    #   テストを自動化するぐらいであればローカルでちゃんとテストを通してから
    #   GitHub 上でテストを通すという事にするのが良い気がする。
    #   そもそも Travis は発火するまでに時間がかかる。それぐらいならば手許である。
    #
    #   然し、手許で毎回テストを実行する訳ではないし、
    #   複雑な事を実装している時に関係のない部分が火を吹いたりすると
    #   頭が混乱するのでテストは一括で行いたい様な気もしたり。
    #   色々考えるとやはり最低限は手許でテストしつつも
    #   自動化して GitHub 上での自動化されたテストにも頼るというので良いという気がする。
    #
    # 3 そして十分な数のテストが存在していないという事。
    #   これはテストを準備しなければならない。。
    #
    # 4 対話的なプログラムのテストを書くのは面倒だという事。
    #   特にテストケースの "正解" をどう記述するのかという事、
    #   どうやってそれを確認するのかという事。
    #
    #   然し、よく考えてみればそういうのはどのプログラムでも同じである。
    #   従って、結局どのプログラムでもテストという物は
    #   一般的なユーティリティの部分だけに留まって
    #   本質的な処理に近い部分のテストはおろそかになる物ではないかという気がする。
    #   なので余り気にせずにコア部分に近い部分だけテストしておけば良いという事なのかもしれない。
    #
    # というかよく考えてみると regression という物を殆ど経験していない。
    # それも大体作ったらそのままで変更する頻度はそんなにないという事。
    # それから変更する場合には実際に使っている箇所を大体ちゃんと確認するので、
    # regression が起こりにくいという事。
    # まあ全くないという訳ではないので多少は役に立つかもしれないというぐらい。
    # 自動化テストというのは一回通せば済むものではなくて、
    # 毎回テストする事に利点があるのである。つまり regression。
    # そういう意味では ble.sh の開発の形態自体が
    # 自動化テストをしなくても大丈夫な形に適合してしまっている。
    #
    # 一方で自動化する事によって新しいテストを書くという動機にはなって、
    # それによって得られる物は大きい気がする。
    # ただ毎回テストするという事には余り意味はないのかもしれないが。
    # 然しそれを言い出すとどのプロジェクトも結局同じ気もする。

2020-04-07

  * menu: menu が表示されている状態で確定すると [#D1315]
    INSERT の行が消える。というより座標計算もずれている気がする。
    今まで status がすぐに消えて何だろうと思っていたがこれで
    再現する事ができるのである。

    | 扨、何故これが起こるのだろうか。menu が表示されているというだけで、
    | 別に menu に入っているという訳ではない。うーん。不思議だ。
    |
    | clear-content の段階では特に問題は生じていない。
    | menu が表示されていない場合でも表示されている場合でもちゃんと初期ょしているし、
    | panel の高さの情報もちゃんと更新できている。
    |
    | そうすると ble-edit/info/reveal の方で問題が発生しているのだろうか。
    | うーん。不思議だ。ちゃんと動作している様に見える。
    |
    | 或いは _ble_canvas_x, _ble_canvas_y の座標がずれている?
    | →別に違いは見られない。
    |
    | うーん。どうも一瞬表示されてそれから消滅している様に見える。
    | 少なくとも高さの確保に失敗している事は確かである。表示している位置がずれている。
    | 追加されるべき行が追加されていない。

    →なんか変だと思ったら分かった。コマンドが実行される前に表示を実行している。
    menu/clear 経由で再描画されているのだった。これは #D1290 の変更が原因である。
    うーん。menu#clear で immediate-clear ではなくて単なる clear にしたら直った。
    clear の時には reveal が呼び出される迄は info の更新は行われないのである。

  * history: 履歴が倍加する現象が再度発生している [#D1314]

    [原因]

    遡ると 8cf17f7 で発生する様になっている。大分前である。
    前回の倍加問題の修正のすぐ後に再度発生する様になっている。
    然し、今まで倍加する問題は観測されなかった。
    という事は何か別の設定と相互作用を起こしてこれが発生している。

    どうやら /etc/bashrc の中に history -a が存在しているのが行けない様だ。
    この時に一体何が起こるのだろうか。というか、ble と関係在るのだろうか。
    と思ったが ble で古い version を使った場合には発生していないので、
    やはり ble との相互作用が原因になっているのは確かである。

    最近変わった事は何かというと /etc/bashrc の読み込みを
    source ble.sh よりも後に移動した事である。うーん。
    もしかしてこれはどのユーザでも同様に発生するのではないだろうか。
    全然駄目である。良くない。
    何れにしても source ble.sh を実行した後に history -a する事で
    何か ble.sh の想定が崩れてしまっているという事が考えられる。
    というか、/etc/bashrc が history -a を実行する時に履歴が空である事を想定している可能性?

    サブシェルの中で history -a を実行しても問題は発生しない。
    という事は history -a を実行した事によって何らかの計算がずれて、
    それによって何か変な事が発生しているという事。

    特に終了時に全体が書き込まれてしまっている。
    うーん。これはつまり、initialize に於いて 0 が初期位置として記録されてしまっている?
    _ble_builtin_history_wskip の値が変になっているのではないか。
    調べると空になっている。辿るとこれは ble/builtin/history/.get-max
    の結果を使っている。そしてこれの結果が空になっている。
    実装を確認すると builtin history 1 の最初の単語を使っている。
    つまり、履歴が読み込まれていない時にこれを呼び出すと空になる。

    うーん。履歴を強制的に読み出すにはどうしたら良いか?

    [現状の振る舞い]

    どうも記憶によると bashrc で履歴を history -r すると、
    その時点で history が倍加してしまうという事だった気がする。

    * history -a
      さて bashrc で history -a を実行した時の振る舞いが分からない。
      見てみると別に何も変化は起こらない気がする。
      或いは手で source した時にその場でそれまでの履歴を保存するのが目的なのだろうか。
      もしそうだとすると履歴が読み込まれていない時には history -a は実行しない、
      という具合に変更する事ができる。或いは履歴が読み込まれていなくても、
      history -a によって何らかの変化が発生する可能性はあるのだろうか。うーん。

      うーん。履歴が読み込まれていない時は history -a は無視するというのが正しい気がする。

    * history -r
      ble.sh をロードしている時に bashrc で history -r を実行するとどうなるか。
      ble.sh がない場合にはこれによって履歴が倍加するのではないかと危惧したが、
      実際に試してみるとそのような事は発生していない様だ。何故?
      或いは古い bash の version だけでの問題だったのだろうか。

    * history -n
      コメントを参照してみると履歴倍加が発生するのは history -n を実行した時の様だ。
      →実際に試してみると確かに再現する。

    [対策]

    うーん。どう対策するのが良いのか。或いは、.initialize の時に
    history -r を実行してしまえば問題が発生しない可能性?
    と思って実行してみたら倍加している。h とした時点で倍加している。
    単に history -r しただけではそうならないのに、
    何故 ble.sh の中から history -r を呼び出すと倍加しているのか。。

    然し、bash で history -a 及び history -w を実行しても何も起こらないのだとすれば、
    history -aw を bashrc の中で呼び出した時には何も実行しないというのが正しいのではないか。
    然しそれでも問題はある。history -s で履歴項目を追加した後に history -a を実行したらどうなるのか。
    そうすると結局履歴を読み込む前の状態で wskip が記録されてしまい、
    終了時に結局履歴が倍加してしまう。

    そもそも bash の振る舞い自体がおかしいのが行けないのではある。
    もし bash の制限がなかったとしたらどの様に振る舞いのが自然だろうか。
    要するに bash の初回 load の後に wskip を設定するべきという事なのである。
    現在の実装ではどうなっているか。bash が内部的に load するのを検出する事はできない。
    一方で、それ以外の history の動きについては追跡する事ができる。

    →bashの振る舞いを確認すると bashrc の中で history -s で履歴を追加した時には、
    実は HISTFILE の読み込みが抑制される様である。
    history -n では抑制されないのに変な事である。

    ble.sh ではどの様に振る舞うべきだろうか。

    | 寧ろ初回にロードした時に history を読み込んでしまう?
    | と思ったがそれだと HISTFILE を設定する前に読み込みが実行されてしまい、
    | 意図しない事になる。最終的な HISTFILE で読み込みをしたいという事を考えると、
    | できるだけ履歴の読み込みは遅延しなければならないのである。
    | そしてそれを実現する為には結局 bash に読み込ませるというのが現実的なのである。
    |
    | * その場合 history -aw は無視で良い。
    |
    | * bash では history -s は実行すると履歴が初期化されなくなる。
    |   これは ble.sh でもそのまま実行すれば良い気がする。
    |   と思ったが本当だろうか。実際に読み込んでいないのに、
    |   rskip の値がファイルの末端に設定される。
    |
    | * history -r をするとその場で読み込んで rskip が設定されるが、
    |   然し、bash によって勝手に追加で読み込みが実施されて履歴が倍加する。
    |   と思ったが実際に試してみるとそういう現象は起こっていない様だ。
    |   これに関しては現状のままで良い?
    |
    |   うーん。微妙である。history -r で明示的にファイルを指定して読み込む事もある。
    |   或いは何も指定せずに history -r を実行した時にのみ読み込みを initialize で実行しない。
    |   それ以外の場合には history -r に先立って明示的に履歴ファイルを読み取る?
    |
    |   或いは history -r の時にはわざわざ履歴を読み出さなくても良いのではという気もする。
    |   但し、これをすると bash による後の読み込みも抑制されてしまう。
    |
    | * history -n を実行してみると…。ble.sh の枠組みの中では何も発生しない様だ。
    |   少なくとも history 1 をしても何も出力されない。
    |   そして履歴の倍加も起こっていない。
    |   本当に何もしていないのだとすれば倍加が起こらないのは当然である。
    |   実装を確認してみる事にする。
    |
    |   →rskip が最初にファイルの長さに初期化される為に読み取りが実施されないという事の様だ。
    |   うーん。これは本来は未だ読み取りが実行されていないのだから rskip は 0 に設定しておいて、
    |   bash が勝手に新しく読みだした時に改めて更新するべきという事の気がする。
    |
    |   うーん。或いは history 1 をして空だったら history -r を実行するという事?

    なかなか仕様が定まらない。

    | どういう振る舞いが自然なのかという方針を明確にしなければならない。
    | 元の bash の振る舞いを多少変更しても構わない。
    | 然し元の bash の上で実現可能でなければならない。
    | 実現可能性に関しては実は頑張ればどうにでもなる気がする。
    |
    | 問題はやはり履歴が未初期化の時にどういう振る舞いが自然なのかという事である。
    |
    | * history -aw に関しては何も実行しない。
    |
    | * history -c に関しては後の履歴読み込みを無効化する。
    |   これは取り敢えず一旦読み取ってしまってその後で -c すれば良い。
    |
    |   →その様に実装したら bash が勝手に履歴を読み取って、
    |   それによって履歴が倍加してしまった。うーん。
    |   一筋縄では行かない。bash が履歴読み取りをするかしないかの条件に
    |   現在空であるかどうかというのも関わってくるという事?
    |
    |   そもそも元の bash ではどの様に振る舞うのだったか。
    |   →history -c をしても bash が履歴ファイルを読み取る。
    |   つまり、history -c の場合も未初期化の場合には何もしない事にすれば良い。
    |
    | * history -s に関してはやはり履歴を読み取ってから、
    |   その後にデータを追記する様にするのが良い気がする。
    |
    |   実際に ble.sh で動かしてみた所、読み取れていない。何故?
    |   と思ったら decode attach していない時には単純に history -s
    |   を呼び出すだけという実装になっていた。これは修正する。
    |   別に初期化はどのタイミングで実行しても問題ない筈なので。
    |
    | * history -r に間しては微妙である。
    |   履歴の読み取りを抑制してしまって良いのか。
    |   元の bash の振る舞いを見ると history -r file でファイルから読み込んで、
    |   更にその後で履歴ファイルからも読み取るという振る舞いになっている。
    |
    |   もう少し色々試してみても良いという気がする。
    |   →試してみた所 bash は history -r を実行すると、
    |   履歴を二重に読み取ってしまう。
    |   実はこれは現在の ble.sh の振る舞いと同じである。
    |   history -r によって履歴が倍加するのは許容する。
    |
    | * history -n に関しては履歴をその場で読み取って、
    |   追加で読み取るという事はしない。
    |
    | 後、単に履歴が空なのと実際に見初期化であるのをどのように区別するのか、
    | という問題が在る。history -c; source ble.sh とした場合に履歴が
    | ファイルから読み込まれてしまうのは果たして自然なのかという事である。
    | その他の方法で見初期化である事を判定する方法は存在するだろうか。
    | →これはどうしようもない。空ならばみ初期化と見做す事にする。


    まとめると、履歴が未初期化かどうかは現在履歴が空かどうかで行う。
    (Bash も履歴が空かどうかで履歴読み出しを実行するかしないかを決める様である。)
    未初期化の時の history の各操作の振る舞いは以下の様に決める。

    * history -awcd は何も実行しない。
    * history -snr は HISTFILE を読み取った後に実行する。
      これは bash の振る舞いとは異なるがこの振る舞いの方が現実的である。
    * history -p に関しては何も対処せず普通に実行する
      履歴の倍加は起こらないという事を確認した。

    この仕様の下で履歴が倍加するのは history -r を実行した時である。
    但し、保存される履歴に関しては倍加されず飽くまでも実行時に倍加するのみである。
    因みに元の bash でも history -r を実行すると履歴が倍加する。
    意図的に履歴を追加で読み取るという操作と区別がつかないのでこの振る舞いで問題ない。

    x fixed: __ble_edit__ が付加される?
      これは何だろう。というよりそもそも __ble_edit__ を付加するのは何故だったか。
      →調べたらこれは __ble_ext__ の間違いであった。
      61f4bd1 で __ble_edt__ を __ble_edit__ に直したが、直し方が違った。
      これは ble-0.3 にはない問題なので commit を分ける必要もない。
      今回、一緒にこれも直してしまう。

2020-04-06

  * global: builtin declare は oil が対応しないと言っている [#D1313]
    そもそも ble.sh でも declare の上書きは削除しているので、
    ここで builtin を指定する必要はない気がする。
    何より他の declare -p だとか local では builtin は指定していない。

    削除している物についての無駄な builtin は消す事にする。
    使われている箇所を確認すると以下の通り。

    | $ grc --exclude=\*.md -Wg,--color=none -o 'builtin [[:alpha:]]+' |
    |     grep --color=none -Eo 'builtin [[:alpha:]]+' |
    |     sort | uniq -c | sort -rn
    | 179 builtin eval
    |  65 builtin history
    |  42 builtin bind
    |  28 builtin read
    |  28 builtin printf
    |  23 builtin trap
    |  13 builtin exit
    |  10 builtin unset
    |  10 builtin echo
    |   8 builtin kill
    |   8 builtin compgen
    |   6 builtin complete
    |   3 builtin cd
    |   2 builtin unalias
    |   2 builtin type
    |   2 builtin sleep
    |   2 builtin mapfile
    |   2 builtin compopt
    |   1 builtin return

    この内で unset によって上書きをキャンセルしているのは以下の3種類だけである。
    eval, unset, unalias

    % * eval: うーん。eval は 179 箇所で builtin eval している。
    %   然し、eval に関してはユーザが勝手に削除すると悲惨な事になると予想されるので、
    %   まあ、取り敢えずそのままにしておく事にするのが良い気がする。
    %   →と思って確認した所 builtin なしで eval している箇所も沢山ある。
    %     数えたら 149 箇所である。これは取り敢えず後で修正する。
    %
    % * ok: builtin unset に関しては調べると unlocal で使っている。
    %   これは確かに関数などに置き換えられていると意図した様に動かない可能性が高いので、
    %   明示的に builtin unset を指定する事にする。Note を追記しておいた。
    %
    %   →やはり全て builtin を記述する事にしたので Note は削除した。
    %   # Note #D1313: unset は上書きできない様にしているので基本的にはbuiltin をつけな
    %   #   くて良いが、unlocal に用いる時だけはローカル変数のスコープの兼ね合いから明
    %   #   示的に builtin unset として置きたい。
    %
    % * unalias については上書き削除の目的だけでしか builtin unalias はない。
    %   そのままで良いという事にする?
    %   うーん。或いは全て builtin で呼び出す事にしようか。

    readonly だけ抜けているのは妙なのでこれも上書きをキャンセルする事にする。
    export, alias, unalias についてはそのままという事にする。

    * done: builtin をつけるかつけないかの一貫性は保って置きたい。
      やはり eval/unset/unalias はすべて builtin をつける事にした。
      eval についてはつけ終わった。unset についても終わった。
      unalias は少ししか無い。

    * done: builtin eval の後に -- を付ける必要のある箇所について確認する。

    * done: unset を自分で定義して readonly にしてしまえば良いのでは?
      →試しにその様にしてみる事にした。

  * util (bleopt): 未定義の設定が name:= で定義されない [#D1312]
    値が同じであると判定されて代入がスキップされていた。修正した。

  * decode (ble-bind): エラーメッセージ修正 [#D1311]
    keymap が見つからない時のエラーメッセージで keymap 名が出力されていない。

  * global: local -i 仕様の削除 [#D1310]
    oil が対応していない。元々排除しようと思っていた。
    良い機会なので削除する事にする。

    g2sgr 及び layer/update が引数を受けるのに使っている。
    使用箇所を確認したが何れの場所も整数しか入らない様に見える。単に削除する。
    ble-measure は内部的に使っていたが意味のない物だったので単に削除する。

  * test: テストフレームワーク [#D1309]

    既存のフレームワークについて確認する。

    * bats
      これは自分で 成功・失敗 を判定しなければならない。
      例えば期待する出力と実際の出力を比較するという様な機能はない?
      唯単に集計するだけの枠組みの様に思われる。

    * oil/test
      これは期待する出力と実際の出力を比較する機能がある。
      終了ステータスを確認する機能もある。
      様々なシェルで同時にテストする機能もある。
      シェル毎に期待する結果を比較する事もできる。

      * 様々なシェルで同時にテストする事ができたのは、
        oil のテストはシェルに対するテストで、
        個別のテストが独立した小さなプログラムだからである。
        通常のシェルスクリプトのテストの場合には、
        シェルスクリプト全体を読み込んだ上で実行しなければならないので、
        ble.sh の様な巨大なスクリプトの場合には向かない。

        対応するとしても、一つのシェルで一気にテストを実行して、
        それを後で集計するという形式にする必要がある。
        その様な実装であれば実は後で実装すれば良いので余り気にしなくても良い。

    * shellspec
      https://qiita.com/ko1nksm/items/9053e9c1e42a2ae9033e
      並列でテストする機能がある。
      coverage を計測する機能がある。
      期待する出力と実際の出力を比較する機能もある。

    既存フレームワークを眺めた結果の考察

    * 実際の所、oil/test 的な仕組みが最も使いやすいのではないかという気がする。
      但し、テストに要する時間に関しては微妙かもしれない。

    * 何れのフレームワークも何らかの DSL を作っている。
      bats 及び shellspec は特に奇を衒った事をしている。
      然し、正直な感想を言えば DSL を作ることで便利になっているのかは微妙である。
      余り DSL を作った事による利点を活かせていない気がする。

      それに DSL にするとその DSL のデザインに気を取られてしまう。
      できるだけシェルとして自然な形にまとめられないか。

      例えば、テストのタイトルは変数に入れる。
      テストのスクリプトは関数として定義する。
      それでも、期待する出力及び終了ステータスは直に書きたい。
      heredoc で定義するしか無いだろうか。

      | TITLE='hello world'
      | test() {
      |   コマンド
      | }
      | ble/test <<EOF
      | ## COMMENT
      | 何らかのコメント
      | ## EXPECT
      | 通常の期待出力
      | ## EXPECT 0 BUG bash-3.0
      | bash-3.0 における出力
      | EOF

      もしくは

      | title='hello world'
      | test() {
      |   ...
      | }
      | ble/test/expect <<EOF
      | ...
      | EOF
      | ble/test/expect -x0 -tBUG -sbash-3.0 <<EOF
      | ...
      | EOF
      | ble/test test

      うーん。或いは、alias を使ってしまう?
      →然し、試してみて思ったのは heredoc だと
      インデントが TAB しか使えないという制限がある。
      そしてそれを意識しなければならないのは辛い。

      heredoc 以外だと oil, shellspec の様にコメントを使う手があるが、
      それだと結局ひとつ上の枠組みで何らかの処理をする必要があり、
      結局 DSL を構築するのと大差ないという気がする。

      そういう事であれば ble.sh の場合には
      mwg_pp を使ってスクリプトを生成するのが自然である。
      と思ったが mwg_pp の枠組みでもインデントを検出するのは難しい。
      そうすると結局新しい DSL を作る事になってしまうのか。

    うーん。取り敢えずすべて忘れて実装してみたが、
    これで良い気がしてきた。取り敢えずはこれでやって行く事にする。

2020-04-01

  * bash-5 で heredoc を failglob で使うと駄目 [#D1308]
    変数に含まれる \ がパス名展開を誘起してそれにより失敗する。
    これも今実行してみると再現しない。但し、これに関しては原因を探れば
    再現する方法も自然に分かるという気がする。

    調べると nparam に問題の文字列を格納している。
    然し、nparam 自体はパス名展開の対象となる様な文脈では用いられていない。
    だとすると stat の方が怪しいだろうか。
    と思って眺めていると ble/syntax:bash/is-complete に怪しい所がある。
    というかこの is-complete とは何だろうか。うーん。

    ble-edit/is-single-complete-line から参照されている。
    複数行でかつ貼り付けでない時に呼び出される。未だ再現しない。
    →分かった。echo <<$(echo EOF) で再現した。
    そして見つけた箇所を修正したらちゃんと再現しなくなった。OK

  * OK: history: "history -d 負の数" にちゃんと対応していたか? [#D1307]
    bash-5.0 changes を見ていて気付いたが対応した記憶がない。
    と思って実装を確認してみたらちゃんと実装していた。OK

  * global: TMOUT が設定されているとあらゆる read が timeout して [#D1306]
    変なことになってしまうのではないだろうか。

    先ず初めに TMOUT の振る舞いについて調べる事にする。
    * -t が指定されている時には TMOUT の影響は無いようである。
    * TMOUT に不正な値を指定してもエラーになる訳ではなく単に無視される。
      '1 2' などの数値の後に何かごみがある場合でも無視される。
    * 算術式展開は実行されない。
    * 負の値を指定しても無視されるだけである。
    * 十六進数リテラルは無視される。

    m check で read があるので基本的に builtin read だけ確認すれば良い。

    * read の TMOUT に対応した。
      と思ったがわざわざ自分で -t を指定する必要はあっただろうか。
      実は builtin read が自動的に TMOUT を読むから不要なのではないか。
      と思ったが、-e を指定している時には自分で処理しなければならない。
      →確認した。この実装で問題ない。

  * global: shopt -s assoc_expand_once という設定は丁度 extra subscript expansions [#D1305]
    を off にする為の設定の様である。然し、これは連想配列に対してしか有効でない様だ。
    以下の例では、連想配列にした途端に添字展開が行われなくなる例。

    $ shopt -s assoc_expand_once
    $ expr='x[$(echo hello >/dev/tty)]'
    $ ((expr))
    hello
    $ declare -A x
    $ ((expr))
    $

    うーん。これを考えると実は連想配列の添字について再度確認しなければならないのでは。

    $ shopt -s assoc_expand_once
    $ declare -A A
    $ key=123; A[$key]=1234
    $ declare -p A
    declare -A A=([123]="1234" )
    $ echo ${A[$key]}
    1234
    $ A["x$key"]=321
    $ declare -p A
    declare -A A=([x123]="321" )

    まとめると、A[...]=... 及び ${A[...]} は影響を受けない。
    算術式の中の配列添字の展開は影響を受ける。
    history.sh の [\$file] は shopt を変更して対応するか、
    或いは shopt の設定に依存しない形に書き換える必要がある。
    これは書き換える方向で調整する事にする。

  * global: OK: shopt -u expand_aliases という設定がある事に気付いた [#D1304]
    現在の ble.sh ではこの設定に関係なく alias を展開している気がする。
    と思って確かめてみたが最初に type で種類をチェックしている。
    どうやら -u expand_aliases の時には type で見つからない様なので、
    現在の実装でちゃんと expand_aliases に応じた振る舞いになっている。
    以下の二つともその様な実装になっている。
    - ble/util/expand-alias
    - ble/widget/command-help/.type

2020-03-29

  * syntax: [!...] が履歴展開文字を含む為に単純単語ではなくなっている (reported by cmplstofB) [#D1303]
    https://github.com/akinomyoga/ble.sh/issues/47

    [!...] に関しては unquoted [! の場合には必ず履歴展開は無効になる様だ。
    例えば [echo!echo] だと履歴展開が有効だが
    [echo[!echo] だと履歴展開は無効である。
    という事なので [! の組み合わせを無条件に単純単語に含めて良い様にしてOK?
    と思ったら [echo[!echo だと履歴展開は有効になる様である。よく分からない。

    [!echo]   無効
    [a!echo]  有効
    [a[!echo] 無効
    [a[!echo  有効

    * reject: 逆に履歴展開を許容するという案はあるだろうか?
      然し、s/aaa/bbb/ は副作用を持つ。
      これが問題になるケースがあるのではないだろうか。
      うーん。やはりある気がする。サブシェルで実行するという手もあるが面倒である。
      何より単語が沢山ある時に速度が低下してしまう。履歴展開の文字が含む場合だけ
      特別扱いしても良いがそれはそれで面倒な事になる。

    ? no: というかそもそも simple-word/eval で履歴展開は実施されるのだったか。
      取り敢えず [! を許容しても eval の内部で履歴展開が発生しない事は確認した。
      少なくともこの変更によって副作用が発生したりおかしな事が発生することはない。

      | $ ble/syntax:bash/simple-word/eval '[A[!echo'; echo $ret
      | [![!echo
      | $ ble/syntax:bash/simple-word/eval '[A[!echo]'; echo $ret
      |
      | $ ble/syntax:bash/simple-word/eval '[a[!echo]'; echo $ret
      | a

    eval で履歴展開が実施されるとしてもされないとしても下手に一致して着色されると
    履歴展開の着色が単語着色で上書きされてしまってそれはそれで分かりにくい。
    やはり履歴展開が起こる場合には履歴展開の着色が有効になっていて欲しい。
    履歴展開は時に破滅的な結果を齎すのでこれが上書きされるのは避けたい。
    [a[! のパターンに関しては現在構文レベルでも判定できていないし、
    閉じる ] を見るまで分からないのでこれは相当先読みしないと判定できない。
    従って将来的に構文的にも対応することはないと思われる。
    従って [a[! のパターンで履歴展開が有効になるケースは取り敢えず無視して良い。

2020-03-27

  * decode: 大量貼り付け高速化に関連する問題の修正 [#D1302]

    * fixed: bash-4.1 で日本語を入力すると謎の空白が入ってしまう。
      以前はこの現象はなかった筈。UTF-8 decode を調べたが特に問題はない。
      ble-decode-key で受信しているキーの列にも問題は見られない。
      どうも batch-insert で変な空白が追加されている様子である。
      →ble/util/chars2s の問題であるという事が判明した。
      →分かった。join する所のエスケープを間違えていた。修正した。

    * fixed: bash-4.3 で途中までしか入力できない。
      nonblocking-read の結果が空になっている。
      うーん。何とそもそも builtin read で一文字も読めていない?
      →builtin read を実行したら 142 になって何も入っていない。
      そして実際にはデータを読み終わっている様子である。

      →実際に試してみると bash-4.3 以下では
      timeout した時には読み取ったデータは失われてしまう様だ。
      これの回避方法は存在するだろうか。うーん。取り敢えず…
      1 byte ずつ読み取る方法で実装してみる事にした。
      →実装した。動作している。まとめて読み取るのよりは遅いが、
      bind -x 経由よりも格段に高速である。

    * fixed: bash-4.3 で .check-abort に失敗している。
      何故か無引数で ble-decode/.hook が呼び出されている様である。何故?
      先ず FUNCNAME を調べる。

        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1073 (ble-stackdump)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4634 (ble-decode/.hook )
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble-decode/.hook 54)

      つまり再帰的な ble-decode/.hook の時に引数を渡すのを忘れている?
      % 調べるとどうやら ble/array#pop が動作していない様である。
      % 手で実行すると動作しているように見える。
      % と思ったら ble/array#pop の使い方を誤っていただけだった。動いている。
      違った、その前に既に _ble_decode_input_buffer に大量の空文字列が登録されている。

      →分かった。これは書き換えた時に split-words が split になってしまっていた。

    * fixed: bash-4.3 nonblocking の読み取りで空白が全て消滅している。どういう事だろう。
      と思ったら分かった。これは IFS である。一文字しか読み取らない場合でも IFS= は必要だ。
      IFS= を設定したら直った。
      bash-4.0 で 10k 文字入力したら遅いが動かない事はない。

    * resolved: bash-4.4 で試したら先ず nonblocking-read でブロックしている気がする。
      少なくとも progress-bar が止まってしまっている。
      動作確認する必要がある。それから nonblocking-read は bash 3.* では使えない。
      少数の read -t に対応していないので。

      local time1=$EPOCHREALTIME
      local time2=$EPOCHREALTIME
      bc -l <<< $time2-$time1; echo N=$N

      確認してみた所、先ず ble/array#push に 1.0s かかっている。
      うーん。これは後で対策を考える必要がある。
      更に、decoding... が表示されるまでに時間がかかる。
      然し、一応待っていれば動作はする様である。
      因みに2回目の貼り付けではそんなに時間がかかっていない?
      不思議である。これは何だろうか…。

      * ble-decode/.hook 内のボトルネック
        array#pop は一瞬で終わっている。
        chars=("${...[@]}" "$@") が 13 秒もかかっている。何故?
        更に分割すると chars=("${input_buffer[@]}") だけでも13秒かかっている。
        うーん。関数経由で chars に代入する様に変更したら 0.4s に減少した。
        然し、push の方は 0.9s からこれ以上縮まりそうにない。
        これは諦める事にする。

      * ble-decode/.hook 内の progress bar (nonblocking-read) が全く動かない
        と思ったがこれは上と全く同じ原因だった。0.9s の push を縮めるしかない。

    * resolved: bash-4.4: 更に processing input が開始するまでにも時間がかかる。
      これも配列のコピーが原因だった。91s かかっていたのが 0.86s にまで短くなった。

    * resolved: bash-4.0: constructing text が終わった後が長い。止まっている。
      もしかしてそもそも editor 起動が有効になっていない可能性?
      CPUはずっと走っている。→ずっと経ってから確認したら editor が起動していた。
      後でCPU時間を確認すると13m走り続けていた様だ。
      何が起こっていたのだろうか。

      と思ったら char2s の中でとんでもない事をしていた。
      毎文字 join していた。ループの外に出した。
      然し、それを修正しても大分時間がかかっている。何故。

      うーん。どうも配列に格納したデータを読み取ると物凄く時間がかかる様だ。
      文字列に 0x80 未満の文字を格納してそれを引く様にしたら一瞬で起動した。
      14s かかっていたのが 0.245s である。

      % debug1=$' \x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F'
      % debug1=$debug1$'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F'
      % debug1=$debug1$'\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F'
      % debug1=$debug1$'\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F'
      % debug1=$debug1$'\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F'
      % debug1=$debug1$'\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F'
      % debug1=$debug1$'\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F'
      % debug1=$debug1$'\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F'
      % function ble/util/chars2s.impl {
      %   local -a buff=()
      %   local c i=0
      %   for c; do
      %     if ((c<0x80)); then
      %       ret=${debug1:c:1}
      %     else
      %       ble/util/c2s.cached "$c"
      %     fi
      %     buff[i++]=$ret
      %   done
      %   IFS= builtin eval 'ret="${buff[*]}"'
      % }

      色々 benchmark して調べたがどうも遅い原因の一つは大量の引数を抱えた関数から
      子供の関数を呼び出すのが思いという事のようである。上で改善したのは純粋に
      文字列にした事で高速化したのではなくて関数呼び出しが減った事による効果である。
      再度計測し直してみた所、寧ろ文字列の index を用いて参照すると遅くなる様である。
      文字列の長さを工夫すればもう少し高速化できるのかもしれないが面倒なので考えない。

2020-03-24

  * ble-bind: Unknown widget `-'. という表示が出る (reported by dylankb) [#D1301]
    https://github.com/akinomyoga/ble.sh/issues/46

    調べてみると未対応の rlfunc があるとこれが必ず出る様だ。
    取り敢えず修正する必要がある。未対応です、という表示が出るのが望ましい。

    或いは無害な物に関しては nop を出して無視する。
    調べたが skip-csi-sequence については nop では駄目である。
    そもそも bind しては行けない。
    無害な物に関しては nop に束縛するのではなくて何にも束縛しない。

    * arrow-key-prefix は何かと思って bash のソースを確認したら、
      次の文字を読み取って ABCD だったらカーソルキーの既定動作に
      dispatch するという感じの物だった。
      恐らく SS3 A/B/C/D だとか ESC A/B/C/D だとか、
      そう言った物に一括で束縛する為の物なのだろうと思われる。
      これは無視ではなくて未対応とするべき。
      というより新しく widget を作っても良いのかもしれない。

    * tty-status は ioctl(TIOCSTAT) を呼び出すらしい。
      これは何かと思って検索したら /* generate status message */
      /* simulate ^T status message */ 等という説明が見られる。
      FreeBSD/OpenBSD にはあるが Linux にはない機能の雰囲気である。
      これは適当に模倣して実装しても良いのかもしれない。
      これも取り敢えず未対応という事で良いだろう。

    取り敢えずちゃんとエラーメッセージは出るようにした。
    次の報告が来た。恐らく emacs-editing-mode と vi-editing-mode
    を bind しようとしている /etc/profiles.d/? があるという事だろう。
    勝手に変な設定をしようとするものがあるのも考えようだが、
    然し、bash 互換を考える上では避けようがないという事なのだろう。
    何処かには ble.sh の様に bash の細かい動作に依存する設定があるはずで、
    つまり ble.sh の上で他の ble.sh 実装が動くかどうかというレベルの話になる。
    少しでも穴があれば動かなくなるという事なのである。

    emacs-editing-mode / vi-editing-mode の動作について確認する。
    bash で試してみた所によるとこれらは set -o emacs / set -o vi
    の設定まで変更する様である。ble.sh ではどの様に対応するべきか。
    set -o emacs を変更せずに実行するか。或いは、実際に set -o emacs
    を実行する事によって対処するか。もし set -o emacs を使って実装すると
    したら実は結構簡単な気がする。然し、default_keymap=emacs 等としていた
    場合には set -o vi をしても振る舞いに変化がないという事になってしまう。
    そういう意味では default_keymap も一緒に弄ってしまうというのが手なのだろうか。

    取り敢えず、ble.sh edit.sh で set -o が変化した時にどう振る舞っているか確認する。
    確認した所、set -o emacs/vi が変わった場合には単に ble.sh が動作の基準としている
    keymap を切り替えるだけであって、その上で何が動いているかに関しては関知していない雰囲気だ。

    * bleopt default_keymap=... を設定した時に reset-default-keymap を実行する様にする。
      現在だとこれを実行してもその場では keymap は変化しない様である。
      →対応した。何事もなく動作している。意外と呆気ない事だ。
    * set -o emacs/vi をどの様に実行するか。
      確認したが .check-detach は gexec の後に呼び出されている。
      つまり、set -o emacs/vi をコマンドとして実行するか、
      或いは、.check-detach で行っているのと同様の操作をその場で実行するか。
      後者で実装するのが自然である。

      うーん。単純に set -o ... してから以下を実行すれば良いだけ?
      ble/decode/reset-default-keymap
      ble/decode/detach
      ble/decode/attach

  * decode: 大量の貼り付けの高速化3 (report by dylankb) [#D1300]

    * うーん。ble/util/c2s が遅いのだと考えて高速化してみた。
      大分高速化した気がする。然し、緑が 99% になってから、
      赤色が表示されるまでの時間は変化していない。

      | # A. NUL を unset してから実行
      | local index0=$index ret ins
      | for ((;index<N;index++)); do
      |   ((chars[index])) || unset -v 'chars[index]'
      |   ble/widget/batch-insert.progress 2357
      | done
      | ble/util/chars2s "${chars[@]:index0}"; ins=$ret
      |
      | # B. 連続する非零のコード毎に変換を実行
      | local p q=$index ret ins=
      | for ((p=q;q<N;q++)); do
      |   if ((!chars[q])); then
      |     if ((p<q)); then
      |       ble/util/chars2s "${chars[@]:p:q-p}"; ins=$ins$ret
      |     fi
      |     ((p=q+1))
      |   fi
      |   ble/widget/batch-insert.progress
      | done
      |
      | # C. 一文字ずつ変換
      | local ret ins=
      | while ((index<N)); do
      |   ble/util/c2s "${chars[index]}"; ins=$ins$ret
      |   ((index++))
      |   ble/widget/batch-insert.progress
      | done

    * decode phase も実は簡略化できる筈。
      receive + decode を read & printf ' に変換するのである。
      と思ったが本当だろうか。整数に変換する必要があるが、
      それを高速に実行する事は可能だろうか。

    もうひとつ気になるのは screen 越しだと
    bracketed paste mode が有効になっていない気がする。
    或いは bracketed paste の終了がちゃんと受信されていない?
    まあ、これに関しては別に考える事にすれば良い気がする。

    * そうすると processing input... の部分が気になる。
      うーん。これは _ble_decode_char__hook を使ってループを回しているのが悪い。
      というか bracketed paste に関しては decode の側で特別に取り扱ってしまって良いのでは?
      但し、それによってどれだけ高速化するのかについては疑問が残るが…。

      見ていて気付いたが progress bar は 50 文字毎に表示している。
      53kB に入力に対しては 1000 回update する事になる。
      これが実はボトルネックなのでは。。と思って確かめてみた。
      50 から 200 にしたら 10s だったのが 6s に縮んだ。
      計算するに 5s 弱が実質の計算時間だったという事。
      逆に言えば 5s よりも早くはならない。

      さて、decode の側で key の解釈の時に一括で処理する事を考えてみたが、
      よく考えてみたら現在は _ble_decode_char__hook に介入しているので、
      key の解釈よりも前の段階での介入である。つまり、key の解釈で
      一括処理する様に変更しても対して意味がないのである。

      _ble_decode_char__hook で本質的に関係する部分だけ抜き出すと。

      * ((_ble_debug_keylog_enabled)) の時は一括処理を諦める。
      * [[ $_ble_decode_keylog_chars_enabled ]] のときも諦める。
      * 次の文字が _ble_decode_Erro の時には処理しない。

      これらの元でループ構造は以下の様に単純化される。

      | while
      |   ((ble_decode_char_rest))
      | do
      |   char=${chars[ichar]}
      |   ((ble_decode_char_rest--,ichar++))
      |
      |   ((char&=~_ble_decode_Macr))
      |
      |   # decode error character
      |   # if ((char&_ble_decode_Erro))
      |
      |   if [[ $_ble_decode_char__hook ]]; then
      |     ((char==_ble_decode_IsolatedESC)) && char=27 # isolated ESC -> ESC
      |     char を処理する
      |   fi
      | done

      うーん。decode.sh の側で "次の文字を読む" という操作を提供しても良い気がしてきた。
      その様に実装した。大分高速になった気がする。

    * さて、緑から赤に移る時の沈黙は何だろうか。
      引数を大量に渡すのに時間がかかっているという事だろうか。
      と思ったらそうではないようだ。

      文字列の置換処理に時間がかかっている?

      X:1584874227.928681
      Y:1584874227.929155
      Z:1584874227.936170
      W:1584874227.942291
      N:1584874231.373286

      と思ったら違う。この処理に時間がかかっている: chars=(${chars//:/' '})
      もしかしてパス名展開が試みられているという事だろうか。
      3秒もかかっている。ble/string#split を使ったら 0.03 にまで短縮した。

      X:1584874420.330993
      Y:1584874420.367348

    * 残っているのは byte を読み取る部分…。
      UTF-8 safe な byte を読み取ったらその次の瞬間に一気に読み取って良いのではないか。
      然し、UTF-8 safe な byte かどうかの判定で余計に時間がかかってはいけないし、
      よく考えたら日本語主体の文章の場合には UTF-8 safe な値はなかなか期待できない。
      一応改行は大丈夫だが改行のない文章が大量にやってきた場合はどうするのか。

      或いは、LC_CTYPE=C にして一気に読み取ってしまえば良いのかもしれない。
      decode に関しても余り深く考えずに一気に実行する?
      うーん。システムのエンコーディングと受信のエンコーディングが一致している
      時に限るが、そのまま組み立ててしまって良いのではないか。

      うーん。取り敢えず実験的に実装してみる事を考える事にする。

      受信をする時に問題になるのは NUL を含む文字列は受信できないという事。
      中途半端なバイトが含まれる時に ${str::x} の様な処理ができないという事。
      mapfile には timeout がないので read に頼るしかない。

    * decode は結構時間がかかっている。
      というか今思ったが現在の decode の処理は改善できる気がする。

      先ず初めに現在の変換時間を計測する。約12.7s
      X:1584885577.441244
      Y:1584885590.163676

      約12.2s 先ず配列に代入してから ble-decode-char を呼び出しているのを、
      直接一つずつ ble-decode-char を呼び出す様に変更してみる。殆ど違いはない。
      X:1584885521.873851
      Y:1584885534.093266

      約11.8s 算術式の不要な空白を全て潰してしまうとどうなるか。
      これも微妙に短くはなるが本質的な違いではない様に思われる。
      X:1584885811.187881
      Y:1584885822.967141

      約11.0s byte<0x80 だけ特別扱いしたらこう。
      X:1584886104.316627
      Y:1584886115.267994
      | ((byte&=0xFF))
      | ((mode)) && (((byte&0xC0)!=0x80&&(cha0=_ble_decode_Erro|code,mode=0)))
      | if ((byte<0x80)); then
      |   char=$byte
      | else
      |   ((byte<0xF0?(byte<0xC0?(byte<0x80?(char=byte):(
      |     mode==0?(char=_ble_decode_Erro|byte):(code=code<<6|byte&0x3F,--mode==0&&(char=code)))
      |     ):(byte<0xE0?(code=byte&0x1F,mode=1):(code=byte&0x0F,mode=2))):(byte<0xFC?(byte<0xF8?(
      |     code=byte&0x07,mode=3):(code=byte&0x03,mode=4)):(byte<0xFE?(code=byte&0x01,mode=5):(
      |     char=_ble_decode_Erro|byte)))))
      | fi

      約11.0s テーブルに入れて見たが速度は変わらない。
      よく考えてみたら byte<0x80 だけ特別扱いするのと対して変わらない。
      X:1584886995.051122
      Y:1584887006.049388
      | ((byte&=0xFF))
      | ((mode)) && (((byte&0xC0)!=0x80&&(cha0=_ble_decode_Erro|code,mode=0)))
      | ((_ble_encoding_utf8_decode_table[byte]))

      約11.0s 完全にテーブルに入れてみても対して変わらない。
      X:1584887425.167250
      Y:1584887436.189649
      | function ble/encoding:UTF-8/decode {
      |   local code=$_ble_encoding_utf8_decode_code
      |   local mode=$_ble_encoding_utf8_decode_mode
      |   local byte=$1
      |   local cha0= char=
      |   local stray='cha0=_ble_decode_Erro|code,mode=0'
      |   ((_ble_encoding_utf8_decode_table[$1&0xFF]))
      |   _ble_encoding_utf8_decode_code=$code
      |   _ble_encoding_utf8_decode_mode=$mode
      |   [[ $cha0 ]] && ble-decode-char "$cha0"
      |   [[ $char ]] && ble-decode-char "$char"
      | }

      約10.9s うーん。変数名を少し短くしてみたら微妙に改善した。
      X:1584887850.303309
      Y:1584887861.235152

      約9.9s decode を複数の引数を受け取るように変更したら改善した。
      X:1584915662.010331
      Y:1584915671.917756

      約4.2s 何と ble/array#push を A[i++]= に書き換えたら物凄く高速になった。
      結局全体で 5s ぐらいしかかかっていない。40s からの劇的な改善である。
      X:1584916592.860743
      Y:1584916597.017316

      大分改善した。取り敢えずはスクリプト上での
      decoder はこれで良しとする。

    * もっと巨大なデータを受信した時に外部プログラムを起動して
      decode する可能性?

      awk を使うか。或いは od を使って上手にできないか。
      或いは、printf $'' してから "${str::}" で読み取る手法?
      これは UTF-8 依存になるので、UTF-8 の側で処理する?

      というか現在の実装だって UTF-8 の側で処理して良い気がする。

      例えばこう。
      ble/util/printf ret '\x%02x' "$@"
      eval "ret=\$'$ret'"

      * 問題は 0 をどうするのかという事。
        0 は 0 に翻訳するという事で良い。

        →0の処理方法について確認しようとしたら微妙。
          \xC0\x80 にしたら実は表現できるかもしれないと考えたが、
          実際にやってみると二文字に分割されて解釈されている。
          文字数のカウントも2文字になっている。

        これが意味する所は、bind 経由で受信した 2B 表現も、
        bash の中で直接にバイトに変換すると破壊されてしまうという事。
        C0,C1 はその意味で特別に処理しなければならないのである。

      * そもそも本当に高速になるのか?
        これは実験してみないと分からない。
        実際に実装してみたが 5.2s である。
        寧ろ遅くなっている気がする。
        X:1584923880.134245
        Y:1584923885.336910

        うーん。何だか振る舞いが変である。
        わかった。修正した。変数 M を上書きしていた。

        改めて計測する。やはり 5.2s である。
        X:1584937548.825580
        Y:1584937554.059262

        その場で printf -v するようにした。
        % 5.7s, 5.6s である。計測ミスだった。
        % X:1584937775.759084
        % Y:1584937781.359048
        % X:1584937714.687243
        % Y:1584937720.327925
        約4.6s になった。高速化している。
        X:1584937868.273119
        Y:1584937872.934848

        元々の s2c の場合の速度を見ると 5.22s だった。
        printf の中で index 指定をするのを避けたら 4.85s になった。
        ${s:k:1} ではなく ${s:k} を渡すと 5.17s に遅くなる。
        長い文字列を渡しているのが遅い原因だろうか。
        %d を '%d' に quote したら 4.86s である。誤差の範囲内。

      さて、元の実装の速度が 4.1s であったから、
      これは寧ろ遅くなっている。
      printf -v で数値を取り出すのは自前で計算するよりも遅いという事。

      そもそも何故この実装を考えたのかというと、
      文字コードを抽出する事を想定していなかったから。
      そのまま文字列を構築してそれをファイルに出力するという想定だった。

      取り敢えず実装は此処に残して置く事にする。

      | function ble/encoding:UTF-8/decode2 {
      |   local C=$_ble_encoding_utf8_decode_code
      |   local M=$_ble_encoding_utf8_decode_mode
      |   local S='e=_ble_decode_Erro|C,M=0'
      |
      |   local -a B; B=("$@")
      |   local -a A=()
      |   local a=0 e= c=
      |
      |   local -a stop=(); stop[0]=1 stop[192]=1 stop[193]=1
      |   local i N=$#
      |   for ((i=0;i<N;)); do
      |     while ((i<N)) && ((stop[B[i]]||M)); do
      |       e= c=
      |       ((_ble_encoding_utf8_decode_table[B[i]&255]))
      |       [[ $e ]] && A[a++]=$e
      |       [[ $c ]] && A[a++]=$c
      |       ((i++))
      |     done
      |
      |     ((i<N)) || break
      |
      |     j=$i
      |     while ((j<N)) && [[ ! ${stop[B[j]]} ]]; do ((j++)); done
      |
      |     local ret
      |     ble/util/sprintf ret '\\x%02x' "${B[@]:i:j-i}"
      |     eval "local s=\$'$ret'"
      |     if [[ $s ]]; then
      |       local k K=${#s}
      |       for ((k=0;k<K;k++)); do
      |         ble/util/s2c "${s:k:1}"
      |         A[a++]=$ret
      |       done
      |     fi
      |     i=$j
      |   done
      |   _ble_encoding_utf8_decode_code=$C
      |   _ble_encoding_utf8_decode_mode=$M
      |   ((a)) && ble-decode-char "${A[@]}"
      | }

    * done: s2c の実装を見直す。

    * done: うーん。bind で -s を経由して受信している時には、
      read を直接実行すると変な事になるのではないか。
      つまり、read を実行するのは通常文字の直後である必要があるのでは。
      取り敢えず、-s 経由で受信される可能性のある文字について init-bind で確認する必要あり。
      -s 経由の受信で一番最後の文字以外の文字については read-nonblock を実行してはならない。

      取り敢えず対応した。また今後の変更の為に init-bind.sh に説明を書いた。
      本当は init-bind.sh の側で変数などを提供するのが良いのかもしれないが、
      面倒だし、今後マクロが追加される事があるのかも不明なので取り敢えず放置する。
      本当は他の人が将来的に編集する可能性なども考えると良くないのかもしれないが。

2020-03-14

  * rps を設定している時に変な文字で右余白が埋められている…。 [#D1299]
    一体これは何だろうか。後で調べる必要がある。

    これは screen-4.99 のバグである。

    | うーん。怪しいと思ったのは ble/textmap#update の中の
    | eraser の生成部分であるが確認してみると変な事は起こりそうにない。
    | というより場合分けが ech があるかないかで決まっている。
    | うーん。端末の方の ECH が壊れている可能性?
    |
    | mintty でも再現するからこれは screen/contra の問題ではない。
    | mintty の場合には空白の様に見えるが実際に選択しようとすると
    | 普通の空白と違って選択する事ができるのでこれはやはり何か変だ。
    | 単に ech しただけではやはりこの変な現象は起こらない。
    | とすると改行がある場合のセル内容を書き換えている別の箇所で問題が起きている?
    |
    | →うーん。空白を挿入した場合には特に問題は起こらない様だ。
    | やっぱり何かが ECH で変? 然し、空白挿入+ECH の場合や、
    | ECH+空白挿入 の場合には問題は発生しない。
    | だとすると問題の謎の文字はこれらの直前に描画されていて、
    | ECH では消えないけれども空白によっては上書きされる、という事?
    |
    | ble/textmap#update では _ble_textmap_glyph に値を代入している。
    | これを参照している箇所は edit.sh ble/textarea#update-text-buffer
    | の変更文字の置き換えだけである。
    | layer:plain/update はどうしているのかと思ったら独自に値を設定している。
    | ここでは改行は _ble_term_el を直接使っている。
    | うーん。調べたがやはり変な事は起こっていない気がする。
    |
    | screen の外では再現しない。と思ったら実は以下で再現すると分かった。
    | printf 'A\e[107m\e[X\n'
    |
    | これは ble.sh のバグではないという事になる。contra のバグであろうか。
    | 取り敢えず screen-4.7.0 では発生しないという事を確認した。
    | mintty x screen-4.99 でも再現する事を確かめた。
    | mintty だけでは再現しない。

  * complete: menu-filter を off にすると変な事になる [#D1298]
    https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/.23257.20typing.20past.20the.20last.20column.20(interactive.20features)

    menu-filter が無効の時は 1. menu filter 着色はしない。
    2. menu から候補を拾う機能は off にしておくべき?
    或いは、前回の menu を表示した時からカーソル位置が変化していない時にのみ使う。
    これは後で対応しなければならない。

    というより menu から候補を拾う時に menu-filter を実行すれば良いのではないか。
    と思っていざ修正しようとしたら既にそういう実装になっていた。
    但し、menu-filter が有効になっているかの判定が足りていなかったのだ。
    2行修正(complete_menu_filter の判定追加)しただけで治ってしまった。

2020-03-13

  * decode: 大量の貼り付けの高速化2 (report by dylankb) [#D1297]
    Ref #D1296 #D1293

    やはり未だ遅い。具体的に計測してみた。dylankb の報告によると
    最初に decode が始まるまでが長いという事であるが。
    手許で計測している範囲では以下の様な構成である。

      recv    9sec
      decode  10sec
      process 50sec
      show    70sec

    別に受信にはそんなに時間はかかっていない。
    show に関しては editor に置き換えればそんなに時間はかからない。
    つまり目下の所のボトルネックは process である。
    色々弄って計測してみる事にする。

    o (20sec短縮) 文字列に追記する様にしていたが配列に変更してみた。
      この時 process は 30sec だった。受信バイト数は 53184 bytes であった。
      もう一度貼り付けてみて process の間に速度低下が見られるか確認する。

    process の間の速度を観察すると実は寧ろ高速化していく。
    つまり残りのバイトを管理している構造がボトルネックになっている気がする。
    $1==126 (~) のチェックをできるだけ早く行って見る事にしたが、
    30sec だった。全然速度は変わっていない。
    batch-insert の時間は 8sec だった。これは殆ど無視できる。

    o (3sec短縮) 配列の容量を時々縮める様にしたら 27sec になった。
      多少は効果があるのかもしれないが誤差の範囲内である。

    o (17sec短縮) ble-decode-char で set -- 及び shift ではなくて
      を使う様に変更したら一気に 10sec にまで縮んだ。
      コードを整理した。今後はこれを使う事にする。

    現在は以下の様になっている。

      recv    9sec
      decode  10sec
      process 10sec (bracketed-paste)
      insert  10sec (batch-insert)
      show    70sec

    * done: recv の過程を表示する様にする。
      特に大量のデータを受信した時に表示すると良い。
      decode_abort_char によるチェックはどのタイミングでするか?
      input_buffer に対する検査を行っている。

      と思ったが recv の途中では decode_abort_char を受信できない。
      パイプに流し込まれた全てのデータを取り出さないと
      ユーザが中止の為に入力した文字は受信できないのである。

      実装してみたが何だか変だ。
      →色々修正した。動く様になった。こんな所だろう。

    * fixed: 何故か2回目以降の貼り付けが物凄く遅い。
      と思ったら editor を起動する時に term/leave,
      enter を実行しなければならないのだった。
      直した。

    * done: batch-insert に関しても大容量の場合には
      progress を表示する事にした。

2020-03-12

  * bracketed-paste: やはり貼り付けに N^2 の時間がかかるのは何だか変な気がする [#D1296]

    1 先ず batch-insert は改行を含んでいるのだろうか。
      →調べてみた所、どうも batch-insert が全く呼び出されていない。

      うーん。has-input の判定が間違っている。
      恐らく input_buffer, char_buffer がある前は動いていたが、
      buffer する様になってから動かなくなったのだろう。
      然し、ble_decode_char_rest があればちゃんと has-input になる筈。
      ということはそもそもこの判定にすら達していない?

      →一文字ずつ入力している時にはちゃんと到達しているが、
      貼り付けをした時には全然達していない。
      と思ったが分かった気がする。bracketed paste である。

      * fixed: どうも bracketed paste で受信した文字列を貯める所が遅い様だ。
        実際に文字を挿入する所ではそんなに時間はかかっていない。
        →どうも paste_end の判定部分の気がする。
        と思って判定を追加してみたら大分高速化した。

      * fixed: 然し、今度は self-insert にかかる時間の方が気になる。
        試してみると emacs の方では大分高速である。
        うーん。改めて vi でやってみるとやはり遅い。
        emacs の方では一文字ずつ挿入するのを諦めている?
        ちょっと調べてみる事にする。emacs は batch-insert を用いている。
        vi_imap が self-insert を使っているのが遅いのである。
        文字数が多い場合には vi_imap でも batch-insert を使う様にするか。
        というか何で始めから batch-insert では駄目だったのだろうか?

        うーん。始めの実装は #D0639 にある。特に記述はない。
        この議論 #D0683 は余り関係ない。
        何故か #D0720 LASTWIDGET の実装時に何か修正している?
        ここの議論を読むと self-insert を拡張して同時に文字を挿入等と書いているので、
        実はこの時点では batch-insert が存在していなかった?
        調べてみると batch-insert が実装されたのは #D0849 である。
        という事は、恐らく batch-insert に対応した時に更新を忘れていたか、
        そのまま置き換えても問題ないか判断がつかなかったから放置された。

        取り敢えず vi_imap でも batch-insert を使う様に変更してみる。
        またテストとして imap repeat が batch-insert でも意図通りになるか確認する。
        →ちゃんと \C-c3a<paste>\C-[ で意図した通りに繰り返される。OK
        vi_nmap での実装も vi_imap の実装を最終的に呼び出している。OK

    2 改行がある度に構文解析をしているという可能性はないか?
      上の対処でかなり高速になったので、構文解析を無駄に実行しているという可能性はない。OK

    報告者の様子を見るとそもそも decoding というのが表示されるまでに時間がかかる?
    多分、結構遅いホストを使っているという事なのだろうと思われる。
    そうだとしても多少は高速化出来ないものだろうか。
    decoding というのが表示されるまでに実行するのは単に input buffer に貯めるだけの筈。

    3 うーん。input_buffer に貯めるという部分はこれ以上の高速化のしようはない気がする。
      律速はスクリプトの側ではなくて readline の側にあると考えてよいのではないか。
      分からないが取り敢えずそう想定して良い気がする。

      すると高速化の余地があるのは結局 bracketed-paste における終了条件だけである。

  * 大量のテキストを貼り付けた時の動作 (suggested by dylankb) [#D1295]
    https://github.com/akinomyoga/ble.sh/issues/45

    * 幾つか確認をしたが結局 C-x C-e を自動で呼び出す様に変更する事になる気がする。
      edit-and-execute をそのまま呼び出してしまって良いのだろうか。。
      然し、よく考えると edit-and-execute を実行するとしても、
      受信したバイト列を使って内容を編集してその後でエディタを起動する必要があるのでは。

      或いはそれ自体を別のプログラムで実行するという可能性?
      例えば awk の方が多少高速に実行できるかもしれない。
      と思ったがどうだろう。微妙である。

      何れにしても batch-insert に介入を行う。
      →と思ったが batch-insert で全て処理されると保証できるのか?
      batch-insert よりも後のユーザ入力が失われてしまう事になる。
      それらも全て処理した上でエディタを起動しなければならない。

      うーん。取り敢えず batch_insert_limit という設定名は変える。
      挿入操作の所々で batch_insert_limit の制限をチェックする事にする。
      →取り敢えず暫定的に edit_capacity, edit_overflow としている。

    x fixed: insert-word が曖昧候補に対して動作していない。
      確認してみたがどうも曖昧の種類を a から amA に拡張した時に
      変更を忘れていたという事の気がする。
      恐らく意図的に mA に対しては実行しないという事ではないと思われる。
      実際に self-insert に於いてはちゃんと ramA に対してテストしている。
      insert-word でも ramA に対して適用する様に書き換えた。

    * done: 取り敢えず discard については実装したと思う。
    * done: rename replace-limited
    * done: replace-limited と adjust 云々はくっつける。

    x fixed: edit-and-execute ではコマンドを灰色にして表示するべき。
      或いはコマンドを表示しない様に隠すべき。
      取り敢えず灰色にして表示する方向。

    * done: edit_overflow=truncate も実装したい。
      それから edit_overflow=editor も実装したい。
      然し、このチェックは一体何処で実行すれば良いだろうか。
      というか edit-and-execute は編集内容を表示したのだったか。

      先ず初めは truncate を実装する事にする。
      何処でチェックを入れるべきだろうか。
      batch-insert の直後でチェックする?
      然し、それだと通常の操作で truncate した時に適用されない。

      全ての入力の後に処理するのは非効率的だ。
      なので描画のタイミングの直前ぐらいでチェックするのが良い気がする。

    * done: 処理が重くなるのを防ぐ為には batch-insert
      でも適宜 truncate するのが良い。
      →その様にした。

    o ok: truncate をテストする必要がある。
      truncate は何となく動いている気がする。

    x fixed: discard に関しては挿入できる所までは挿入する筈なのに
      限界に達する時には何も挿入されないという事態になっている。
      何故だろうか。.replace-range が動いていない気がする。
      → inslimit を使って制限する所を iend-ibeg で制限していた。
      元々 inslimit を inslimit = max(inslimit, iend-ibeg) と書こうとして、
      そのまま次の操作と融合して変な記述になっていた。修正した。

    * done: 次に実装するのは editor である。
      簡単に実装した。これで本当に動くのだろうか。

    * ok: editor をテストする
      取り敢えず動いている気がする。
      コマンドラインに何も表示しないのは寂しいので
      コメントで範囲を超過したというメッセージを残す事にした。

    * done: 設定変数 editor を追加する
      blerc / wiki.ja / wiki.en

    * done: 設定変数 x 2
    * done: 設定変数 x 2 in wiki ja
    * done: 設定変数 x 2 in blerc
    * done: 設定変数 x 2 in wiki en

    * done: 後、履歴に巨大なデータが残るのも困る。
      history_limit_length という設定変数も追加したい。
      実装した。説明も追加した。

    * done: エディタの起動に失敗した場合はどうなるのか。
      truncate した方が良いのではないか?
      →その様に実装した。

    * done: truncate 等する時に特殊モードを抜ける。
      truncate する時にも mark や ind などがずれるので
      auto_complete や nsearch 等の様々なモードで変な事が起こりそうである。
      それを避ける為には特別のキーを発行してそれで truncate を処理するという手もある?
      例えば content_truncate もしくは content_editor 等の様に。
      →或いは truncate が起こったら truncate を実行してから
        content_truncate または content_editor を呼出して通知するという事にする。

      これは後で実装する事にする。
      →実装する。実装した。動いている。
      と思ったが何か変な気がする。

      isearch の途中にこれが発生したら何が起こるのか。
      うーん。isearch が強制終了する? それだけなら良いが、
      isearch の途中で editor が起動するというのは変である。
      editor が起動する条件を変更するべきなのではないか。
      というか edit-and-execute だって、vi_nmap では違う振る舞いをするべきなのでは。
      色々考えると、line limit というキーではなくて "キャンセル" 的なキーを実装して、
      更に元のモードによっては edit-and-execute は実行しないという様にする必要があるのでは。

      % と思ったが、その場でそれを実行することはできるのだろうか。
      % つまり queue に溜まっているキー入力に先立って処理する事は可能だろうか。
      % あと描画のタイミングで処理するというのも変である。
      % と思ったが decode.sh の中に直接チェックを書き込むのも変だし、
      % EPILOGUE 辺りに書き加えるのが正しい気がする。
      % →実装を確認してみたが ble-decode-key を呼び出せば
      %   その場で実行する様になっている。
      %   つまりこれに関しては気にしなくても良い。

      改めて keymap を観察する。うーん。read 等でも
      edit-and-execute が発生すると困る。
      色々考えるにこの edit-and-execute の呼び出しは、
      寧ろ keymap の上で実行するべきの気がする。

      safe, emacs, read, vi_imap, vi_cmap, vi_nmap で対応した。
      isearch, nsearch, lastarg, yankpop では握り潰すのが良い気がする。
      vi_smap, vi_xmap, vi_omap, vi_digraph では何も処理しない (エラー)。
      menu menu_complete auto_complete dabbrev でも握り潰す。
      取り敢えず全ての keymap に対して処理は書いた。

      結構書き換えてしまったので改めてテストする必要がある。

    o vi_imap, emacs では動いた。
    x fixed: read で動いていない。何故?
      と思ったが EPILOGUE を呼び出していないので当然といえば当然。追加した。
    x fixed: 今度は syntax で assertion が火を吹いている。何故。
      _ble_edit_str を直接編集すると起こる種類の問題である。
      然しその様な事はしていない様に見える。
      →と思ったら _ble_edit_str に直接代入していた。修正した。
    x fixed: vi operator が全く動かなくなっている何故?
      つい直前までは動いている。という事はまた何かを破壊した?
      不思議だ。何も破壊していない気がする。
      →これは vi_omap の __default__ が line_limit を受信して、
      それによって omap を抜けているのが問題だった。
      __line_limit__ は無視する事にした。
    x fixed: vi_nmap では一応動いているが truncate の時に
      vi_imap に落ちるのは分かりにくい。
      edit-and-execute を実際に行う場所で vi_imap に落ちる様に変更した。
    x fixed: 2文字以上の組み合わせの keyseq が使えなくなっている。
      これは全然駄目だ。その様に考えると __line_limit__ は、
      mouse と同様に keyseq には関与するべきではないのでは。
      と思ったが、処理が重くなるのも嫌なので長さの検査をしてから
      __line_limit__ を呼び出す方が良い気がしてきた。
      →その様に変更した。
    o ok: 取り敢えず read, vi_nmap は確認した。
    x fixed: vi_cmap で表示が変になっている。うーん。
      これはどうしたら良いのか。
      →分かった。 .newline していたのが行けない。修正した。
    x fixed: vi_digraph では無視する様にしないといけない気がする。
      (実際に呼び出される事があるのかどうかは不明だが)

    今の所、emacs, vi_[inc]map, read は動作確認した。
    isearch, vi_omap でも問題ないことを確認した。
    safe は emacs と本質的に同じなので気にしなくて良い。
    vi_digraph にも対応した。vi_[sx]map はまあ大丈夫だろう。
    握りつぶしている物に関しては基本的に問題ない筈。

    * done: 既定値は editor で良いのだろうか…。
      いきなり editor が起動すると混乱の元なのではないか。
      或いは none の方が良いのでは? うーん。取り敢えず none にする。

  * test: test-core.sh がエラーを吐いている (reported by andychu) [#D1294]
    https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/.23257.20typing.20past.20the.20last.20column.20(interactive.20features)

    調べたら ble/string#escape-for-bash-specialchars の仕様変更による物である。
    3番目の引数に flags を受け取る様になって、そこに b を指定した時にだけ
    brace の quote を行うという様に変更されている。反映した。
    更に言うと test-core.sh という名前も古い。test-util.sh でなければならない。

  * decode: modifyOtherKeys の時の abort [#D1293]
    C-\ で abort するという話を書いたが。
    よく考えてみると modifyOtherKeys にしている時には動かないのでは。

    さて、modifyOtherKeys にしていると C-c を押しても 3 は決して入って来ない。
    ble-decode-key の直前で待ち伏せしなければならない。
    然し、現在の実装だと ble-decode-key の結果はキャッシュされていないので、
    其処で待ち伏せする事にするとそれより前の処理は全て実行された後になる。
    それだとキャンセルした事にならない。
    或いは key の計算と実行を切り離して key を検査してから実行を行うべきか。

    然し、確認してみて思ったが検査はやはり byte のレベルで実行しなければならない。
    実際に char のキャッシュも byte のレベルでしかキャンセルしない様になっている
    (唯、制御文字に関しては decode を通しても変化しないという前提はある気がする)。

    その様に考えると、decode_abort_char に複数のバイトから為るシーケンスを
    登録できる様にしなければ動く様にはならないという気がする。

    うーん。decode_abort_seq なる物を定義して byte を受け取った時に判定する。
    然し、それだとユーザが端末ごとに正しい値を設定しなければならない。
    更に modifyOtherKeys なので理解するのが難しい。
    やはり自動的に検出する様にしなければならない。

    うーん。可能なシーケンスは実は有限個しかない。
    と思ったが本当だろうか。chars と bytes に跨って記録される事もあるのでは。
    然し、シーケンスの到着のタイミング等を考えるとそれが起こるとは考えにくい。
    取り敢えずは bytes に全て含まれている場合を考える事にする。

    CSI の表現で 2 種類ある。> の有無で 2 種類ある。CSI >? 27 ; 5 ; code
    27~ 形式 と u 形式で 2 種類ある。

    →これについては実装した。

2020-03-08

  * vi: vi-commandn/nth-column の算術式がおかしい (reported by andychu) [#D1292]
    https://github.com/oilshell/oil/issues/620#issuecomment-596189684

    osh -n で見つかったバグである。後で全体的に確認する必要があるという気がする。
    多分、osh -n は一番最初に見つかった物しか報告していない。
    →やはりそうだった。もう一つバグを見つけた。
    然し殆どは ((${prefix}xx=...)) の形式だった。

2020-02-27

  * 2020-02-06 quoted-insert で制御文字を入力できる様にする [#D1291]
    mintty で modifyOtherKeys を有効にしているので
    quoted-insert で C-t 等の基本的なキーですら修飾されている。
    つまり、制御文字を入力する事ができない。

    然し、本当に modifyOtherKeys を入力したい場合や、
    或いは、本当に端末が送ってくる内容を知りたい場合もある。
    その場合には勝手にキー入力をいい感じに翻訳されると困る。
    然し、やはり制御文字を入力したいという事がある気がする。

    C-q と C-v で二種類あるのだから片方に別の物を割り当てるという手もある。
    やはり特殊なキーシーケンスを取得するという場合よりも、
    C-q 等の特殊文字を入力する場合の方が多い。C-x に対しては、
    やはり C-x が挿入される様にするべきである。しかしそれを実行するには
    key を decode しなければならない。するとその他の key に関しては
    それを発生させたシーケンスを復元するか記録するかしないといけない。
    記録するとしても Meta が関わってきた場合には更に複雑になってしまう。
    或いはキーを完全にデコードする前に判定する事は可能だろうか、
    と思ったが CSI u で送られてくる以上は最後まで見ないと分からない。

    a 或いは寧ろ予め用意したシーケンスをそのまま返す様にしてしまう?
      然し、それはそれで混乱の元である。特別なキーに対して実際の端末と異なる物を挿入すると、
      ユーザが端末のテストなどをする際に変な事になってしまう。
    b 或いは各キーに対してどのシーケンスが使われたかという情報を decoder 側で全て記録する?
      然し、それをするぐらいであれば現在のキーに対応するシーケンスだけ取得できる様にすれば良い。

    結局現在のキーを構築するに至ったキーの列を記録する事にした。
    取り敢えず動いているので満足である。

    RLogin は ! 等に対して S-1 等を送信して来る。単に S- を除去するだけでは駄目。
    S-数字の時には日本語キーボード配列を想定して適当に記号に変換する事にした。
    但し、S-数字 にしか対応していない。純粋は記号キーについては補正していないが、
    実は RLogin は既定では記号キーは修飾しない設定になっている。
    うーん。端末識別をもう少し詳しくしてみる事にした。

  * complete: clear menu on discard-line (reported by animecyc) [#D1290]
    https://github.com/akinomyoga/ble.sh/issues/44
    これは意図した振る舞いである、と書こうとしたが振る舞いが変である。
    ソースコードを見ると history.onleave 経由で menu/clear 呼び出される筈である。
    実際に確かめてみると呼び出されてはいるが既に menu が非アクティブになっている。
    最初からアクティブになっていない可能性? と思ったがちゃんとアクティブになる
    コードパスを通過している。

    と思ったら edit.sh 側に active を解除するコードがある。
    というより正に .newline の中で明示的に clear している。
    確認するとこれが追加されたのは aae8b264 である。
    これは menu-filter 着色を解除して最後に行内容を表示する為の処置である。
    insert-newline を呼び出す時に内部で再描画を行うので。

2020-02-19

  * term: menu が正しく消去されないとの事 (reported by killermoehre) [#D1289]
    https://github.com/akinomyoga/ble.sh/issues/42

    これは terminfo と termcap で同じ名前の項目 dl があった所為だった。
    二文字の terminfo で termcap と異なる物は注意して調べた方が良い。

    ri: OK, el: OK, il: OK, ed: 駄目, dl: 駄目
    一方で ed, dl に対応する termcap 側の cd 及び DL は曖昧ではない。
    これらに関しては terminfo/termcap 両方対応している環境では
    cd, DL を確認する事にする。

    % もし ed, dl で terminfo 側を優先させる環境があったとすれば
    % それはそれで問題になる気がするが仕方がない。
    % と思ったが、DL 及び cd を使っている限りは問題が発生しないので、
    % これでちゃんと解決できている。OK

  * term: support contra SPD [#D1288]
    contra で SPD(3) 等を実行してもカーソル移動が破壊しない為に
    terminfo cache の書き換え。CU[UDFB] の代わりに [HV]P[RB] を使う。

  * 2020-02-14 時々 bind が壊れる現象があって何かと思っていたら [#D1287]
    TERM を変更すると Bash は inputrc を再読込するらしい。
    TERM=xterm infocmp 等とするだけで壊れるのである。

    これを検出する方法はあるだろうか。或いは阻止する方法。
    厄介なのは変更してまた元に戻しても壊れるという事。

    a reject: 或いは typeset -r TERM してしまうという手は?
      →そうすると全く変更できなくなるので駄目。

    b reject: 或いは拾えなかった時に rebind する?
      と思ったが拾えないのだから検出できない。

    c reject: INPUTRC=/dev/null に設定する?
      と思ったが問題が発生するのはユーザ環境なので、
      ユーザ環境で一時的に INPUTRC を復元している時に問題が起こる。
      INPUTRC を上書きした状態でユーザ環境に戻すと、
      今度はユーザが bash 等を起動した時に inputrc が読み込まれなくなってしまう。

      →気付いたのはこれは inputrc とは関係ないという事。
      inputrc 読み込みを阻止しても readline 自体の初期化によって
      terminfo を元にして bind が実行される。

    d 実行が完了する度に全 bind を実行する手
      然し、全 bind の時には unbind もしなければならない。
      inputrc が編集された場合には前回の unbind スクリプトは使えない。
      すると unbind を自動的に生成しなければならない?

    e 或いは、実行が完了する度に builtin bind -ps をチェックする手

      a 後者は bind -s の出力結果が ble.sh 自身の物なのか判定が必要。
        結局完全に対応する為には awk を起動するなどする必要がある。
      b 或いは前回の呼び出しと状態を比較するというので十分の気がする。
      c bind -p だけチェック。
        確認した所 inputrc と関係なく書き換えられる様である。
        そして beginning-of-line 等が必ず書き換わる様に見えるので、
        取り敢えず bind -p だけチェックすれば十分だろうか。
        そして # 以外で始まる行が含まれていれば検出したとする。
        単に builtin bind -p | grep -v ^# でも良いのかもしれない。

    | またチェックするのと全 bind を実行するのとどちらの方が重いのかという話。
    |
    |   以下を実行すると 1.6ms である。Cygwin では 33ms
    |   $ check1() { ble/util/assign hello 'builtin bind -sp'; [[ $hello == "$value2" ]]; }
    |   $ ble-measure check1
    |
    |   以下は 2.86ms (Cygwin 77.5ms) だった。
    |   $ ble-measure 'builtin bind -p | grep -v ^#'
    |
    |   以下は 4.5ms である。Cygwin では 31ms
    |   $ ble-measure ble/decode/rebind
    |
    |   以下は 19.2ms である。Cygwin では 247ms
    |   $ ble-measure 'ble/decode/detach; ble/decode/attach'
    |   変な設定に shadow されない為にはこちらを実行する必要がある。
    |
    |   % Cygwin は何れにしても遅い様だ。ファイルに書き込むからだろうか。
    |   % どうも ble/util/assign の中で出力する内容の量に比例して時間がかかっている。
    |   % 取り敢えず Cygwin の事は考えなくて良いという事にする。
    |   %
    |   % うーん。今 ble/decode/bind/unbind の実装を確認して気付いたが、
    |   % 実は昔にキャッシュした結果を使って unbind している。
    |   % つまり、キャッシュした時から変化があったりすると unbind できない。
    |   % 指示通りに設定していれば bashrc の先頭で実行するので
    |   % ユーザの設定に左右される可能性は低いが、
    |   % inputrc の設定には左右されてしまう。
    |   %
    |   % と思ったが何か変だ。このキャッシュしている内容は
    |   % ble.sh による binding の設定・削除である。
    |   % 元々の binding の復元・削除ではない。
    |   % 確認するべきなのは
    |   % ble/decode/detach と ble/decode/attach なのだった。
    |
    | コマンド実行の時間と比べれば 4.5ms や 31ms は短いので
    | そんなには気にならない様にも思う。或いはもっと別のタイミングで再チェックを行う?
    | と思ったが、コマンドの実行以外にもっと疎らなチェックのタイミングはない気がする。
    | もしコマンドの実行でチェックしないとその後の編集の何れかのタイミングで再度
    | binding を実行しなければならないので面倒である。
    |
    | ? TERM を書き換えると勝手に初期化される振る舞いは妥当なのだろうか。
    |   例えばユーザが明示的に home になにか割り当てていた時に、
    |   TERM が書き換わる度にそれが上書きされてしまうという事にならないのか。
    |   と思って振る舞いを確認した所、既にその binding が存在している場合には、
    |   勝手に上書きしてしまう等の事は発生しない様だ。
    |   ちゃんとできている。
    |
    |   prefix の \e や O を単体で取り出したい等という変な事をしない限りは
    |   これでちゃんと動く様になっているのである。うーん。これには文句はつけづらい。

    コマンドを実行する度に bind をチェックするのが一番速い。
    対応としては bind -p の出力を記録して比較する。
    特に Cygwin で遅いが stty が 55ms なのでそれに比べれば小さい。
    bind -p だけならば 21ms で比較できている。

    取り敢えず実装する。

    * ok: 初回はコマンドを実行する前に記録するべきの気がする。
      →これは decode/bind/bind の側で記録する事にした。
    * done: TERM を記録しておいてそれが変更したらチェックしなくても再読み込みを実施する。
    * ok: 動作確認

    追記: ble-reload の時に変なメッセージが出る様になったと思ったら
    これが原因だった。bind している状態の時に限り rebind を実行する様に変更した。

    # エラーメッセージは emacs mode ではないのに keymap 'emacs' is empty となっていて、
    # これは source ble.sh した時に default keymap が emacs に取り敢えずなって、
    # 本来は attach の時に正しいものに決定されるはずが、attach の前に ble/decode/attach
    # を呼び出してしまってエラーになっていたという事である。

2020-02-12

  * 2020-01-17 syntax: ${var/#} ${var/%} も特別に着色する [#D1286]

  * decode: ble-import -d (--delay) [#D1285]
    * ble-import の guard は常に絶対パスで行う様に変更した。

  * decode: macro 無限ループ防止? [#D1284]
    macro 再帰に条件を設けても良いのでは? と思ったが、
    現在の仕組みだと一旦一番上に抜けてから実行する様になっているので、
    macro の階層は簡単には分からない様になっている。
    macro の階層ではなくて文字数で判定するのでも良いかもしれない。
    然し、問題は階層・文字数で制限したとしても一つのマクロから呼び出される
    マクロが2以上だと鼠算式に増えるので容易に実質止まらないループを作れる事。

    要するに一つのマクロ呼び出しから起こるマクロ呼び出しの総数に制限を掛ければ良い。
    マクロの中ではないマクロ呼び出しでカウンタをクリアして、
    マクロの中でのマクロ呼び出しではカウンタをインクリメントしながら回数に制限を掛ける。
    マクロの中なのかそうでないのかはどう判定すれば良いか?
    これは ble-decode-key 辺りで変数を定義する事にすれば良い?

    →実装した。

  * decode: ble-bind -L が BSD sed でエラーを出す (reported by dylankb) [#D1283]
    https://github.com/akinomyoga/ble.sh/issues/41#issuecomment-585068803
    何と sed -r を使っていた。恐らく ble-bind -L は元々自分のデバグの為に作った
    関数を ble-bind の機能として転用した為に環境依存の実装が残っていたのだろう。

  * ble-sabbrev は complete 経由でなくても呼び出せる様に改良する [#D1282]
    対応した。

  * complete: auto_complete で failglob の時 ^? が直接挿入される問題 [#D1281]
    及び fzf で auto-complete の時に complete -D を使うと
    fzf の設定が bash-completion で上書きされてしまう問題。

    fzf completion を試していた時に auto-complete で ^? が self-insert される状態になった
    これは何かのバグだろうか。

    fzf で最初の候補を選択した直後に auto-complete 状態になるが、
    その時に backspace を押すと ^? が self-insert される。何故?
    その他の場合にはそういう事にはならない。

    →これも auto-complete では fzf を起動しない事にしたので、
    余り気にしなくても良いのかもしれない。しかし、
    何故こういう事になってしまうのかについては調べる必要がある?

    そもそも self-insert されるというのが不思議である。
    →これは vi_imap/__default__ であろう。
      問題は何故元々の C-? が働かずに __default__ が呼び出されているのかという事。
      然し、C-? が bind されていない map があったろうか。。

    というかどの様に再現したら良いのか。。改めて設定を変えて試す必要がある。
    駄目だ再現できない。最近の変更で変わったとは思えない。
    最近の変更はコメントの編集と reconstruct-user-settings だけである。
    或いは reconstruct-user-settings で bind が上書きされた可能性もなくはないが、
    そうだとしたら ^? が挿入されるという振る舞いにはならない筈。

    再現した。vim ** <TAB> で再現した。と思ったら再現しなくなった。

    * fixed: 然し一度 vim ** で fzf を実行して確定すると以降は二度と fzf が起動しなくなる。
      補完設定を確認してみると _filedir_xspec に置き換わっている。
      fzf が内部で dynamic loading を実行しているのが原因だろう。
      然し、これは ble.sh なしでも再現するのではないか?
      →試してみたが ble.sh なしでも勝手に置き換わるという事は無い様だ。

      そもそも ble.sh の上で vim ** が動いていない。
      メニューは出るがその後で置換が発生していない。
      詳しく何が起こっているのか確認する必要がある。

      最初に fzf の completer はロードされている。
      誰かが上書きしている。
      ble.sh による __load_completion の呼び出しは行われていない。
      fzf が自身で書き換えている可能性も見たがそうでもない。
      外側で書き換わってしまっている。

      complete を hook して調べる必要がある。
      うーん。_python_argcomplete_global というのが勝手にロードしている。
      そして _python_argcomplete_global は complete -p -D に登録されている。
      そもそもの話、何故 complete -p -D が呼び出されているのかという話でもある。
      あー。分かった。auto-complete で default にフォールバックしているからだ。。
      これの work around はどうすれば良いか。

      元々意図した事は default の fzf でない補完設定を実行するという事。
      然し、fzf でない補完設定の -D は complete を呼び出してしまう。
      或いは fzf に既定の補完を呼び出させるのが良いのではないだろうか。

      うーん。取り敢えず -o default を指定するのではなくて別の方法で
      default の呼び出しを抑止してみる事にした。然し駄目だ。何故だろう。
      と思ったら -o default を fzf が指定しているのだった。
      -o default が指定された時には complete -D
      を呼び出すのではなくて組み込みの補完を呼び出さなければならない。
      というか実は初めからそのような実装になっていた。
      従って前回の変更で付け加えた機能は不要だったのである。
      削除した。この問題は発生しなくなった。

    * ^? が挿入される問題は未だ解決していない気がする。
      然し再現できない。再現の条件が良くわからない。

      auto-complete が表示されているという事は auto-complete の中にいると仮定して良い?
      この時に ^? を受信するとどうなるかというと auto-complete を一旦抜けて外で
      処理を行ってその後でまた auto-complete に入る。もしくは auto-complete の中にいる儘で
      ^? を挿入する。

      ble/widget/auto_complete/self-insert の実装を見ると 0x7F が直接入って来た場合には
      そのまま挿入される事になる。恐らく __defchar__ もその様になっているのだろうと想像される。
      然し、何処で 0x7F が発生するのだろうか。
      ble/widget/vi_imap/__default__ が変換している?
      そしてそれを auto-complete が受け取っている可能性?

      再現する気配がないので昔の状態に戻して改めて再現を試みる。

      $ touch a\*\*b
      $ vim a**

      この状態で \C-i\C-g\C-? とすると再現する。
      もう一回試した。やはり再現する。
      うーん。最新の commit にすると再現しなくなる。

      この変な状態を調べる。
      取り敢えず self-insert に stackdump をしかける。
      →どうやら self-insert は引っ掛かっていない様だ。
        という事は auto_complete/self-insert に引っ掛かっている?
      引っ掛かっていた。stackdump の引数の機能が欲しい。cherry-pick する事にする。
      →git checkout 1f14571 src/util.sh で取り出した。

      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble/widget/auto_complete/self-insert )
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:46 (ble-decode/widget/.call-keyseq )
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:58 (ble-decode-key/.invoke-partial-match 127)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:45 (ble-decode-key 127)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:79 (ble-decode-char/.send-modified-key 127)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:51 (ble-decode-char 127)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:45 (ble/encoding:UTF-8/decode 127)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble-decode/.hook 127)

      どうも 127 がそのまま変換されずに到達している様だ。
      よく考えてみれば確かに 127 は DEL として取り扱っているので、
      そのまま変換されずに到達するというのは今迄の意図した取り扱いである気がしてきた。
      * 他の keymap で問題が起こらなかったのは DEL が明示的に bind されている為。
      * auto-complete でも問題が起こらなかったのは ^? で始まる補完候補がなかった為。
        然し、何故か今回の判定では ^? が続きにあるという勘違いをしてそのまま挿入してしまう。

      具体的にどういう事になっているのか調べる。と思ったら…。成る程。

      comp_filter_type='head' compv_new='' _ble_complete_ac_cand='.git'

      failglob になって、その結果として compv_new='' になって、
      空文字列が入力されている状態という事になって、
      結果として何でも受け入れてしまうという状態になっているという事。

      [修正]

      対処方法としては (1) done: 先ず DEL を直接送信する設計は止める事にする。
      (2) done: 展開に失敗したら素直に諦める。
      DEL に対する bind は改めて確認してみたが特に問題になりそうにはない。

2020-02-10

  * [bash-completion] failglob: 以下のエラーメッセージが補完で出る [#D1280]
    "[murase@hp2019 0 bin]$ ln -s ~/.mwgbash: 一致しません: \~/.mwg"

    →これはbash-completion の問題だった。
    そもそも bash-completion は failglob に対応できていない。

    | 何故? そもそもグロブパターンですらないのに
    | →調べたらエラーが出た。うーん。
    | どうも \ が含まれているだけでパターンとして取り扱われる様だ。
    |   value='\~/.mwg'
    |   echo $value
    |
    | 何処でこのエラーメッセージが発生しているのだろうか。
    | と思ったら再現しなくなった。うーん。これは fzf の方のバグだろうか。
    | →再現した。ln コマンドで再現する。ln _fzf_path_completion である。
    |
    | 辿って行くと _longopt (bash-completion) がエラーを発生させている。
    | _longopt に対して bash-completion は ln ~/.mwg -s という引数を渡している。
    | うーん。ble.sh なしで bash-completion を使った時にも failglob で同じエラーが発生する。
    | つまり、これは bash-completion の問題である。

  * util: ble/util/stackdump は >&1 に出力するべきなのでは [#D1279]
    使う側が目的に応じて出力を変更するべき。
    後 ble/util/stackdump を直接使っている箇所を ble-assert
    もしくは ble/util/assert に置き換えられないか。
    →ble/util/assert で書き直した。

  * [棄却] edit: 既定で bind している fg は builtin fg の方が良い? [#D1278]
    或いは fg のままの方が良い?
    もしユーザが fg を上書きしているのだとすればそれなりに機能を追加している
    という事の気がするので fg の儘の方が良いのではないかという気がする。

  * complete: BSD sed? が bind -p の解析で misencoded char のエラーを出す (reported by dylankb) [#D1277]
    https://github.com/akinomyoga/ble.sh/issues/41#issuecomment-583892006
    これは最近追加したコードが悪いのに違いない。分かった。修正した。

    →実際に FreeBSD 試してみた所エラーメッセージはでていない。
    つまり、これは BSD sed ではない? どの sed がエラーメッセージを出しているのだろう。
    然し、検索するとどの頁も macOS の sed は BSD sed だと言っている。
    BSD sed にも色々亜種が有って FreeBSD の物と macOS の物では振る舞いが違うという事なのか?

2020-02-09

  * edit: PS1, PROMPT_COMMAND, PRECMD に於いて BASH_COMMAND, _ を復元 [#D1276]
    cygwin 問題報告の例を作る上で BASH_COMMAND を用いる use case が
    ある事に気付いたが、これが ble.sh では動かない。修正した。

  * complete: fzf complete cd が動かない (reported by dylankb) [#D1275]
    https://github.com/akinomyoga/ble.sh/issues/41
    fzf が動かないという話。これは既に解決済みの話。彼は古い version を使っている。
    然し、二つ目の項目に関しては前の修正とは関係ない。
    先ず再現を試みたがそもそも fzf の振る舞いを再現する事ができない。

    [原因]

    少なくとも cd の補完に関しては ble/cmdinfo/complete:cd で処理しているので、
    fzf が幾ら設定を追加しようとも関係ない筈だ。そして ble/cmdinfo/complete:cd
    が報告されたエラーを出力している筈である。しかし、そうだとしても、

      -bash: cd: too many arguments
      [ble: exit 1]

    というのはどういう事であろうか。まるで cd ** でコマンドを実行したかの様である。
    というか [ble: exit 1] と表示されるという事は実際に
    cd ** でコマンドを実行したということであろう。
    fzf をロードしていると同じ事が起こるのだろうか?

    少し fzf だけをロードして試してみる事にする。
    先ず cd **TAB とするとちゃんと fzf が起動する。そして置き換わる。
    また cd ** で直接実行すると報告されたのと同じエラーメッセージが出る。
    恐らく dylankb は TAB で fzf を起動してそのまま一番最初の物で確定する癖になっているのだ。
    その想定で、先ず fzf がちゃんと起動する様に修正する必要がある。

    取り敢えず ble/cmdinfo/complete:cd を取り除く。
    それから fzf が呼び出されているかの確認を行う。

    分かった。二種類の問題がある。

    x ble/cmdinfo/complete:cd
      これは unset するしかない。

    x < /dev/null にしているという事。
      うーん。< /dev/null に関しては
      ユーザの側で </dev/tty を開く様にお願いすれば良い。
      (しかし、こういう微妙な仕様の違いでひっかかるのは注意を要する。)
      →これも /dev/tty に繋ぐようにして試してみたが直らない。

    x '**' を ble.sh が独自に最初の単語に展開している事
      と思ったがそうでもない。
      fzf にはちゃんと '**' という文字列が渡っている。
      どうした理由かは分からないが。

    x 分かった。原因は COMP_WORDS である。

      これの解決方法は。どの様にして COMP_WORDS を調整するか。

    [解決方法]

    a ユーザに comopt を指定してもらう。指定がある場合に振る舞いの変更を行う。
      complete の設定に予め含めるというのはできない。非標準のオプションだから。

      "" 等の quote の事も考えると pathname expansion だけ実行しない
      という様にするのか、或いは展開そのものを全くしないという事にするのか。
      中途半端に展開しても今度は '**' と指定した時に困るのだから、
      展開そのものを全く実行しないという様にするのが自然である。

      その為には _fzf_dir_completion という関数を上書きしなければならない。
      % 然し、_fzf_dir_completion 側の実装と合わせなければならない。
      % そう言えば以前デバグの為に関数に処理を付け加える advice 云々という関数を定義した様な気がする。
      % しかし今簡単に探してみると見つからない。
      % そもそもどういう関数名だったかなど。うーん。 '"function' で探して見つからないので、
      % その関数は恐らく全然別の所で定義した物の気がする。
      % →分かった。song526 の ble.sh の中に measure.sh という commit していないスクリプトがあった。
      %   中を覗いてみたが advice の様な汎用性を持たせた実装にはなっていなかった。

      何れにしても新しく関数を追加する必要があるという事なのである。

      →結局他にも問題が沢山あるという事が分かった。
      オプションを指定するだけで解決できる様な問題ではない。

    b 或いは ble/cmdinfo/complete:cd を上書きしてもらう?
      こちらの方が手軽である。然し comp_reply を読む必要がある。
      と思ったが、nospace だとか色々のオプションをどの様に処理するのか?
      これまでの方法だと compgen が色々何とかしてくれた。

      function ble/cmdinfo/complete:cd {
        local COMP_LINE=$comp_line
        local -a COMP_WORDS=("${comp_words[@]}")
        local COMP_CWORD=$comp_cword
        local COMP_POINT=$comp_point
        local -a COMP_REPLY=()
        _fzf_dir_completion "${comp_words[0]}" "${comp_words[comp_cword]}" "${comp_words[comp_cword-1]}" >/dev/pts/7
        compopt() { echo "compopt $*"; }
        comp_opts+=:nospace:
        local cand
        for cand in "${COMPREPLY[@]}"; do
          ble/complete/cand/yield word "$cand" ""
        done
        ble/textarea#invalidate
        return 0
      }

      うーん。結構長い関数になってしまう。

      実際にこれを動かして試してみると無限ループになっている。何故?
      未だ再現していない。うーん。再現しない。何だったのだろうか。

      x fixed: 更にもう一つの問題点は fzf が表示を書き換えてしまっているので、
        表示が乱れてしまっているという事。これは invalidate を呼び出せば良い。
        実際に試してみて解決する事を確かめた。

      x もう一つの問題点はこれが interactive な補完を呼び出すという事。
        現状の実装では auto_complete も同じ枠組みを使っているので、
        auto_complete によって fzf が呼び出されてしまってこれは面倒。

      更に色々試してみた結果 compopt の処理もしなければならないし、
      色々面倒である。結局やはり ble.sh の progcomp 経由で実行した方が良い気がする。

    c 結局 fzf の側の関数を動的に書き換えて振る舞いを変更する事にした。

    * 一旦適当に reply しておく。

      % ## 3. ble.sh closes stdin/stdout while `fzf` is used
      %
      % Sometimes a user-provided completer consumes or flushes stdin
      % unintentionally. But this causes the problem for
      % auto-complete. Because auto-complete is performed in the
      % background, the user inputs will be lost if the background
      % user-provided completer flushes stdin. For this reason, ble.sh
      % by default closes the standard streams of user-provided
      % completers. If user-provided completers really want to do
      % something with stdin/stdout, the completer need to open
      % `/dev/tty` for itself. But `fzf` does not do that.

      調べながら書いていたら時間を食ってしまった。
      後、上の内容は結局本当か分からない。
      実際に fzf のソースを見てみると /dev/tty を開いている箇所がある。
      従って、試している時に発生した hang はこれとは関係ないのかもしれない。

      →実際に試してみたらやはり fzf は /dev/tty を開かずに実行しようとして、
      それで hang してしまっている。やはり /dev/tty の対策はしなければならない。

    [実装]

    取り敢えずおおまかな実装をしてから細かい振る舞いの調整を行えば良い。
    以下の二つを上書きすれば良い気がする。

      __fzf_generic_path_completion
      _fzf_complete
      追加: _fzf_complete_kill

    * 無限ループになっている原因は分かった。auto-complete である。
      auto-complete の中では fzf を起動しない様にした所、動いている。

    * 今度の問題は ble.sh が勝手に変換結果をフィルタしてしまうという事。
      ** のまま変化しない。
      うーん。候補の生成まではちゃんとできている。
      しかし再度の候補生成が試みられてそれで何も生成されずに終わっている。

      →あー。何が起こっているのか分かった。補完がキャンセルされている。
      何故かと言うと fzf が DSR(5) を要求してその返答が届いているから。
      ble.sh は補完の計算中にユーザ入力が来たと思って補完処理を中断する。
      これによって何も起こらないという事が発生している。

    * ESC [ 0 n が not found というエラーメッセージが出ている。
      % bind していても処理されないという事。
      % というか bind '"\e[0n":...' はどのレベルで処理されるのだろう?
      % →確認してみた所、以下の様に登録されていた。うーん。
      % ble-bind -m 'vi_imap' -f 'M-[ 0 n' 'redraw-line'
      %
      % これはどうしたら良いか。blesh では認識できない
      % escape sequences は無視する様にしている。
      % それは terminal が不意に何か変な response をした時に
      % ユーザの入力と勘違いして変な振る舞いをしないようにする為。
      % なのでこの設計を変更するつもりはない。
      %
      % ならば正しい設定は一体何か?
      % 結局これを正しいシーケンスとして登録する事である。
      % ble-bind -k 'ESC [ 0 n' DSR

      うーん。結局 fzf の DSR(5) による hack を封じる事にしたので
      これの対策はしなくても良いのである。

2020-02-08

  * proghl の中で行った fix を ble-0.3 にも適用しなければならない [#D1274]
    続いて patch を適用していく必要がある。適用した。

  * msys1: C-d の受信について [#D1273]

    mkfifo がエラーになっている。Function not implemented と表示される。
    sleep に関しては cygwin 用の実装を使っている。
    stderr.pipe に関してエラーになっている様だ。これの所為で C-d も受信できていない。

    C-d の受信に関しては bind 'set bind-tty-spacial-chars off' にしたら
    受信できるかもしれないと考えたが実際に試してみるとできない。
    やはり駄目の様だ。

    もしかして msys2 も駄目なのかもしれないと思って msys2 で mkfifo を試したら動いた。
    つまりやはり msys1.0 に fifo (pipe) が実装されていないという事なのだ。
    因みに coproc も 3.2 以下には存在しない。

    そうすると、pipe を使わない代替実装を考えなければならない。
    実は以前は pipe を使わない実装だったような気もする。

    | a pipe を単に普通のファイルに置き換える実装を考えてみたが駄目そう。
    |   > stderr.pipe としても一度 exec したものをそのまま使っていると、
    |   以前の末尾の位置の続きに書き込まれてしまう。
    |   毎回 exec する必要があるのではという気がする。
    | b プロセス置換で実装してみようとしたがプロセス置換も
    |   Function not implemented になった。
    | c そうすると何度も sleep しながら待つ実装になるだろうか。。
    |   試しに tail -f を実行してみたら良い感じに動く。
    |   更にファイルを truncate した事もちゃんと検出してくれる。
    |   tail は優秀なのではないか。然し、遅延があるのが気になる。
    |   内部的に sleep して実装しているのだろうか。
    |   自分で細かく sleep コマンドを呼び出すよりは良い。
    |   取り敢えずこれで実装する事にする。
    |
    |   →実装してみたが微妙。遅いし消滅している入力もある気がする。
    |   後、親 Bash が死んだ後も生き続けている気がする。
    |   もっと別の実装方法を考える?
    |
    |   入力が消滅するのは stderr.off の瞬間にファイルをクリアするからだった。
    |   クリアしないで追記する様にしたら入力は消滅しない様になった。
    |   但し、エラーを沢山出すとディスクに際限なく書き出してしまう。
    |
    |   sleep を使うにしてももっと実装を工夫しなければならない。
    |
    |   解決しなければならない問題が幾つか在る。
    |   x いつ誰がファイルをクリアするのか。
    |     書き込み元がクリアする事にすると
    |     読み取りする前に消えてしまう行が出てくる。
    |     読み取り側がクリアする事にすると、
    |     書き込み元はそれを知らないので、
    |     いきなりファイルの途中から続きを書き出してしまう。
    |
    |     或いは2つのファイルを交互に使う等してこの制限を回避する事は可能だろうか。
    |     然し、読み取り側は書き込み元がどちらのファイルを使っているのか検出する術がない。
    |     ファイルAとファイルBのどちらの内容の方が先に読み取るべき物なのか分からない。
    |
    | d 思いついた。これは書き込み元が新しくファイルを開く時に、
    |   データの出力先が有限のサイズを持っている場合には、
    |   新しく別名でファイルを開く事にすれば良いのである。
    |   そして読み取り側がファイルをクリアする事にする。
    |
    |   書き込み元がファイルサイズをチェックしてから
    |   実際にファイルを開く間に何か変化があるという事はない。
    |   読み取り側はファイルを短くする事はあっても長くする事はないので、
    |   一旦空のファイルであると判定が出たらそれが他の要因で変化する事はない。
    |
    |   実装してみる事にする。と思ったが駄目だ。
    |   x 読み取り側がどれを読み取ったら良いのかが分からない。
    |     若い番号から順に読み取れば良いと考えていたが、
    |     考えてみるとファイルをクリアしてしまうと、
    |     親がまた若い番号から書き込み始めてしまうので、
    |     一概に若い番号から順に読み取れば良いという訳ではない気がする。
    |     →クリアは大きい番号のファイルから順番にするという規則にする。
    |       x それでも駄目。順番に消していっている途中に書き込み側が
    |         有限の番号で開くとその後でそれより若い番号を消去する事になる。
    |   x それに読み取り側がどのタイミングでファイルの末端が来たと
    |     判断すれば良いのかも分からない。
    |     未だ書き込み中かもしれないからである。
    |     或いは、特別な信号を書き込む事にする?
    |
    |   色々バグがあったりして動かなかったりしたが動く様になった。
    |   と思ったら C-c で子プロセスが勝手に終了してしまう。
    |   うーん。trap -- '' INT QUIT としたら終了しなくなったが、
    |   今度は遅延が生じる様になってしまった。どうして trap が遅延に影響するのだろう?
    |   良くわからない。
    |
    |   更に sleep を高頻度で回しているのでやはり HDD のアクセスが気になるのである。
    |   うーん。tail -f の方が現実的なのかもしれない等と考える。
    |
    | e うーん。或いは lastpipe 等を弄って何か上手にできないのか。
    |   cat | exec 5<&0 みたいな事をする等…。
    |   然し、これはデータの流れが逆である。寧ろ first pipe 的な物が必要である。
    |
    |   試しに cat README.md | exec 5<&0; read line <&5 として見たが
    |   ディスクリプタは開いてなかった。と思ったが last pipe するのを忘れていた。
    |   然し shopt -s lastpipe を実行した後でも <&5 しようとすると
    |   bad file descriptor と出て、fd がそもそもない場合と同じエラーメッセージ。
    |   Bash が色々の fd を閉じてしまっているという事の気がする。
    |   或いは元の状態を復元している。
    |   なので、lastpipe を使って何とかする事はできない。

    最初に試したのは c の実装

    | : >| "$_ble_edit_io_fname2.pipe"
    | {
    |   tail -f "$_ble_edit_io_fname2.pipe" 2>/dev/null | ble-edit/stdout/check-ignoreeof-loop tail & disown
    | } &>/dev/null
    | function ble-edit/bind/stdout.off {
    |   ble/util/buffer.flush >&2
    |   ble-edit/bind/stdout/check-stderr
    |   exec 1>>$_ble_edit_io_fname1 2>"$_ble_edit_io_fname2.pipe"
    | }

    x どうも消滅している入力がある気がする。
      更にユーザの入力が前後してしまって UTF-8 を破壊したり
      色々遅延に関係して変な事が起こっている。

    x この実装だと無限に読み取り続けようとしてしまう。
      親を定期的にチェックして親がいなくなったら終了する様に書き換えてみたが、
      それでも tail の方が終了しないで残ってしまう様だ。
      tail -f は誰かが kill しなければならないのである。

    結局、d の複数のファイルに分散して書き込む方向性で実装して
    以下の様なコードができたが思い通りに動かない。

    | {
    |   builtin trap -- '' INT QUIT
    |   while kill -0 $$ &>/dev/null; do
    |     declare index=0 processed=
    |     while file=$_ble_edit_io_fname2.$((index++)); [[ -e $file ]]; do
    |       [[ -s $file ]] || continue
    |       processed=1
    |       while :; do
    |         if ! IFS= builtin read -r line && [[ ! $line ]]; then
    |           kill -0 $$ &>/dev/null || exit
    |           ble/util/msleep 100
    |           continue
    |         fi
    |
    |         [[ $line == __BLE_STDERR_EOF__ ]] && break
    |
    |         [[ $line == *[^$_ble_term_IFS]* ]] &&
    |           ble/util/print "$line" >> "$_ble_edit_io_fname2"
    |
    |         if ble-edit/stdout/check-ignoreeof-message "$line"; then
    |           ble/util/print eof >> "$_ble_edit_io_fname2.proc"
    |           kill -USR1 $$
    |           ble/util/msleep 100
    |         fi
    |       done < "$file"
    |       : >| "$file"
    |     done
    |     [[ $processed ]] || ble/util/msleep 100
    |   done & disown
    | } &>/dev/null
    |
    | _ble_edit_io_fname2_write=
    | function ble-edit/bind/stdout.on {
    |   exec 1>&$_ble_edit_io_stdout 2>&$_ble_edit_io_stderr
    |   [[ -s $_ble_edit_io_fname2_write ]] &&
    |     ble/util/print __BLE_STDERR_EOF__ >> "$_ble_edit_io_fname2_write"
    |   return 0
    | }
    | function ble-edit/bind/stdout.off {
    |   ble/util/buffer.flush >&2
    |   ble-edit/bind/stdout/check-stderr
    |   local index=0 highest=-1
    |   while [[ -e $_ble_edit_io_fname2.$index ]]; do
    |     [[ -s $_ble_edit_io_fname2.$index ]] && highest=$index
    |     ((index++))
    |   done
    |   _ble_edit_io_fname2_write=$_ble_edit_io_fname2.$((highest+1))
    |   exec 1>>$_ble_edit_io_fname1 2>"$_ble_edit_io_fname2_write"
    | }

    問題点は以下の通り

    x trap -- '' INT QUIT をして置かないと C-c 等を入力した時に
      この補助プロセスが終了してしまう。

      一連の一時ファイルを削除する補助プロセスがないと、
      一時ファイルがどんどん増えて親シェルの動作がどんどん重くなる。
      これについては補助プロセスがいなくなった事を検出して
      適宜再起動する様にすれば良い気もする。

    x trap -- '' INT QUIT をすると今度は謎の遅延が発生する様になる。
      次の入力を受け取らないとシグナルが受信されないという事になる。

    x また sleep を頻繁に呼び出すので常にディスクがアクセス状態になる。
      command sleep 以外の待ち時間の費やし方を考える必要がある。
      適当に /dev/udp/127.0.0.1/0 等を開いて誤魔化す? にしても、
      read が小数に対応していないので timeout できない。

    % 今の所は単純に C-d を諦めるという実装にするしかない気がしている。

    もしこのシステムが msys1 なのだとしたら、
    gcc があると期待して良い。
    そして gcc があるという事は C プログラムが使える?
    g++ は使えないかもしれない。
    何れにしても gcc が使えるならば Sleep も使える。
    そして tail -f の代替をコンパイルする事もできる。

    然し tail -f 方式はタイミングの問題で
    出力が失われてしまうのが問題なのだった。
    やはり複数ファイルを使う必要があるのか。
    或いは、一つのファイルで頑張る方法があるだろうか。

    複数ファイルを使う方法に頼ると子プロセスが消えた時に
    無限にファイルが増えていく事になる。これは避けたい。
    とするとファイル数に上限を定める事になる。
    それぐらいならば 2 つのファイルで頑張る方法を考えるべきでは?

    gcc が使えるのであればファイル名を変更する事が可能である。
    ファイル名を変更できるという事は、可能性が増えるという事。
    改めて考え直す事にする。

    親プロセスを A としてバックグラウンドプロセスを B とする。
    A は既存のファイル F に只管追記する事にする。
    B は mv F G してから G を読み続ける。
    新しく F が生成される迄は G の読み取りを試み続ける。
    これで行ける気がする。

    ? yes: 問題は今書き込んでいる途中のファイルを読み取れるのか。
      そして読み取れたとして一旦 EOF に達した後に続きが書き込まれた時に、
      再度続きの読み取りを再開する事ができるのかという事。
      試してみた所できる様だ。

      1文字ずつ読み取るのはできた。まとめて読み出すのもできた。

    ? 次の問題は親プロセスが存在しているかどうかをチェックする事ができるのかという事。
      これは WINPID を知っていればできる筈。然し、WINPID を取得することは可能か?
      或いは普通に親プロセス? と思ったが親プロセスなのか親の親プロセスなのか分からない。
      うーん。msys には /dev も /proc もない。

      少なくとも cygwin PID から WINPID に変換できれば Win API が使える。
      https://stackoverflow.com/questions/1679337/convert-a-cygwin-pid-to-a-windows-pid

      cygwin の場合には include <sys/cygwin.h> とすれば良い様だ。
      msys の場合にはそんな簡単な訳ではない様だ。
      或いは msys の dll を見たら行けるのかもしれないが面倒なので止める。
      結局 ps コマンドを実行してその結果を解析するしか無いのだろうか。

      取り敢えず WINPID は取得できる。次にするべき事は。
      Windows でのプロセス存在確認は GetExitCodeProcess で行うそうだ。
      https://stackoverflow.com/questions/1591342/c-how-to-determine-if-a-windows-process-is-running
      その為に PROCESS_QUERY_INFORMATION を指定して OpenProcess する。

      % 実装して動かそうとしたら駄目。
      % unlink に失敗している。unlink せずに真面目に rename する事にしてみたが、
      % それも失敗した。どういう事だろうか。開いていると rename できないのか、
      % 或いは tmp に作成しているから rename できないのか。。色々試す必要がある。
      %
      % HOME に作ったファイルは rename で移動できる。
      % tmp の下の $_ble_base_run に作ったファイルも rename で移動できる。
      % うーん。変だファイルを開きっぱなしにしていてもちゃんと移動できる。
      % 更に移動した後も続きが書き込まれているという事を確認した。
      % →これは結局 is_file の実装のバグだった。return FALSE するのを忘れていた。
      %
      % それならば rename せずに unlink でも行けるかもしれないと思ったが駄目だった。

      取り敢えず何となく動く様にはなったが、
      沢山入力すると permission denied のエラーが発生する。うーん。
      そもそも入力を受け取る度にファイルを作成するというのも効率が悪い。
      特定の回数毎に開き直すという実装でも問題ないのではないかという気がする。
      ファイルを開き直すのは時々にするという手もあるのかもしれない。
      →と思って試してみた所駄目だった。どうも dup するともう使えなくなる様だ。。

      ではエラーメッセージを封じるのか? というと難しい。
      エラーメッセージを封じる為には 2 をリダイレクトしなければならないが、
      今は 2 の接続先を変更したいので 2 をリダイレクトする訳には行かないのである。
      うーん。最初に適当なファイルに繋いで、それから 2 をリダイレクトする?

    [関連項目]

    * fixed: この bleopt_internal_ignoreeof_trap という変数は意味があるのか?
      サブシェルの中で見ているので親シェルで設定が変化しても追随できない。
      寧ろ、受信する側で bleopt_internal_ignoreeof_trap に応じて無視するべきでは。
      或いは、bleopt_internal_ignoreeof_trap が空ならそもそも対策コードを実行しない。
      →これは抑もの bleopt_internal_ignoreeof_trap の使い方が間違っていた気がする。直した。

2020-02-07

  * MSYS 1.0 を使ってみたら全然動かない [#D1272]

    * msys の version 判定は uname -r を実行すれば良い。
      というか _ble_term_CR が空かどうかで判定できる気がする。

    * MSYS1.0 に至っては _ble_term_CR=$'\r' ですら効かない様だ。
      仕方がないので _ble_term_cr=$'\e[G' で代用すれば良い。

    ? check $_ble_base_cache/cygwin.term
      cygwin.term を確認してみると cr, ich, dch, ech, Ss が空欄になっている。
      重要なのは cr だけである。それなのに _ble_term_cr=$'\e[G' しても未だ変だ。
      他に実装されてはいるが振る舞いが変な制御機能があるという事なのだろう。
      例えば RI や IND が実装されていないという事だろうか。

    ? yes: これは cygwin console か?
      というより TERM を cygwin にしているがこれは本当に cygwin console か?
      実は cygwin pseudo console の気がする。と思ったが実際に実行してみると
      256色対応もちゃんとできていないのでこれは pseudo console ではない。
      やはり cygwin console なのである。
      pcon に切り替える機能は実装されていないだろうから当然である。
      丁度 cygwin-3.0.7 と同様に特別な事をしていなければ cygwin console なのである。

    * fixed: _ble_term_xenl と _ble_term_ind を修正したら何となく動く様になった。

    ? ok: xenl が効いていない?
      % しかしよく見てみると _ble_term_xenl=1 にすると無条件に eol mark が表示される。
      % _ble_term_xenl=0 にすると無条件に eol mark が表示されない。
      % と思ったがこれは勘違いである。echo hello として eol mark が表示されないと勘違いした。

    * fixed: getent が無いというエラーメッセージが出る。
      →検査している気になっていたが実は bash 3.1 では、
      type a b c の中で一つでも存在していれば成功するという事なのか?
      →どうもその様である。つまり ble.pp にあるコードは修正する必要がある。
      調べた所 Bash 4.0 以上で全てのコマンドが見つかった時に真になる様だ。
      修正した。

    * fixed: よく考えたら構文解析で bash version をチェックするのを忘れていた。

  * MSYS2 では paste-from-clipboard という readline 関数が追加されている様だ? [#D1271]
    確認するとやはり paste-from-clipboard は cygwin 版の bash にはない。
    何れにしても新しく対応する事にする。これは /dev/clipboard を見れば良い。
    →実装した。動作確認した。動いている。OK

  * msys2: 端末の座標計算が時々おかしい。 [#D1270]
    https://github.com/akinomyoga/ble.sh/issues/40#issuecomment-582941178

    DA2R を見ると mintty 30000 の気がする。
    実際に Options... を開いてみると mintty 3.1.0 is available
    という感じの内容が表示される。

    或いは何か msys の terminfo か tput が壊れているという事だろうか。
    うーん。これについてもちゃんと調べる必要がある。
    取り敢えず cygwin の term cache と比較してみる?

    → xterm-256color.term (Cygwin) と xterm.term (MSYS2) を比較してみたが、
    着色と DECSCUSR しか違いは見られなかった。これらは配置には関係ない。
    従って、やはり MSYS2 の mintty の振る舞いが変なのだという気がする。
    もしそうだとしたらどの様にして変な振る舞いの原因を特定するのか。
    そしてどの様にして workaround をすれば良いのか。
    結構面倒な問題である。そもそも他の端末で異常は発生していない。
    もし純粋に mintty のバグであるのであれば、これは ble.sh で対処しなくても良い。

    これは CR が効いていないという事? 或いは stty の状態が変?
    以下は stty -a の diff である。微妙な違いはあるが関係ない気がする。
    実際に cygwin を msys 側に合わせてみたが問題は再現しない。
    | --- stty -a (cygwin)^I2020-02-07 07:21:43.088892300 +0800
    | +++ stty -a (msys)^I2020-02-07 07:21:47.549238700 +0800
    | @@ -4,7 +4,7 @@
    |  werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
    |  -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
    |  -ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff
    | --iuclc ixany imaxbel iutf8
    | +-iuclc -ixany imaxbel -iutf8
    |  opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    |  isig icanon iexten echo echoe echok -echonl -noflsh -tostop echoctl echoke
    |  -flusho
    次に CR の振る舞いを確認する。特に問題なく動いている様に見える。
    何と ${#_ble_term_cr} を出力してみたら中身が空である。。

    分かった。_ble_term_cr='^M' を実行すると中身が空になる。
    _ble_term_cr=$'\r' だと大丈夫。
    その他の駄目なパターンはあるだろうか。
    変数に入っている _ble_term_cr の場合は大丈夫の様だ。

    うーん。これの対策方法は不明である。
    a 一つの方法は _ble_term_cr で CR を使わないという方法。
      別の制御機能 (hpa) 等を用いて _ble_term_cr を模倣する。
      これの問題は本当に CR が欲しい所で _ble_term_cr を使っている箇所がないかという事。
      確認してみた所そういう場所はないようである。
    b もう一つの方法は _ble_term_cr=$'\r' という形式で記録するという事。
      うーん。前者の方が楽だが、こちらの方が妥当の気がする。
      declare-print-definitions を修正する?
      修正したほうが良い気がする。もし MSYS2 でこれが一般に問題になるのであれば、
      その他の場所で記録した CR も消滅するという事である。
      という事であれば declare-print-definition 等で根本から修正する必要がある。

    declare -p の振る舞いについて確認しておく。

      bash-3.1 declare -- a="\$"  bash-3.1 declare -a a='([0]="\$")'  ")'h-3.1 declare -a a='([0]="
      bash-3.2 declare -- a="\$"  bash-3.2 declare -a a='([0]="\$")'  ")'h-3.2 declare -a a='([0]="
      bash-4.0 declare -- a="\$"  bash-4.0 declare -a a='([0]="\$")'  ")'h-4.0 declare -a a='([0]="
      bash-4.2 declare -- a="\$"  bash-4.2 declare -a a='([0]="\$")'  ")'h-4.2 declare -a a='([0]="
      bash-3.0 declare -- a="\$"  bash-3.0 declare -a a='([0]="\$")'  ")'h-3.0 declare -a a='([0]="
      bash-4.1 declare -- a="\$"  bash-4.1 declare -a a='([0]="\$")'  ")'h-4.1 declare -a a='([0]="
      bash-4.3 declare -- a="\$"  bash-4.3 declare -a a='([0]="\$")'  ")'h-4.3 declare -a a='([0]="
      bash-4.4 declare -- a="\$"  bash-4.4 declare -a a=([0]="\$")    bash-4.4 declare -a a=([0]=$'\r')
      bash-5.0 declare -- a="\$"  bash-5.0 declare -a a=([0]="\$")    bash-5.0 declare -a a=([0]=$'\r')

      どうも declare -p は一貫して ".." に囲んで出力する様だ。
      但し、Bash 4.4, 5.0 で制御文字が含まれている場合を除く。
      Bash 4.4, 5.0 の場合にはそもそも ^M が含まれないという事だから、
      ^M が含まれる場合には "" の中にあると仮定して良いだろう。
      従って ^M を $_ble_term_CR に変換する。
      _ble_term_CR は本体の方で直接 $'\r' を代入すれば良いだろう。

      固定文字列とそうでない物は大文字と小文字で区別する事にする。
      * _ble_term_{soh,del,fs} も変更する?
      * 然しそうすると _ble_term_nl も変更しなければならず面倒だ。
        取り敢えず _ble_term_nl は出力に使っているから変更は保留。
        他は特殊用途でしか使っていないのである。

    取り敢えず動いている気がする。これで良い。
    ble-0.3 に移植した。動いている。OK

  * ble-decode/has-input [#D1269]
    →これはマージのミスだった。修正した。

2020-02-06

  * [勘違い] msys2: inputrc の `$if` が正しく解析されていない [#D1268]
    https://github.com/akinomyoga/ble.sh/issues/40#issuecomment-582941178

    うーん。これはシェルコマンドに変換している筈なので、
    そんなに問題になる事はない筈。
    一旦どの様なシェルコマンドに変換されているのか確認する必要がある。

    →これは実はちゃんと処理できていた。勘違いだった。
    paste-from-clipboard という関数が定義されている特別な状況に対する
    $if なのかと思ったが、実は MSYS bash は拡張機能として
    paste-from-clipboard という機能が用意されているのだった。

  * inputrc のコメントが正しく除去されていない [#D1267]
    https://github.com/akinomyoga/ble.sh/issues/40#issuecomment-582941178

    元々の実装の時にコメントは実は行頭から始まらなければならない
    という事を確認したのではなかったのか。
    これについても実際に試して調べる必要がある。

    "\C-t": end-of-line
    "\C-t": end-of-line # hello   ->comment
    "\C-t": end-of-line# hello    ->not-comment
    "\C-t": "end-of-line # hello" ->not-comment

    うーん。ちゃんと quote も考えた上での処理になっている様だ。
    そして # は単語の先頭でなければならない。
    更に、bind '...' に指定した時でもちゃんと # をコメントとして認識している。
    bind -x '"\C-t": echo hello # world' の場合には # world 以降もコマンドの一部になっている。
    bind '"\C-t": "echo" # world' の場合にはコメントとして取り扱われている。
    single quote でも実はマクロとして取り扱われ、
    中にある # はコメントとして取り扱われてしまう事はない。
    $ bind '"\C-t":'\''echo\'\'' # \'\''world test'\'
    で試してみた所 echo' # 'world test という文字列が登録できたので、
    single quote の中でも \' は有効なのだと思われる。

    取り敢えず実装した。未だ見落としがあるかもしれないが取り敢えずこれで良い気がする。

  * ble-0.3 に於ける ble-reload は未だにおかしい [#D1266]
    https://github.com/akinomyoga/ble.sh/issues/40#issuecomment-582941178

    Ref: #D1223 #D1199 #D1130

    ble-update を ble-0.3.2 に対して実行してみたら
    PS1 等の環境変数が失われている。というかコマンド実行されている?
    直した筈の問題が直っていない。
    取り敢えず一番最初に修正するべきなのはこれの気がする。

    commit d35682a で導入した .prologue 呼び出しを
    commit 59c1ce4 で別の場所に移動している。
    これは ble-0.3 ではどの様に適用されているだろうか。
    ble-0.3 に適用したのは ce93c08 である。
    別に prologue が消滅する等の事は起こっていない。

    うーん。実際に症状を確認してみると [ble: detached] と表示されている。
    改めて cygwin で確認してみると再現する。やはり MSYS2 特有の問題ではない。
    ble-0.4 では再現しないので ble-0.3 特有の問題である。
    取り敢えず [ble: detached] を手がかりに調べる。

    どうも。ble-reload を --attach=prompt にしたのにも拘らず、
    check-detach において prompt-attach の時の処理を省略したのが原因の様だ。
    改めて色々ちゃんと動くか確かめる事にする。
    * ble-detach
    * ble-attach
    * ble-detach && ble-attach
    * ble-reload
    * source ble.sh --noattach && ble-attach
    * source ble.sh --noattach
    * source ble.sh --attach=prompt
    * source ble.sh --attach=attach

    一応何れも問題なく動いている様な気がする。

    * ble-reload && PROMPT_COMMAND=

    これは駄目だった。。。どの様にするのが良いだろうか。
    修正した。PROMPT_COMMAND を再度上書きする方式で良かった。
    改めて上記のテストも行った。全て大丈夫である。

  * msys2: root 権限があるかどうかの判定ができない [#D1265]
    https://github.com/akinomyoga/ble.sh/issues/40#issuecomment-582941178

    cygwin の手法を流用しようとしたら常に root 権限がある事になってしまう。
    調べてみると全てのユーザを msys を起動したユーザと見せかけている。
    然し、実際には異なるので何か書き込もうとすると permission denied で失敗する。
    というか Windows の標準のコマンドで管理者権限が在るかどうか
    判定できる物はないのだろうか。

    或いは EUID もしくは UID を見たら分かったりするだろうか。

    と思ったら実際に起動してみると何故かちゃんと判定できている。
    判定には EUID を用いているが実際に EUID を実行してみても 0 ではない。
    しかも $_ble_edit_prompt__string_root を出力してみると '$' である。
    何処で入れ替わっているのか?? 或いはもしかして元の bash の PS1 が表示されている?

    と思ったら分かった。そもそも PS1 に # がハードコードされている。
    逆に言えば何処かに判定するコードが存在しているという事である。
    探せば良い。

    今これが作業中なのでこれについて調べる事にする。
    /etc/bash.bashrc に検出コードがある。
    if [[ -n "$(command -v getent)" ]] && id -G | grep -q "$(getent -w group 'S-1-16-12288' | cut -d: -f2)"
      then _ps1_symbol='\[\e[1m\]#\[\e[0m\]'
      else _ps1_symbol='\$'
    fi

    これを見ると、_ps1_symbol が定義されていて # を含んでいたら privileged と思って良い。
    と思ったが、その直後に unset しているので駄目だ。役に立たない。
    自分で改めて同様のコードを走らせる必要があるだろうか。
    上を参考にして実装した。動作確認した。OK

  * msys2 で動かない [#D1264]
    https://github.com/akinomyoga/ble.sh/issues/40

    見た所 sleep の実装が火を吹いている。cygwin と同じ取扱で良いだろう。
    取り敢えず動くには動く様になった。

    その他調べると色々と振る舞いがおかしい。
    これらは別項目で処理する事にする。

    うーん。面倒なので proghl を merge してしまう事にしよう。

2020-02-05

  * decode: fix error message "command=${[key]-}" for mouse input [#D1263]
    マウスは正式対応していないが contra のテストで有効にして
    試していたらエラーメッセージが出る。
    確認してみると、思い切り未初期化の変数を参照している。修正した。

2020-02-03

  * 2020-01-17 Minix における問題 [#D1262]

    x resolved: ble-reload の後に固まる問題ももしかしてこれだろうか?
      と思ったが症状的に独立な問題だろう。
      →これは別項目で修正した。

    x ok: minix を試していると固まる。と思ったら core.784 として巨大な
      ファイルができている。1.7GB である。道理で固まる訳である。
      ファイルシステムが固まるので他のプロセスもブロックされる。
      検索すると以下の頁が見つかるが余り参考にはならない。
      https://wiki.minix3.org/doku.php?id=soc:2011:debugger

      而もこれは ble-detach した状態であった。但し CPU は 100% ではなくて
      50% になっていた。何らかの別の原因で segfault して、
      その結果として core を dump するのに忙しくて 50% になっていたと
      考えるのが自然である。

      これは恐らくまた別の問題である。これに関しては気にしない事にする。

    x ok: set: tabcomplete というオプションはありませんというエラーになる。
      /etc/profile に set -o tabcomplete というのが記述されている。
      bash にはその様なオプションはない (或いは過去のバージョンにはあったのだろうか)。
      →これは minix の問題であって ble.sh の問題ではない。

    * TERM=minix support
      x fixed: 起動時に c という文字が現れる事について。
      x fixed: コマンドを実行する度に 200404;1 等と表示される。
        これは明らかに bracketed paste mode と modifyOtherKeys である。
        どうやら CSI ? h ですら minix は対応していない様だ。
        取り敢えず対応した。他にも CSI ? を使っている箇所は在る気がする。
      x fixed: eof 判定が動いていない。xenl cap が誤っている?
        xenl=0 にしてみても変化はなかった。
        取り敢えず行末での振る舞いがどうなっているか調べる必要がある。
        →一応 xenl の様な気がする。今の実装はどうなっているのだったか。
        →どうやら SC,RC を使っている様だ。SC,RC を使わない実装?
        →使わない実装に切り替えて見た。多分大丈夫。
      x fixed: SCOSC,RC が動いていない。tput sc / tput rc は失敗する。
        \e7\e8 も動かない。恐らく minix にはないのだろう。
        これの対策は何? 先ず離れた場所に移動しない。
        一行上か或いは panel 3 を利用する。
        一行上を利用するのが自然の気がする。

        ? 然し、delay 後のカーソル位置を取得する方法が分からない。
          特に delay は別プロセスで実行しているので、
          そのプロセスは fork 時の _ble_canvas_x しか知らない。
          メッセージを消去するのは諦める?
          →諦める事にした。
        - canvas.sh 未ロード時の vbell も rc を使っているが、
          対応はしない事にする。実際、使われていない気がする。
          使っているとしても稀なので気にしない事にする。
      x fixed: delete が ^? になっている。
        これは tput kD || tput kdch1 を参照して決める事にした。
      x fixed: C-r が効かない ... reprint undef にしたら直った。
        これも対策を加えた。

    * locale: 例によって locale を切り替えられないというエラーが出ている。
      何処から発生しているのだろうか。一つずつ確認していくしかない?

      取り敢えず補完で沢山メッセージが出るので source:argument を塞いで見たが沢山出る。
      どうも関係ない様だ。そもそも起動した時にエラーメッセージが出る。

      これらは単体で実行しても特に変なメッセージは出ない。
      done: ble/util/.has-bashbug-printf-uffff
      done: ble/util/is-stdin-ready
      done: ble/util/msleep/.check-sleep-decimal-support

      以下の関数は対策が必要な気がする。
      done: ble/widget/.locate-forward-byte
      ok: ble/decode/bind/.generate-source-to-unbind-default
      done: ble/builtin/bind/.parse-keyname
      done: ble/builtin/bind/.reconstruct-user-settings
      done: ble/widget/vi-command/nth-byte

      % どうも ble/util/is-stdin-ready が怪しい気がする。
      % と思って色々変更してみたがどうも関係ない様だ。

      改めて補完の振る舞いを調べるとメニューを表示する時に、
      メニューの項目と同じ数だけメッセージが表示される様だ。
      trace が悪いという事だろうか?
      ble/canvas/trace-tex を手で実行してみたら再現した。
      こういう関数で再現する事が分かった。
      どうもローカル変数の始末は 2>/dev/null がなくなってから?

        fun() { local LC_COLLATE=C; } 2>/dev/null

      trace-text を修正したらメッセージは出なくなった。

  * 2020-01-17 Haiku における問題 [#D1261]

    x ok: Haiku で ble-reload 時に変なメッセージが出る。
      まあこれは bash-4.4 の問題かもしれない。
      →CentOSでやると日本語でエラーメッセージが表示されていて、
      その長さなどが一致している気がするので Haiku のエラーメッセージは
      やはり bind 回りの Bash のバグだろう。

    x ok: また、sleep を呼び出すと Terminal のタイトルバーに
      それが一々表示されて面倒である。別の実現方法を考えた方が良い?
      もし /dev/zero があるならば /dev/zero を読み出そうとするとどうなるか確認してもよい。
      CPU を食わないのであればそれで行く。

      →read -t 1.0 でも同様に Terminal のタイトルが変更される。
      どうも何のプログラムであってもブロックされていると何か出る様だ。
      短い read -t 0.01 をループで回しても同じだった。
      なのでこれはどうしようもない。

2020-02-02

  * decode: 遅延 bind で正しい key に割り当てられていない [#D1260]
    これは cmap が初期化されていないのに ble-bind を呼び出したからである。
    bashrc の中から ble-bind も bind も呼び出される可能性がある事を考えると、
    cmap/initialize 及び decode/initialize はそれぞれ ble-bind, bind から
    呼び出す様にしておかなければならない。もしくは初めから呼び出しておく。
    ble-bind がある度に初期化済みかどうかを確認するのは非効率的だろうか。
    余り考えない事にする。そもそも ble-bind は重いので気にしない。

    序でに blerc を遅延で読み込む事も考えてみたが、
    ble.sh による PS1 等を待避した特別な環境で評価すると変な事になるので、
    やはり今まで通り最初にロードする事にする。

    一連の変更により ble-bind は自動的に遅延される様になったので、
    eval-after-load により手で遅延させる必要がなくなった。
    これに伴い wiki の記述も変更して良いのでは→更新した。

  * 2019-02-09 bind: `bind -XpPS` 等から現在の設定を読み取る? [#D1259]

    現状で bind -X が信用出来ないので、完全な対応は不可能である。
    その様に考えるとやはり builtin bind を上書きして設定を読み取る方が現実的である。
    なので、現在の bashrc の冒頭でロードして、末尾で attach するという形式は当面変わらない。

    * Note: 2019-12-14 bind -X については bash に修正が入った。
      https://lists.gnu.org/archive/html/bug-bash/2019-12/msg00053.html

    * Note: 2019-12-30 detach 時の復元に関して。
      現状では bind -X の設定を読み込んでから
      bind -ps の設定を読み込む様にしている。
      これで古い bind -x の設定によって bind -ps の設定が上書きされてしまう事はなく、
      逆に bind -x の設定を bind -ps で上書きした後には ble.sh の復元でも上書きされる。
      問題が起こるのは bind -x した後にそれを bind -r して、
      それ以降に何も bind していない場合である。
      試してみたが何にも bind していないキーは列挙されない。

    * Note: 2019-12-30 特にこの項目が意図しているのは
      detach 時の復元ではなくて attach 時に ble.sh keymap に反映させるという話である。
      一方で bind -Xps の出力は \C-\ の振る舞いが微妙なので色々面倒である。

    2020-02-01 やはり README を読まずにいきなり bashrc の末尾で source して
    ble.sh が key binding を上書きしている。unbind が設定できるようにするべき、
    等と言いがかりをつけて来る人が現れた。やはり bind -Xps から設定を読み取れる様にしたい。

    ? Bash \C-\ vs \C-\\ Bug の処理
      さて、その時に問題になるのが C-\ をどう解釈するのかという事。
      取り敢えず \C-\M または \M-\C 以外の時は単独で解釈する事にする?
      否、\C-\\ も特別扱いしなければならない。うーん。
      →これは ble/builtin/bind の実装の問題なので別に考えるべき事?
      或いは ble.sh では \C-\\ に対応する事にして、
      但し、bind の出力は補正して記録する様にする。という事?
      そもそも補正する事は可能なのだろうか。

    先ず、既定の設定との差分を取りたい。
    取り敢えず既定の設定は以下の様な感じにして取得できる。
    bash-$a --norc -i -c 'bind -p' | sed '/^#/d;s/"\\M-/"\\e/'
    既定の設定との差分はどの様にして取るのが良いか。
    diff を呼び出してその結果を解析するのは面倒である。
    それならば awk で複雑になるかもしれないがちゃんと処理する方が良い気がする。
    →取り敢えず awk を使って検出できる様にはなった。
      然し、検出した物をどのタイミングで評価すれば良いのか。

    inputrc を読み取る作戦にしていた時はどのようにしていたか。
    うーん。inputrc の読み取り自体を遅延して、
    最初に bind を呼び出した時に読み出す様にしていた気がする。
    →やはりそうなっている。

    ? では何故その場で bind を評価する様にしていたのか。

      | 何故 bind 自体を遅延する様にしていなかったのか。
      | これには何か理由があった様な気がするが思い出せない。
      | →inputrc の読み取りに最初に対応したのは #D1038 であった。
      | inputrc の読み取りのタイミングについて議論があるのは #D1127 である。
      | ここでの議論によると、bind をした順序によってどちらが上書きされて
      | どちらが残るのかが変わるので順序は変更できない。
      | なので、bind を実行する前に inputrc は読み込んでおかなければならない、
      | という話になっている。

      bind の順序を保持する為に bind 前に inputrc を読んでおく必要があるという話

    それならば全ての bind を遅延させる事にしておけば問題ないという気がする。

    [実装]

    * done: bind の評価は keymap 初期化迄遅延する様にする #D1258
    * done: readline 既定の設定をキャッシュする
      これは簡単。
    * done: ユーザ設定を読んでそれを反映させる。
      これも実装した。特に問題なく動いている気がする。

    * done: \C-\, \C-\\ の補正の可能性
      https://lists.gnu.org/archive/html/bug-bash/2020-01/msg00037.html
      そもそも ble/builtin/bind ではどの様に解釈していたのだったか?
      と思って確認してみると ble/util/keyseq2chars で解釈している。

      ble/util/keyseq2chars の解釈は微妙に間違っている気がするので、
      新しい Bash-5.1 の解釈に合わせて更新することにした。
      取り敢えず動いている様である。

      更に、bind の出力結果をこの形式に合うように補正する事を考える。
      どの様に補正するか? 取り敢えず \C-\ の次に \ が来て文字列が終わっている場合は OK
      それ以外の場合には \C-\ は C-\\ に修正するべきなのである。
      →修正するコードを書いた。

    取り敢えず動いている。良いのではないだろうか。
    但し、bind -X は Bash 4.3 以降でしか使えないので、
    Bash-4.3 以降でしか "何処でも source ble.sh できる" とは書けない。

  * decode: bind の評価を keymap 初期化迄遅延 [#D1258]

    どの keymap に記録する様にするのが良いのか。
    1. bind に直接 -m が指定されている時はそれを使う。
    2. bleopt で keymap が指定されている場合にはそれを使う。
      inputrc の中ではそれは無視する? うーん。
      inputrc の中で keymap を指定している時にはそれを使う。
      或いは bind 経由の時には ble の keymap は無視して、
      その時の vi/emacs の keymap で処理してしまって問題ない?
      取り敢えず default_keymap は考えずに実装する。
      そもそも今迄もその様に実装していたのではなかったのか。

    実装を辿っていくと
    ble-decode-key/{bind,unbind} 辺りが最終的には呼び出されている。
    ble/builtin/bind の枠組みよりは更にその上の枠組に於いて、
    bind の呼び出しを遅延させる方が実装として自然である。
    その様に修正する事にする。

    現在の実装では ble-decode/DEFAULT_KEYMAP を呼び出した時に
    keymap も完全にロードしてしまう仕組みになっている。
    うーん。完全にロードする必要がない時には別の関数を呼び出す?

    * done: ble-decode-key/bind の引数に kmap を指定する様に変更する
    * done: DEFAULT_KEYMAP は INITIALIZE_DEFMAP に改名した

    うーん。遅延させる様にしようとしたが、
    これだとあらゆる keymap が遅延されてしまう。
    どのタイミングで具体的に keymap を生成するのか。
    遅延させるのは default-keymap だけで良いのではないのか。

    そもそも現在の keymap の初期化順序としてどのような可能性があるのか分からない。
    ? INITIALIZE_DEFMAP は必ず通過するのか? 調べてみたがそうでもない気がする。
    以下の様な構成になっている。

      | ble-decode/keymap/load
      |   <del>ble/util/import "keymap/$1.sh"</del>
      |   ble-decode/keymap:$1/define
      |   ble-decode/keymap/register "$1"
      |
      | ble-decode/keymap/push
      |   ble-decode/keymap/load 同上
      |
      | ble/builtin/bind/.initialize-kmap
      |   ble-bind/load-keymap
      |     ble-decode/keymap/load 同上
      | ble-bind
      |   ble-bind/load-keymap
      |     ble-decode/keymap/load 同上
      |
      | ble-edit/bind/load-keymap-definition
      |   ble-edit/bind/load-keymap-definition:"$name"
      |   source "$_ble_base/keymap/$name.sh"
      |   ここでは /define までは必ずしも呼び出さない。呼び出す場合もある。

    * done: ble-decode/keymap:$1/define の中で regiter, onload を呼び出す。
      と思ったが /define の呼び出し元が限られているのだとすれば、
      呼び出し元を本当に制限して、呼び出し元の側で必要な処理を実行すれば良い気がする。

      /define の呼び出し元を列挙する。結局本質的に一箇所しか無い様なのでOK

      と思って修正したが、よく考えると各 editing-mode でのキャッシュは
      onload でユーザの指定した修正を適用する前の物を dump しなければならない。
      うーん。opts=raw とした時には onload は実行しない様にする?
      或いは opts=dump とした時に特定の fd に対して raw の定義を出力する?
      後者を採用する事にした。

    * done: ble-decode/keymap:$1/define に関しては keymap/$1.sh は参照しない。
      これは本当にそれで良いのだろうか。
      将来的にはこちらの方を keymap/$1.sh にして、editing mode の方を別名にするべきでは。
      と思ったが現状で利用していないのでそれで良い。
      それにその keymap を利用する機能がロードされた時に
      ble-decode/keymap:$1/define が定義される様に計らうべきである。
      よって、 ble-decode/keymap/load からは keymap/$1.sh のロードは削除する。
    * done: ble-edit/bind/load-keymap-definition の中の source は import に置き換える。
    * done: ble-edit/bind/load-{keymap-definition -> editing-mode}
    x fixed: 見事に起動しなくなった。駄目だ。うーん。ble-bind が動いていない様だ。
      →これは簡単なミスだった。修正した。
    * done: /define の中で自分で ble_bind_keymap 等を設定しなくても良くなった。削除する。
      削除した。動いている。

    | 結局、以下の様な仕組みになっている様だ。
    |
    | 1. 先ず初めに編集モード全体の読み込みを行う
    |   ble-decode/INITIALIZE_DEFMAP
    |     ble-edit/bind/load-editing-mode
    |       ble-decode/keymap:$1/define の存在を保証
    | 2. 次に必要になった時に各 keymap を初期化する

    * done: ble/builtin/bind/.initialize-kmap, ble-bind/load-keymap の呼び出しを省略する
      取り敢えずこれらの関数では basemap 名の取得に留める事にした。
    * ble-decode/INITIALIZE_DEFMAP の呼び出しを削減する。(初期化を遅延する)
      * done: ble/builtin/read で ble-decode/keymap/push read する前に
        ble-decode/INITIALIZE_DEFMAP を呼び出していたが無駄な気がするので削除する。
        これは本当に大丈夫だろうか? keymap/pop した後に固まる可能性は?
        →やはり keymap/pop した後も _ble_edit_read_accept=1 経由で停止するので、
        元々設定されていた keymap が使われるという事は起こらない。
        やはりなくて良い気がする。
    * ok: ble-decode/INITIALIZE_DEFMAP を適切な名前に変更
      これは現状のままで良さそうな気がする。
    * done: .onload で遅延させた設定を読み込む様にした

    * ok: keymap:*/define に対して軒並み autoload しているが
      % これは今でも必要だろうか。今回の改修で不要になった可能性は?
      % 元々の動機を調べて不要になったのであれば削除する。
      →これはやはり ble-bind で変な keymap に誤って登録しない為に、
      どの様な keymap が存在するかを事前に分かる様にする為に残す事にする。

    [動作確認]

    本当に遅延されているのだろうか? 初期化のタイミングを調べれば良い。
    x fixed: bind.delay.$keymap の中を覗くと引数が全く保存されていない。
      これは ble/util/pritn-quoted-command のバグだった。修正した。
    取り敢えず遅延はされている様である。
    しかし、widget が見つからないというエラーメッセージが出る。
    うーん。widget のチェックも遅延させるべきだろうか?

2020-02-01

  * syntax: ((1))a と入力するとエラーメッセージが出る [#D1257]
    これは恐らく着色のコードが悪い。修正した。
    coproc 対応の時の抜けだった。

  * Bash Readline 束縛との互換性 [#D1256]
    fzf の様な既定の bash の binding を想定する様な枠組みの場合、
    ble.sh 側の binding が少しでも違うと動かなくなる。
    その意味でちゃんと何れの機能もそれなりに同じ振る舞いをする様になっているか?

    * emacs mode に関しては全ての widget に対応している。
      binding に関しては完全に一致させているか確認していないが、
      だいたい大丈夫だろうという気がする。問題が出てから対処すれば良い。

    * vi に関しては未だ対応していない機能が幾らかある。
      しかしこれらは default の binding を持つものだろうか?

      vi-back-to-indent
      vi-complete
      vi-eof-maybe
      vi-overstrike
      vi-overstrike-delete
      vi-tilde-expand
      vi-yank-arg
      vi-yank-pop

    確認する必要がある。

    * vi_nmap:
      * done: backward-word (C-left, M-left) forward-word
        実はこれらに関しては既に登録されている。
        vi-command/forward-vword (C-left)
        更に M-left, M-right にも対応する?
        特に vi_nmap ならば M- を設定しても問題ない気がする。
        然し本当に問題ないだろうか。

        isolated ESC 関係の判定は ble-decode/uses-isolated-esc で行っている。
        中を確認すると vi の時には問答無用で isolated ESC は ESC として処理される。
        M- 束縛があっても M- 修飾にはならない様である。
        なので M-... を束縛しても問題は起こらない。

        然し、一方で他に何も M- が束縛されていない状態でこれを束縛するのは
        統一性にかけるのではないかとも思う。そもそも vi-command には他に
        M- は登録されていなかったのだろうか。或いは積極的に登録されている?
        →調べてみた所他には登録されていない。M-left, M-right だけが登録されている。

        もう一つの問題として実際に CSI 1 ; 3 D や CSI 1 : 3 C を送る端末があるのか、という事。
        もしそのような端末が存在しないのであればわざわざここで対応する必要もないのではとも思う。
        然し、世の中には絶対はない。設定して問題ないのであれば設定しておいて問題もなかろう。
        という訳で設定する事にした。

      * done: kill-word (C-delete)
        これに関しては新しく widget を作成する必要がある気がする。
        作成した vi-rlfunc/kill-word

      * done: insert-comment (#)
        うーん。これに関してはどの様に対応するのが良いか。
        これは編集行に対する編集を伴う。
        その様なコマンドの実装例があるとやりやすい。

        確認すると replace-char, undo ぐらいである。
        中を見ると両方とも
        ble/keymap:vi/mark/{start,end}-edit-area を使っている。

        ble/keymap:vi/repeat/record はどのように呼び出せばよいのか?
        と思ったが insert-comment は実行を伴うので . で繰り返せるというのは変である。
        なのでこれは完全に無視して問題ない。

      * done: quoted-insert (C-q, C-v: batting している)
        これは仕方がない。無視する。
        唯、widget は準備しても良いのかもしれない。

        うーん。これはどうやって実装したら良いのだろうか。
        →丁度 vi-command/replce-char と quoted-insert を組み合わせれば良い。

      * done: unix-line-discard (C-u: batting)
        これは現状では vi_nmap/backward-line-scroll になっている。
        難しい。unix-line-discard の方がシェルとしては自然な気がする。
        backward-line-scroll を実際に使っている人がどれだけいるのか?
        特にシェルでは複数行の操作をする事は余りない。
        という事を考えると unix-line-discard にした方が良い?
        然し、unix-line-discard が破壊的操作であると考えると現状の方が安全である。
        うーん。これも保留という事にする。

        但し、明示的に unix-line-discard を bind した時に対応できるようにはするべき。

      * done: vi-eof-maybe (C-d: batting)
        これは現在 bind されている機能とは違う物だろうか。
        →振る舞いを調べてみると vi-eof-maybe は現在のコマンドを実行する様だ。
        もし空の場合には終了する。
        →新しく widget だけ実装した。

      * done: vi-tilde-expand (&)
        これは新しく実装しようとしたが @edit tilde-expand で良い気がする。

      * vi-yank-arg (_)
        うーん。これの対応は面倒である。
        →readline の振る舞いを調べた所、一旦 insert-mode に入ってから
        挿入を行う様である。という事であれば対応はそんなに大変ではない。
        引数は認識していない気がする。

        うーん。D と似たような感じに実装すれば良い?
        と思ったけれども違う。
        面倒なので append-mode を呼び出して self-insert, insert-last-argument
        を順番に呼び出すという安直な実装にした。多分これで大丈夫なのではないか。
        と思ったが irepeat による記録が行われていない…。うーん。

        然し、insert-last-argument の様な複雑なモードの後も
        imap repeat が有効というのも変な気がするので、
        いっその事 imap repeat はキャンセルする事にする。

        取り敢えず動いている様な気がするのでもう気にしない。

    * ok: vi_imap に関しては対応できていない物はない気がする。

    * ok: bash の s, S vi-subst は一体何?
      →これは s と S を共通の rlfunc から呼び出せる様にしたというだけの物だった。
      現状のままで振る舞いとしては一致しているので気にしなくて問題ない。

  * fzf が動かないという問題の報告 (reported by jpninanjohn) [#D1255]
    https://github.com/akinomyoga/ble.sh/issues/38
    これは fzf が shell-expand-line & history-expand を使っている為に起こった問題である。
    彼は README を読んでいない。

    ? 然し、何故 history-expand を実行する必要があるのだろうか。
      最初から展開結果の文字列を出力しては駄目だったのだろうか。
      末尾の改行の為? →試してみて分かった。shell-expand-line だと勝手に改行が削除される。

      然し、試した結果 "`command`" ならば改行がちゃんと保持される様である。
      確かに echo `...` で生成すると単語分割の対象になって、
      改行の類は効果としては空白と同じなので自然である。
      * 然し、だからと言って fzf に "`__fzf_history__`" を提案したとすると、
        今度は ble.sh の側で明示的に quote された状態になってしまって動かない。
        従って、fzf に "`...`" の形式を提供しても意味がない。

    * ble.sh の振る舞いを Bash の振る舞いに近づけるとしても。
      echo "echo hello" が echo echo hello に展開されたり、
      或いは "`...`" がコマンドの実行結果その物になったり、
      色々と振る舞いが異なるのである。

      近づけるというよりは破壊的に変更しなければならない気がする。
      然し、元々の機能が echo "echo hello" を echo echo hello
      に変換してしまうぐらい潔い物なのだとしたら、
      逆にそれに合わせても良いのかもしれない等とも考える。

    bash の振る舞いに合わせる事を考える。
    更に fzf の他の binding もちゃんと動くか確認する。

    * done: shell-expand-line の振る舞いを bash と同様の物に修正する事にした。
      その前に bash の振る舞いについて再度確認しておく。

      * 展開結果に含まれる quote は一切処理されない。
        ~$ function ff2 { echo '"echo hello"'; }
        ~$ echo `ff2`
        -> echo "echo hello"

      うーん。quote を実行している一行をコメントアウトしただけで
      bash と同じ振る舞いになった様な気がする。
      shell-expand-line に引数として quote を与えなければ、
      bash と同じ振る舞いになる様に変更した。

    o fzf の動作確認
      その他の binging (C-t, M-c) も試してみたがこれらは問題なく動いている。
      これでよしという事にする。

  * syntax: eval の引数のファイル名が着色されていない [#D1254]
    というか、eval の引数はコマンドとして解釈しつつ着色したい気がする。
    一方で。'...' としてコマンドを記述できる事を考えると、
    awk '...' や sh -c '...' で考えているのと同様に着色したい気もする。

    取り敢えずの所は引数として着色するのが妥当なのではないか?
    →確認してみると単語の種類は ARGEI になっている。
      補完はコマンド名になっている。
      着色はされていない。

    % 分かった気がする。コマンドとして補完されているのは、
    % 恐らくコマンドラインの一番最初の単語になっているから。
    % eval a=() echo としていたので a=() の手前でコマンドラインが途切れている。
    % →と思って確認してみたが eval echo g++ としても全てコマンドとして補完される。

    実装を確認すると CTX_ARGEI に variable:= command file が割り当てられていた。

    x fixed: CTX_ARGEI の補完でディレクトリ名が a/ と a になっていて
      絞り込みが出来ていない。コマンドの場合にもディレクトリ名には / を入れずに、
      suffix に / を指定するべきでは。と思ったが、その場合にはコマンド名と
      ディレクトリ名が重複していた場合に問題にならないか。

      更に言うと、異なる種類の見た目が同じ候補があった場合に
      どちらの action を採用するのかという問題が残る。
      結局、補完対象の文字列を合わせたとしても問題は解決しない。

      そもそもコマンド名でもファイル名でもどちらでも良い、
      という文脈が不自然なのである。どちらか限定できる様にならないか?

      →結局この文脈ではコマンド名の生成時にディレクトリを列挙しない様に修正した。
      source:command で引数を受け取る様にして、
      D が含まれている時にはディレクトリ名列挙を抑制する。

    さて、補完はこれで余り気にしなくて良い気がする。
    問題の着色が為されていない問題について。何故着色が為されていないのだろうか。
    コマンドの抽出はちゃんとできているだろうか?
    →分かった。肝心の progcolor/word:default で CTX_ARGEI を見るのを忘れていた。修正した。

  * OK: syntax: eval a=() echo helo=() の構文エラーを検出できていない [#D1253]
    →と思ったが、これは eval の時点で構文エラーになっているのではなくて、
    eval から呼び出されたコマンドの評価の場面で構文エラーになっているのではないか。
    実際に以下を試してみたら何もエラーは発生しなかった。
    $ bash -n -c 'eval a=() echo c=()'

  * syntax: 何と coproc に対応していない [#D1252]

    普通のコマンドと同様に処理しておけば取り敢えず問題ないと思っていたが、
    実際にやってみるとエラー着色になってしまっている。
    そもそも coproc のコマンド部分には特別なコマンドも指定できる。

    | 然し、coproc はどうやって [COPROC] の部分を変数名かコマンド名か判断しているのだろうか。
    | 試しに coproc hello echo としたら、hello がコマンド名と認識された。
    | というか coproc COPROC echo -e hello としても COPROC がコマンド名として解釈された。
    |
    | coproc var ((...))
    | coproc var { ... }
    | coproc var do
    |
    | どうも関数と同じ構文の様な気がする。つまり、後に複合コマンドを期待する。
    | もし複合コマンドが来なかったら通常のコマンドとして処理する。
    |
    | 1. coproc の後に普通のC単語以外の単語が来たらコマンドだと思う。後は通常処理。
    |   C単語が来たら取り敢えず変数の可能性を考える。
    | 2. C単語の後に複合コマンド (キーワード) が来たら受け付ける。
    |   (coproc var と複合コマンドの間には改行も入れられない様だ)
    |   それ以外の場合にはC単語をコマンドという事にして、新しい単語は普通の引数という事にする。

    [文法まとめ]

    a coproc の次の単語がキーワードなら、複合コマンドとして取り扱われる。
      因みに then, coproc, fi, ! 等の複合コマンドの開始でないキーワードでも、
      取り敢えず複合コマンドとして解釈をしようとし、後の文法エラーになる。
      但し、time は例外である。ここではキーワードとして扱われない。
      キーワードとして扱われる物を列挙する。
      - ( ((
      - { } ! [[
      - if then elif fi, while until do done, for select case esac
      - coproc, function
    b それ以外で、次の単語がC単語でない時は、通常のコマンドとして取り扱われる。
    c それ以外の時、次の単語はC単語である。更にその次の単語 word2 を調べる。
      c1 word2 がキーワードなら、word1 は変数名として取り扱い、
        word2 は複合コマンドとして取り扱われる。
      c2 それ以外の時は、word1 は通常コマンドとして取り扱われる。

    | どの様に実装するのが良いだろうか。
    |
    | a coproc が来たら取り敢えず特別な文脈にする。
    |   最初の単語の読み終時に単純な単語かどうかの判定を行い、
    |   もし単純な単語であるならば前方に先読みを実施する。
    |   [[:space:]]*(複合コマンド) の形式をしていたら、
    |   最初の単語は変数名であったと見做して着色・単語設定する。
    |   それ以外の場合にはコマンドとして着色・単語設定する。
    |
    | b 実は coproc を受け取った時点で先読みを実施してしまっても良いのでは?
    |   先読みを実施する時に何か問題が起こるだろうか。
    |
    |   % o 寧ろ無闇に文脈値を増やすよりは良いのではないだろうか。
    |   %   と思ったが、文脈値は結局増やさなければならない気がする。
    |   %   "変数名の後に複合コマンドを期待する文脈"
    |   %   というのを新しく追加しなければならない。
    |
    |   文脈値をどうせ増やすのであれば、a の方針で良い気がする。
    |
    | →a の方針で実装する。

    実装した。動いている。

    x fixed: progcolor が中途半端にしか動いていない?
      coproc hello world から単語を削除して coproc hello に
      すると progcolor ではない単語着色になっている。
      (単語着色がされていないという訳ではない。)

      どの様なコマンド抽出になっているのかを確認する必要がある。
      確認した所、以下の様になっていた。coproc が親コマンドになっている。
      うーん。自身が CTX_CMDI の時には親を抽出しない様にすれば良い?
      comp_cword='1' comp_line='coproc hello' comp_point='12' comp_words=('coproc' 'hello')

      確認した。自身が CTX_CMDI であっても兄を探索する様になっていた。修正した。

2020-01-31

  * 2020-01-23 Cygwin でテスト vi_test が失敗している [#D1251]

    | 操作を実行した後のカーソルの位置が一文字ずれている様だ。
    | コマンドラインで実行すると特に変な振る舞いをする事はない様だ。
    |
    | ble-0.3.1 でもテストが失敗している。こちらは linux でも再現する。
    | テスト自身のバグである可能性が高い様な予感がしている。
    |
    | うーん。そもそも何故 linux と結果が異なるのか。
    | Cygwin 特有の処理に問題があるとすればもっと広範に渡って影響が出るのではないか。
    | bash の version の違いかとも思ったが version を合わせても再現する。
    |
    | 実際に再生されている内容を確認してみると変な事になっている。
    | 65 32 104 101 108 108 111 0 0 0 0 0 0
    | C-[ と入力した物が 0 0 0 0 0 0 に変換されている。どういう事か?
    | 記録されているレジスタの中身は "A helloM-xM-^DM-^@M-^@M-^AM-^[" である。
    |
    | どうもレジスタの値に変換する時点で変な事になっている様だ。
    | 記録されたキー列は 65 32 104 101 108 108 111 67108955 であるが、
    | それを文字列に変換した結果が $'A hello\370\204\200\200\201\233' になっている。
    | これは変だ。ble/decode/charlog#encode の実装を確認してみると
    | 唯単に文字コードから文字列に変換しているだけ。linux で動いているという事は、
    | キー列の時点で修飾が外れているのか、或いは文字にエンコードしても
    | 巨大なコードポイントを持つ UTF-8 文字として取り扱われているのか。
    | →linux で動いているのを確認してみた所、ちゃんと一つの文字として扱われている。
    | →更に文字列に変換した結果も同じになっている。
    |
    | →うーん。記録された register の値を出力する時に表示が異なる。
    | 本質的にはバイナリとしての中身は同じであるのにも拘らず (本当か?)。
    | OSについている UTF-8 復号器が真面目に不正な文字を除去するか、
    | 或いは素朴な UTF-8 復号をそのまま用いるかの違いという事だろうか。
    | ? UTF-8 6byte 表現の各バイトを更に UTF-8 符号化している可能性?
    |   →バイト数を確認してみた所 13 であり、これは 'A hello' (7) + 6 に
    |   なっているので 6 byte 表現は 6byte 表現のままである。
    | ? そもそもこの記録された文字列の文字数はどう数えられている?
    |   →13になった。つまり、UTF-8 の不正な表現は1文字ではなくて、
    |   6文字と数えられているという事になる。うーん。
    |
    | つまり。。ここで考えなければならないのは、
    | charlog#encode, decode で巨大な数を保存・復元できる様にする事。
    | 特に復元の際に UTF-8 5,6バイト表現としての復元を試みる?
    |
    | (但し、bash 3.2 ではうまく変換できていない様にも見える)
    |
    | * そもそも何故 linux と cygwin で振る舞いが変わっているのか。
    |   これは bash の実装の問題なのかもっと下の枠組みの問題なのか。
    |
    | * 巨大な文字コードを無理やり文字に変換することの是非
    |   現在は UTF-8 を仮定しているから動いているが、
    |   例えば LANG=C の場合にはそもそも 256 以上のコードを表現できない。
    |   ESC seq に頼るしか無いのではないか。
    |
    |   これを実装した時にはどの考えていたのだったか。
    |   blame で確認する。commit は 06698a4f である。#D1026 に議論がある。
    |   うーん。大して考えていない様な気がする。
    |   他の文字コードに対応する時には、その文字コードで割当てられていない
    |   文字を用いて特別に処理するしかない。

    取り敢えず状況を整理する。
    * 修飾したキーを記録する為に巨大な数を UTF-8 encode している。
      結果として UTF-8 としては本来不正である様な表現に変換される。
    * Linux ではその文字の長さは 1 になるが Cygwin では 6 になる。
    * 復号する時に一文字ずつ復号するのでその時に
      Cygwin では元の文字が分解されてしまう。不正なバイトなので 0 になる。

    | 確認する。
    |
    |   linux$ ble/util/c2s 67108955; echo "${#ret}:$ret" | cat -A
    |   1:M-|M-^DM-^@M-^@M-^AM-^[$
    |   cygwin bash-4.4$ ble/util/c2s 67108955; echo "${#ret}:$ret" | cat -A
    |   6:M-xM-^DM-^@M-^@M-^AM-^[$
    |   cygwin bash-5.0$ ble/util/c2s 67108955; echo "${#ret}:$ret" | cat -A
    |   6:M-xM-^DM-^@M-^@M-^AM-^[$
    |
    | と思って出力された内容を見ると何だか変だ。
    | 最初の文字が M-x になっている。Linux では M-l である。
    |
    | 調べてみると printf \Uxxxxxxxx が駄目の様だ。
    | 以下のコマンドが linux と cygwin で異なる結果になる。
    | cat が勝手に変換している可能性も考えたが od -tx1 で見るとやはり違う。
    | $ printf '\U0400005b\n' | cat -A
    |
    | つまり、これは復号の問題ではなくて key -> s 符号化の問題?
    | 何故 cygwin と linux で振る舞いが変わるのかというと実際に使っている実装が異なるから?
    | printf の実装を確認してみると u32cconv という関数を呼び出している。
    |
    | うーん。u32cconv の実装を見ると早速変な所がある。
    | 取り敢えず wchar_t が 4B の環境では wctomb を使っている。
    | 2B の環境では surrogate pair に変換してから wcstombs にしている。
    | もし wcstombs がちゃんと surrogate pair に対応しているのであれば問題は起こらない。
    | さて、今回の場合はそもそも値が Unicode の範囲外である為、
    | この wcstombs も呼び出される事はない (そもそも surrogate pair で表せない)。
    |
    | さて結局 u32toutf8 という関数の返す結果が壊れているという事が分かった。
    | うーん。この最後の if の 1B 目が間違っている気がする? f8 ではなくて fc では。
    | そしてこれは最近報告に上がっていた物である気がする。
    | これだ https://lists.gnu.org/archive/html/bug-bash/2019-11/msg00042.html
    | そして patch の中身を見ると自分が思ったのと完全に同じ修正だった…。
    |
    | * 影響を受ける bash のバージョンは?
    |   さて、Bash のバグだと分かった所で。どうやって対処するべきか。
    |   因みにこのバグはいつからあるものだろうか。先ずそもそも printf が \U....
    |   に対応したのは bash 4.2 からで、最初から間違っていた様だ。
    |   → Bash 4.2 -- 5.0 の全て。
    |
    | * 果たして復号の方は問題ないのか確認が必要である。
    |   →駄目だった。
    |   $ ret=$'\xfc\x84\x80\x80\x81\x9b'; echo "${#ret}:$ret" | cat -A
    |   1:... linux
    |   6:... cygwin
    |
    |   $ ret=$'\xfc\x84\x80\x80\x81\x9b'; ble/util/s2c "$ret"; echo $ret
    |   67108955 linux
    |   0 cygwin
    |
    |   linux で動いている物が cygwin では動かない。
    |
    |   $ ret=$'\xfc\x84\x80\x80\x81\x9b'; printf %d "'$ret"
    |   67108955 linux
    |   0 cygwin
    |
    |   切り出しだけの問題かと思いきや、' を指定した場合でも駄目の様だ。
    |
    |   この printf %d 'c の実装を確認する。整数引数を読み取る時に、
    |   getintmax という関数を呼び出している。その中で ' を確認できたら、
    |   asciicode() という関数の結果を返している。
    |   というか ' の代わりに " でも良い様だ…。知らなかった。
    |
    |   うーん。asciicode の中を確認すると mbtowc という関数を呼び出していて、
    |   この関数が -1 を返している。つまり不正な UTF-8 である事を検出している。
    |   これは bash の側に無理やり変更を押し込む訳にも行かない。
    |   かと言って cygwin の mbtowc の実装事態に変更を押し込むのも変である。
    |   (linux では mbtowc が恐らく変な UTF-8 でもそれなりに解釈するのだろう)

    改めて整理する。
    * key値から文字列に変換する時、以下で報告されているバグによって誤った形式になる
      https://lists.gnu.org/archive/html/bug-bash/2019-11/msg00042.html
    * それとは別に Cygwin の mbtowc は範囲外 UTF-8 に対してエラーを検出する。
      恐らく Linux の mbtowc は範囲外 UTF-8 でも旧規格の通りに復号するのだろう。

    | そもそも現在の実装は UTF-8 を前提としている。
    | UTF-8 に依存しない実装に変換するべきなのではないか。
    | 文字列として埋め込む事ができるのは "文字" と制御文字だけである。
    |
    | 以前の実装ではエスケープシーケンスを用いていたが問題として長くなり過ぎる。
    | →今あらためて確認した所カーソルキーはエスケープシーケンスに変換されている。
    | 他にも様々な入力を試してみたが何れもちゃんとエスケープシーケンスになっている。
    | C-[ だけがエスケープシーケンスになっていないのであった。調べる。
    | vi.sh の側で加工しているのだろうか、と思ったがそうではなかった。
    | decode を通過する文字をそのまま記録している様だ。
    | ble-decode-char の中を通過する文字をそのまま計測している様だ。
    |
    | つまり更に上の ble-decode-byte が C-[ を処理している。
    | ble-decode-byte は各符号化方式で実装していて特に ESC について意識している訳ではない。
    | とすれば最終的には init-bind に行き着く? うーん。然し中を確認すると U+07FF を送信している様に見える。
    |
    | 何処で C-[ になるのか分からない。と思ったら分かった…。
    | これはテストが悪いのだった。
    |
    | _ble_keymap_vi_test_ble_decode=ble-decode-char で評価関数を ble-decode-char にしながら
    | C-[ という修飾キーを指定したのが悪かった。
    | これにより本来文字として受信しない筈の文字を受信させてテストを実行していたのだった。

    結論としては
    * vi_test が悪かった。テストのデコーダに ble-decode-char を指定しているのに
      テストの入力に key C-[ を指定していたのがいけなかった。
    * charlog#encode, decode は key の符号化・復号はそもそも想定していなかった。
      なので Unicode 範囲外の文字に対して対策はしなくて良い。

    kspec に IsolatedESC を指定できる様にする。
    或いは U+07FF の様な形式で文字を指定できる様にする。
    →@ESC @NUL U+xxxx の形式に対応した。

    x fixed: Linux 上でマクロが動かなくなった。と思ったら ble-decode-kbd の
      中のチェックで keyname は _alnum で構成されていなければならないというチェックが入っていた。
      _alnum に加えて @ も keyname を構成する文字として許す事にした。
    x fixed: U+07FF が動かない。と思ったら正規表現の誤りだった。修正した。

    テストが全て通る様になった。OK

2020-01-30

  * auto-complete: C-e でも補完確定にするべきなのでは? [#D1250]
    追加した。

  * highlight: pathname に含まれるディレクトリのシンボリックリンク [#D1249]
    ディレクトリとしての着色になっているが、シンボリックリンクの時には
    そうなる様に着色した方が親切である。
    →実装を見て気づいたが実は普通のディレクトリ名の判定の時点で
    シンボリックリンクのディレクトリ名であっても末尾に / がついていると、
    通常のディレクトリであるかの様に着色されていた。
    末尾に / がついている場合には [[ -h dir ]] は失敗するのだ。

    末尾に / がついていてもそれがシンボリックリンクかどうかを判定する様にした。
    実装した。確認した。

  * 履歴の上下で menu-filter が保持されている。これは変だ [#D1248]
    動作上の問題はないが設計として何だか変である。

    調べると menu-filter は menu がアクティブの時にしか有効にならない。
    更に、履歴を移動すると menu は消える筈だ。なので menu-filter は働かない筈。
    と思ったら、履歴を移動した時に menu が消えるのは menu-filter が消しているのだった。
    従って履歴を移動しても前の内容と一貫している場合には menu は消えない。
    履歴を移動した時に menu を消すようにして良い気がする。

    history_onleave に登録すれば良い。登録した。動作確認した。OK

2020-01-26

  * progcolor: / を含むコマンド着色が変だ [#D1247]
    パスを指定して呼び出すコマンドが全てディレクトリであるかの様に着色されている。
    / を含む関数名の場合には問題は起こっていない。
    最近の変更によって問題が起こる様になった→これは簡単だった。修正した。

  * global: 一箇所でしか使われていない識別子 [#D1246]
    一箇所でしか使われていない識別子は怪しい。
    ./make_command.sh check-words でそういう物を検索できる様にした。
    怪しい物を幾つか直した。結構バグが沢山ある様だという事。
    他に ./make_command.sh check-varnames も作った。

    * ret が leak している。alias 展開関連の様である。
    * 他に ch が漏れている。
      これの修正は簡単だった。すぐに見つかった。
      然し更に見ていると ble/builtin/bind/.parse-keyname で
      致命的に間違えている事を発見した。C-SPC や DEL や Rubout
      等が全く解釈できていなかった。修正した。
    * dist が漏れているがこれは mshex bashrc m/g だろう。
      →と思ったが dist という変数は使われていなかった。
      更に ble.sh の中も検索してみたが dist という変数は使われていない。
      問題のセッションで history | grep してみたがやはり見つからない。
      不思議な事だ。ble.sh のセッションでも確認するとやはり dist に値が入っている。
      →declare の出力を検索して分かった。mshex/cdhist/cd だった。
      直した。然し今まで気づいていなかった事が不思議である。

  * progcolor: コマンド毎の着色の設定を可能にする [#D1245]

    コマンド毎に引数の着色を実行するには。
    % * コマンド毎の着色を行う関数の名前について。
    %   現在 ble/cmdinfo/{help,complete}:command が使われている。
    %   ble/cmdinfo/highlight:command を使う事にする。
    % * と思ったが標準入力だとかヒアドキュメントだとかについての設定は?
    %   これは別の関数を用意するか或いは引数の振りをして渡すか。
    %   別の関数を用意するのが自然に思われる。
    →#D0581 の考察を確認した所 color, color-stdin が提案されている。
      #D0581 の名前を採用する事にする。

    現在着色を計算しているのは
    ble/highlight/layer:syntax/word/.update-attributes という関数である。
    この関数は木構造を使って色を決定している。
    単語毎に着色を計算しているので現在の実装ではコマンドが分からない。
    各単語毎にコマンドを抽出するのは如何にも非効率である。
    それとは別にやはり一回の highlight:command の呼び出しで全て着色したい。

    [仕様]

    * done: ble/cmdinfo/color:command を用いる。
    * done: comp_line 等一連の変数を提供する
    * comp_dirty 的な配列に各単語の着色を更新する必要があるかどうかを格納する。
      着色を更新したら comp_dirty に更新した事を表す値を書き込む。
      →comp_flags 的な変数に "d" という文字を入れる事にする。
      →これは現状では wattr に - が設定されているかどうかで判定している。
        実際に今迄の実装でもその様にしていた気がする。
        もし上書きするのであれば敢えて set-wattr を呼び出せば良い。

    [実装]

    問題が複雑化してきたので複数に分けて実装する事にする。

    * done: cmdinfo/color が存在している場合にはそれを呼び出す。
      cmdinfo/color の中で使いやすい様に関数名は変更する。
      また変数名も被らない様にする必要がある。
      うーん。特に i である。
      →これは取り敢えず TE_i TE_nofs という変数名を使う様に書き換えた。

    * done: 先ずコマンド毎に着色する様に修正する #D1242

    * done: コマンド名を使って着色設定を探索する。
      これは core-complete.sh の設定を参考にすれば良い。
      →着色設定を呼び出す所まで実装した。

      x fixed: コマンド名だけの時にカスタム着色が動いていない気がする。
        これは extract-command-by-noderef 関数が
        CTX_CMDI に対して動作していなかったのが原因だった。修正した。
      x fixed: 引数を入力して行くと着色が消えてしまう。
        これは umin,umax の範囲内にある属性は全て消去されるのが原因。
        その後で _ble_syntax_word_{umin,umax} の範囲内の単語が再着色される
        予定になっている。つまり、この範囲の外の単語について着色をすると
        その着色は全て消去されてしまうという事になる。
        →_ble_syntax_word_{umin,umax} も更新する様に変更した。


  * progcolor: proghl の名前を考える → progcolor に変更 [#D1244]

    proghl は余りにも分かりにくい。
    * proghilite, proghighlight 長い。
    * highlight (ble/syntax/highlight)
      単なる highlight は既に色々な所で使っている。
    * proglite, proglight, proglit
      何の事だか分からない。分かりにくい。
    * proghili もっと何が言いたいか分からない。
    * philite, philight: 変だ。
      何か既存の単語で良さそうな意味があって
      似た響きの物があれば使っても良いのかもしれない。
    * progcolor, progcol
      実の所、色だけではない。装飾も含まれる。
      然し、既存の枠組みで既に color という名前は使っている。

    後、これらに共通するのは単語単位の着色であるという事が
    名前に現れていない。prog があれば補完と同様に単語単位に
    動くという事が連想されるかもしれないというぐらい。

    * wordlite, wordcolor, wordgraphics, wordg
    * proggraph, progg, progface, wordface
      実際に設定するのは g 値であって実は face ではないのだ。

    うーん。この中では progcolor, proglight,
    wordface だろうか。或いは proglite。
    →progcolor or proglite
    うーん。余り奇を衒わずに progcolor で行くのが良い気がする。

2020-01-25

  * この肥大化した memo.txt は何とかした方が良い [#D1243]

    [動機]

    幾ら git が差分で管理してくれると言っても、
    例えば git pull の時にはダウンロードするファイルの集合について
    差分を計算して圧縮してくれても、手元にある分からの差分にはしてくれてない気がする。
    というのも ble-update の度に 1MB ぐらいのデータをダウンロードしている。
    多少のアップデートの癖に 1MB もダウンロードするのは避けたい。

    それに巨大な memo.txt が見える所にあるのも見苦しい。
    memo subdir の中に過去のログについては移動するのが良い気がする。
    然し、追跡などを考えると、うーん。
    今の memo.txt という名前のファイルは一旦変更する?
    ファイル名を変更しないと移動を検出してくれないのだ。

    [変更]

    取り敢えず現在の memo.txt は memo/done.txt 辺りに移動する事にする。
    そして todo に関しては todo.txt に移動する。
    ChangeLog に関しては memo/ChangeLog.txt に移動する?
    今まで C-prior C-next で移動して記入していたが面倒である。
    その様に考えると分離した方が楽だ。
    というか見た目をチェックしたいので ChangeLog.md にしてしまうのが良い。

    x うーん。然し、溜まってきたら一気に done.txt に移動する方式だと、
      無駄に編集行数が増えてしまう事になるのではないか。
      然し、毎回 done に追記する方式にすると結局同じ事になる。
      という事を考えると適当にファイルを分割して昔のファイルには触らない様にするのが正しい?
      git 的にはそういう事になるのだろう。然し、それはそれで不便である。
      という事になればやはり git の差分の行が増えるのは仕方がないという事にして
      時々一気に移動する事にする。

    でももし上記の様に git の都合を無視するのだとすれば、
    実は今まで通りに一つのファイルで作業しても良いのではないかという気がする。
    うーん。しかし、それはそれで運用が面倒なのである。
    git が大規模なソースコードの移動を検出してくれれば問題はないし、
    或いは git が巨大なファイルの一部だけの変更を検出してくれれば問題ない。
    うーん。これは結局利便性がどうだとか git がどうだとかではなくて見た目の問題なのだろうか。
    後は git におけるダウンロードの問題。そういう実利的な事を考えれば。

    今までの問題
    x git のダウンロードが遅くなる。
    x 巨大なファイルがトップレベルにあって見苦しい。
    x 他の人が見た時に何がどうなっているのか分かりにくい。

    分割した時の問題
    x 検索が二つのファイルに跨っていて面倒。
    x 時々一気にログを移動する事にすると編集量が無駄に増える。
      また移動した時にはダウンロードが遅くなる。

    他の代替案はあるだろうか。

    a 実のところ本当に項目ごとにファイルを作るという手もある。
      しかしそうすると今度は検索がもっと面倒な事になってしまう。
      或いは、grep を使うべきなのだろうか。

    b 或いは 100 項目ごとに done.txt を分けるという手もある。
      100 項目であればそんなに巨大にはならないし、毎回追加して良い。
      そして将来的にくっつける事は絶対にしないという規則にする。
      そうは言っても検索はますます面倒になる。

    c 編集するのは一つの塊のファイルだけれども、
      git に保存する時には適当に分割して保存する様にする?

      % 或いは自動的に make でくっつける様にする?
      % しかしそれはそれで編集が面倒だ。
      % 編集したら分割した内容を保存する仕組みなど作れるかもしれないが面倒である。
      % と思ったがこれはこれで一つの手なのかもしれない

      これは技術的には可能だし色々の物事を解決する様な気もするが、
      たかがメモのためにこれをするのは大袈裟だしやらなくて良い。

  * 2019-12-31 progcolor: 単語着色をコマンド単位で実行する様に変更 [#D1242]

    * done: 中で extract-command を呼び出す?

      と思ったが extract-command は単語の位置情報などは抽出しない。
      それっぽいコマンドを再構築してしまって、
      元の文字列の情報は失われてしまうのである。

      a extract-command を拡張する?

      b extract-command と同様の手法を新しく実装する?
        extract-command で使わない機能があればそれを整理できる。
        と思ったが comp_line 等の変数をそのまま提供する事にすると
        機能を減らす事はできない様な気がする。
        従って extract-command を拡張する方が自然である。

      因みに node[ofs+4] をチェックしているので
      同じ単語を二度以上着色する事は既に防いでいるので余り気にしなくて良い?

      ? 但し、子ノードに対する処理がどうなっているかについては確認が必要。
        | どうも子ノードの処理は "単語" の子としてではなくて、
        | "入れ子" の子として処理している様である。
        | なので単語の処理の時には気にしなくて良いという事だろうか?
        | と思ったがそうでもない? tree-enumerate-in-range は
        | 木構造とは全く関係なく列挙する機能だろうか。
        | →実際に読んでみるとその様に記述されている。なる程。
        |   特に末尾から順番に列挙されているのだとすれば、
        |   何も考えずに実装すれば良い気がする。
        結論: 単語着色の決定に用いている tree-enumerate-in-range
          は入れ子構造に関係なく末尾から列挙する関数なので気にしなくて良い。

      うーん。i nofs 及び node という変数を参照できる。
      extract_command を拡張するとすれば i と nofs を記録すれば良い?
      取り敢えず i と nofs を tree_words という配列に書き出す事にした。

      ちゃんと抽出できている様な気がする。
      また重複して着色が計算されるという事も起こっていない。

    x と思ったら $() の入れ子が閉じていない時にちゃんと動いていない。
      nest の外側を抽出してしまっている?

      | うーん。分かった extract-command は位置しか受け取っていないので、
      | 同じ位置で複数の単語が入れ子構造で閉じていると、
      | そのどれか一つだけしか着色しないという事になるのである。
      |
      | なので extract-command を実施する時には nofs も指定できる様にしなければならない。
      |
      | 現在の処理では以下の部分で単語を見つけて、
      | その後で .construct を呼び出している。
      | 実は見つける処理は不要なのではないかという事。
      |   if [[ $wtype =~ ^[0-9]+$ && ! $EC_has_word ]]; then
      |     EC_has_word=$wtype
      |     return
      |   fi
      |
      | 外部から指定したオプションでこの辺りを制御できる様にしたい。
      | 外部から i,nofs を指定したとしてどの様にすれば良いのか?
      |
      | a 外から指定した単語に対応する親を見つけるにはどうしたら良いのか?
      |   結局末尾から全て探索しなければならないのではないか。
      |   或いは親を見つけずにコマンドラインを構築する方法はあるだろうか。
      |   つまり弟要素を親を見つけずに見つける方法。
      |   結局末部から探索しないとならないので親を見つけるのと大差ない。
      |   親は一回見つければ良いのに対して子は幾つもあるので、
      |   実際には親から見つけた方が効率が良い。
      |
      | b それならば最初から着色単語を見つける時に親情報を取れば良いのでは。
      |   しかし現在は enumerate-in-range を使っている。親情報なしに
      |   指定した範囲の構造を取得する様にしている。
      |
      |   それならば末尾から探索して行って親情報と一緒に
      |   tree-enumerate した方が良いのではないか。
      |   然しこの方法だとコマンドラインが長くなった時に効率が悪くなる。
      |   然し、現在の方法が本当に効率が良いのかというのは微妙である。
      |   と思ったが殆どの更新は文字単位であるのでやはりそういう微妙な
      |   更新に対して高速に動作して欲しい。
      |
      |   親情報をキャッシュしてもし変更があれば修正するという構造にできないか。
      |   これは最初の実装の時に詳しく考察した筈である。
      |   然し、結局確定的な答えは得られていない。
      |
      | そもそもよく考えたら効率の良い単語着色の方法は
      | 未だに模索の途中だったのだ。従ってこれを機に考え直しても良い。
      | →2015-08-16 の議論が正にその議論である。
      |   丁度 tree-enumerate-in-range の改善についても考察している。
      |   tree-enumerate-in-range の問題点についても述べられている。
      |   その時の議論では補助的なデータ構造を構築する可能性や、
      |   解析時に構築する情報の拡張についても考えているが、
      |   取り敢えず高速化は置いておいて tree-enumerate
      |   で末端から探索する形に変更するというので良い気がする。
      |
      | c reject: 逆方向から並行して解析しておく案?
      |
      |   現在の解析は先頭から順番に実行して、或る点での情報は
      |   後ろの情報に依存しない様になっている。これによって、
      |   途中からの解析に対応しているのである。従って、
      |   未来の情報である弟ノードの情報は本質的に取得できない。
      |
      |   では逆に末端から解析する様にしたらどうなるだろうか。
      |   その様にすれば弟ノードも列挙できるのではないか。
      |
      |   x 然し、それだとコードを大幅に書き直す事になるし、
      |     そもそもシェルの言語として末端からの解析ができる様に
      |     なっているかというと怪しい。例えば $() や <() や
      |     $(()) 等は何れも先頭から読むからできるのである。同様に
      |     {} や ${} もそうである。
      |   x そもそも書き途中で括弧が閉じていない
      |     場合には末端がどのような文脈か分からないので解析を始められない。
      |     或いは末端が普通の文脈であるという仮定で解析を無理やり
      |     実行できるかもしれないが、その結果として得られる文法エラーの結果は
      |     ユーザの直感とは全くかけ離れた物になるだろうと思われる。
      |   x そもそも先頭からの解析と末端からの解析が矛盾してしまう
      |     ので両方の結果を用いて兄弟の単語を抽出するという事自体が
      |     一体どういう事なのかというのが分からなくなる。

      現状をまとめると:

      * 指定した単語 (i,nofs) についてコマンドを抽出したい。
        具体的には兄弟ノードを全て集めて単語を探索する。
      * 兄ノードに関しては辿る事ができるが、
      * 弟ノードに関しては親からでないと辿ることができない。
      * 然し、親を知るためには結局末尾から探索しなければならない。
        - 高速化の為に事前に木情報を構築する可能性もあるが、
          更新がある度に効率的にその木を更新するのは困難である。
        - 逆方向の解析案はそもそも文法的に定義が難しい

      | d 前方に順番に探索していって最初に現れた一つ上のレベルの
      |   ノードが親であるという様に判断すれば良いのではないか。
      |
      |   この方法と末尾から辿る方法とどちらの方が効率的だろうか。
      |   末尾から辿る方法だと子ノードの細かい構造をスキップする事ができる。
      |
      |   前方に探索する場合だと弟ノードとその子孫の全てをチェックする事になる。
      |   しかし末尾から辿る方法だと続くコマンドについても全て列挙する事になる。
      |   どちらのケースの方が可能性として多いのかという事である。
      |   後者の方がケースとしては多いのだという気がする。
      |   という事を考えると、実は前方に探索する方が良いのではないか。
      |
      |   x ok: もう一つの問題は前方に探索する場合には一セルずつ処理しなければならない、
      |     という事である。末尾から探索する場合には木情報を利用するので、
      |     配列に対する検査は単語の数だけに留まっている。
      |     或いは何らかの方法を用いて次の非空ノードまでの距離を検査できるだろうか。
      |     →これは実装可能な気がする。non-empty-indices みたいな物を作れる。
      |
      | e 末尾から探索する時に適当な場所で当たりをつけて処理を
      |   省略することはできないか。
      |
      |   つまり沢山のコマンドが後ろに並んでいる状態だと、
      |   その全ての単語について検査を行わなければならない。
      |   もしコマンドが何らかの入れ子の中にある場合には、
      |   大体の場合はコマンドはトップレベルにあるだろうから、
      |   適当な真ん中あたりの単語についてそれがトップレベルであれば、
      |   親はそれよりも後ろにあるという事を結論づける事ができる。
      |   x 然し、適当な真ん中あたりの何処に単語があるのか探すのは
      |     それはそれでもう一つの探索処理である (一応対処方法はある)。
      |   x そもそも入れ子の中にある状況は限られている。
      |     うーん。これは大した高速化にはならないだろう。
      |   x 当たらなかった場合のコストが高い。
      |     最悪の場合は全体が一つの入れ子の中にある場合で、
      |     その場合には二分法をしようにも末端まで繰り返し
      |     テストを繰り返した挙げ句に結局末尾から探索しなければならない。
      |     →まあ、一回テストに失敗したら諦めるという手法を用いれば良い。

      取り敢えず前方に探索して親ノードもしくは次の弟コマンド
      が見つかったら其処から探索を開始するという方針を取る事にする。

      前方に探索する場合には工夫して次の木情報がある単語まで
      スキップするか、或いは普通に一セルずつ確認するか。
      思うに工夫する為のコストも軽くはないし、
      唯実装が複雑になるだけなので今回は一セルずつ確認する。

      [実装]

      | 先ずデータ構造がどうなっているのか改めて確認する。
      | 1 nofs が有限であれば
      |   その親が既に親になっているので其処から探索を始めれば良い。
      | 2 nofs==0ならば親になるノードを探索する。
      |   特に _ble_syntax_tree を前方に一セルずつ確認する。
      |
      |   ここで疑問は単語の情報だけを見て親が存在するか
      |   どうかを判定する事は可能だろうかという事。
      |   nest との関係はどうなっていたのか。
      |   - 現状の実装では nest も word も tree に格納されている。
      |     両者が混ざり合う事はなくて必ず親要素の中に収まる様になっている筈。
      |     従って word/nest を意識せずに単に親を調べれば良い。
      |     然し、ここでの問題はその単語に親が存在するかどうかの判定。
      |   - 余り覚えていないが word の親は必ず nest である。
      |     単語の下に直接単語があるという状況は考えにくい。
      |   うーん。不可能の気がする。今構造を確認したところによると、
      |   _ble_syntax_tree には自分の深さに関連する情報や
      |   親に関する情報は全く記録されていない。
      |   構造を拡張するのはそれはそれで複雑である。
      |
      |   現状の情報を用いて実装するにはどうしたら良いか。
      |   というかそもそも親ノードが存在するかどうかを知る必要はあるか?
      |   考えてみればない気がする。
      |
      | というか実装していても思ったがそもそも弟を辿るのであれば、
      | その時点で単語を回収すれば良いのでは。。。

      取り敢えず実装した。tree#next-sibling, tree#previous-sibling という
      関数を新しく実装してそれを使って実装したら綺麗にできた。
      既存の extract-command もこれを使って実装したらもっと楽で
      見通しが良かったのではないかとも思う。

      さてこれで再度テストを行う事にする。
      見た所動いている様な気がする。

    x fixed: tree-enumerate の内部変数名の変更に伴う問題。
      書き換えてみたら echo $(echo hello) 等が正しく着色できなくなった。

      そもそもなぜ変数名を書き換えようと思ったのだったか。

      % うーん。tree-enumerate の中で動作する関数を作るとすると。
      % 勝手に tree-enumerate の情報が書き換わると動作しなくなる。
      % 然しだからと言って i nofs を local で被覆して使えなくすると、
      % 今度は内部でまた続きの tree-enumerate をしたい時にできなくなる。
      % 然し、それは具体的にどの様な状況だったか。

      →取り敢えず二箇所変更漏れを修正したら動く様になった気がする。
      変数名を書き換える事が得策なのかは分からないが、
      取り敢えずこれをベースにして考える事にしたい。

      更にこの修正によって前者の症状についても消えてしまった。
      然し前者の問題は独立に解決しなければならない問題である。

2020-01-24

  * Bash 3.2 ^A, ^? を含む配列に対する対策 [#D1241]

    更に履歴に格納されている値も変化している。
    history -s で登録されている値は合っている。
    何処でずれるのだろうか。。。

    よく考えたらこれは可也広範に亘るのではないだろうか。
    そもそも配列の複製 arr2=("${arr1[@]}") を安全に実行できるのだろうか。
    これは別項目を立てて対策を考えるべきである。

    どういう操作が安全でどういう操作が駄目なのか。
    対策する事は可能だろうか。

    * arr2=("${arr1[@]}") これは安全の様だ
    * arr1=("$del" "$soh") これも安全の様だ

      取り敢えず _ble_term_del 等に入れれば良い?
      これで declare-print-definitions に関しては大丈夫な気がする。

    ble.sh の中で特に問題になりそうなのは何処か。

    * history の読み取り。
      これはスクリプトを構築してそれを eval している。
      うーん。対策を入れてみたが効いていない気がする。
      これはまた別の所で問題になっているのだろうか。
      或いは置換が効いていない?
      →これは簡単なミスだった。修正したら動く様になった。

    * binding のキャッシュ?
      →これは declare-print-definitions の方を対策した。
      恐らく大丈夫だろう。直接 declare -p を呼び出している箇所を全て塞げばOK

    * vi のマクロの記録?
      これは eval の様な事はしていないので大丈夫の筈。

    他に "eval -- ..." となっている箇所を探してみたが恐らく大丈夫。
    基本的に直接 ^A や ^? の文字が arr=(...) の形式の中に現れていなければ大丈夫なのだ。

  * BASH_REMATCH は local と宣言してから使うべきなのではないか [#D1240]
    或いは、local と宣言する事ができない可能性はあるだろうか?
    これは試してみる価値はある。と思って試してみたら、
    local と宣言する事ができなかった。エラーが表示される。
    更に、無視して実行するとグローバルの BASH_REMATCH が書き換えられてしまう。
    従って、この方向性に基づく BASH_REMATCH 書き換え対策はできない。

  * Bash 3.2 で存在する変数名を入力すると無限ループになる [#D1239]
    ble-0.3 では発生していない。

    これは予想通り 93dab7b が原因の様である。
    然し不思議なのは無限ループが発生する要素が何処かにあるのか? という事。

    どうも既に出ていた bash-3.2: _ble_syntax_attr[i-1]: bad array subscript
    というエラーは実はこれに関連している様である。これが意味する所は。。
    i=0 になってしまっている?

    一箇所修正した。これで無限ループは直った。
    然し bad array subscript は依然として出ている。
    改めて bad array subscript がいつから出る様になったのか確認する。
    やはり 93dab7b が原因の様である。

    改めて探してみると未だ BASH_REMATCH の書き換えの影響が出そうな部分があった。修正した。

  * stty: Bash 3.2 で変なエラーメッセージが出ている [#D1238]
    /usr/bin/stty: invalid integer argument: `\001\177'
    /usr/bin/stty: invalid integer argument: `\001\177'

    調べると ^? $'\x7F' を arr=() の形式で配列に代入すると勝手に ^A^? になる様だ。
    更に調べると declare -p は ^? を勝手に ^A^? に変換するらしい。面倒だ。
    というか配列の要素の中に ^? が含まれている場合、
    これを正しく補正して arr=() の形式にする事ができない。うーん。
    取り敢えず別項目を立てて処理する事にする #D1241

  * ble/syntax/parse の遅延が動いていない [#D1237]
    update-syntax で is-function でチェックしているが、
    これだと autoload で定義している物に当たってロードされてしまう。

    これは遅延させると何か問題でも発生したのだったか?
    以前も同じ事を確認した様な気がしないでもない。
    それに今でもちゃんと遅延されている様な気もする。

  * ble-update: 実は |& は Bash 4.0 の機能だった [#D1236]
    使わない様に修正した。

    序でなので文法の方も bash version をチェックして処理を切り替える様にした。

  * decode (ble/builtin/bind): keyseq を読む時に標準入力を見ているがこれは変 [#D1235]
    #D1233 の問題を再現する過程で bind '"...": ...' を呼び出す事によって、
    後々の Bash の終了に寄与することが分かった。理由は "..." を解析する為に
    ble-decode-char を使っていて、その中でユーザの入力がないか確認しているからだった。
    然し、"..." を解析する時にはユーザの入力を確認する必要はないし、
    もし仮にユーザの入力があったとしても其処で処理は変わらない筈である。

    と思って確認したら確かにちゃんとユーザの入力の有無に寄らない振る舞いになっていたが、
    チェックの順序が反転していた (元々は生起確率の低い判定を後に回そうとしていたが、
    ユーザの入力の有無の確認はコストの高い判定なので先に判定しても変ではない。
    何より論理的には先に判定するのが自然である。) 修正した。

  * decode: bleopt_default_keymap=safe で inputrc がエラーになっている [#D1234]
    これは ble/builtin/bind/rlfunc2widget でちゃんと処理されていないのが原因

2020-01-23

  * 2020-01-17 ble.sh: cygwin コンソールで実行するとすぐに閉じてしまう [#D1233]
    →これは結局 cygwin のバグだった。bug-report の方で取り扱う。

  * vi_test: stackdump [#D1232]

    また別の stackdump。Cygwin で C-\ C-\ を実行するとテストに失敗する。
    続いて失敗したテストを手で再現しようと思って "qaA hello" まで入力したところで stackdump が出た。
    再現してくれない→再現した。

    何か編集文字列がある時にテストを実行してその後に発生する。
    Cygwin 以外でも再現した。つまり、これは Cygwin でテストに失敗するのとは別の理由。

    現在の再現手順は "w C-\ C-\ i SP" である。
    まず初めにこれが最近の変更と関係していないか確認する。
    ble-0.4.0 で再現する。ble-0.3.1 はまた別のバグが出ている。
    これはまたテスト自身のバグだろうという気がする。
    遡ってみたがだいぶ昔から問題があった様だ。
    途中でテスト自体の不良などによって追うのが面倒になったので何処で始まったかは気にしない事にする。

    取り敢えずテストのコードを弄って最小化する。
    と思ったらテストコードで最初の状態を復元している所でミスを見つけた。
    復元しているのに復元されていなかったので変だったのだ。

2020-01-22

  * benchmark: ble-measure の較正 [#D1231]
    現在の自動較正だと a=1 が負になるなど問題が起こっているので、
    もっとちゃんと計測する様にする。特に a=1 の評価にかかる時間も考慮する。
    と思ったのだがどうも計測環境で速度が変化する?
    よく考えたら a=1 でちゃんと評価できているのであれば
    a=1 に対してはほぼ 0 になって欲しい。しかし有意に負になっている。

    もしかすると関数内で評価すると時間が違うという事なのだろうか?
    →なるほど。確かに 100ns ぐらい差がある様に見える。
    計測が行われている環境を調べると

      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7 (ble-stackdump)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4 (ble-measure)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:2 (ble/util/msleep/.calibrate-loop)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble/util/msleep/calibrate)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:35 (ble/util/idle.do/.call-task)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4 (ble/util/idle.do)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:16 (ble-edit/bind/.tail)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:50 (ble-decode/EPILOGUE)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble-decode/.hook)

    という事になっているので、9 段階ぐらい入れ子になっている。
    この入れ子に対する評価もした方が良いのだろうか?
    取り敢えず試しに計測してみる事にする。

    真面目に較正する関数を ble-measure/calibrate とした。
    然しこれには時間がかかる。従って、普通にロードした時は a=1
    の計測結果を元に最終的な結果を比例で予測する事にした。

    実際には測定のループ回数等色々な要素に影響される気がする。
    これ以上は追求しない事にする。

  * refactor: merge subdir "test" into "memo" [#D1230]
    test というディレクトリになっているが実際テストでない。
    これは実装上の実験に使っている。寧ろ memo の下に移動するべきである。

    * test/bash_history.erasedup.sh

      このファイルは実装に関係している筈で、
      ここよりは memo/ の中にあるべきファイルの気がする。
      然し、どの項目に対応するファイルだろうか。
      ファイル名を memo.txt の中で検索してみても見つからない。
      blame してみて分かったのは、実はこのファイルは一番最初の commit から存在している。
      つまり本当に最初の最初に追加された物である。

      memo.txt を辿ると本当の最初の commit は
      恐らく 2013-06-13 の状態から殆ど変えていない。
      従って 2013-06-13 以前の項目のどれかに対応している。
      特に議論もないので最初に対応した時に既に試したという事の気がする。
      #D0016 が恐らく最初に対応した時のメモである。

    * ファイル test-source.sh は何だろう。
      確認してみるとこれも最初から存在したファイルの様だ。
      中を覗くとこれは恐らく ble.sh のファイルの位置を特定する方法を模索した時の物。
      うーん。何処で最初にこの機能を実装したのか。他のファイルを読み取るのに必要。
      例えば初期のファイルで言えば cmap 等が他のファイルとして用意した物。
      #D0028 に _ble_term_sc の言及が在るので恐らくこれ以前に既に test-source.sh はあった。
      然し、直接に対応する項目は記録されていない様に見える。

    結論から言えばこれらのファイルはごくごく
    最初期のファイルなので対応する項目はないと考えて良い。
    この時にどの様にファイルに名前をつけるか。

    今後、対応する項目を一切作らずにテストファイルだけ追加するという事はあるだろうか。
    もしないのであれば、対応する項目のないテストファイルは
    D0000 にしてしまっても良いかもしれない。

  * history: fix a bug that history append does not work with "set -C" (reported by cmplstofB) [#D1229]
    https://github.com/akinomyoga/ble.sh/issues/37
    "bash: /run/user/1000/blesh/NNNN.history.app" というエラーメッセージが出るとの事。

    これは見落とし。他にも類似の物がないか探したが他は古いテスト用のコードしかなかった。
    またチェックするのも面倒なのでテスト用のコードも全部修正する。

2020-01-21

  * util: 16進数リテラルの着色に失敗している (reported by cmplstofB) [#D1228]
    https://github.com/akinomyoga/ble.sh/issues/36#issuecomment-576625143

    何か正規表現を間違えている? と思って確認したらそもそも対応を忘れていた。

  * util: ble/util/{save,restore}-vars に失敗している (reported by cmplstofB) [#D1227]
    https://github.com/akinomyoga/ble.sh/issues/36

    * 変数名の抜けはないか? →無いような気がする。
      未初期化の変数が配列ではなくて変数として記録されている可能性?
      (然し、一旦配列になったのであればそれ以降は配列のままでいて欲しい)

    * 或いは未だ restore-vars に問題が残っているか。
      →全て配列として復元すれば元に戻る筈と思って試したら直らない。
        つまり変数名の列挙に失敗しているという事になる。

    と思ったが間違う要素がない。。何がいけないのだろう。
    そもそも座標計算がおかしいという事は、
    スカラーの復元に失敗しているという事である。

    うーん。かなり謎。何で? 少し色々実験してみる必要がある。
    先ず、vars を配列として保存・復元する様に書き換えてみる。
    →違いは見られない。

    一つずつ書き換えて確かめてみる事にした。
    と思って書き換えている内に分かった。
    多分この部分を書き直すのを忘れている、と思ったらそうだった。
    修正した。

2020-01-18

  * cygwin: cygwin console で USER が空になっている [#D1226]
    取り敢えずユーザー名はもし設定されていなければ設定する。
    id -un でユーザー名は取得できる筈である。

    これも #D1225 と一緒に対応した。

  * cygwin: cygwin console で "-u指定されたファイルが見つかりません" エラー [#D1225]

    これは 3.0.7 でも発生している。恐らく補完だろう。
    "-u指定されたファイルが見つかりません" というメッセージが表示される。
    64bit でも 32bit でも同様に出る。中で更に起動した Bash では再現しない。

    この行が駄目だった。
    ble/util/assign-array arr 'ble/bin/sort -u <<< "$compgen"' # 1 fork/exec

    そして ble/bin/sort を見てみると
    ble/bin/sort() { '/cygdrive/c/WINDOWS/system32/sort' "$@"; }
    等という事になっていた。道理で駄目な訳だ。
    他にも Windows に同盟のコマンドがあるという事がありそう。
    うーん。面倒なのでもう先頭に追加してしまう事にする。。

  * main: .blerc がない時は ~/.config/blesh/... から読み取っても良いのでは [#D1224]
    然しどういう名前が良いだろうか。
    ~/.config/blesh/blerc なのか、
    ~/.config/blesh/blerc.sh なのか、
    ~/.config/blesh/init.sh なのか、
    或いはもっと別の名前が良いか。
    取り敢えず init.sh にする事にした。

  * ble-reload の後に固まる (reported by dylankb) [#D1223]
    https://github.com/akinomyoga/ble.sh/issues/35

    [再現]

    | 再現できない。色々の OS で試してみたが再現しない。
    |
    | うーん。或いは Bash 5.0.11 の問題である可能性はあるか?
    | →確認してみたが Fedora で 5.0.11 でも再現しないし、
    | また FreeBSD も確認してみた所元から 5.0.11 だった。
    |
    | 再現しないと思ったがもしかして。。。--noattach が駄目?
    | あー。そうだった。うーん。#D1199 で直した筈なのだが。
    | 確認してみると D1199 で直したのは単純に source ble.sh --noattach
    | した時の話であって、source ble.sh --noattach && ble-attach
    | したら固まった。全然直っていなかった。

    $ source ble.sh --noattach && ble-attach で再現する

    [状況]

    | これを直す為にはどうしたら良いのか。
    | #D1199 でどの様に直したのか確認する必要がある。
    | 調べると #D1199 の commit がないと思ったら ble-0.3 の問題として
    | ble-0.3 に修正が入っていた。と言っても対症療法的な物で、
    | ble-reload に対してしか修正が入っていなかったのだった。
    | 5bcea69 がその修正である。参考にならない。
    |
    | 参考にするべきはこれである #D1130 d35682a caa46c2
    |
    | うーん。分かった。
    | _ble_edit_detach_flag に値が設定されている時、
    | ble-attach は ble-detach (遅延) をキャンセルする事になるので、
    | 何もせずに抜けてしまう。これによって attach しているのにしていない、
    | という様な中途半端な状態になってしまっているのである。
    | 然し、そもそも _ble_attached になっているのが行けないのでは?
    | _ble_attached の設計を考え直すべきなのではないかという気がする。
    |
    | 今一度 _ble_edit_detach_flag と _ble_attached の意味について考える。
    | _ble_attached は実際に attach されているかどうかにするべきである。
    | そして、_ble_edit_detach_flag は複数の値を取りうる。
    | それぞれの意味について確認する。
    |
    | _ble_edit_detach_flag=detach
    |   これは ble-detach を呼び出した時に設定される。
    |   もし epilogue でこれが設定されていればその時に detach を実行する。
    |   或いは ble-attach でキャンセルする事も可能である。
    |
    | _ble_edit_detach_flag=reload これは reload 検知時に設定される。
    |   特に reload 検知前に attach していた時にこれが発生する。
    |   その場で完全に detach してしまいその後で reload を設定するのである。
    |   % 後の振る舞いとしては自動的に再 attach する事を示唆する。
    |   % と思ったが本当だろうか。違う気がする。
    |   % source した時に --noattach 等を指定していた場合には、
    |   % やはり勝手に attach しないという事になるのであろう。
    |   後の振る舞いとしては。現在の bind -x が終了する時に
    |   detach 状態であるのであればメッセージを表示する、という所だろうか。
    |
    |   さて、この時に ble-detach が呼び出された場合にはどうなるのか?
    |   うーん。_ble_attach が設定されていれば ble-detach を実行する。
    |   もし _ble_attach が設定されていれば実行の必要はない。
    |
    |   うーん。実はこれは detach と等価なのでは?
    |   と思ったが .prologue を呼び出しているという所が異なる。
    |   うーん。何だか分からないが色々複雑な状態を復元しなければならないので
    |   呼び出す必要があるという事だろうか。
    |
    |   然し、source ble.sh を実行した時点で色々と状態を調整している。
    |   そして抜ける瞬間にそれを復元している。しかしながらその状態は
    |   更にその外側で復元される?? 何だかよく分からない。
    |
    |   先ず記録されているのは実行環境であって、
    |   ble.sh環境は一意であると考えている。
    |
    |   attach が発生する場合は以下の様になる。
    |
    |     コマンド実行               source ble.sh              attach      epilogue
    |     [ble.sh]    →[実行環境A]→[ble.sh] → [実行環境B] → [ble.sh] → [ble.sh?]
    |
    |   attach が発生しない場合は以下の様になる。
    |                                                           epilogue    prologue
    |     [ble.sh]    →[実行環境A]→[ble.sh] → [実行環境B] → [ble.sh] → [実行環境]
    |
    |   もしここで prologue を呼び出していないとするとどうなるのだろうか?
    |   つまり代わりに detach と同じ処理をするとどうなるのかという事。
    |   うーん。PS1 等が消滅するという事は考えにくいし、何も問題がない気がする。
    |   そもそも PS1 が消滅していたのは何故だったか。
    |   恐らく epilogue を重複して呼び出してしまったから?
    |   epilogue が重複すると ble.sh 環境を実行環境として記録する事になってしまう。
    |   色々考えるとやはり prologue は必要がない気がする。
    |
    |   やっぱり何か不思議だ。detach の時にはほんの少ししか復元をしていない。
    |   何故問題が起こらないのだろうか? と思ったが分かった気がする。
    |   どのタイミングで detach を実行したかの違いなんだ。
    |   reload の時には先に detach してしまうので epilogue で状態が壊される。
    |   なので再び prologue を呼び出す必要がある。
    |   detach の時には epilogue の後に detach しているので、
    |   その時点でちゃんと状態が作られている。なので、簡単で良い。
    |
    |   という事は .check-detach に入った時の _ble_attached の状態で場合分けすれば良い。

    _ble_attached の意味を変更して実際に attach/detach しているかの状態を保持する事にした。
    _ble_edit_detach_flag に関しては reload と detach を区別しない処理に変更した。
    代わりに、_ble_edit_detach_flag が立っているのに既に detach されている状態と、
    まだ detach していない状態で場合分けする本来の目的に適う実装方法である。

    [確認]

    取り敢えず修正して動かして振る舞いを確認する。チェックするのは、

    ble-reload
    ble-detach; ble-attach
    source "$_ble_base/ble.sh" --noattach
    source "$_ble_base/ble.sh" --prompt
    source "$_ble_base/ble.sh" --noattach && ble-attach

    一応問題なく動いている気がする。

    x source "$_ble_base"/ble.sh --noattach してから ble-attach すると変だ。

      普通に ble-detach してから ble-attach する時との違いは何だろうか。
      やはり状態として変な状態になっている? ちゃんと復元しきれていない?
      然し attach 直前は別に変な振る舞いは見せていなかった筈。

      ble-attach する時に PS1 の restore に失敗している可能性?
      うーん。何がおかしいのだろうか。

      というか状態がおかしいというよりは [EOF] のマークが表示されているのが問題。
      ble-attach した時にプロンプトをその場で描画してしまうかそうでないかの違いは何?

      うーん。やっぱり attach 時に [EOF] が表示されるのは変である。
      .prologue で何か変な物がしかけられたのが原因だろう。

      分かった。ble-decode/PROLOGUE で
      ble-edit/exec:gexec/restore-state を呼び出して、
      ble-edit/exec:gexec/.epilogue が呼び出されている。
      その時に EOL 補正が入ってしまっているのである。
      対症療法的ではあるが _ble_edit_exec_inside_prologue= を設定する。

    ? よく考えるとこれだと prompt に失敗した時にやはり変な状態になるのでは。
      →実際に確かめてみたところ駄目になった。追加で修正する必要がある。
      修正した。

  * 2019-02-09 manual: 英語版 [#D1222]
    取り敢えず完成した。

2020-01-17

  * Error `ble/builtin/trap: invalid signal specification "-".` (reported by dylankb) [#D1221]
    https://github.com/akinomyoga/ble.sh/issues/33#issuecomment-575476866

    | うーん。何故だろう。調べるとこのエラーメッセージを出力するのは、
    | trap -p で sigspecs に - が含まれていた場合、もしくは、
    | trap で sigspecs に - が含まれていた場合。
    | うーん。何れにしても sigspecs に - が混入するのが怪しい。
    | sigspecs に - が混入する状況で怪しい箇所がある。
    | この箇所に入る条件は何か hlpE の何れも指定されていなくて、
    | 更に sigspecs が何も登録されていない場合に、
    | command を上書きしてそれから…あ、分かった。
    |
    | trap INT とすると INT のハンドラが削除されるのだ。
    | それを実現する為に ble/builtin/trap では、
    | 1. trap INT を引数として順番に処理すると最初は INT が command として解釈される。
    | 2. 引数解析の終端で引数がもう終わっているという事が分かったら、
    |   trap INT を trap - INT であったかの様に書き換える。

    本来の trap は trap INT で INT のハンドラが削除される。
    ble/builtin/trap でそれに対する対応が壊れていた。修正した。

2020-01-15

  * codespell [#D1220]

    gawk のメーリングリストに fossil というサイトの人が投稿している。

    | codespell という機能を使って spell ミスを発見しているのだという。
    | その spell ミスの発見はローカルで動かせないのだろうか、と探してみる。
    | GitHub で探してみたら以下のプロジェクトが在る。
    |
    |   https://github.com/codespell-project/codespell
    |
    | この codespell の頁に heads-up (注意喚起) がある。
    | fossies.org の頁に codespell を使っているのだと書かれている様だ。
    |   https://github.com/codespell-project/codespell/issues/1315
    |   https://fossies.org/features.html#codespell
    |
    | 其処にコメントしている jschleus というのが Jens つまり fossies の宣伝をしている人。
    |   https://github.com/jschleus
    |   https://github.com/letsencrypt/boulder/issues/4633
    |
    | 検索すると他にも様々なプロジェクトに対して去年の10月ぐらいから投稿している様だ。
    |   https://github.com/search?q=codespell+fossies&type=Commits
    |
    | この人は他の人の作った物を自分の物であるかの様に人に貢献している。


    取り敢えず codespell にかけて見た。

    * brance expansion in memo.txt
    * print filename and lines for -i 2
    * 他の候補を入力できる様にする。
    * 短い単語や大文字の短い単語 (略語) は無視するオプション
    * -i2 と -i1 の書き換える時の操作が違うので間違える。
      -i1 でそのまま C-m すると書き換えられる。
      -i2 でそのまま C-m すると書き換えが起こらない。
      何も入力せずに C-m した時には書き換えは起こらない様にするべきなのではないか。
    * -i2 で行が長い時にどの単語か分からない。
    * 辞書に登録されている "変換" だけにしか対応していない。
      文字の交換だとかについても全部手で一つ一つ登録されている。
      自動的に一致度を計算してどうとかそういう仕組ではない様だ。
      不毛である。

2020-01-13

  * util: 自動補完の区切り文字を設定できる様にする (suggestion by dylankb) [#D1219]
    https://github.com/akinomyoga/ble.sh/issues/33#issuecomment-573528032

    / で区切る様にしたいとの事だ。
    試してみると確かに fish では / も区切りになっている。
    新しい機能なので ble-0.4 に入れる事にする。
    と思ったけれどどうしようか。取り敢えず ble-0.4 に実装する事にした。

2020-01-12

  * util: 構文着色を単体で呼び出せる様にする [#D1218]
    history の一覧を表示して着色したり、
    或いは単語内の着色で別の言語を着色する時に必要である。

    * done: 各 layer の initialize-vars を実装する。
    * change: update-syntax は呼び出し側で管理する事にした。
    * done: ble/highlight/layer/update の interface を変更する。
      BLELINE_RANGE_UPDATE は廃止する。というか誰も使っていない。
      →一箇所使っている箇所があったがそもそも本当に正しかったのかも謎。
      →と思って適当に umin に書き換えたら動かなくなった。
        DMIN 変数に内容を保存してそれを使う事にした。

    単体で構文着色を実行する関数を作成する。作成した。

    然しよく考えたら別に現在の複雑な仕組みを使わなければならない言われはない。
    他の拡張や普通の構文着色の仕組みと同じように正規表現で一括で一致させてしまえば
    良いのではないだろうか。現在の枠組みを使う事の利点は部分更新に対応できるという事である。

    という事を考えるとやはり部分更新に対応するのが良い気がするのである。
    だとするとキャッシュを指定できるようにしなければならない。

  * util: {save,restore}-arrs は {save,restore}-vars に統合する [#D1217]

    実の所、全て配列であるかの様に取り扱っても問題ないし、
    また ble/is-array の判定は最新の bash では ${parameter@a} を使っているので
    そんなに重くない。毎回 arrs と vars の両方を呼び出すのは不毛なので、
    全て {save,restore}-vars で処理する様にして問題ない。

    * done: save-arrs, restore-arrs を削除する。
    * done: ARRNAMES を VARNAMES に統合する。

  * 2020-01-05 Homebrew でインストールしたら動かないという報告 [#D1216]
    https://github.com/akinomyoga/ble.sh/issues/33

    これは結局手元では再現できなかったし、
    何だか良く分からない内に向こうでも直ってしまった様だ。
    相手の報告を見ると相手の勘違いという事はなくて
    * 確かに変な状態が発生していたのは確かである。
      keymap をキャッシュから読み取った時に配列ではなくて普通の変数になっていた。
    * それも相手の環境では再現性があった
      (新しく ble.tar.xz をダウンロードして最初の1回は動くがそれ以降は動かない
      という事を書いていたので何度か試してその振る舞いが判明したという事である)。

    | [原因解明]
    |
    | 変だ。Homebrew には登録していない。
    | 取り敢えず返信でどうやって formula を使ったのかという事を質問した。
    | 然し、後で調べてみるとどうも GitHub から自動生成する事ができる様だ。
    | 何だかよく分からない。
    | →結局 Homebrew で ble.sh を入れたというのは勘違いだった。
    |
    | 更に keymap/emacs.sh がなかったとしても別のエラーになる。
    | また cache の keymap.emacs の中身を空にした場合でも
    | もっと前のチェックで引っかかるので別のエラーメッセージになる筈だ。
    | - まるで DEFAULT_KEYMAP の上書きに失敗しているかの様だ。
    |   取り敢えず DEFAULT_KEYMAP を上書きしなかった場合に同じエラーメッセージになる事を確かめた。
    |
    | 然し他に手がかりがない。。
    |
    | うーん。DEFAULT_KEYMAP を readonly にした場合でも同じ問題が生じる様だ。
    | また上書きエラーのメッセージは表示されない様だ。
    | 然し探しても関数を常に readonly にする機能がある訳でもない気がする。
    | 本当にこれが勝手に readonly になってしまう事があるだろうか。
    | 取り敢えず readonly かどうかは以下のコマンドで確認できる。
    | declare -f +r ble-decode/DEFAULT_KEYMAP
    |
    | その他の可能性として何があるだろうか。
    | 例えば _ble_decode_emacs_kmap_ が local になっている可能性?
    | 関数内部から source をするのは既に試したが問題は起こっていない。
    |
    | それよりも後で source して実行すると動くというのも不思議である。
    | bashrc 中で実行すると起こる何らかの不具合だろうか???
    |
    | というか彼は何故 bash_profile に設定を書いているのだろうか。
    | それがそもそもの間違いである可能性は?
    | 試してみたが bash_profile に書いたとしても
    | 全く呼び出されないか或いはちゃんと動くかのどちらかである。
    |
    | 分からないので取り敢えず返事待ちである。
    |
    | ? ok: cache が cache.d になっているのは何故なのだろうか。
    |   XDG の判定に失敗しているという事だろうか。
    |   →あー。分かった。これは ~/.cache というディレクトリが存在していないという事。
    |     なのでこれは飽くまで意図した動作の範囲内である。
    |
    | 追加の返信が来た。
    |
    | * 色々の問題が複雑に絡み合っている気がする。
    |   - ble-edit/detach を実行すると ble-decode/... is not found になったそうだ。
    |     何でだろう。余り考えにくい事である。 ble-decode なので ble-edit/detach を
    |     うち間違えた訳ではない。
    |   - 更にもう一度入力したら今度は shell が終了してしまったそうだ。
    |     実際に試してみたがエラーは起こらないし、もう一度入力しても何も起こらない。
    |     但し、stty の状態は復元しない様子である。
    |   - 更にまた別のセッションで実行すると syntax error になったそうで。
    |   何が起こっているのか全く分からない。
    |
    |   取り敢えずこれに関しては最新の ble-0.3 を試してもらって
    |   様子を見る事にする。もしかすると治るかもしれない。
    |   何れにしても最初のロードではちゃんと動くので何かが変なんだ。
    |
    | * 分かった事は _ble_keymap_emacs_kmap_ が配列になっていないという事。
    |   何が原因だろうか。nawk による処理で print definition がちゃんと動いていない?
    |
    |   nawk では ENVIRON が使えないという噂があったので調べてみたが動いている気がする。
    |   というかどうやって dump していたのだったか。
    |   ble-decode/keymap/dump emacs を使っている。
    |   更に内部では ble/util/declare-print-definitions という関数を使っている。
    |
    |   うーん。nawk に差し替えてもちゃんと動いている。Bash 5 でも Bash 3.2 でも問題ない。
    |   $ ble/bin/awk() { /usr/bin/nawk "$@"; }
    |   $ ble/util/declare-print-definitions arr
    |   arr=([0]="1" [1]="3" [2]="4321" [3]="231")
    |
    |   うーん。何が原因なのだろうか。向こうで実行してもらうという手もある。
    |   何れにしても改めて向こうに以下を試してもらう必要がある。
    |   $ grep _emacs_ "$_ble_base_cache/keymap.emacs"
    |   $ arr=(1 2 3)
    |   $ declare -p arr | cat -A
    |   $ ble/util/declare-print-definitions arr | cat -A
    |   $ cat -A <<< $IFS
    |
    |   うーん。もしかして IFS が変な値を持っているのが原因という可能性はある?
    |
    |   取り敢えず _ble_keymap_emacs_kmap_ の出力結果が
    |   配列でなくスカラーになっていた時に現象が再現するかについて確認する。
    |   →取り敢えず右辺を '...' で囲むと報告されているのと同じ状態になるという事は分かった。
    |   やはり ble/util/declare-print-definitions が不味いという事なのだろう。
    |
    |   ? 或いは busybox awk など更に別の実装を使っている可能性はあるだろうか。
    |     nawk, mawk, busybox awk の何れを試しても ble/util/declare-print-definitions
    |     はちゃんと動いている様に見える。やはりよく分からない。
    |
    | * is-keymap は配列かどうかも含めて検査するべきではないか。
    |   と思って実装を確認したがこれはどうやら register されたかどうかの判定。
    |   従って関係ないのであった。これはまあ修正しなくても良い。
    |
    | + done: 解決後に bash_profile ではなくて bashrc に書く様にお願いする
    |   →これは適当な折に説明を書いた
    | + done: 解決後に chsh しないのかという事を尋ねる
    |   →これも向こうが疑問に思っていたのでその折に説明した

2020-01-11

  * ble.sh session からログアウトした時の Bash の終了ステータス [#D1215]

    C-d で抜けると 2 や 255 になっている。
    exit コマンドで抜けた場合は 0 である。この違いは何処から?
    普通の Bash session から C-d でログアウトした時は 0 である。

    →これは何故か exit の引数に "$ext" を渡していて、
    然し ext という変数がそもそも存在していなかったのが原因だった。
    恐らく ble/builtin/exit の実装における builtin exit "$ext" をコピーしたからか、
    或いは実装の途中で "$ext" が実際に存在していたかのどちらかである。
    何れにしてもこれを exit 0 に書き換える事にした。

  * 未だ linux console の振る舞いが変だ [#D1214]

    最後の行で DL (CSI M) しても何も起こらない。この振る舞いは普通じゃない。
    もし ANSI に反していないのだとしても修正しても良いのではないだろうか?
    (然し、他のプログラム vim や emacs はこれをどの様に取り扱っているのだろうか。)

    * Linux console を調べる
      % Linux に対する修正を考える場合どの様にしたら良いのだろうか。
      % 様々な文書に目を通さなければならないらしい。
      % https://github.com/torvalds/linux/blob/master/Documentation/translations/ja_JP/howto.rst
      %
      % そもそも問題の linux console は linux に含まれているのかという所から謎。
      % https://elixir.bootlin.com/linux/latest/source/include/linux/console.h#L145 これは多分違う。
      % /dev/console 的な意味でのコンソールである。うーん。clone する?
      % 実のところどれだけの容量があるのか分からない。実際に clone を試みると712万のファイルがある。
      % 例によって github の connection は 30KiB/s と低速である。
      % 1/1000コピーした時点で 4MiB になっている。つまり合計で 4GiB ぐらいある?
      %
      % 調べると github は単なるミラーで本家は kernel.org にあるそうだ。
      % という訳で github は遅いので kernel.org からクローンする事にする。
      % と思ったら kernel.org は github にも増して遅い。駄目だ。

      うーん。cygwin でも同じ振る舞いになるという事は、まあ許容するしかないのだろうか。
      後で興味があれば該当部分のコードを確認する事にする。

      * 後で見たらダウンロードが終わっていた。結局 1.2GiB 程度だった様だ。
        また時間帯によるのだろうか平均で 52KiB という事だった。
        20秒で1MiB,1分で3MiB,100分で300MiB,400分で1.2GiBである。約6時間。
      * grc '\bSGR\b' で検索するとどうやら linux/drivers/tty/vt/vt.c に console の機能がある。
        * CSI M, L の機能は csi_{M,L} という関数で実装されていて、
          実際の処理は con_scroll という関数で実行している。この con_scroll が怪しい。
        * 因みに 2;R;G;B にも対応している様だ (表示できるかどうかは別なのだろうが)。
          →調べてみると rgb_{fore,back}ground という関数で色相を元にして 16 色コードに変換している。

    取り敢えず ble.sh 側で対策を考える。
    というかこの振る舞いは cygwin コンソールと同じ? #D1147 に記録がある。
    うーん。最終行に於ける DL は信用できない物なのか。

    * そもそも最終行の時にだけ注意すれば良いのだろうか?
      以前 cygwin の console を観察した時には丁度ぴったり
      下にある行が消える時には必ず動かないという事だった。
      →今確認した所そういう問題は発生していない様だ。

  * linux console での振る舞いが怪しい [#D1213]
    調べると arch では発生していない。arch の kernel は 5.4.8-arch-1 である。
    ubuntu では 5.0.0-37-generic である。うーん。取り敢えず古い kernel の方に合わせて
    変なシーケンスは送らない様に修正する?

  * highlight: ${var@a} 等の変換に対する着色に対応していない (for bash 4.4) [#D1212]

  * highlight: 変数名で配列名・整数・読み取り専用などに応じて色を変えるか? [#D1211]
    →取り敢えず配列・読み取り専用・整数の属性について判定を行う事にした。

    環境変数かどうかの属性と大文字・小文字属性もある。
    というかこの機能は知らなかった。

    ? -l -u を使えば tolower をもっと簡単に実装できるのでは?
      x 然し調べてみると、問題点は全角アルファベットなども全て変換してしまうという事。
        これが実際に望ましい結果なのかどうかは用途に応じて考える必要がある。
        因みに ${var,,?} の形式の場合にも全角も含めて全て変換される。
        但し、こちらの場合には ${var,,[A-Z]} 等の様にして制御する事が可能である。

      実際に string#tolower の使用箇所を見てみると、
      特に半角だけを特別扱いする必要のある場所もない。
      従ってこのままで良い。

      また、-l, -u の機能は Bash 4.0 からであり、
      ${var,,} の機能も Bash 4.0 からなので、結局どちらを使っても良い。
      -l, -u を使うと一旦別の変数に代入しなければならなくなるので、
      実の所、現状のまま ${var,,} を使うのが良いだろうという気がする。

    * Bash 4.3 の ChangeLog に -c という属性に対する言及があるがこれは何?

      | j. Converting an existing variable to a nameref variable now turns off the
      |    -i/-l/-u/-c attributes.

      うーん。ChangeLog の他の箇所には出て来ないし、
      また、declare --help にも書かれていない。
      然し、実際に実行してみたところ使える様だ。

  * highlight: 変数名の着色、算術式の着色 [#D1210]

    * fast-syntax-highlighting は変数が存在するかしないかによる判定も行っている

      というか ble.sh でもこれは簡単にチェックできるのではないだろうか。
      存在する変数と存在しない変数。現在の解析は純粋に文法で行っているので
      変数の存在・不存在によって着色を変えるという事は考えていなかった。
      これは文法レベルの着色で対応するべき事なのか或いは
      もっと上のレイヤーで着色するべき事なのか。
      うーん。というか変数の中身が空かどうかにも応じてチェックして良いのでは。

    set -u の時にはエラー着色をしようと思ったが、
    ${var-} や ${var+} の時にはエラーにならないなどの規則が面倒。
    と思ったが、現在の解析では - や + が続きにあるかどうかを
    その場で判定しているのでこれの対応はそんなに難しくない。
    一方で、編集している途中で変数の状態が変わってしまう可能性はあるだろうか?
    それから構文解析する関数の中で使っている一時変数が勝手に存在する事になる可能性?

    算術式の変数名に関しても着色できるはず。
    配列・連想配列や整数の属性? 読み取り専用やexport,local,etc.

    頭が動いていない。今何をしようとしていたのかと言うと、
    declare の引数の色は何処で決まったのかという事。
    これは実は単語の始まりの時に既に決まっているのではないだろうか。
    書き換えようとして思ったが declare aaa の時には変数が存在していても
    存在していなくても文法的には有効なのであるから色を変える必要はないのでは。
    と思ったが、一貫性を考えるのであればやはり色を与えても良い気がする。
    うーん。その文脈で色が必要かどうかに関係なく着色する事にする。

2020-01-10

  * util: support Minix (OS) [#D1209]

    Minix の上でも msleep の実装が駄目だった。
    今度は read -u 番号 による指定が使えない雰囲気である。

    また Minix では HOSTNAME が IP Address になっていた。
    この場合に PS1 の \h が IP アドレスの最初の番号だけを表示する。
    これは都合が悪いので IPv4 の形式の場合には \h は省略しない事にした。

    他に Minix に ble.sh を持っていく時に make dist しようとしたら
    エラーが発生したので修正した。

  * util: support Haiku (OS) [#D1208]

    Haiku 上で動かしてみると先ず sleep が動かない。
    mkfifo 等の機能が完全ではないという事の様に見える。
    Cygwin と同様に /dev/udp/0.0.0.0/80 を使ってみたがそれも駄目だった。
    通常の sleep コマンドに fallback する事にした。
    一応 GNU coreutils sleep が入っているので全く動かないという事はない。

    次に stty がエラーメッセージを出力している。lnext はないと言っている。
    確かに POSIX を見るとサポートされている文字の種類はそんなにない。
    https://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html
    現在使っているのは kill lnext werase erase intr quit susp である。
    kill intr erase quit susp はある。lnext, werase はない。
    仕方がないので初回起動時にチェックする事にする。

    後は cmap で home,end,insert,delete の類の表現を調べるのに使っている
    tput で terminfo を想定していたが termcap でも大丈夫な様に修正した。

2020-01-07

  * global: workaround Solaris awk [#D1207]

    % Solaris の awk は ENVIRON が使えない。POSIX には ENVIRON が載っているのにも関わらず。
    % POSIX "In addition, all environment variables shall be visible via the awk variable ENVIRON."
    % 最近 POSIX に載ったという事なのだろうか。なるほど、
    % "Several features have been added based on newer implementations of awk:" のリストに載っている。
    % これによると -v assignment も新しい機能だそうだ。
    %
    % 何れにしても ENVIRON がなくても動くようにしなければならない。
    %
    % どの様にして文字列を渡すのが懸命だろうか。
    % a 一つの方法は -v var=... で渡す方法。
    %   然し、... の部分をエスケープしなければならない。
    %   どの文字をエスケープする必要があるだろうか。\ だけ?
    %   更に -v も新しい機能だそうだ。
    %   実際に Solaris の awk に対して使ってみるとエラーになる。
    %
    % b 或いは "..." の部分に埋め込むしかないのだろうか。
    %   面倒な事である。
    %
    % * !a[$0]++ が使えないので a[$0]++ != 0 としなければならない。
    % * また BEGIN を二つ以上含む事もできない。
    %   というか一番最初でなければならない様だ。
    % * 何と Solaris の awk は user-defined function すら定義できない?
    % うーん。これはどうしようもない。

    Solaris の awk は絶望的に使えない。関数が使えないのでもうどうしようもない。

    調べると普通は /usr/xpg4/bin/awk (nawk) を使うそうな。

    何と。xpg4 awk も他の awk と異なる動作をする。nawk と同じであるかの様に説明されていたが、
    実際のところ他の nawk とも違う振る舞いをしている様だ。以下の様にすると確かめられる。
    $ echo "'" | /usr/xpg4/bin/awk -v apos=\' '{APOS=apos "\\" apos apos;gsub(apos,APOS);print}'

    APOS=apos "\\\\" apos apos にすれば良いかと思いきや、
    そうすると今度は別の gawk,nawk,mawk が期待したのと異なる結果になる。
    うーん。どの様にしたらまともな動作にする事ができるだろうか。
    取り敢えず動くようにした。問題なく動いている様に見える。
    後で問題が起こるかもしれないが、取り敢えずこれで良い事にする。

  * color: ble-color-setface の警告メッセージ (reported by cmplstofB) [#D1206]
    https://github.com/akinomyoga/ble.sh/commit/1885b541dfc200d9a0d2b5e8d6959d132462a008#r36687109

    古い形式 face:*, iface:* を使った時の警告メッセージが間違っていた。

  * global: FreeBSD, Arch Linux, etc. 対策 [#D1205]

    - make が GNU make とは限らない。
    - which があるとは限らない
    - man があるとは限らない
    - LC_COLLATE を変えようとするとエラーメッセージが出る @ Arch Linux
      何故かは分からない。
      →これは分かった。日本語の locale しか生成していなかった。
      実際に試した環境は LANG=en_US.UTF-8 であったが、
      実は en_US.UTF-8 の locale が生成されていなかったのである。
      何れにしてもシステムの設定に少し異常が在るだけで使えなくなるのも不便なので
      やはり無理やりメッセージは封じ込める事にする。

  * [自然解消] 2019-07-02 term: tput が terminfo (ncurses) ではなくて termcap の場合? [#D1204]
    Ref #D1203

    | sentaku ではそれに対応している。ble.sh では terminfo ではなかった場合には、
    | 既定で ANSI のシーケンスを用いる様になっている。

    これは実際には問題にはならないと思っていたが実際に問題になっていた。
    terminfo の項目名と似た名前の別の termcap 項目が呼び出されて変な事になっていた。

  * term: FreeBSD に入れてみたら着色が動かない [#D1203]
    どうやら tput が terminfo ではなくて termcap で動いているのが理由。
    修正することにした。今は動いている。

  * Makefile: BSD sed では i... と書けないそうだ (reported by dylankb) [#D1202]
    https://github.com/akinomyoga/ble.sh/issues/33#issuecomment-571234160

    修正しなければならない。修正した。

2020-01-06

  * syntax: 解析状態の異常 in Bash <= 4.1 [#D1201]
    function a { local IFS=\;; hello+=("${@:1}"); }; a 1 2 3; declare -p hello
    で hello の直前で C-u すると解析状態のエラーになる。
    function x { local A=\;; h+=("${@:1}"); } でもなる。
    function x { h+=("${@:1}"); } でもなる。
    { h+=("${@:1}"); } でもなる。
    { h+=("$@"); } でもなる。
    { h=("$@") でもなる。
    { h=("$a") でもなる。
    { h=("$(echo)"); } でもなる。

    Bash 5 では再現しない。Bash 4.2 でも再現しない。
    Bash 4.1 で再現する。これの対応は調べるのが面倒そうだ。
    ble_debug=1 で状態の違いを比較する。

    | Bash 4.0
    | _ble_syntax_attr/tree/nest/stat?
    | 18 a    000 '{' ++   word=CMDI:0-1>@0/(wattr=d) word="none":0-1 nest=(CMDI w=CMDX:0- n=- t=-:-) stat=(CMDX w=- n=- t=-:-)
    | 17 a    001 ' '      stat=(CMDX1 w=- n=- t=$1:-)
    |  7 a    002 'h' |    stat=(CMDX1 w=- n=- t=$1:-)
    |  8 a    003 '=' |
    | 12 a    004 '(' ||   nest=(VRHS w=_ble_attr_VAR:2- n=- t=-:$1)
    |  9 a    005 '"' |||| nest=(VALI w=VALI:5- n='none':4- t=-:-) stat=(VALX w=- n=@4 t=-:-)
    | 14 a    006 '$' |||| stat=(QUOT w=- n=@5 t=-:-)
    |  7 a    007 'a' ||||
    |  9 a    008 '"' ||++ word=VALI:5-9>@8/(wattr=d) word="none":5-9 stat=(QUOT w=- n=@5 t=-:-)
    | 12 a    009 ')' ++   word=_ble_attr_VAR:@0>2-10>@9/(wattr=d) word="none":4-10>@8 stat=(VALX w=- n=@4 t=$9:-)
    |  |    s 010 ^@      stat=(CMDXV w=- n=- t=$10:-)
    |
    | Bash 4.2
    | _ble_syntax_attr/tree/nest/stat?
    | 18 a    000 '{' ++   word=CMDI:0-1>@0/(wattr=d) word="none":0-1 nest=(CMDI w=CMDX:0- n=- t=-:-) stat=(CMDX w=- n=- t=-:-)
    | 17 a    001 ' '      stat=(CMDX1 w=- n=- t=$1:-)
    |  7 a    002 'h' |    stat=(CMDX1 w=- n=- t=$1:-)
    |  8 a    003 '=' |
    | 12 a    004 '(' ||   nest=(VRHS w=_ble_attr_VAR:2- n=- t=-:$1)
    |  9 a    005 '"' |||| nest=(VALI w=VALI:5- n='none':4- t=-:-) stat=(VALX w=- n=@4 t=-:-)
    | 14 a    006 '$' |||| stat=(QUOT w=- n=@5 t=-:-)
    |  7 a    007 'a' ||||
    |  9 a    008 '"' ||++ word=VALI:5-9>@8/(wattr=d) word="none":5-9 stat=(QUOT w=- n=@5 t=-:-)
    | 12 a    009 ')' ++   word=_ble_attr_VAR:@0>2-10>@9/(wattr=d) word="none":4-10>@8 stat=(VALX w=- n=@4 t=$9:-)
    |  |    s 010 ^@      stat=(CMDXV w=- n=- t=$10:-)

    特に違いは見られない。エラーが起こった後の状態についても確認してみる。

    | Bash 4.0 _ble_syntax_attr/tree/nest/stat?
    |  7 a  s 000 'h' |    stat=(CMDX w=- n=- t=-:-)
    |  8 a  s 001 '=' |
    | 12 a  s 002 '(' ||   nest=(VRHS w=_ble_attr_VAR:0- n=- t=-:-)
    |  9 a  s 003 '"' |||| nest=(VALI w=VALI:3- n='none':2- t=-:-) stat=(VALX w=- n=@2 t=-:-)
    | 14 a  s 004 '$' |||| stat=(QUOT w=- n=@3 t=-:-)
    |  7 a  s 005 'a' ||||
    |  9 a  s 006 '"' ||++ word=VALI:3-7>@6/(wattr=d) word="none":3-7 stat=(QUOT w=- n=@3 t=-:-)
    | 12 a  s 007 ')' ++   word=_ble_attr_VAR:@-1>0-8>@7/(wattr=d) word="none":2-8>@6 stat=(VALX w=- n=@2 t=$7:-)
    |  |    s 008 ^@      stat=(CMDXV w=- n=- t=$8:-)
    |
    | Bash 4.2 _ble_syntax_attr/tree/nest/stat?
    |  7 a  s 000 'h' |    stat=(CMDX w=- n=- t=-:-)
    |  8 a  s 001 '=' |
    | 12 a  s 002 '(' ||   nest=(VRHS w=_ble_attr_VAR:0- n=- t=-:-)
    |  9 a  s 003 '"' |||| nest=(VALI w=VALI:3- n='none':2- t=-:-) stat=(VALX w=- n=@2 t=-:-)
    | 14 a  s 004 '$' |||| stat=(QUOT w=- n=@3 t=-:-)
    |  7 a  s 005 'a' ||||
    |  9 a  s 006 '"' ||++ word=VALI:3-7>@6/(wattr=d) word="none":3-7 stat=(QUOT w=- n=@3 t=-:-)
    | 12 a  s 007 ')' ++   word=_ble_attr_VAR:0-8>@7/(wattr=d) word="none":2-8>@6 stat=(VALX w=- n=@2 t=$7:-)
    |  |    s 008 ^@      stat=(CMDXV w=- n=- t=$8:-)
    |
    | @@ -6,5 +6,5 @@
    |  14 a  s 004 '$' |||| stat=(QUOT w=- n=@3 t=-:-)
    |   7 a  s 005 'a' ||||
    |   9 a  s 006 '"' ||++ word=VALI:3-7>@6/(wattr=d) word="none":3-7 stat=(QUOT w=- n=@3 t=-:-)
    | -12 a  s 007 ')' ++   word=_ble_attr_VAR:@-1>0-8>@7/(wattr=d) word="none":2-8>@6 stat=(VALX w=- n=@2 t=$7:-)
    | +12 a  s 007 ')' ++   word=_ble_attr_VAR:0-8>@7/(wattr=d) word="none":2-8>@6 stat=(VALX w=- n=@2 t=$7:-)
    |   |    s 008 ^@      stat=(CMDXV w=- n=- t=$8:-)

    確かに違いが現れてはいるが。。うーん。-1 という要素に何か親がいるかの様な取り扱いになっている。
    更新範囲についても確認しておく事にする。うーん。Bash-4.0 では最初の 4 文字についてだけの更新である。
    Bash-4.2 では全体に対して更新が実行されている。うーん。再計算範囲は一致しているのだろうか。

    何れにしても Bash-4.2 以上では正しく動いているのだからこれはアルゴリズムの問題というよりは
    Bash の仕様の問題である筈だから修正はそんなに難しくはないのだと思われる。

    * 再計算範囲 in ble/syntax/parse を出力して確かめる
      ble/syntax/parse/determine-parse-range の結果は同じ様だ。
        i1='0' i2='0' j2='2'
        i1='0' i2='0' j2='2'

    * shift を実行した直後の状態は以下の通り。やはり違いはない様だ。

      | _ble_syntax_stat=(
      |   '1 -1 -1 -1 -1 -1 none 1'
      |   '17 -1 -1 -1 0 -1 none 1'
      |   '17 -1 -1 -1 0 -1 none 1' '' ''
      |   '23 -1 -1 1 -1 -1 none 1'
      |   '5 -1 -1 1 -1 -1 none 1' ''
      |   '5 -1 -1 3 -1 -1 none 1'
      |   '23 -1 -1 5 0 -1 none 1'
      |   '13 -1 -1 -1 0 -1 none 1'
      |   '1 -1 -1 -1 1 -1 none 1'
      |   '1 -1 -1 -1 2 -1 none 1'
      |   '43 -1 -1 -1 0 -1 none 1')
      | _ble_syntax_tree=(
      |   '2 1 0 -1 d nnone 1 -1 -1 -' '' '' '' '' '' '' ''
      |   '24 4 0 -1 d nnone 4 -1 -1 -'
      |   '7 8 0 8 - nnone 6 1 -1 -' '' ''
      |   '2 1 -1 3 d')
      | _ble_syntax_nest=(
      |   '2 0 1 -1 -1 -1 none none' '' '' ''
      |   '11 2 7 -1 -1 2 none none'
      |   '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_attr=('118' '17' '7' '8' '12' '9' '14' '7' '9' '12' '12' '1' '119')
      |
      | _ble_syntax_stat=(
      |   '1 -1 -1 -1 -1 -1 none 1'
      |   '17 -1 -1 -1 0 -1 none 1'
      |   '17 -1 -1 -1 0 -1 none 1' '' ''
      |   '23 -1 -1 1 -1 -1 none 1'
      |   '5 -1 -1 1 -1 -1 none 1' ''
      |   '5 -1 -1 3 -1 -1 none 1'
      |   '23 -1 -1 5 0 -1 none 1'
      |   '13 -1 -1 -1 0 -1 none 1'
      |   '1 -1 -1 -1 1 -1 none 1'
      |   '1 -1 -1 -1 2 -1 none 1'
      |   '43 -1 -1 -1 0 -1 none 1')
      | _ble_syntax_tree=(
      |   '2 1 0 -1 d nnone 1 -1 -1 -' '' '' '' '' '' '' ''
      |   '24 4 0 -1 d nnone 4 -1 -1 -'
      |   '7 8 0 8 - nnone 6 1 -1 -' '' ''
      |   '2 1 -1 3 d')
      | _ble_syntax_nest=(
      |   '2 0 1 -1 -1 -1 none none' '' '' ''
      |   '11 2 7 -1 -1 2 none none'
      |   '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_attr=('118' '17' '7' '8' '12' '9' '14' '7' '9' '12' '12' '1' '119')

    * 中途停止条件についても確認する

      | _tail_syntax_stat[i-i2]='17 -1 -1 -1 0 -1 none 1' _stat='1 -1 -1 -1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 1 -1 -1 none 1' _stat='23 -1 -1 1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 1 -1 -1 none 1' _stat='5 -1 -1 1 -1 -1 none 1'
      |
      | _tail_syntax_stat[i-i2]='17 -1 -1 -1 0 -1 none 1' _stat='1 -1 -1 -1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 1 -1 -1 none 1' _stat='23 -1 -1 1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 1 -1 -1 none 1' _stat='5 -1 -1 1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 3 -1 -1 none 1' _stat='5 -1 -1 3 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 5 0 -1 none 1' _stat='23 -1 -1 5 0 -1 none 1'
      | _tail_syntax_stat[i-i2]='13 -1 -1 -1 0 -1 none 1' _stat='13 -1 -1 -1 0 -1 none 1'

    * 分からないのでもっと詳しく。うーん。不思議だ。_tail_syntax_* は一致しているが、
      ble/syntax/parse/nest-equals の結果が異なっている。
      という事は比較する瞬間の _ble_syntax_* が異なっているという事だろうか。

      | _tail_syntax_stat=('17 -1 -1 -1 0 -1 none 1' '' '' '23 -1 -1 1 -1 -1 none 1'
      |   '5 -1 -1 1 -1 -1 none 1' '' '5 -1 -1 3 -1 -1 none 1' '23 -1 -1 5 0 -1 none 1'
      |   '13 -1 -1 -1 0 -1 none 1' '1 -1 -1 -1 1 -1 none 1' '1 -1 -1 -1 2 -1 none 1'
      |   '43 -1 -1 -1 0 -1 none 1')
      | _tail_syntax_tree=('' '' '' '' '' '' '24 4 0 -1 d nnone 4 -1 -1 -'
      |   '7 8 0 8 - nnone 6 1 -1 -' '' '' '2 1 -1 3 d')
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _tail_syntax_attr=('7' '8' '12' '9' '14' '7' '9' '12' '12' '1' '119')
      | _tail_syntax_stat[i-i2]='17 -1 -1 -1 0 -1 none 1' _stat='1 -1 -1 -1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 1 -1 -1 none 1' _stat='23 -1 -1 1 -1 -1 none 1'
      | inest='2' ext='1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 1 -1 -1 none 1' _stat='5 -1 -1 1 -1 -1 none 1'
      | inest='3' ext='0'
      |
      | _tail_syntax_stat=('17 -1 -1 -1 0 -1 none 1' '' '' '23 -1 -1 1 -1 -1 none 1'
      |   '5 -1 -1 1 -1 -1 none 1' '' '5 -1 -1 3 -1 -1 none 1' '23 -1 -1 5 0 -1 none 1'
      |   '13 -1 -1 -1 0 -1 none 1' '1 -1 -1 -1 1 -1 none 1' '1 -1 -1 -1 2 -1 none 1'
      |   '43 -1 -1 -1 0 -1 none 1')
      | _tail_syntax_tree=('' '' '' '' '' '' '24 4 0 -1 d nnone 4 -1 -1 -'
      |   '7 8 0 8 - nnone 6 1 -1 -' '' '' '2 1 -1 3 d')
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _tail_syntax_attr=('7' '8' '12' '9' '14' '7' '9' '12' '12' '1' '119')
      | _tail_syntax_stat[i-i2]='17 -1 -1 -1 0 -1 none 1' _stat='1 -1 -1 -1 -1 -1 none 1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 1 -1 -1 none 1' _stat='23 -1 -1 1 -1 -1 none 1'
      | inest='2' ext='1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 1 -1 -1 none 1' _stat='5 -1 -1 1 -1 -1 none 1'
      | inest='3' ext='1'
      | _tail_syntax_stat[i-i2]='5 -1 -1 3 -1 -1 none 1' _stat='5 -1 -1 3 -1 -1 none 1'
      | inest='3' ext='1'
      | _tail_syntax_stat[i-i2]='23 -1 -1 5 0 -1 none 1' _stat='23 -1 -1 5 0 -1 none 1'
      | inest='2' ext='1'
      | _tail_syntax_stat[i-i2]='13 -1 -1 -1 0 -1 none 1' _stat='13 -1 -1 -1 0 -1 none 1'
      | inest='-1' ext='0'
      |
      | --- a1.txt^I2020-01-06 18:58:23.708919459 +0800
      | +++ a2.txt^I2020-01-06 18:58:14.185056620 +0800
      | @@ -10,4 +10,10 @@
      |          _tail_syntax_stat[i-i2]='23 -1 -1 1 -1 -1 none 1' _stat='23 -1 -1 1 -1 -1 none 1'
      |          inest='2' ext='1'
      |          _tail_syntax_stat[i-i2]='5 -1 -1 1 -1 -1 none 1' _stat='5 -1 -1 1 -1 -1 none 1'
      | -        inest='3' ext='0'
      | +        inest='3' ext='1'
      | +        _tail_syntax_stat[i-i2]='5 -1 -1 3 -1 -1 none 1' _stat='5 -1 -1 3 -1 -1 none 1'
      | +        inest='3' ext='1'
      | +        _tail_syntax_stat[i-i2]='23 -1 -1 5 0 -1 none 1' _stat='23 -1 -1 5 0 -1 none 1'
      | +        inest='2' ext='1'
      | +        _tail_syntax_stat[i-i2]='13 -1 -1 -1 0 -1 none 1' _stat='13 -1 -1 -1 0 -1 none 1'
      | +        inest='-1' ext='0'

    * ble/syntax/parse/nest-equals を呼び出した時の _ble_syntax_nest, _tail_syntax_nest を比較する

      | inest='2' ext='1'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '' '' '' '' '' '' '' '')
      | inest='3' ext='0'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      |
      | inest='2' ext='1'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '' '' '' '' '' '' '' '')
      | inest='3' ext='1'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | inest='3' ext='1'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | inest='2' ext='1'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | inest='-1' ext='0'
      | _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      | _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      |
      | --- a1.txt^I2020-01-06 19:04:07.351970453 +0800
      | +++ a2.txt^I2020-01-06 19:06:12.204172380 +0800
      | @@ -1,6 +1,6 @@
      |  inest='2' ext='1'
      |  _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      |  _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '' '' '' '' '' '' '' '')
      | -inest='3' ext='0'
      | +inest='3' ext='1'
      |  _tail_syntax_nest=('' '' '11 2 7 -1 -1 2 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')
      |  _ble_syntax_nest=('' '' '11 2 7 -1 -1 -1 none none' '24 0 24 1 -1 -1 none none' '' '' '' '' '' '' '')

      うーん。何と状態は完全に同じなのに違う結果を返している?

    * ble/syntax/parse/nest-equals の中の動作について詳しく追う。

      | parent_inest='2' i1='0' i2='0'
      | parent_inest='2' _onest='11 2 7 -1 -1 2 none none' _nnest='11 2 7 -1 -1 -1 none none'
      | parent_inest='3' i1='0' i2='0'
      | parent_inest='3' _onest='24 0 24 1 -1 -1 none none' _nnest='24 0 24 1 -1 -1 none none'
      | onest=('24' '0' '24' '1' '-1' '-1' 'none' 'none')
      | parent_inest='0' _onest='' _nnest=''
      | onest=()
      |
      | parent_inest='2' i1='0' i2='0'
      | parent_inest='2' _onest='11 2 7 -1 -1 2 none none' _nnest='11 2 7 -1 -1 -1 none none'
      | parent_inest='3' i1='0' i2='0'
      | parent_inest='3' _onest='24 0 24 1 -1 -1 none none' _nnest='24 0 24 1 -1 -1 none none'
      | onest=('24' '0' '24' '1' '-1' '-1' 'none' 'none')
      | parent_inest='2' _onest='11 2 7 -1 -1 2 none none' _nnest='11 2 7 -1 -1 -1 none none'
      | parent_inest='3' i1='0' i2='0'
      | parent_inest='3' _onest='24 0 24 1 -1 -1 none none' _nnest='24 0 24 1 -1 -1 none none'
      | onest=('24' '0' '24' '1' '-1' '-1' 'none' 'none')
      | parent_inest='2' _onest='11 2 7 -1 -1 2 none none' _nnest='11 2 7 -1 -1 -1 none none'
      | parent_inest='2' i1='0' i2='0'
      | parent_inest='2' _onest='11 2 7 -1 -1 2 none none' _nnest='11 2 7 -1 -1 -1 none none'
      | parent_inest='-1' i1='0' i2='0'

      parent_inest の更新に失敗している様だ。

    とここで分かった。算術式のバグを踏んでいる。修正した。問題は発生しなくなった。

  * 今度は Bash 3.2 で ble-reload の後に core-*.sh が読み込まれない問題が発生している [#D1200]
    bash-3.2: ble/complete/sabbrev/expand: No such file or directory 等と言っている。

    振る舞いを調べると新しく load するとこれらの関数は delayed load の関数に置き換わり、
    delayed load の関数では最初に自身を unset してから ble/util/import して、
    その後に再実行するという作戦を取っている。
    この unset によって関数が削除されてそのまま実行できない状態になるという事だろう。

    そして ble/util/import が再実行できない様になっている。うーん。
    つまり以前の読み込み済みのマーカーを削除できていない。

    と思ったら bash 3.2 では BASHPID が存在していない?

    どうやってサブシェルかどうかを判定すれば良いだろうか。
    $SHLVL はサブシェルでは更新されていなかった。
    $PPID もサブシェルでは更新されていなかった。
    Linux ならば /proc/self を readlink すれば良い?
    と思ったが実はこれだと readlink の pid が得られるだけだった。

    検索したら質問があって其処で sh -c 'echo $PPID' というのが紹介されていた。
    更にその下で紹介されていたのは BASH_SUBSHELL という変数だった。
    https://unix.stackexchange.com/questions/524506/how-can-i-detect-if-im-in-a-subshell

    調べてみると BASH_SUBSHELL は 3.0 で導入されたが、
    4.4 未満では echo $BASH_SUBSHELL | cat や <(echo $BASH_SUBSHELL)
    ではこの値が inc されないという問題があったそうだ。
    なので現在 subshell にいるかどうかの判定に使うのには信頼性が低い。

    * done: 0.1, 0.2 にも同様の修正を適用する

  * ble-0.3 で ble-reload の hang は直っていない様だ… [#D1199]
    前に修正した時の物と同じ物だろうか。
    一応 ble-0.3 にも同じ patch を適用しているが修正しきれていないという事になるか。
    関連する前の修正はこれである: #D1130 d35682a caa46c2
    #D1130 の記録を見てみたがよく分からない。余り参考にならなさそう。

    * fixed: 一応 ble/base/unload-for-reload を実行した時の症状は似ているのではないか。

      仕方がないのでこれは一つずつ確かめていく必要がある。
      先ず処理の流れを確かめる。

      ble/base/unload-for-reload で _ble_edit_detach_flag=reload が設定される。
      ble-edit/exec:gexec/.end で .check-detach が呼び出されて、
        更にその中で _ble_edit_detach_flag=reload の時には
        メッセージが出力されて ble-edit/exec:gexec/.eval-prologue が呼びされる。
        何故ここで eval-prologue なのだろうか。PS1 等を復元する為?
      更に .end の中で通常ならば ble/term/enter,
        ble-edit/bind/.tail が呼びされる所、
        何も呼び出されずに終了する事になる。
      .end は最後に実行されるコマンドである。

      さて、この時にどの様な状態になるのかというのが問題である。
      特に .tail が呼び出されないという事は出力がそのまま端末に繋がった儘という事。
      それは寧ろ期待している事なのではあるまいか。
      ble/term/enter が呼び出されないという事は
      端末の状態も通常のコマンドを実行しているのと同じという事。

      では何故コマンドの入力が効かないのか。
      というか ble-decode/detach 等はしなくても良いのだろうか。
      うーん。ble-edit/detach, ble-decode/detach の療法を実行している。

      うーん。どのコマンドを入力しても
      bash: self-insert: コマンドが見つかりません
      bash: accept-line: コマンドが見つかりません
      という状態になってしまっている。これはどういう事なのか。
      そもそも self-insert, accept-line をコマンドとして実行しようとする文脈が分からない。
      更にあらゆる入力が self-insert 及び accept-line しか呼び出さない状態になっている。
      →何と bind -x '"...":self-insert' で復元されている? 様な気がする。変だ。

      less "$_ble_base_run/$$.bind.save" で復元用のスクリプトを見ると全てに -x がついている。
      うーん。分かった。ble/bin/echo が定義されていないのに ble/bin/echo を使う様に
      patch が追加されたのがいけなかった。これでエラーが発生して、
      __BINDP__ というマーカが出力されない事によって復元用の全ての bind が -x になってしまっていた。
      これについて修正した所 ble/base/unload-for-reload に関しては動く様になった。

    * fixed: 然し、ble-reload で固まってしまう問題に関しては全く直っていない。
      うーん。どうも bind できていないという気がする。
      やはりだ。ble.sh を読み込んだ時に ble-decode/bind が呼び出される。
      ble-reload を呼び出した時に ble-decode/unbind だけが呼び出されて、
      ble-decode/bind が呼び出されていない。

      実際に ble-0.4 の場合にはちゃんと ble-decode/bind が呼び出されている。
      この違いは何処から出てくるのだろうか。
      ble-0.4 で ble-reload で再 attach が呼び出される経路を見ると。
      どうも最後に描画状態を更新する時にプロンプトの再計算があって、
      其処で attach される様だ。

      stackdump:
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:17 (ble-stackdump)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:38 (ble/decode/attach)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:10 (ble-attach)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble/base/attach-from-PROMPT_COMMAND)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:13 (ble-edit/prompt/update/.eval-prompt_command)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:46 (ble-edit/prompt/update)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble/textarea#render)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:15 (ble-edit/bind/.tail)
        @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7 (ble-edit/exec:gexec/.end)

      素早く入力しても起こる事は変わらない様子だ。
      では ble-0.3 の場合には何が起こっているのだろうか。
      というか ble-edit/bind/.tail は呼び出されているのだろうか?

      うーん。そもそも何故 .tail が呼び出されているのかというのが謎である。
      うーん。ble-0.4 では普通に .check-detach を通過している。
      調べてみると ble-0.3 の reload でも普通に .check-detach を通過している。

      どうも reload した時にどの戦略を取るのかというのが違っている様子である。
      うーん。prompt 経由で attach する戦略を既定にしたら動く様になるのだろうか?
      →動くようになった。既に PROMPT_COMMAND が設定されている場合でも動くだろうか。
      →動く。OK

  * util: Bash-3.2 で bash-preexec.sh と一緒に使うと初回コマンド実行時にエラーメッセージ (reported by dylankb) [#D1198]
    https://github.com/akinomyoga/ble.sh/issues/33#issuecomment-570949575

    $ echo hello
    bash-3.2: read: ` prompt_command_array': not a valid identifier
    hello

    prompt_command_array の read に失敗している。
    うーん。prompt_command_array なる変数は ble.sh では使っていない。
    調べてみると bash-preexec.sh にその様な変数が存在している様だ。
    正に以下の行が問題を起こしている事を示唆している。
    IFS=';' read -ra prompt_command_array <<< "$PROMPT_COMMAND"

    * bash-preexec.sh を一緒にロードするとどうなるかテストする。

      https://github.com/rcaloras/bash-preexec
      git@github.com:rcaloras/bash-preexec.git

      エラーメッセージが再現した!
      然しその他のエラーは再現していない。
      つまりこれは独立した問題なのだろうという気がする。

    症状を見ると bash-3.2 では起こるが bash-5 では起こらない。
    bash-4.0 でも起こらない。bash-3.1 で起こる。
    bash-3.0 ではそもそも bash-preexec.sh が文法エラー。

    ble-0.4 でも同様の症状が発生する。

    x 実はそれとは別に trap コマンドの引数の解析が誤っている。
      というのも invalid signal spec "-" というエラーメッセージが表示される。
      これについては bash の仕様を改めて調べる必要がある。

    取り敢えず先に ` prompt_command_array' の方を片付ける事にする。
    うーん。どうも変だ。あー。分かった。これは引数解析のバグだ。
    と思ったが ble/array#push が悪いという事の気がする。
    IFS を設定すると動かなくなるという事が確認できた。
    $ array=(1); ble/array#push array 1 3; declare -p array
    $ array=(1); IFS=\; ble/array#push array 1 3; declare -p array
    うーん。然し実装を見てみると eval "$1+=(\"\${@:2}\")" である。
    これは bash 3.2 のバグである?

    うーん。然し普通に hello+=("$@") を実行しても問題は発生していない。
    どうやら hello+=("${@:1}") の形式を使うと駄目な様だ。
    (IFS=\;; function a { printf '(%s)' "${@:1}"; }; a 1 2 3)
    これでも "${@:1}" の形式では引数がくっついてしまう。

2020-01-05

  * main: 複数の ble.sh の version を使っている時に cache が混ざるのでは? [#D1197]
    cache 全般の問題として
    複数の ble.sh version を混ぜて使っていると駄目なのでは。
    cache ファイルが ble.sh 本体と比べて新しいかどうかで判定しているが、
    複数の ble.sh を混ぜて使っているとその関係が反転したりする。
    従って更新されないという事が普通に起こる気がする。

    これに対応する為には cache ディレクトリ自体に ble.sh version を入れるか、
    或いは cache ファイルのそれぞれに ble.sh version を入れるかする必要がある。
    うーん。cache ディレクトリに ble.sh version を入れる事にする。
    適当に ${BLE_VERSION%%[-+]*} でも加えたら良いのでは。
    →patch level で形式が変わる可能性は低いし、
      異なる patch level を複数使い分ける事も考えにくい。
      major.minor だけで充分の気がする。

  * ble-update は shallow clone で良い気がする [#D1196]
    ただ、これを今更変更しても 0.3.0 には反映されないのでは。
    と思ったがこれも fix として投入してしまえば問題ない。

  * decode: "Failed to load the default keymap" で失敗した時に状態復元できていない (reported by dylankb) [#D1195]
    https://github.com/akinomyoga/ble.sh/issues/33
    これも上の報告のエラーメッセージの後に変な状態になっている様子から気づいた。

    ? Failed to で失敗した時に stty を復元するべきでは?
      調べてみると復元している気がする。
      と思ったが stty/finalize を呼び出していて、ここでは stty -echo にしている。
      何故だろう? と思って遡って見るがどうも最初に stty/finalize を作成した時 (2015-02-11)
      からずっと stty -echo だった様である。今と昔では detach の方法が違うので、
      実はこれについては変更しても良いのではないかという気がする。後で考察する必要がある。

      * done: これについて整理する。stty/finalize は ble/term/finalize から呼び出されている。
        ble/term/finalize は ble-detach/impl (ble.pp) と ble-attach 失敗時 (ble.pp)
        ble-decode/detach (decode.sh) 内部で呼び出されている。
        - ble-attach 失敗時には直前に ble-decode/detach が呼び出されている事が期待できる。
        - ble-detach/impl の場合にはやはり ble-decode/detach が直前で呼び出されている。
        - ble-decode/detach が呼び出されるのは上記の二箇所以外に
          set -o vi|emacs によって編集モードが変わった時の reattach の時である。

        うーん。ble/term/finalize は ble-decode/detach
        の中で呼び出されるという事にして問題ない気がする。
        というのも attach の場合には ble/decode/attach で
        ble/term/initialize を呼び出しているからである。

        無駄な呼び出しを削除した。確認してみると ble/term/{initialize,finalize}
        共に一箇所だけから呼び出される様になった。前よりもすっきりしたと思う。

      さて、ble/term/finalize 引いては ble/term/stty/finalize も一箇所だけから呼び出される。
      この時に stty echo でも問題が生じないかについて調べる。
      取り敢えず問題は発生していない気がする。ble-detach では大丈夫。
      人為的に Failed to load the default keymap を起こした時も大丈夫。

  * util: macOS での初期化時に bash-3.2 で "usage: sleep seconds" のエラーメッセージが出る (reporeted by dylankb) [#D1194]
    https://github.com/akinomyoga/ble.sh/issues/33
    これは上の報告のエラーメッセージを見ている時に気づいた。

    ? sleep の引数がどうのこうのというエラーが出てもいる。関係は?
      →これはまた別の問題だった。というか sleep の小数対応判定が完全に間違っていた。
      coreutils sleep であっても false になってしまっていた。
      また macOS の場合には sleep は期待した物であると考えて良さそう。
      なので macOS のチェックと "usage: sleep seconds" が両方表示されたら OK という事にする。

2020-01-02

  * 2019-05-27 history: 履歴のリアルタイム同期? [#D1193]
    現在は新しくコマンドを実行した時にだけ同期を行っている。
    履歴を参照する度に毎回同期を行う様にしたい。

    更新のタイミングに関して。
    一回の widget の実行の中で読み込みを何度も実行すると、
    途中で get-index 等の値が勝手に変化したりする事になって混乱の元である。
    という事を考えると widget 毎に初回の history access の時にだけ更新するのが良い。
    widget を呼び出す時にローカル変数か何かを設定しておいてそれをクリアする様にする。
    初回の history アクセスの際にそのローカル変数が空だったら値を設定して更新を行う。
    更新は、もし履歴が初期化済みだったら増えた分だけ配列に追加するというのを実行する。

    vim の mark 等で現在履歴項目に対して記録してある内容は shift する必要がある。
    他に現在の履歴項目関連で修正しなければならない物は何があるだろうか。
    例えば isearch の位置に関しては修正が必要になるのではないか。
    isearch の範囲に関しても修正が必要になる気がする。
    これらは以前まとめた history コマンドの対応の項目とも関連してくる。
    実のところそちらを先に実装してからの方が良いのかもしれない。
    - history: _ble_edit_history_ind の修正などが必要
    - ble-edit/undo: hindex の修正などが必要

    同期のタイミングは難しい。
    例えば履歴を遡っている時に編集中の最新のコマンドはどうなるのか。
    最新のコマンドは _ble_edit_history_edit[N] に記録されている。
    この時新しいコマンドを読み取ってしまうと最新のコマンドは上書きされてしまう。
    vi.sh の mark や undo 等も同様である。
    最新の内容は新しいコマンドを読み取る前に待避して置かなければならない。

    * 2020-01-02 これに関しては一番下の項目にいる時にだけ同期を実行する事にすれば良いのでは。
      % 或いは一番下の項目にいて更に下キーを押した時に限り自動ロードを試みる事にする。
      % →と思ったが現在の編集行の後に新しく履歴が追加されるのが自然なのか、
      % 或いは現在の編集業の前に新しく履歴が追加されるのが自然なのかは難しい。
      % その様に考えるとやはりコマンドを実行した時など履歴に登録がなされて
      % 新しい行がロードされる機会に更新が行われる方が動作として分かりやすい。
      % →やはり新しい履歴は現在の編集行の前に挿入されるべきである。
      % そうしないと履歴の順序などが変な事になってしまう。

      逆に一番下の項目から遡ろうとする時に同期を実行するという手?
      或いは一番下の行に戻ってきた瞬間に同期を実行する。
      その様にするのが現在の所一番自然な気がする。

    そもそも勝手に読み込みが為されるのが分かりやすいのかどうかというのもある。
    他の端末で大量にコマンドを実行した時に、
    現在の編集中のコマンド履歴が遠くなってしまうのは分かりにくくないか。
    しかし、それはそもそもコマンド履歴の共有をする時の分かりにくさでもある。
    コマンド履歴の共有を行っているのであれば実は大量のコマンドがあっても
    それを共有するというのが自然な振る舞いなのではないだろうか。

    [実装]

    取り敢えず一番下の履歴項目への(または、からの)移動の時に
    履歴の読み込みを試みる方向での実装を考える事にする。

    一番下の履歴項目に関連して何か登録してある物があれば
    それを更新する必要がある。然し、それはコマンド履歴を登録せずに
    新しい行をロードする時にも同じ事なのではないか。
    つまり現状の実装で大丈夫ならば一番下の履歴項目に関連して
    ロードしている限りに於いては問題は起こらないのではないかという気がする。

    * 自動読み込みによってプロンプト (\!) は変更されるか?
      所で履歴項目の番号がプロンプトに表示されるのだとすれば、
      それが読み込みの瞬間に変化するというのは見られるのかもしれない。
      と思って確かめたが履歴項目の番号に展開される backslash はなかった。
      と思ったが違った \! というのがそれに対応するのだった。
      然し、途中で履歴項目の番号が変化したとしても prompt の更新は
        local version=$COLUMNS:$_ble_edit_lineno
      で判定しているので更新はその場ではかからないのである。
      →変更されない。これはややこしい。
        或いは読み込みがあった時には強制的に _ble_edit_lineno
        を更新しても良いのかもしれないが。うーん。でもそれはそれで変だ。
        _ble_edit_lineno は独立した意味を持っている。
      然し実行した後で履歴展開を使用したい場合を考えると、
      其処に表示されている番号は当然正しい番号であって欲しい。

    取り敢えず現在の実装を確認する事にする。
    history_share がある時には option:n を呼び出していて、
    更に ble/builtin/history/.read が呼び出されている。
    この中で新しい項目の読み込みを行っている。
    - 更に呼び出している ble/history:bash/resolve-multiline/readfile
      を確認してみたがこれは違う。bash の history に対する修正を行っているのみである。
    - ble/builtin/history/.read を確認すると ble/history:bash/load を呼び出していて、
      これが丁度 background で while case (0)...(6) をやっている関数である。
      中を確認するとここで mapfile で履歴を読み取ると共に
      複数行履歴の解決も実行している。
    何を確認するのだったか。どのように更新されるのかを確認するのだった。
    更新されるのは _ble_history 及び _ble_history_edit である。
    従って現在編集中の行が存在する場合には _ble_history_edit の内容は待避する必要がある。
    確認する事にする。というか undo 履歴などもある筈である。全て shift する必要があるのでは。

    blehook の history_delete, history_clear に対応して
    逆に history_insert 的な操作を実装する必要がある気がする。

    * undo 情報は何処で clear されているのか?
      というか空の行で実行した時に undo 履歴が clear されないのでは??
      と思って確認してみたら clear されていた。どうなっている?
        空の行を実行すると .newline が呼び出される。
        中では ble/history/onleave.fire
        ble/widget/.newline/clear-content が呼び出されている。
        - clear-content の方は何も実行していない。
        - onleave.fire の方は history_onleave を invoke している。
          然し history_onleave に登録されているのは
          ble/keymap:vi/mark/history-onleave.hook だけである。

      どうも変だと思って再度確認した所、
      実は undo 情報は clear されていなかった。
      空行で実行した後も undo 履歴は残っているのだった。
      これはこれで妥当な振る舞いの様な気がする。

    取り敢えず謎は解けた。history_insert でも対応する事にするのが良さそう。
    option:n の読み取りに於いて history_insert が呼び出される様に実装した。
    取り敢えず history_share で option:n を呼び出す様にする。

    [テスト]

    一応動作はしている様子であるが変な事がある。

    x fixed: 何故かロードが起こると bell が鳴る
      まあ n 件履歴項目が更新されましたなどと表示できるならばそれはそれで便利かもしれない。
      どうも option:n の中で発生している気がする。

      調べてみるとどうも ble/widget/.bell が直接 ble-edit/history/goto の中から呼び出されている。
      あー。これはどうも分かった。option:n の中で更に history/goto が呼び出されている。
      内部では get-count が未だ更新されていない状態なので変な事になる。
      と思ったがどの経由で呼び出されているのかが分からない。
      history.sh では少なくとも直接は呼び出していない。

      うーん。どうも ble-edit/history/history-insert.hook である。
      blehook/invoke history_insert の前に count を更新するのが良いだろうか。
      →_ble_history_count を更新してから invoke history_insert する様に変更した。

      x fixed: 同時に二重に呼び出された時の振る舞いについて考えて置かなければならない。
        ちゃんと関数を呼び出し直す等の対策が必要になるのではないだろうか。
        →改めて goto を呼び出し直す事にした。
      x fixed: と思ったら無限ループになってクラッシュした。
        修正した。読み込みが起こった時にだけ goto (2回目) を呼び出す様にした。

      x fixed: 未だ bell が鳴る。詳細を調べてみる。分かった。そもそも行き先の index の値が変だ。
        何故この様な結果になるのだろうか。。。

        分かった。ble-edit/history/history-insert.hook の中で履歴項目を移動しているが、
        実は history.sh の側で既に履歴項目を移動しているのである。
        うーん。これによる移動をどうやって処理するのが正しいのか。。

        調べると _ble_history_ind は edit.sh 側では一切触っていない。
        従ってこれの移動に関しては history.sh に任せるべきなのでは。
        これの移動に伴って edit.sh 側でしておかなければならない処理はあっただろうか。
        つまり単に移動するだけではなくて goto を呼び出す必要があった理由は何だろうか。

        確かめてみると _ble_history_ind はちゃんと history.sh の側で更新されている。
        つまり今まで二重更新になっていた。
        うーん。goto を呼び出す事によって ind, mark が更新されるという事はある様だ。
        然しそれ以外の事に関しては何もない。そして ind,mark が勝手に更新されるというのも変な話だ。
        つまり単純に処理をしないというのが自然な実装である。単に hook を削除する事にした。

    x fixed: 何故か PS1 が更新されない。PS1 の更新は試みられないのだったか?

      どうやら内部的にはちゃんと prompt は変化している様子である。
      単に出力されていない。prompt の更新だけ簡単にできないかと思ったが
      色々と複雑そうだ。更に、prompt の変化があったかどうかも判定しなければならないが、
      rps だとか色々ある。仕方がないので invalidate を直接呼び出す事にした。

    x fixed: うーん。検索中にキャンセルして現在編集位置に戻って来た時にロードが起こったりすると面倒。
      という事を考えると特別な keymap の時にはやはり history_share は off にするべきなのでは。

      keymap を検索して isearch の時には読み込みを抑制する事にした。
      一方で nsearch や lastarg は history/goto を呼び出す事はないので
      そもそも history/goto に入ってくる事はないのでチェックしなくて良い。

2020-01-01

  * history: history コマンドが --help に対応していない [#D1192]
    x 'unknown option "-$c"' という文字列が出力される。

  * shopt -s xpg_echo の時変な事になるのではないか [#D1191]
    現在様々の出力を ble/bin/echo を通して行っているが、
    ble/bin/echo は builtin echo を使っていて、
    builtin echo は xpg_echo の影響を受けてエスケープシーケンスを解釈する様になる。
    これは予期せぬ振る舞いの原因になる。

    printf で実装したいが完全なる echo の代替実装は難しい。
    先ず echo -n とそれ以外の echo で分ける必要がある。
    また複数の引数が指定されている時にどうするか?
    と思ったが複数の引数が指定されている場合は単に "$*" とすれば良いのだ。

    ble/bin/echo 自体の関数名についての議論は #D1035 で行われている。
    この記録を見ると ble/bin/echo という関数名は取り敢えずの物の様だ。
    また関数名が速度に影響するとは言っても微々たる物なのでそんなに気にしなくて良い。
    echo という関数名を保持したのは -n という引数を解釈していたからである。
    今内部実装を printf に切り替えるとしたら -n という引数は使えない。
    ややこしいので別の関数名にするべきである。

    以下の二種類の関数にする事にした。
    ble/util/print (改行を出力する)
    ble/util/put   (改行を出力しない)

  * ble.sh はプロンプトやエイリアスの設定を提供する物ではなくて [#D1190]
    基盤の枠組みを提供する物であるという旨を何処かに書いておくと良いかもしれない。
    つまり他の bash-it や oh-my-bash と併用する事もできるのだという事。

    ただ、bash-it や oh-my-bash がそんなに便利で凄いかというと微妙。
    結局プロンプトを提供しているだけなのではないかという気がする。

  * edit: support "shopt promptvars" [#D1189]
    この設定が存在している事に気づいていなかった。
    この設定が unset 状態にある時 PS1 の展開に於いて
    パラメータ展開、コマンド置換、算術式展開、クォート削除が実行されないそうだ。
    現在の実装について確認する。クォート削除が実行されないとすると、
    このクォート削除を想定としたクォートは必要ないという事になる。
    振る舞いについて確認する必要がある。

    →うーん。やはり試してみた所 $ や ` が \ された形で埋め込まれてしまう。
    うーん。適当に対応した。promptvars が設定されていない場合には
    $`"\ の escape は実行しない様に変更した。多分これでちゃんと動いている。

  * color: face の定義で ref を設定しても良いのではないか [#D1188]
    算術式なので簡単に実現できる気がするが技術的にはどうだろう。
    →調べてみると face に対応する sgr はキャッシュされている。
    _ble_faces_sgr という配列に格納されている。
    然し、この配列を触っている箇所は少ないので
    実はそんなに問題ではないかもしれない。

    更に実はこのキャッシュは殆ど使われていないのではないか。
    syntax は ble/syntax/attr2g で直接 g 値を得ている。
    _ble_faces_sgr を使っているのは iface2sgr 及び face2sgr だけである。
    調べてみると iface2sgr は ble/color/list-faces しか使っていない。
    と思ったが face2sgr の方は結構使われている。
    - core-syntax は ble/syntax/print-status/ctx の中からしか使っていない。
      debug 用の関数なので速度に関しては実はそんなに気にしなくて良いのでは。
    - color.sh は ble/highlight/layer:{region,disabled}/update で使っている。
    - util.sh は bleopt, blehook の現在の状態の表示に使っている。
      他に ble/term/visible-bell の表示色の決定に使っている。
    やはり余り速度が重要になりそうな場面では使っていない。
    実装を g 値 → sgr という様にその場で変換する様に書き換えて問題ない気がする。
    或いは遅ければ別の枠組みを整えれば良いのである。
    或いは ref の時だけは空欄にしておいて空欄の時は毎回生成するという仕組みにする?
    →面倒なので何も考えずに毎回生成で良い気がする。

    仕様について考える事にする。今までの face:... iface:... の意味を変える?
    もしくは新しく faceref:... の様な定義方法を使う?

    恐らく使っている人は皆無である。従って問題にはならない。
    もし使っている人がいたとして循環する様な定義にしていたとしても、
    Bash 算術式には上限があるので意図的に回避しない限りは無限ループになる事はない。

    従って意味を変える事にする。設定のコピーもできる様にしておく。

    * done: _ble_faces_sgr を使わずにその場で g2sgr を呼び出す様に変更

    * done: ble/color/{i,}face2{g,sgr} の戻り値を g, sgr に格納しているが
      この仕様は他の類似の関数と異なっている。
      これを ret を返す様に変更してはどうか。
      g や sgr に代入する関数は getg や get-sgr 的な
      関数名であるべきである。

      他に g や sgr を直接に返す仕様の関数は存在しただろうか。

    * done: setface の face:... iface:... の意味を変更する
      と思ったが ref:... copy:... に変更する事にした。
      そして face:... iface:... は廃止する事にした。obsolete
      取り敢えずサポートは続けるが警告を出す。

    * done: wiki に説明は書いた


2019-12-31

  * complete: alias についても展開後のコマンド名を元にして [#D1187]
    補完関数を見つけに行っても良いのではないだろうか。

    と思ったが mshex で定義されている alias の場合は微妙かもしれない。
    d や v や *:date や *:view に展開されるが、だからと言って
    date や view コマンドと同様に使うことができるかというと微妙。
    一応 g や m は git や make として使う事もできるので使っても良い。
    これに関しては mshex の側で良い様に取り扱えば良い。
    一部のコマンドだけ mshex/alias/git の様な関数名にするのも
    変だし mshex/alias:git に対する補完設定を登録するのが自然な気がする。
    その時には他のコマンドの設定を参照するという設定を行いたい。

    * done: 他のコマンドの設定を参照するという設定

      | a complete -F として空白を含む物も指定できるという事を悪用すれば、
      |   complete -F "dummy --import git" g 的な記述もできる。
      |   そうすると実際に読み取る際には complete -F dummy --import git g になる。
      |   然し、この方法は危ない。将来的に空白を含む関数名を指定できなくなるかもしれない。
      |   それに ble.sh を load していない時には全く使えない設定になってしまう。
      |
      | b しかしだからと言って complete -F --import:git g 等とすると
      |   今度は原理的な問題として --import:git という名前の関数と区別がつかない。
      |   またその様な関数が定義されていなかったとしても、
      |   ble.sh を load していない時にはエラーメッセージの元になる。
      |
      | c 或いは complete -F ... -- '--special g' という感じに登録する?
      |   これはスペースを含む様なコマンドが存在しない事から、紛らわしい事はない。
      |   問題はスペースを含む様なコマンド名が将来的に禁止されるかもしれないという事。
      |
      |   やはり complete を使って無理やり登録するというのは違う気がする。
      |
      | d ble.sh の補完関数の仕組みから progcomp を呼び出せる様にする?
      |   これが妥当な気がする。というより何故今までこれができなかったのだろう。
      |   構造を確認する事にする。
      |
      |   どうも ble/complete/source:command/.progcomp を呼び出すだけの様だ。
      |   但し、指定したコマンド名に対応する規則で補完する為には
      |   comp_words, comp_line, comp_point を書き換えなければならない。
      |   うーん。或いは、規則を検索するのに使うコマンド名だけ変えれば良い?
      |
      | これは d で実装する事にする。
      | progcomp の第二引数にコマンド名を指定する事にした。

      →最終的な仕様は ble/complete/progcomp git 等の様にして関数を呼び出す事とした。

      g に関しては単純に以下の様な関数を定義すれば良い気がする。
      function ble/cmdinfo/complete:g {  ble/complete/source:argument/progcomp '' git; }
      実際に試してみたが動かない。うーん。分かった。
      補完設定は遅延ロードになっていてその遅延ロードに使うコマンド名は
      comp_words から拾っている。従って comp_words を弄らなければ動かないのである…。

      →結局 comp_words, comp_line, comp_point を再構築する事にした。
      動く様になった。これに関してはこれで良いという事にする。

    alias に関してはどの様にするのが良いだろうか。
    complete で見つからなかったとしても complete -D による
    completion loader で実際には定義が見つかる可能性もある。
    然し completion loader まで行ってしまうと _minimal 等になってしまう。
    つまり本来は completion loader まで行ってその中で見つからなかった時に
    alias による展開結果に対して補完を試みるという様にしたいのである。
    然し、ble.sh の枠組みの中からではそれを検出するのは難しい。

    うーん。或いは。complete -D に行く前に既に定義済みの物がないか確認する。
    というのの方が自然ではないか。こうするとその alias 専用の
    completion loader による遅延補完設定があった時にそれが使われなくなってしまうが、
    まあ alias に対して補完設定があるとも思えないのでそれで良いだろうか。
    うーん。然し本当だろうか。alias diff='colored diff' みたい
    になっていて colored 及び diff に対する遅延補完設定が存在していると、
    diff に対する補完設定は永久に呼び出されない。常に colored になってしまう。
    唯、この場合には colored が diff の補完設定を呼び出すべきではないか?
    と思ったがそれを実行させる為には comp_line の構築で colored diff の
    diff の部分も含める様にしなければならない。しかし、その様にすると
    実際には文法的にどの様な構造が入ってくるか分からないので、
    再度単語などの解析を実行しなければならない状況になる。面倒である。

    * done: 取り敢えず実装した。遅延ロードとの関係については気にしない事にする。

    * done: 或いは解決の際に勝手に __load_completion を呼び出しても良いのではないだろうか。

    * done: alias で展開した時に増えた引数も comp_line の復元に入れるべきなのではないだろうか。
      →入れる事にする。但しその時に comp_cword の書き換えも実行しなければならない。
      テストしてみる事にする。

    * done: 補完設定の検索は ble/cmdinfo も一緒に行うべき。
      alias の展開による補完関数の呼び出しが動いていない。
      と思ったら分かった…。g は ble/cmdinfo 経由で補完しているので
      補完設定が見つからないのだった。つまり補完設定の検索は外側の枠組みで実行するべきという事では。
      一つ外側の枠組みで補完設定を検索する事にした。
      ユーザが呼び出す ble/complete/progcomp という関数は、
      ble/cmdinfo/complete:cmd と complete -p cmd の両方を参照して補完を実行する。

2019-12-30

  * 2019-11-23 complete: comps_flags の b と B が重複している [#D1186]
    nocaseglob の時に動かなくなるという旨がコメントで説明されているのにも
    関わらずその直上で b と B に別々の意味を割り当てているのである。
    これは simple-word の時点で重複した定義になっている事に注意する。

    うーん。調べたが b が設定されている箇所を見つける事ができない。
    b はブレース展開の途中にいる時に設定されるそうだ。
    →分かった。これは core-complete.sh の中で設定していた。
      simple_ibrace に非自明な値が設定されていた時に b が設定される。

    →ブレース展開の途中にいる時は x を使う事にした

    ? fixed: 所で書き換えている途中で気づいたのだが ble/complete/util/construct-glob-pattern
      の中で comps_flags に i が含まれていないかテストしている。
      しかし、調べても i が設定される箇所はないし、何処にも説明もない。
      I ($"...") を意図しているとは考えづらい。これは何だろうか。

      →これは恐らく :$comp_type: == *:i:* の誤りである。
      何故この様に二重にチェックしている構造になっているかというと、
      実は先に construct-ambiguous-regex を実装して、
      その実装を元にして construct-glob-pattern を実装したからではないかと思われる。

      取り敢えずその様な想定で書き直した。
      再度確認する。やはり comps_flags に i が入り込む経路は存在しない。

  * 2019-01-20 manual: Emacs 編集モード [#D1185]
    簡単にページを作った。特に詳しく説明する事もなく
    キー束縛を列挙するだけに留めたが、それで十分だろう。

2019-12-29

  * color: true color support [#D1184]

    https://github.com/brujoand/sbp

    256色でもまあ問題はないだろうと思っていたが。
    よく考えてみたら既存の PS1 の設定の中には true color を使っている物もある。
    ble.sh の実装では PS1 を ble.sh で再解釈して terminfo で変換して出力するので、
    PS1 に true color を設定していてもそれがプロンプトに反映されない。
    つまり ble.sh が 24bit color に対応していないというだけで済まず、
    24bit color を想定したプロンプトの設定も動かなくなる。
    対応しなければならない。

    [実装方法]

    | 現在 gflags は何 bit 残っていただろうか。確認する。
    |
    | bit 0-8  : bold italic underline revert invisible strike blink
    | bit 8-16 : 前景色
    | bit 16-24: 背景色
    | bit 24,25: 前景色・背景色のon/off
    |
    | うーん。bit 26-32 の6bit と 32-64 の 32bit が残っている。
    | 本当に 24bit x 2 対応をするのか。。
    | 色の記録に追加で 32bit 必要になる。
    | 更に 24bit かどうかの判定に 2bit 必要になる。
    | そうすると残り 4 bit しかなくなる。うーん。
    | 将来的に fast blink だとか他の物に対応する余裕は全くなくなる。
    |
    | a もっと上手に code extension する方法を考える。
    |   今 8-16,32-48,24 の 25bit の組み合わせで何を表現できるかについて考える。
    |   現在使用している空間は以下の通りである。
    |     0000000 ... transparent
    |     10000XX ... 256色
    |   加えて以下を true color として使いたい。
    |     0XXXXXX ... RGB 24bit
    |       但し黒色 000000 は transparent
    |       に既に使われているので表現できない。
    |       代わりに256色16番を使って表現すれば良い。
    |   実は
    |     1YYYYXX ... 256色 + 他の属性
    |   という様にすれば他の属性を保持できない事もない。
    |   但し、24bit color と共存する事はできない。
    |
    |   この方法の問題点は処理が複雑になるという事。
    |
    | b 或いは 24bit 本当に必要なのだろうか。。という疑問。
    |   Web で考えると実のところ #rrggbb でなくて #rgb で足りる様な気もする。
    |   つまり 12bit で十分なのではないかという可能性。
    |   だとすれば 8bit 拡張するだけで良いのではないかという。。
    |
    | 然し何れの方法を取るとしても ble の内部実装の問題なので、
    | 実はいつでも好きに切り替える事ができる。何なら bleopt で
    | 切り替えられる様にしても良い。なので、ここは気楽に実装して問題ない気がする。
    | 取り敢えず後半の 32bit は使ってしまう事にする。

    結論: gflags の内部表現はいつでも切替可能なので気にせず実装する
    それに将来別の属性が増えるとも考えにくい (増えるとしたら色空間だろう)。

    [実装]

    * 先ず後半 24bit に値を格納しても問題ない事を確認する

    * done: 後半 24bit に値がある時にそれを出力するコード
      減色処理と一緒に実装しなければならない。

    * done: gspec を解釈するコード

    うーん。減色するに当たって 6x6x6 cube の階調がどうなっているか
    意識しなければならない。

    * info: 6x6x6 cube 及び 24 grayscale 階調について。

      | 等間隔で分割するならば 0 51 102 153 204 255 になる。
      | 一方で Poderosa の場合には 0 95 135 175 215 255 になっている。
      | うーん。両方実装する? 或いは…。うーん。取り敢えず等間隔を想定して実装する。
      | 等間隔でない場合に対しては後で考える事にする。
      | 24 gray scale に関しては 10k + 8 である。
      | と思ったがこれも何だかやってみると変である。
      | 元を辿ってみる。Poderosa の mwg.Rosa/Colors.cs の Xterm256Gray24
      | の表の中から拾った物で、これは 0x08 から始まって 0xEE で終わっている。
      | 0xEE = 255 - 17 = 238 である。うーん。全然等間隔ではない…。
      |
      | 等間隔で変換するならばどうなるか。
      | 10*23=230, 11*23=253 うーん。RLogin はどの様な実装になっているか。
      | RLogin は単に 11k になっている。offset はない。
      | 結局色々の terminal を調べる事にした。
      |
      | 11k       0..253 RLogin
      | 10k+8     8..238 Poderosa, xterm, contra, urxvt256c, mintty, mlterm, alacritty
      |
      | 51k        0..255 RLogin
      | k?55+40k:0 0..255 Poderosa, xterm, contra, urxvt256c, mintty, mlterm, alacritty
      |
      | % 6x6x6 cube の等間隔でない場合に対応する?
      | % 実はこれは 88colors の 4x4x4 に変換する時にも問題になる気がする。
      | % →圧倒的に非等間隔の端末が殆どなのでそれに従う事にする。
      |
      | % alacritty は grayscale の黒 232 以外は xterm と同じ。
      | % grayscale の黒 232 は本当に黒である。
      | % →変だと思って再度試してみたら 8 になった。
      | %   丁度文字の上をスポイトで抽出していただけの様だ。
      | %   結局 xterm と完全に同じ

      RLogin 以外は xterm に従っている。
      Poderosa, xterm, contra, urxvt256c, mintty, mlterm で試した。
      更に alacritty, termit, lxterminal も試した。

      terminology はなんか変な結果になる。何かの補正をかけているのだろうか。
      真っ黒が 2:2:2 であり、真っ青 (0,0,5) が 15:15:255 である。
      (0,0,1) が 4:4:97 である。(0,0,2)=6:6:137 (0,0,3)=9:9:177
      (0,0,4)=12:12:216 ちょっと規則が掴めない。彩度に制限をかけているのだろうか。
      gray scale に関しては特に変な事はなく xterm と同じく 8..238 の様だ。

      RLogin は 6x6x6 は 51k で、grayscale は 11k である。単純明快。

    [テスト]

    うーん。取り敢えず一通り対応した様な気がする。本当だろうか?
    取り敢えず。実行してみる。

    * 減色モードからテストする。
      x fixed: 構文エラー。算術式の括弧を閉じ忘れていた
      x fixed: 前景色の代わりに背景色が設定されている。
        g#setbg-index がないと怒られる。
        これは背景色用の関数名が g#setfg-index になっていた。
      x fixed: 構文エラー "g&>>16&0xFF"
        これは実装後に整理していた時に紛れたエラー。& 消し忘れ。
      x fixed: うーん。微妙な色を指定しても全部青になってしまう。何故?
        確認してみるとどうやら g 値への変換は期待通り動いている。
        然し、sgr に変換する時に駄目になっている気がする。
        分かった。g=$((ccode>>8&0xFF)) が g=$((ccode>>8&&0xFF))
        になっていた。

      x resolved: fg=#08d,bg=#f15 を設定したら誤った添字エラーになった。
        負の添字の配列要素は作れないのだった。
        どうしたら良いか…。ずらす? うーん。4bit 全体にずらす事にする。

        というか今気づいたが今分断されている bit をまとめても良いのでは。
        改めて配置について考える事にする。例えば以下の様にする。。

        00-08: attributes
        08-32: fg
        32-56: bg
        57 fg indexed
        58 bg indexed

        x ok: この方法の問題は intmax_t が 32 bit のシステムで動かないという事。
          うーん。まあ仕方がない。というか shift 量が 32 を超えている時点で
          現状の実装でも 32bit の環境では動かない事になる。
          と思ったが実は 24bit color に触らない様にさえしていれば大丈夫?

          然し、疑問は intmax_t が 32 な環境が果たしてこの世に存在しているのか
          という事である。或いは bash は 64bit 整数は使っていないのだろうか。
          https://www.jpcert.or.jp/sc-rules/c-int00-c.html やっぱり 64 bit 整数は
          少なくとも規格上は必ず存在する事になっていて、従って intmax_t は 64bit
          以上になるような気がする。但し、全てのシステムが規格に準拠しているとは
          限らないということには注意しなければならない。

          うーん。取り敢えず intmax_t < 64 なシステムは捨てて良いだろう。
          捨てるというのが現状で妥当な判断である。

        取り敢えず対応した。動いている。

    * 24bit モードをテストする。

      x fixed: term_true_colors を設定しても変わらないと思ったら、
        SGR がキャッシュされていたのだった。
        term_true_colors の変更と共に SGR のキャッシュを削除する様にした。
        表示されている。OK。

    * sbp を試してみた。
      x fixed: sbp を試してみた。着色されない。もしかして PS1 の解析ルーチンは別?
        と思ったが trace でも ble/color/read-sgrspec を使っている筈。
        何故動かないのか。うーん。どうやら setbg-rgb が動いていない。

        確認した所 rgb の r,g,b が g を被覆していた。
        rgb から RGB に書き換えたつもりだったが書き換え漏れがあったのだった。直した。

      取り敢えず truecolor support はできたかなという気がする。

    [256色判定]

    * 256色判定はどうするのか?
      terminfo にそれ専用の項目があったようななかった様な。

      https://gist.github.com/XVilka/8346728 によると
        "RGB" cap がある場合には setaf, setab を使って設定できるらしい。
        というか、今までの 256 色指定をしたい時はどうしたら良いのか謎。
        この仕様は D. Thomas による嫌がらせとしか思えない。
        https://lists.gnu.org/archive/html/bug-ncurses/2017-02/msg00018.html
        https://lists.gnu.org/archive/html/bug-ncurses/2013-10/msg00008.html
        要するに DT の主張は initc で十分の筈だという事。
        それから ncurses は 16bit 整数で動いているので 24bit 色は無理という事。

      http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=e463e57
      https://qiita.com/__hage/items/4d8ad65b70e4d6142599 では
        Emacs の為に "setb24", "setf24" という項目を追加すれば良いという事になっている。
        TERM に -24bit (38:2:r:g:b) もしくは -24bits (38;2;r;g;b) を付ける話もある。

      http://lists.schmorp.de/pipermail/rxvt-unicode/2016q2/002251.html
        tmux は "tc" という cap を見る様だ。

    うーん。判定は難しい気がする。
    結局ユーザが #xxxxxx だとかを使ったらもうその時点で
    24bit 対応であると想定して良いのではないだろうか。
    それで変な結果になっても仕方がないという事にする。

    将来的には自動判定を行う様にしたい。
    現段階では強制的に有効と見做す事にする。

2019-12-28

  * wiki: 設定集を書く事にする Recipes とでも名前をつけようか [#D1183]

    - [ble: exit %d] の消し方
    - auto-complete の色の変更の仕方

    うーん。Q&A的だが他にも色々書ける筈。
    rps1 に現在の git の位置を表示するとか。

    * #M0004 を参考に animation gif を作ろうとしたが
      使ったソフトウェアが分からない。何も記録に残っていない。
      前回の日付 2018-03-18 を元に Chrome のダウンロード履歴を
      探ったら LINEcap というソフトウェアをダウンロードしている。
      使ってみると覚えがあるのでこれである。

      キー入力を表示するソフトウェアも分からない。
      これはダウンロードの履歴を見ても分からなかった。
      記憶によるとソースコードを弄って改造した筈である。
      なので何処かにソースコードがあるか GitHub にあるか GitLab にある。
      GitHub を確認してみたが fork していないので、GitHub にはない。
      GitHub の star にも記録は残っていなかった。寧ろ LINEcap が star されている。

      適当にまた Google で検索してみる。KeyCastOW 何だか見覚えがある気がする。
      https://github.com/brookhong/KeyCastOW これだろうか。
      そうだった。ファイルを検索したら mag:.mwg/src/ble.sh/test/capture/KeyCastOW にあった。
      また分からなくなると嫌なので移動する事にする。GitHub にも上げた。

      と思って実行しようとしたら Avira に隔離された。
      Avira の隔離を復元したら戻ってきたが今度は管理者権限を使っても
      ファイルが書き換えられないし削除もできない状態になった。
      これだとコンパイルできない…。親ディレクトリごと移動した後で削除できた。
      しかしその後も同じファイル名でファイルを作る事ができない。
      仕方がないのでプロジェクトのディレクトリを再び丸ごと移動した。

      取り敢えず前と同様にキャプチャできる様になったので #M0004 を更新する。

  * edit: [ble: exit %d] のメッセージを消したいという要望があった [#D1182]
    https://superuser.com/questions/1512618/autocompletion-background-colour-in-ble-sh#comment2288342_1512656

    取り敢えず TRAPERR を定義してくれという様に書いたが分かりにくい。
    そういう設定変数を用意しようと思う。

    * done: 実装した。
    * done: update blerc
    * done: update wiki

    * done: TRAPERR と関係なく常に実行する様にしてはどうか。
    * done: trap ERR の設定も実行するべきなのではないか。
    * done: 終了ステータスを再設定して TRAPERR, trap ERR を呼び出すべきでは。
      ble/builtin/trap/invoke, blehook/invoke, ble/function#try で
      終了ステータスを伝播する様に修正した。

    * done: 仕様変更について comment を残す。

    README か何処かに設定について記述する。
    Q&Aページでも作る事にしようか。英語で書く?
    Wiki に英語版と日本語版を作りたい。
    説明書の下部に作るか。或いは別のページとして作るか。
    うーん。説明書とは独立なページにしたい気がする。
    Q&Aというよりは設定集という感じにするのが良さそう。
    →これは別項目を建てる事にした。

2019-12-27

  * complete: bash-completion-partial-path を試してみたら変な動作をする [#D1181]

    元々 bash-completion-partial-path は以下の help-bash に対する投稿で知った。
    https://lists.gnu.org/archive/html/help-bash/2019-12/msg00014.html
    この作者は今年の 7 月にプロジェクトを始めた段階で大々的に宣伝している。
    StackOverflow でもあらゆる場所で関連する質問に対して回答しているのだった。

    展開内容が重複して挿入されてしまう。置換されるべき内容が消えてくれない。
    何が起こっているのだろうか。生成した候補を insert-common の見ると自前での候補生成と同じだ。
    更に調べてみるとどうやら comps_flags に a が含まれているかいないかの違いの気がする。
    然し a が含まれていなかったとしてもそれはそれでそれなりの結果になるべきなのではないか。

    更に調べると determine-common-prefix の時点で変な結果が返ってきている様子だ。
    うーん。原因が分かった。comp_type に amAi が含まれている時には、
    曖昧前方一致であると解釈して一致しない部分に関しては保持する様になっている。
    然し、実際には曖昧一致という訳ではないのに i が入っている所為でこの処理が入ってしまっている。
    i だけしかない時には強制的に置換してしまって良いのではあるまいか。

      然し果たしてそれで良いのだろうか。もし候補が複数あって、
      共通部分だけを挿入した時に候補が減少する様だと困る。
      問題はそういう曖昧一致を progcomp の側で実行された時。
      どのような曖昧一致戦略を取ったのか分からないので、
      曖昧一致部分だけを挿入するという事ができない。
      結局挿入は行わないというのが正しい選択なのだろうか。

    [対策]

    * done: 曖昧一致共通部分に含まれない部分を保持する処理を cand_count>1 の時にだけ実行する?

      うーん。結局この処理の部分全体を cand_count>1 の時に実行する様にすれば良いのか?

      * 前にこの辺りの判定については弄った事がある気がする。

        | どのように弄ったのか確認する必要がある。
        | →調べてみた 6456d87d (2018-09-05) の時点で既に cand_count に関わらず
        |   曖昧一致の場合には一致しなかった部分を保持する様になっている。
        | →更に遡ると 64cdadc7 (2018-08-01) に於いて曖昧一致が実装されて
        |   この時点では cand_count に関わらず曖昧一致で
        |   元の文字列に一致しない場合は一切の補完を実行しない様になっていた。
        |
        |   | Commit 64cdadc "complete: implement ambiguous matching (bleopt complete_ambiguous)"
        |   | lib/core-complete.sh
        |   |
        |   | if [[ $opt_ambiguous ]]; then
        |   |   # 曖昧一致に於いて複数の候補の共通部分が
        |   |   # 元の文字列に曖昧一致しない場合は補完しない。
        |   |   [[ $common =~ $rex_ambiguous_compv ]] || common=$COMPV
        |   | fi
        |
        | つまり。cand_count>1 を敢えて cand_count==1 でも同様に処理する様にしたのではなく、
        | 始めから何も考えずに cand_count==1 でも制限をかけていた。という事になる。
        | うーん。或いは一番最初の設計の時にその辺りまで考察したのだったか。
        | 調べて見る必要がある。該当する項目は #D0707 であった。
        | 読んでみると其処までは考えていなかった様だ。
        | つまりこの部分の処理は全て cand_count > 1 の時にのみ実行する様に変更して良い気がする。

        結論: 最初の実装から cand_count については確認していなかった。

      * 改めてこの変更によってどのような影響が出るかについて少し考察しておく事にする。

        先ず曖昧一致の候補を生成する時に、生成時点で filter してしまって、
        実のところ入力済みの部分全体に一致する訳ではない候補が生成される可能性はあるだろうか。
        例えば function name で最初の */ までしか候補として列挙しないという処置など
        によって曖昧一致候補の前半部分だけが単一の候補として列挙されて、
        入力文字列の後半部分が補完挿入時に失われてしまう可能性について。

        うーん。その様な可能性はない気がする。やはり既に入力している文字列があるのであれば、
        候補生成ではそれも含めて生成しなければならない。
        もしそれを省略してしまって補完によって挿入済みの部分が失われてしまっても、
        それは補完候補生成器が意図した事なのかそうでないのかは外からは判定できない。

        その様に考えるとやはり単一候補の場合には完全に置換してしまって良い気がする。

      結論: 実施する。cand_count>1 の時にだけこの対処を実行する。

    * done: 上の対策だけでは不十分である。実際に候補生成器が曖昧一致で複数候補を生成した時に
      どの様にして挿入を実行したら良いのだろうか。
      ble.sh の側ではどの様に曖昧一致が実施されたのかを知る術はない。
      挿入は行わない様にするのが自然な気がする。

      x ok: 然しそうだとしても menu-filter が走ると候補が全て消滅してしまう。
        →と思ったが menu-filter の実装を見てみると head, substr, hsubseq, subseq の
        順番に試して一番最初に生き残る物を採用するという仕組みになっている。
        従って候補生成器が勝手に曖昧一致で生成してもちゃんと生成できる。OK

      うーん。曖昧一致でないのに先頭一致しない候補が複数生成された時は
      補完挿入は実行しない。という実装に問題はあるだろうか。

      →結局、曖昧一致でない時は共通部分が入力文字列の拡張になっていない場合には、
        補完挿入を実行しないという実装にする事にした。
        もし共通部分が入力文字列を拡張する場合には、
        補完挿入を許す事にする。

    * done: ignore-case でない場合も対策しなければならない
      然し、よく考えたら i が入っていなくても progcomp が
      前方を書き換える様な候補を複数生成する事は可能性として残る。
      その様な場合にはどうしたら良いのだろうか。

      現状の実装ではコメントに "Note: #D0768 文法的に単純であれば (構造を破壊しなければ)
      遡って書き換えが起こることを許す。" と書かれている。
      #D0768 の議論を確認した。うーん。ここの考察では勝手に progcomp が
      前方一致しない候補を生成する事に関しては想定していない様だ。
      前方一致するかどうかの判定を追加する事にする。

    [検証]

    取り敢えず動いている。候補が複数生成される場合にちゃんと展開が抑止される事も確認した。
    実のところ bash-completion-partial-path を読み込まない時の方が良好に動作する。
    というのも ble.sh がちゃんと曖昧一致であるという事を知って determine-common-prefix する為。

    然し、普通に ble.sh なしで bcpp を動かしてみるとちゃんと
    共通部分の挿入まで実施してくれる。うーん。どうするのが良いのだろうか。
    実際に bash で mkdir -p aloha/hello/{wip/tt,world/{tech,test}} としてやってみると、
    echo a/h/w/t が echo aloha/hello/w になってしまう。t の情報が消える。
    但し、続けて TAB を押した時に限れば menu-complete に入って候補が選べる。
    menu-complete に入らずに別の操作をすると入力内容が失われる。

    そういう意味で言えば ble.sh でも曖昧な候補によって
    入力済み文字列が消滅する事を許しても良いのかもしれない?
    menu-complete を既に実装しているのであるから。
    試しに一回消滅する事を許してみる。うーん。動く。

    [対策2]

    オプションで外部の枠組みで生成された先頭一致しない候補によって、
    入力済み文字列が失われてしまう事を許可する事にする。
    設定変数 complete_allow_reduction を追加した。

  * 検索してみたら丁度2時間前に質問が superuser.com に来ていた… [#D1180]
    https://superuser.com/questions/1512618/autocompletion-background-colour-in-ble-sh

    Issue を建てるのが恥ずかしかったのだろうか。取り敢えず対応して返信してしまう事にする。
    * done: ble-color-{set,def}face を無引数で呼び出した時に現在の設定の一覧を出力する様にした。
    * done: README に追記した。OK

2019-12-18

  * bind -X の修正が入ったのでキーバインドの復元に bind -X を入れられる [#D1179]
    またユーザ設定を起動時に読み取るというのもできるのではないか。

    →確認したところ既に復元の時に bind -X を入れる様になっていた。
    つまり bind -r した設定も一緒に復元されてしまう。
    他の bind で上書きしたのが復元されてしまうのは困るので、
    他の bind の復元の方を後に持ってくる様に変更する事にした。

    ユーザ設定を起動時に読み取るのは面倒なので対応しなくて良い気がする。
    そもそも bind -x に限らず現状の実装では設定を読み取る事は試みていない。

2019-12-16

  * edit: 現状の実装では改行と同時に更に次の文字が来ている時 [#D1178]
    その場でコマンドを実行せずに複数行編集に入るようになっている。
    然し、ssh を使っている場合やそもそも使っている機械が遅い時、
    簡単に複数行モードに突入してしまって使いづらい。

    * 先ず初めにこの振る舞いをオプションにする。

      この振る舞いは何処で判定していただろうか。
      ble-edit/is-single-complete-line という関数だろうか。

      →bleopt accept_line_threshold という変数を追加した。

    誤ってペーストしてしまった時には悲惨な事になるが仕方がない。
    或いは何文字以上の時には複数行編集モードに入るなど、
    そう言った制御をする事は一応可能である様に思う。
    現状で大量の入力があった場合には取りあえず読み取るだけ読み取って
    その後で処理するという仕組みになっている。

    * 大量の入力があった時 (n文字以上) の時にだけ
      複数行編集モードに入る様にする。

      これに対応する為には現状で大量の入力があった時に
      どの様に振る舞うのだったかを確認しておく必要がある。
      →_ble_decode_input_buffer に格納している。

      _ble_decode_input_count は has-input 等からも参照している変数である。
      この変数を元にして残り文字数を判定してそれで改行を実行するかどうかを
      判定するというので良い気がする。
      →実際にやってみると動かない。どうも文字デコードまで終わった上で
      実際のコマンドが実行されている様だ。つまり、ble_decode_char_rest
      も参照すれば良い?

2019-11-23

  * 2019-09-03 menu-complete: グロブパターンを含む単語をメニュー補完すると正しくない結果になる [#D1177]
    echo *.p として menu-complete から a.pdf を選択すると *.pa.pdf になってしまう。

    % →と思ったがそもそも *.p に一致するファイル名が存在しない場合であり、
    % この場合には *.p の末尾から新しく補完が始まるのであった。
    % つまり a.pdf は *.p に一致するファイル名として生成されたのではなく、
    % *.p と関係なく完全に新しく生成された候補である。
    %
    % 問題点はその場所で生成された候補であるのにも拘らず、
    % *.p を含むように候補が生成されている事である。

    分かった。*.p に一致する候補が存在しない場合 failglob になっていると、
    空文字列に展開されて、更にその空文字列から候補が生成されているのであった。

    failglob になった瞬間に glob によるパターン絞り込みに変更するのが筋である。
    そしてそれでも一致する候補がなかった場合に限りそのままの文字列を保持する。

    eval の箇所で何が起こっているのか調べる必要がある。
    →やはり failglob している。failglob すると空文字列の展開結果になって、
    それを元にして候補を生成してしまっている。

    failglob の時にはそもそも候補を生成しないか、
    或いは続きに何か入力すれば候補が存在する様にできる、
    という状態を期待して word* で候補を生成する。

    取り敢えず実装した。

    * 共通部分の挿入を実装する可能性について。

      x 共通部分を挿入した事によって何らかのファイル名に厳密一致してしまうと、
        それ以降はそのファイルしか補完できなくなってしまう。
        例えば a1x.pdf a2x1.pdf というファイルがあったとして、
        a?x で補完を実施して共通部分として a?x.pdf まで挿入してしまうと、
        その時点で a2x1.pdf が候補として列挙されなくなってしまう。

      だからと言って a?x*.pdf という具合に挿入するのも面倒である。

      x また * の部分に手動で何か入力したかったかもしれない。

      その様に考えると勝手に共通部分を挿入するのはお節介の気がする。
      実装も面倒である。取り敢えずここでは対応しない事にする。
      後でもしこれが有用であると思われればその時に実装すれば良い。

2019-11-17

  * 2019-10-02 ble.sh で ${!var_@} がエラー着色になっている [#D1176]

    x fixed: 調べると $10 は bash では ${1}0 と解釈されるのに
      ${10} であるかの様に処理されていた。
      これについても修正を行った。

    適当であるが修正した。${!head@ ... } の ... の部分は
    エラー着色する様にしてみたが対応はいい加減である。

2019-11-15

  * vim-arpeggio 及び ble-bind -T wiki に追記する [#D1175]

2019-11-14

  * kj 及び jk の "同時押し" による操作の要望が来た (request by divramod) [#D1174]
    https://github.com/akinomyoga/ble.sh/issues/31

    単独の k, j と区別する為には timeout に対応する必要がある。
    これに対応する為にはどうすればよいか。

    a ESC の受信に用いている方法は汎用的には使えない。
      特に ESC の timeout と他の timeout を独立に設定できない。
      そんなに重要な機能ではない様に思われるので、

    b idle (bash-4.0 以降) を用いて実装するというのが良い気がする。
      idle を用いて実装するとして timeout の情報をどの様に記録するのか
      という問題が存在する。

    調べてみると現在の実装ではそれまでに入力されたキーの
    列から続きがあるかないかについて判定している。
    つまりキーの列を登録する時に続きがあるかどうかも含めて
    木の情報を構築している。ここに timeout の情報を記録するには、
    先ず、各キー列に対する timeout を記録すると共に、
    キー束縛を更新する度に最長の timeout を更新するという事が必要になる。

    或いは別の方法として各キー列に対して timeout を設定するのではなくて、
    各ノードに対して timeout を設定するという事にしても良いのかもしれない。
    例えば jk 同時押しに対応するのだとしたら "j" と "k" に対して timeout
    を設定しておく事にする。もし timeout が設定されていて続きがあるキーの場合には
    "_100:command" を登録する事にする (100 が timeout である)。
    もし待っているキーが存在しなくてかつ 100 待っても何も来なければこの時点で
    command を実行する。待っているキーがあって 100 待つ内に続きのキーが到着したら、
    続きのキーを処理してそれでも解決しなければ command を実行する様にすれば良い。
    うーん。"解決しなかった時" は続きのキーが存在しない場合として処理する必要がある?

    つまり、以下の様な方針で実装する必要がある。
    * キー列の解決に失敗した時の再一致の際には timeout は無視してその場で確定する
    * 通常の解決の際にだけ timeout を処理する事にする

    現状の実装で再一致はどの様に実装していただろうか。
    →.invoke-partial-match で特別に処理していた。
      timeout を導入してもこの部分の処理を変更する必要はなさそう。OK

    とりあえず実装した。結局 idle を使って実装するのではなくて、
    その場で入力待ちをして実装する事にした。
    timeout 待ちの状態で自動補完が走ったりしても混乱の元であるから、
    却ってこの実装で良かったのではないかという気がする。

    - bind, unbind, print で対応した。
    - dispatch 及び invoke-partial-match でも対応した。
    - "ble-bind -T kspecs timeout" に対応した。
      注意としては kspecs を先頭部分に含む別の kspecs に対して
      既に key bindings を設定している時にのみ使えるという事。

    - github のページを確認して何が要求されているか改めて確認する。
    - ユーティリティ関数を追加しても良いという気がする。
      vim-arpeggio というのの説明を読んだ。
      vim-arpeggio では3つ以上のキーも受け付ける様である。
      何れにしてもユーティリティ関数を vim-arpeggio.sh という名前の拡張で提供する事にした。

2019-09-22

  * edit: read, exit に --help を指定しても説明が表示されない [#D1173]
    対応した。

2019-09-04

  * prompt: 変な文字が出力されてしまう (reported by Dave-Elec) [#D1172]
    https://github.com/akinomyoga/ble.sh/issues/30

    調べてみると \[\] に対応して出力している筈の
    \1 \2 がそのまま出力されている気がする。うーん。
    ble/canvas/trace を調べてみた所、\001, \002 を処理しているが、
    それに伴って \001, \002 自体の出力を抑止する処理を忘れていた。直した。

2019-09-03

  * 2019-08-05 [自然解消] vi: 起動した瞬間のカーソルの形状 [#D1171]
    調べてみるとちゃんと最初に 0 を設定している。
    これは完全に contra のバグだったと思って良いのだろうか?
    現状で tx11 を起動してみると確かに問題は解消している様な気がする。
    これに関しては再現したらその時に考え直す事にする。

2019-08-25

  * edit: コマンド a[{1,2}]=3 を実行するとエラーになって状態がおかしくなる [#D1170]

    $ a[1+]=2
    でもなる。
    $ eval 'a[1+]=2; echo hello'
    としてもなる。
    $ a[1+]=2; echo ]
    としてもなる。eval の中でも影響が残ってしまうというのは不思議だ。

    以下の様にして試してみる。"a" とエラーメッセージしか表示されない。
    配列添字で算術式のエラーが生じると、
    eval どころか関数呼び出しの入れ子も全て無視して実行が中断する様だ。
    $ function f() { eval 'a[1+]=1'; }
    $ echo a; f; echo b

    failglob の時には中断は eval の外までは波及しなかった。
    これに対する対策はどうした物だろうか。
    そもそも全く実行しないという手?

    少なくとも epilogue 等の呼び出しに失敗したとしても、
    正しく状態が復元される様にはしたい所なのである。
    そもそも何故 PS1 が失われてしまうのか。
    調べると adjust/restore-PS1 とは独立に明示的に PS1= している箇所がある。
    これは adjust-PS1 経由でクリアする事にした。

    また、途中で実行が中断されて epilogue/end が呼び出されなかった場合の為、
    それを検出して必要に応じてその場で epilogue/end を呼び出す様に修正する。
    関数呼び出しが深いので FUNCNEST があると動かなくなるが
    滅多に起こらない事なので気にしない事にする。

  * prompt: bash の cd //... と PS1 \w の表示 (information by cmplstofB) [#D1169]
    https://github.com/akinomyoga/ble.sh/commit/2cf8cc7a2c39f1c0ceb3016a5f3ca745c27b9b5d#r34820891
    試したら PS1 の中の \w と \W の表示が変になるという事が分かったので修正する。

2019-08-17

  * complete: cygwin で "echo //" と入力すると待たされる [#D1168]
    これは何だろうか…。何処かで処理が止まっているという事。
    bleopt complete_auto_complete= としても遅いのは変わらない。

    色々調べると問題が起こっているのは一箇所では無い様に見える。
    time [[ -e //$RANDOM || -h //$RANDOM ]] とすると物凄く時間がかかる。
    bash --norc の上で実行しても同様に時間がかかる事から ble.sh の所為ではない。
    Windows の何か特殊なディレクトリでも見に行っているという事なのだろうか。

    というか問題が起こっている箇所は一箇所ではない。
    少なくとももう一つ止まっている箇所がある。
    以下に列挙していく事にする。と思ったが一つずつ
    潰して行った方が効率が良いのではないか。

    - ble/syntax:bash/simple-word/locate-filename

    探してみると echo //* というのを実行しても待たされるという事が分かった。
    一般に Cygwin では // で始まるパスは駄目な様だ。
    更に、// は / と同一視されるのかと思いきや、そうでもない。
    全く触る事ができないパスになっている様な気がする。
    何しろ echo //* としても何も表示されないし、
    または ls -la // とすると Permission denied という事になる。
    ls -dl // とするとディレクトリという事になる様なので '//' の時だけ有効?

2019-08-13

  * [棄却] char_width_mode=emacs での斜め矢印の文字幅 [#D1167]
    この文字である ↗

    ble.sh の上では幅2と計算されている。しかし、
    emacs 上での取り扱いは幅1であり、そして contra でも1である。
    自前の screen の cjkwidth emacs でも 1 であり、
    それから自前の Poderosa の文字幅計算でも 1 である。
    これは ble.sh の方を合わせるべきの気がする。

    どうも contra のコードを調べてみると、
    これは絵文字と判定されている様である。
    一方で A ではない文字とも判定されている。

    これは emoji_width の設定の問題なので bash 自体の問題ではない。
    取り敢えず emoji_width を設定せずに使う事にした。
    絵文字を使う為にはやはり emacs/screen/端末 などが
    全て対応していないと幅の計算が駄目になるのである。

  * exec: failglob したコマンドがサブシェルにあると固まって動かなくなる [#D1166]
    例えば echo ? | echo で固まってしまう。
    よく考えたらどう対処したら良いか分からない…。
    →分かった…これは subshell で ble/base/unload が起こっているのが原因である。
    ble/base/unload で BASHPID をチェックする様にしたらあっさりと直った。
    他の hook に関してもチェックした方が良いのではないか。

2019-08-06

  * syntax: 何とサブシェル () の直後に then 等を置いても OK らしい [#D1165]
    yash のサンプルを見ていて気づいた。bash でもそうだった。
    試すと then, fi, 等が置ける。(()) の直後は駄目の様だ。
    [[ ]] の直後も駄目の様子である。} の直後は大丈夫。
    その様に考えると } の直後と同じ文脈という事になるか。
    どうも完全に CTX_CMDXE の様である。CTX_CMDXE にする。

2019-08-03

  * vi_test: マクロ再生に失敗している [#D1164]
    手動で実行してみるとちゃんと動作する様に見える。
    マクロ再生中にマクロ再生は再帰的に実行しない、
    というのが引っ掛かっているのだろうか。という気がする。

    と思ったらそうではなかった。
    ちゃんと再生部分までは到達しているが記録を読み出す所で失敗している。
    うーん。a (97) は空である…。マクロ記録中の再帰の抑制だろうか…。

    うーん。ちゃんとマクロ記録の設定は開始しているが、
    何故か一文字もマクロからの文字が ble-decode-char の
    該当部分を通過しない…何故だろうか。
    と思ったら分かった…。vi_test は ble-decode-char は介さずに、
    直接に ble-decode-key を呼び出しているのでキーボードマクロは使えないのだ…。

    代わりに ble-decode-char を呼び出す様にしてみたが、
    そうすると今度は処理が遅延されてしまってその場で実行されない。
    と思って ble-decode-char の中を覗いたら ble_decode_char_sync という変数がある。
    これを使ったら期待通りに動く様になった。

  * vi_nmap: C-x が効かなくなっていると思ったら、 [#D1163]
    C-x C-e を登録してしまった為に動かなくなっていたのだった。
    うーん。テストは通る様になったがそれでもやはり C-x がすぐには効かない。
    C-x は二個の組でしか受信できていない様子である。
    vi_test で実行するとちゃんと一個ずつ受信できているので、
    decode.sh の中で詰まっているという訳ではない様に思う。

    何と bash-4.3 では動くけれども bash-4.4 以降では動かなくなっている。
    うーん。実際に出力してみると C-x に対する作戦が異なる様だ。
    というか emacs と vi で bind の戦略を変更しても良いのかも知れない…。
    面倒なので binder の中に emacs/vi の判定条件を入れる事にした。

    (というかそもそも何故条件判定を使わずに bash version 毎に
    スクリプトを生成していたのだったか。恐らく初期化の速度を気にしての事だろう。
    実は物凄く高速なので気にしなくても良いという気もするが、
    何れにしても bash-5.0 では条件分岐も必要ないのでこれで良いという気がする)

  * init-bind: "C-\ C-\" が効かなくなっている @ bash-5.0 [#D1162]
    そもそも受信できているのだろうか…。
    うーん。受信できていない…。
    どうも bash-5.0 から受信できなくなっている様である。
    うーん。前に修正した物との関連は? #D1078 これである。
    これの気がする。単に表示が変なだけではなく実際に振る舞いが変なのである…。
    取り敢えず bind "\x1c" とすれば動かない事は無いようである。

2019-07-30

  * util: "bash: INT 云々" というエラーメッセージが出る [#D1161]
    declare | less で \<INT\> を検索して見てみると
    _ble_builtin_trap_handlers=([1000]="INT") という状況になっている。
    そしてこれは以下の部分で引き起こされているのではないかという気がする。
    function ble-edit/exec:exec/.eval-epilogue {
      trap - INT DEBUG
      ble/base/adjust-bash-options

    と思ったがこれは gexec ではなくて exec なので関係ない気がする…。
    という事はまた何処か別の所で引き起こされている…。
    何れにしても恐らく古い trap 呼び出しによって変な物が登録されているのである。
    そしてそれは状況を見るに trap - INT DEBUG なのである。
    試しに実行してみる事にする。再現した…。引数の読み取りが変なんだ。

2019-07-27

  * syntax: echo "${var/[a/b]/c}" これが正しく解析できていない [#D1160]
    echo "${var#[a}" これも駄目である。
    →これは物凄く単純なミスだった。修正した。

  * syntax: echo ${var##@(((a)))} とした時の着色が変だ [#D1159]
    echo @(((a))) に対してはちゃんと動いている。
    取り敢えず対応する開始部分と同じ色に着色する様にする事にした。

  * 2015-02-16 ${ ... } 内の文法チェック [#D1158]
    extglob (但し '}' で強制終了する必要がある。
    一旦全て読み取ってから後付けで着色する?)
    →これは #D1157 と一緒に対応した。

  * 2017-11-22 syntax: ${var##...} における check-glob の対応 [#D1157]
    ctx-bracket-expression に関しては、
    新しい nctx への対応が必要になる。

    実はこれに関しては文法の解釈には寄与しない。

    a つまり、CTX_PATN に対しても @( は } が来たら終了する。
      これだと CTX_PATN についても bashc を弄る必要が出てくる。
      実は親が CTX_PWORD の時に '}' を追加して、
      check-word-end で終了する様にすれば良いだけなのではないかという考え方もある。

    b そもそも CTX_PATN に入らずに @+?!(|) を全て着色するという手もある。
      しかしそれだと pattern ではない物まで着色されてしまう。
      それならそもそも色を付けない方が良い。

    c 或いは CTX_PATN を複製して CTX_PWORD から呼び出した時用の新しいものを作る。
      と思ったが現状の CTX_PATN と比べて殆ど違いはないので a の方が良さそうに思う。

    所で CTX_PWORD と言っても様々な文脈がある。
    文脈によってはパターンが無効になる場合もある。
    % 以下の xxx の場所では有効で yyy では無効である。
    %   ${a//xxx/yyy} ${a#xxx} ${a%xxx}
    %   ${a:-yyy} ${a:=yyy} ${a:+yyy}
    %   ${a,xxx} ${a^xxx}
    % →試してみたが yyy だとパス名展開に使われる様だ。つまり有効である。
    現状では何も考えず全て CTX_PWORD にしている。
    そもそも文法的に許されないものも全て許可している。
    パターンの着色に対応する前にこの様々なパラメータ展開の着色に対応するべきである。

    * 現状では CTX_PATN 内部でブレース展開が常に有効になっている。
      ${var#pattern} を解析しているとき
      CTX_PATN からブレース展開が呼び出されない様にする。
      これは CTX_PATN が "}" で終了することを許すかどうかと同じ条件判定を使えば良い。

    2019-07-27 cmplstofB さんから報告があった。
    https://github.com/akinomyoga/ble.sh/issues/29
    成る程、構文解析を適当にやっているとこういう事になるのである。
    ちゃんと対応する必要がある。

    * ${a//.../...} の形式の時は / で globpat は中断する様である。
      つまり、${a//[a/a]/hello} は、${a//'[a'/'a]/hello'} と解釈される。


    ? CTX_BRAX 及び CTX_PATN については入れ子等で
      外部の文脈をどう継承するかが複雑だった気がする。
      どの様になっていたのだったかを調べる。

      →#D0622 の 7 に詳しく書かれている。
      特にブレース展開まで絡んできた時の振る舞いなのであった。
      引用すると以下の様になっている。

      > 以下のとき、ブレース展開は無効となり通常文字列として読み取られる。
      > - CTX_CONDI/CTX_VRHS/CTX_RDRS からブレース展開を試みるとき
      > - CTX_VRHS/CTX_RDRS によって不活性化した CTX_PATN/CTX_BRAX からブレース展開を試みるとき
      > - CTX_CONDI の直下にある CTX_BRAX(有効) からブレース展開を試みるとき
      > 以下のとき、ブレース展開は不活性となりブレース展開として有効になったときエラーを設置する。
      > - CTX_RDRF/CTX_RDRD からブレース展開を試みるとき
      > - 不活性の CTX_BRACE1/CTX_BRACE2 から入れ子のブレース展開を試みるとき
      > その他のとき、ブレース展開は有効になる。但し、bash と違い以下の場合を含む
      > - CTX_BRAX によって不活性化した CTX_PATN からブレース展開を試みるとき
      > CTX_BRACE1/CTX_BRACE2 から CTX_PATN/CTX_BRAX に入る時は特別な処理は何も必要ない。

      この話でいうと CTX_PWORD の時は特に "CTX_VRHS/CTX_RDRS によって不活性化した
      CTX_PATN/CTX_BRAX" 等と同様にブレース展開を無効にすれば良い。
      CTX_BRAX 及び CTX_PATN 自体の複雑さではなかったという事か。

      然し、この入れ子を遡ってどの文脈にいるのかを判定するのが、
      どの様に実装されているのかは確認しておく必要がある気がする。
      うーん。ntype に glob_attr=* という形式の文字列を格納している様だ。
      そして * の部分に親の文脈値を入れている。実は此処に CTX_PWORD を入れておけば良いのでは?

    ? うーん。現状の CTX_BRAX の動作が分からない。
      解析の結果を見ると "a[b(" と入力すると、
      "(" が現れた時点で CTX_BRAX を抜けている気がする。
      然し、そもそも ble/syntax:bash/check-glob に入って来ない。
      →もしかすると ble/syntax:bash/ctx-bracket-expression.end で抜けている?
      →うーん。そうだった。多分ここで抜けている。

    取り敢えず実装する。CTX_PWORD で check-glob を実行する。

    * done: ${var%%@(a|b[hello} の時 CTX_BRAX も CTX_PATN も同時に抜けるべき。
      現状の実装では実は CTX_PATN の強制終了条件は存在していない様だ…。

    色々実装した。動いている気がする。

  * syntax: 'a=[' と入力するとエラーメッセージが出る [#D1156]

    というか試していたら凄いバグを見つけた。
    a=[ と入力しただけでエラーメッセージが出力される。
    これは failglob か? と思ったが failglob を外していてもメッセージは出る。
    先にこれを片付ける事にする。何処から発生しているのだろうか。

    うーん。構文解析か或いは単語着色か…うーん。単語着色が怪しい気がする。
    →試しに update-word-table を /dev/null にして見た所メッセージが出なくなった。
    どうも ble/syntax:bash/simple-word/evaluate-path-spec の中で発生している。
    ble/syntax:bash/simple-word/evaluate-path-spec [ / noglob  で再現する。
    ble/syntax:bash/simple-word/eval-noglob [ でまた再現した…。うーん。

2019-07-24

  * edit: 何と DEBUG トラップが物凄く大量に呼び出されている気がする [#D1155]
    うーん。そもそも DEBUG を登録するのは SIGINT を停止する為である。
    それなのに DEBUG を常に trap していると処理が遅くなるのではないか。

    実際に何回呼び出されたのか、というのを調べてみると
    やはり物凄い勢いで呼び出されている。
    すぐに数百回の呼び出しに到達してしまう。
    やはり動的に trap/untrap を実行する様にした方が良い気がしてきた。

    うーん。どの様にするのが良いか。
    現状ではどの様に動作するか…。
    というかそもそも ble.sh の内部で動いている時には DEBUG trap は不要である。
    という事を考えればコマンドを実行する直前に DEBUG trap を有効にして、
    コマンドを実行した後に DEBUG trap を削除するという様にしても良い気がする。
    更に言うとコマンドを実行する前ですら DEBUG trap を必ず入れる必要があるかは微妙。
    そもそも DEBUG trap を入れるのは SIGINT を捕まえた時にそれを停止する為である。
    それならばその時点で DEBUG trap を仕掛ける様にすれば良いのではないだろうか。

    * done: 先ず設計としては blehook DEBUG は取り敢えず廃止するという事。
    * done: 次に必要のある時にだけ builtin trap DEBUG するという事。

    x fixed: うーん。C-c が動かなくなっている。
      前は確かに動いていたのだという事は確認した。何がいけないのだろうか。
      うーん。そもそも SIGINT を捕まえられていない気がする。
      然し、builtin trap を見るとちゃんと登録されているし、
      手で blehook/invoke INT を呼び出してもちゃんと動くと確認できる。
      → builtin trap -- 'blehook/invoke INT' INT を改めて実行する様にしたら動く様になった。

    * done: 次に ble/builtin/trap DEBUG は prologue/epilogue の間でしか起こらない様にするという事。

    x fixed: やはり漏れがある。ble-edit/exec:gexec/.* に対しては呼び出さない事にした。
    x fixed: 未だ変だ。と思ったら直接 builtin trap -- ... DEBUG されている?
      これは ble/builtin/trap/reserve を忘れていた。
    x fixed: コマンドの終了ステータスが0以外の時にも何故か余分に呼び出されている。
      しかも同じコマンドに対して2回呼び出されている。何故?

      % echo A; false; echo C という具合にすると
      % false の直前で TRAPDEBUG が2回呼び出される。

      echo A; bash -c 'echo X;false'; echo C で調べた所、
      直前で2回呼ばれるのではなくて、実行直前と実行直後の2回呼ばれる様子である。
      うーん。もしかして ERR トラップを実行する直前に
      DEBUG も呼び出されているという事か?

      どの様に解決するかというと…。
      例えば ERR トラップを解除してそれからまた設定するという具合にする?
      というよりそもそも何の為に ERR を捕まえていたのだったか…。
      現状のコードを見ても何か特別な処理をしている様には見えない。
      元々のソースコードを見ると ERR は実際には使われていないのだった。

      うーん。ERR関連は削除する事にした。
      ユーザが自分で ERR を設定した時には諦める事にする。
      というか bash の既定の振る舞いとしてそれは正しいのだろう。

    * done: ble/builtin/trap DEBUG を prologue/epilogue の間で呼び出した時には、
      その場で exec:gexec/trap を実行する様にする必要がある。

      これには ble/builtin/trap 側で set/reset
      関連で関数を呼び出す仕組みを追加すれば良い。

      x fixed: 実際に実装してみた所、ble/builtin/trap の中で実行している
        return 0 に対しても反応してしまっている…。
        まあ、これは面倒なので気にしない事にしようか…。

        a 或いは、現状の振る舞いの方が寧ろ自然とも考えられるかもしれない。
          何れにしても ble の関数をユーザから呼び出せば trap は発動するのである。
          と思ったらそんな事はなかった trap を設定した関数呼び出しより外にしか効果はないのである。
        b 或いはグローバルで発生した DEBUG だけを取り扱う様にすれば良いだろうか…
          と思ったがグローバルかどうかを検出する方法は実は存在しない。
        c 或いは ble/builtin/trap を明示的に跳ねる? と思ったが、
          これも BASH_COMMAND に ble/builtin/trap が入っている訳ではないので
          検出する事ができない。
        d trap 側で return 0 を使わない様にする?
          と思ったがそれだけだと不十分である。複数の trap を同時に仕掛ける場合などに
          続く trap を設定する段階で沢山の DEBUG を呼び出してしまう。
        e その様に考えると ble/builtin/trap の中にいるかどうかを
          表す変数を作っても良いのかもしれない。
          結局 _ble_builtin_trap_inside という変数を作ってそれで判定する事にした。

    * done: DEBUG の trap は終了ステータスが意味を持つ
      .TRAPDEBUG の意味を反転させれば良い?
      →紆余曲折あったが意味は反転させた。
      ちゃんと 2 以外の時には単に終了ステータス失敗を返す様になっている。

2019-07-23

  * main: 実は FUNCNEST 対策はそんなに難しくないのではないか [#D1154]

    試してみる。
    - FUNCNEST=0 の時には制限はない。
    - FUNCNEST=1 の時には一回は関数を呼び出すことができる。
    - eval f1 や eval 'eval f1' や eval "eval 'eval f1'" の様な入れ子は幾らでもできる。
    - 更に初めに呼び出した関数の中で local FUNCNEST= 等としておけば
      その中では自由に関数を呼び出す事ができる。
    - 関数の中で FUNCNEST を小さな値にしたらその場で死んでしまうのか?
      →別に何も問題は起こらない。続きも実行されるし、
        関数を抜ける時にエラーになるという事もない。
        つまり FUNCNEST は関数に入る時にだけチェックされるのである。


    set -ex の類と同様に ble/base/adjust-bash-options と
    ble/base/restore-bash-options で退避・復元する事にした。
    問題は ble/base/adjust-bash-options を呼び出す迄に死なないかという事と、
    それから ble/base/restore-bash-options を呼び出した後に死なないかという事。

    ble/base/adjust-bash-options を呼び出している箇所は以下の通り。
    - ble.pp ロードの初め → 最初の関数呼び出しがこれなので OK
    - ble/attach → これも ble/attach さえ呼び出す事ができていればOK?
      と思ったが微妙かも知れない…。FUNCNEST=1 だと ble/attach は呼び出せるけれども、
      その退避を行う為の adjust-bash-options は呼び出せないという事になる。うーん。
      local FUNCNEST で呼び出してから unlocal を使ってグローバルを修正する?
      と思ったけれども、それだと unlocal が必要かどうかの判定ができない。
      やはり外で FUNCNEST 退避を行うべきだろうか。

      仕方がないので変数に実行するべきコマンドを入れて、それを eval する事にした。
    - edit.sh の save-last-exit 及び epilogue で呼び出されている。
      これに関しては save-last-exit, epilogue で FUNCNEST を調整すれば良い。

    ble/base/restore-bash-options を呼び出している箇所は以下の通り。
    - ble.pp ロードの末尾。これはOK。一番最後に付け加えれば良い。
    - prologue の中。.setexit は直接記述する様に変更しなければならなかった。
    - ble-edit/bind/.check-detach の中。
      check-detach で return 0 すればもう関数は呼び出さない?
      check-detach は exec:gexec/.end からしか呼ばれていなくて、
      この .end の中では check-detach が 0 を返したらすぐ終了する様になっている。
      また gexec/.end はトップレベルで呼び出される事になっているので、
      改めて関数が呼び出されるという事もない。OK

    多分。これで大丈夫。これで動かなかったらそもそも set -e で死んでいる筈。
    取り敢えず死ぬという事はないけれども実は FUNCNEST が消去されてしまっている。

    うーん。どうやらコマンド実行中に trap 経由で実行される物は FUNCNEST が退避できていない。
    - blehook/invoke では local FUNCNEST= してしまう事にする。

  * main: set -e の設定が消滅している気がする [#D1153]
    % と思ったが…。うーん。もしかすると意図的に対応を諦めた?
    % そんな気もする。しかし #D0930 では特に議論されていない様にも思う。
    % それに ble/base/restore-bash-options では明示的に復元を試みている。
    うーん set -e にすると何も起こっていないのではなくて、
    その場ですぐに抜けてしまっていてそれに気づいていなかったという事らしい。
    然し、エラーを発生させていないのに終了してしまうというのは怖い。
    何があったのだろうか…。あー。分かった気がする…。直した。

    また set -x にすると trap/invoke DEBUG が物凄く沢山のメッセージを出してしまう。
    これに関しても対策を施した。

  * blehook: trap を置き換える? [#D1152]
    その為には trap の仕様を確認しなければならない。

    * done: blehook で引数を渡すのは関数名またはコマンド名を指定した時だけにする事にした。

    * 取り敢えず実装した。少し動かしてみたがちゃんと動いている気がする。置き換えても良い気がする。

    * ERR が無駄に沢山呼ばれる。setexit で呼ばれている気がする…。
      ERR に対しても介入するべきではあるまいか。

  * bind: コマンドを実行した後はプロンプトを再計算するべきなのではないか [#D1151]
    特に C-z を fg に割り当てているが、これによって出入りしてプログラムが終了した後には
    やはりプロンプトを再計算したいという気がするのである。
    特に、何も実行しないコマンドであっても次の行に表示上移動するのだから。

    現在の実装では ble-edit/prompt/update で
    local version=$COLUMNS:$_ble_edit_LINENO を見てプロンプトの再計算が必要かどうか判定している。
    LINENO だけではなくて ble/widget/execute-command でも何かカウントするべきなのでは。
    ble/widget/.insert-newline で _ble_edit_lineno++ する事にした。
    ble/widget/.newline は _ble_edit_lineno++ _ble_edit_LINENO++ の両方を実行する。
    ble/widget/.insert-newline は片方だけ実行するという事にした。
    _ble_edit_LINENO が変化する箇所は他にはないので _ble_edit_LINENO
    の代わりに _ble_edit_lineno を prompt の version 判定に用いて問題ないだろう。

  * highlight: 入力した URL の最初の // だけが着色されるのは変な感じがする [#D1150]
    http:// の形式をしている時には : 区切りにするのをやめるべきなのではあるまいか。
    →URLの形式の単語を着色する所まで実装した。

2019-07-22

  * bash 2 でロードしてみた所 ble.sh がロードされないのは良いが、 [#D1149]
    何のメッセージも表示されない。と思ったら set -x 対策として
    標準出力・エラー出力を封じているのだった。
    ble.sh からのエラーメッセージだけは表示する様に修正する。

    他に builtin コマンド (非標準) を使っている所を使わない様に修正した。

2019-07-21

  * 以下の設定に関してはもう ble.sh 側で勝手に弄っても良いのではないか? [#D1148]
    どうせ bashrc の一番始めに書いてもらう事になっている。

    ((_ble_bash>=40100)) && builtin bind 'set skip-completed-text on'
    ((_ble_bash>=40300)) && builtin bind 'set colored-stats on'
    ((_ble_bash>=40400)) && builtin bind 'set colored-completion-prefix on'

  * Cygwin console のバグについて [#D1147]

    - Cygwin は ED(2) "ESC [ 2 J" が駄目
    - Cygwin は RI の振る舞いがおかしい
    - Cygwin は最終行での DL "ESC [ M" が駄目
    - Cygwin は CUF() の行き先が行末 $ の時に何処にも移動しない。

    これは最新の cygwin を確認したら全て直っていた。
    但し、TERM=xterm-256color になっているので区別はできる。
    また最新版でも ED(2) はカーソル位置を変える、等の振る舞いの違いはある。
    何れにしてもこれは別の場所で扱う事にする。

  * blehook: blehook に hook 名を指定しても無視される [#D1146]
    これは単純なミスだった。修正した

  * blehook: 初期化の順序によって load hook が実行されない事がある [#D1145]

    % cygwin で M-b 等が全部 ESC b と解釈されている
    Cygwin は関係なかった。

    [状況整理]

    | 0.4.0-devel1+30cc31c の既存のセッションでは再現していない
    | 0.4.0-devel1+362ab05 の既存のセッションでは再現している。
    | 最新の version でも再現している。
    | 確かに checkout して比較してみるとそれぞれその通りになった。
    | 二分法で絞り込む。2ea7cfd は未だ大丈夫である。
    | caa46c2 はもう駄目になっている。af758e5 も駄目。
    | af758e5~ だと大丈夫である。という事は犯人は af758e5 である。
    | .inputrc の読み取りタイミングの変更で駄目になった。
    |
    | 特に bind で ESC から始まる何かを登録するともう駄目なのだろう。
    | と思ったがそれを削除しても問題は再現するままである。
    | --noinputrc を指定したら再現しなくなった。
    |
    | うーん。ble-bind -m vi_imap -P の結果を見比べた所、
    | そもそも inputrc で ESC で始まる物が登録されていた場合、
    | hook が呼び出されていない? という事の様だ。うーん。
    | つまり inputrc の中で vi_imap がロードされて、
    | その後で blerc などの設定が適用されている?
    |
    | というのも変だ。そもそも mshex による設定も消えてなくなっている。
    | という事を思えばまた別の理由によって load hook
    | が呼び出されなくなっているという事か。
    |
    | 実際に試してみるとやはり load hook が起動された瞬間には未だ
    | 登録されていない様である。
    | うーん。そもそも mshex の load hook も定義されていない。
    | どのタイミングで load hook が呼び出されているのだろう…。

    しなければならない事は (1) 現状で何が起きているかの解明と、
    (2) load_hook に関しては既にロード済みであればすぐに実行する、
    という仕組みを整えるという事。

    調べてみるといきなり keymap_load が実行されている様子だ。
    どうも blerc の中で keymap_load, keymap_vI_load が実行されている。
    確かに blerc の中で bind を呼び出しているのでそうなるのは分かる。
    以前同じ事が起こっていなかったのは bind 呼び出し時に keymap 初期化をする
    というのを最近追加したからである。

    [対処]

    どの様に対処するのかという事。

    * 少なくとも load hook に関しては既に load 済みであれば
      その場で実行する事にする。

      * ok: どの様な関数名にするのが良いだろうか。これは emacs を参考にする。
        そういう関数名があった筈と思ったが思い出せない。
        →探したら mwg-doxygen.el で使われていた eval-after-load である。

        ble/util/eval-after-load という関数名にでもするか。
        或いは blehook/eval-after-load の方が良いだろうか。
        取り敢えず後者で定義する事にしようかと考える。

      * done: そして blehook/eval-after-load を実行する為には
        それが既に実行されたかどうかという情報を記録しておく必要がある。

        a それ専用の変数を定義しておくか。
          変数名をどうするのかという事と変数の汚染が気になってしまう。
        b 或いは辞書にするか。
          辞書にすると bash-4.0 未満に対する対応を別に実装しなければならないので面倒である。
        c 或いは変数の代わりに関数を定義するか。
          うーん。関数を定義する方法だと reload の時に関数を削除するのが面倒である。
          然し変数で記録したとしてもそれを消去する必要性を考えたら面倒である事は変わりない気はする。

        取り敢えず変数に記録する事にする。OK

      * done: 変数名を変更する事にした。変更した。
        取り敢えず blehook_h_NAME に handlers を格納し、
        blehook_c_NAME にこれまでの呼び出し回数を格納する事にした。

      * done: というか今思ったのだが blehook に関して、
        blehook_* という変数名にしておく必要はあるのだろうか。。

        bleopt の場合には source する前に何か値を予め設定しておきたい可能性もあった。
        然し、blehook の場合には結局 def.sh で =() として初期化してしまうのだという事を考えると、
        公開変数にしておく意味がない。或いは、既存の hook を保持する事にするか?
        然し、blehook は上書きではなくて累積なので既存の hook を残しておくと、
        だとすれば ble-reload の時にどんどんと hook が累積して行く事になり駄目。

        従って、これに関しては blehook は _ble_hook_ 的な変数名に改名するのが賢明だろう。
        そうは言いつつもそんなに影響は広範には亘らないので変更は少なくて済みそうである。
        今慌てて修正しなくても後でゆっくり名前を変えれば良いという事の気がする。

        結局変数の使い方を変えたので一緒に名前も変更する事にした。

      * 同時に _ble_version という変数も用意する事にした。
        単一の変数で大小比較をできる様にしたスカラー値。

    これで枠組みを変更してしまったので既存の枠組みを使っている
    人に対する警告の様な物を表示するべきなのではないだろうか。
    然し、そのチェックは何処で実行するのか。
    idle で実行すれば良い気がする。
    idle が実行されるのは keymap 関係はロードし終わった時の筈だから。
    と思ったが単に blerc を読み込んだ後で実行すれば良い気がする。
    bashrc の中で設定している人に関しては関知しない事にする。

2019-07-20

  * cygwin: 未だ cygwin での振る舞いが変である [#D1144]
    行末補正が効いていない。というか塗りつぶされてしまう。
    _ble_term_xenl=1 にしてみると余分な改行が入ってしまう。

    取り敢えず調査を継続する事にする。
    そもそも行末補正の為に何を出力しているのだったかを確認する。

    先ず eol mark を出力して restore cursor する。
    実は eol mark は関係無さそう。
    その後で行頭から CUF で COLUMNS-3 文字進む。
    更に二文字挿入してから CR で行頭に戻る。という事をしている。
    うーん。実際にその様に制御シーケンスを出力させるとちゃんと動いている。
    分かった事は printf A だと行末補正が効くが printf AAA だと効かないという事。
    もっと調べると丁度 3 文字の時にだけ変な事が起こる…。

    →printf で再現できた。
    $ printf 'AA\e[154C12\rX\n'
    $ printf 'AAA\e[154C12\rX\n'  # 駄目
    $ printf 'AAAA\e[154C12\rX\n'

    $ printf 'AAA\e[154CX\r\nhello\n'
    うーん。分かった。丁度 $((COLUMNS+1)) 列目に移動しようとすると
    "動かない" という動作になっている…。
    この場合どの様に対処したら良いのだろうか…。

    二つの対処が在る。先ず Cygwin の側での何故その様になっているのかの解明と、解決。
    それから ble.sh の側での対策である。Cygwin の側は後で考える事にして、
    ble.sh の側でどの様にして対策するのかという事。
    a うーん。一つの方法は現在位置を問い合わせてそれに応じて出力するかどうかを決定するという物。
      正直この方法は採用したくない。ユーザによる入力と前後してしまうからである。

    丁度ぴったり移動する場合でもちゃんと前に移動する方法はあるのだろうか。

    b 例えば一文字ずつ前に進む? うーん。酷いやり方だが他に方法がないのであれば仕方がない。
      これが現実的な解という事になってしまう。例えば 157 列あるのだとすれば、
      157 x 3 (\e[C) = 471 bytes 出力する事になる。

      - 移動に使える別のシーケンスは存在するだろうか。

    c 或いは b の方針で一文字ずつではなくて2文字4文字等と組み合わせて何とかならないか…。
      然し現在位置に対して何の仮定も置けないのだとすると、
      2文字以上を実行する時は常に失敗の危険性がある…。
      と思ったが現在位置が問題の位置より左にあれば大丈夫だし、
      問題の位置より右にあれば其処で失敗しても後の CUF で十分に末端に到達できる。
      とにかく目的は末端に到達する事なのである。末端に到達できさえすれば良い。

      兎に角目標は"少なくとも N 文字前進する"という事である。
      取り敢えず N = N/2 + (N-N/2) に分けて、
      取り敢えずN/2進めれば残りは "(N-N/2)文字前進する" という同様の問題に帰着できる。
      一気に N/2 文字進む事ができれば余り沢山の文字列を出力しなくても済む。

      今、残り前進可能数が R とする。またN>1であると仮定する。RとNの大小関係は分からない。

      a a=N/2進むとすると、
        丁度 a==R+1 の時に問題になってしまう。
        この時 R = N/2-1 であるから、R < N/2 <= N-N/2 なので
        後半の "N-N/2前進する" というステップに於いて、
        十分に行末まで達する事が可能である。

      b 代わりに N-N/2 + N/2 に分ける場合はどうだろうか。
        つまり取り敢えず a=N-N/2 だけ進む。
        N-N/2==R+1 の時に問題が発生してこの時 R = N-N/2-1 である。
        Nが奇数の時 R = N-N/2-1 = N/2 である。
        Nが偶数の時 R = N/2-1 である。従って、 R <= N/2 である。
        なのでこの様にしても十分に行末まで達する事ができる。
        こちらの方が効率が良さそうである。

      つまり、N文字前進したい時、取り敢えず ceil(N/2) だけ進んで
      floor(N/2)前進したいという問題に帰着できる。
      半々になるので log の長さの文字列で大丈夫になる。

    ? ここで気になるのが何故 margin を "  " と二文字にしているのかという事。
      これは何らかの理由でその様にしたのだったか。blame してみる。

      $ g blame src/edit.sh
      5084b02a ble-edit.sh (Koichi Murase 2018-08-31 13:40:32 +0900 3846)   ble/canvas/put.draw "  $_ble_term_cr$_ble_term_el"
      $ g blame 5084b02a~ -- ble-edit.sh
      650b3f14 (Koichi Murase 2015-03-04 01:17:38 +0900 2984)   ble-edit/draw/put "  $_ble_term_cr$_ble_term_el"
      $ g blame 650b3f14~ -- ble-edit.sh
      ^c68412b (Koichi Murase 2015-02-09 03:13:19 +0900 2100)   echo -n "$_ble_term_sc${eof}$_ble_term_rc((xenl?cols-2:cols-3))C  ^M"
      これが initial commit である。つまり一番初めから空白二文字でやっていた。git では追跡できない。

      #D0004 を読んだらちゃんと説明が書かれていた。これは xenl の時に
      "(1)行末に移動する(2)次の行に移動する"という具合に2文字必要だからなのであった。

      つまり xenl でない時には気にしなくても良いという事である。
      特に Cygwin 専用のコードを書く上では考えなくて良いという事である。

  * cygwin terminal で久しぶりに動かしてみたら様子がおかしい [#D1143]
    一番下の行で -- INSERT -- が残った儘になってしまうし、
    vbell が表示される度に描画位置がどんどんずれていく。
    うーん。全然駄目だ。実は 0.1 の時からずっと動いていなかったらしい。

    試してみて分かった事は、cygwin terminal では、
    1. RI 及び IND は必ず其処に行を挿入してしまうという事
      本来は画面の一番上にいる時にのみ行を挿入するべきなのである。
    2. DL で現在行以降の行数以上を引数に指定すると何も起こらないという事。
    3. 更に \e[$((LINES+1))H すると画面の
      一番下に行って IND したのと同じ効果がある…。

    さて対策或いは代替手段はあるだろうか。
    効率の悪い方法だったとしても TERM=cygwin の時にだけそれをすれば良い。

    [Cygwin の振る舞いについて調査]

    | というか cygwin に patch を送りたい気分ではある。
    | cygwin のソースコードを確認してみる。
    | 以前 cygwin の release note で DECSCUSR の事が書いてあった事を思い出して
    | newlib-cygwin/winsup/cygwin の中で grc DECSCUSR したら直ぐに見つかった。
    |
    | $ grc DECSC
    | ./fhandler_console.cc:1980:    case 'q': /* Set cursor style (DECSCUSR) */
    | ./fhandler_console.cc:2642:       else if (*src == '7')         /* DECSC Save cursor position */
    |
    | というか cygwin をビルドし直した所でそれをテストするのは面倒である。
    | うーん。或いは bash を同じディレクトリに入れてダブルクリックすれば良いだけか?
    |
    | * IL,DLのコードは以下の通り。
    |
    |   | case 'L':                           /* AL - insert blank lines */
    |   |   n = con.args[0] ?: 1;
    |   |   cursor_get (&x, &y);
    |   |   scroll_buffer (0, y, -1, -1, 0, y + n);
    |   |   break;
    |   | case 'M':                           /* DL - delete lines */
    |   |   n = con.args[0] ?: 1;
    |   |   cursor_get (&x, &y);
    |   |   scroll_buffer (0, y + n, -1, -1, 0, y);
    |   |   break;
    |
    |   而もILをALとtypoしている? 然し ICH を IC
    |   と書いていたりもするから何か古い略号なのかもしれない。
    |   肝心の部分は恐らく 0..y+n を y だけ scroll するという意味?
    |   本来は y..$ を n 行スクロールするべきの気がする。
    |
    |   振る舞いを見るとどうも y+n が範囲外の時には何も起こらないという事の様だ。
    |   でもよく分からない。scroll_buffer の実装を観察しようか。
    |
    |   | void __reg3
    |   | dev_console::scroll_buffer (HANDLE h, int x1, int y1, int x2, int y2,
    |   |                             int xn, int yn)
    |   | {
    |   | /* Scroll the screen context.
    |   |    x1, y1 - ul corner
    |   |    x2, y2 - dr corner
    |   |    xn, yn - new ul corner
    |   |    Negative values represents current screen dimensions
    |   | */
    |   |   SMALL_RECT sr1, sr2;
    |   |   CHAR_INFO fill;
    |   |   COORD dest;
    |   |   fill.Char.UnicodeChar = L' ';
    |   |   fill.Attributes = current_win32_attr;
    |   |
    |   |   fillin (h);
    |   |   sr1.Left = x1 >= 0 ? x1 : dwWinSize.X - 1;
    |   |   sr1.Top = y1 >= 0 ? y1 : b.srWindow.Bottom;
    |   |   sr1.Right = x2 >= 0 ? x2 : dwWinSize.X - 1;
    |   |   sr1.Bottom = y2 >= 0 ? y2 : b.srWindow.Bottom;
    |   |   sr2.Top = b.srWindow.Top + scroll_region.Top;
    |   |   sr2.Left = 0;
    |   |   sr2.Bottom = (scroll_region.Bottom < 0) ?
    |   |     b.srWindow.Bottom : b.srWindow.Top + scroll_region.Bottom;
    |   |   sr2.Right = dwWinSize.X - 1;
    |   |   if (sr1.Bottom > sr2.Bottom && sr1.Top <= sr2.Bottom)
    |   |     sr1.Bottom = sr2.Bottom;
    |   |   dest.X = xn >= 0 ? xn : dwWinSize.X - 1;
    |   |   dest.Y = yn >= 0 ? yn : b.srWindow.Bottom;
    |   |   ScrollConsoleScreenBufferW (h, &sr1, &sr2, dest, &fill);
    |   | }
    |   |
    |   | inline void
    |   | fhandler_console::scroll_buffer (int x1, int y1, int x2, int y2,
    |   |                                  int xn, int yn)
    |   | {
    |   |   con.scroll_buffer (get_output_handle (), x1, y1, x2, y2, xn, yn);
    |   | }
    |   |
    |   | inline void
    |   | fhandler_console::scroll_buffer_screen (int x1, int y1, int x2, int y2,
    |   |                                         int xn, int yn)
    |   | {
    |   |   if (y1 >= 0)
    |   |     y1 += con.b.srWindow.Top;
    |   |   if (y2 >= 0)
    |   |     y2 += con.b.srWindow.Top;
    |   |   if (yn >= 0)
    |   |     yn += con.b.srWindow.Top;
    |   |   con.scroll_buffer (get_output_handle (), x1, y1, x2, y2, xn, yn);
    |   | }
    |
    |   コメントを読んで引数の意味が分かった。
    |   結局矩形 (0,y+n)-($,$) に関して、左上を (0,y) に持って行きなさい、
    |   とそういう指定の仕方をしているのである。
    |   そして基本的にはそれを ScrollConsoleScreenBufferW に渡している。
    |   実はこれは Win API である。
    |   https://docs.microsoft.com/en-us/windows/console/scrollconsolescreenbuffer
    |   これは BitBlt 的なそういう感じの API なのである。
    |   従って、もし移動する元の rectangle が潰れていると何も起きないという事だろうか。
    |
    |   うーん。これを直すとすると、移動する矩形が潰れる時には代わりに消去を行うという事。
    |   もしくは、スクロールした後の部分を明示的に空白で埋めるという事。
    |   余り綺麗な方法ではない。単に cygwin にバグ報告するだけに留めて置くか。
    |
    | * RI の方に関しては…
    |
    |   何と単純に "scroll down" として実装されている…。
    |
    |   | else if (*src == 'M')         /* Reverse Index (scroll down) */
    |   |   {
    |   |     con.fillin (get_output_handle ());
    |   |     scroll_buffer_screen (0, 0, -1, -1, 0, 1);
    |   |     con.state = normal;
    |   |   }

    まとめると。Cygwin はスクロールには Win API を使っていて、
    スクロール対象が潰れてしまう時は DL が効かない。
    また RI に関しては完全に1行スクロールとして実装されてしまっている。

    Cygwin のこの様な変な振る舞いを逆に利用して何かいい感じに処理できないだろうか。
    \e[H で範囲外に移動できてしまうという事を思えば実は \e[A でも範囲外に移動できるのでは?
    と思ったらそうだった…。RI に関してはそれで何とかする事にする…。
    但し、本当に一番始めに起動した時には \e[A で上に行く事ができない。RI なら上に行く事ができる。
    仕方がないので、\e[A に補正する時に RI で上に行を挿入してしまう事にした。


    [Cygwin の識別に関して]

    | 一応 Cygwin terminal の DA2R を見ておく事にする。
    | 67;201102;0 であった。うーん。これは version によって変わったりするのだろうか。
    | Google で検索してみる。どれだけ安定しているのか。と思ったら検索すると一件として当たらない…。
    | Cygwin DA2 で検索しても有用な情報は出てこない。というか直接ソースコードを見れば良いのか?
    | 以下の行が当たった。
    |
    | ./fhandler_console.cc:2204:     __small_sprintf (buf, "\033[>67;%d%02d;0c",
    |
    | 実際にソースコードを当たってみると…
    | うーん。そもそも 67 は Cygwin 固有の様である。
    | というか contra で採用した 67 と被っている気がする。。
    | まあそれは後で考える事にする。
    |
    |     /* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
    |        to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
    |        and cygwin version for terminal version. */
    |     __small_sprintf (buf, "\033[>67;%d%02d;0c",
    |                      CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
    |
    | マクロの値を確認すると…。
    |
    |   ./include/cygwin/version.h:13:#define CYGWIN_VERSION_DLL_MAJOR 3001
    |   ./include/cygwin/version.h:14:#define CYGWIN_VERSION_DLL_MINOR 0
    |
    | ぜんぜん違う値である気がする。blame で追跡してみる。
    |
    |   $ g blame -L 2200,2300 fhandler_console.cc
    |   ...
    |   8fd4bd2bf1 (Corinna Vinschen   2009-12-19 15:37:10 +0000 2203)     and cygwin version for terminal version. */
    |   8382778cdb (Takashi Yano       2019-04-01 00:47:47 +0900 2204)  __small_sprintf (buf, "\033[>67;%d%02d;0c",
    |   8382778cdb (Takashi Yano       2019-04-01 00:47:47 +0900 2205)                   CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
    |   8fd4bd2bf1 (Corinna Vinschen   2009-12-19 15:37:10 +0000 2206)       else
    |   ...
    |
    | 何と最近書き換わっている…。しかも日本人…。
    | http://cygwin.1069669.n5.nabble.com/PATCH-Reworks-for-console-code-td145437.html#a145459
    | ここに記録が残っている。巨大な変更と一緒にしれっと DA2 を書き換えている。
    | 何れにしても 24bit color が cygwin で使える様になったのだろうか…。
    |
    | と思ったがただ単に改行が追加されただけの様である。
    | というか体裁を勝手に変更するというので追跡をしにくくするのはやめて欲しい。
    | 而も別の変更に紛れ込ませてそれを実行するというのが行儀が悪い。やばい。
    | 何れにしても、その前の変更は 2009 年なので大分昔である。
    |
    |   $ g blame -L 1600,2300 8382778cdb~ -- fhandler_console.cc
    |   ...
    |   b86f999af1 (Christopher Faylor 2011-06-06 05:02:13 +0000 2078)  /* Generate Secondary Device Attribute report, using 67 = ASCII 'C'
    |   b86f999af1 (Christopher Faylor 2011-06-06 05:02:13 +0000 2079)     to indicate Cygwin (convention used by Rxvt, Urxvt, Screen, Mintty),
    |   8fd4bd2bf1 (Corinna Vinschen   2009-12-19 15:37:10 +0000 2080)     and cygwin version for terminal version. */
    |   8fd4bd2bf1 (Corinna Vinschen   2009-12-19 15:37:10 +0000 2081)  __small_sprintf (buf, "\033[>67;%d%02d;0c", CYGWIN_VERSION_DLL_MAJOR, CYGWIN_VERSION_DLL_MINOR);
    |   8fd4bd2bf1 (Corinna Vinschen   2009-12-19 15:37:10 +0000 2082)       else

    [実装]

    結局 DA2R が ^67;[0-9]{3,};0$ の形であれば良さそうなのである。
    というかこれは何処で判定すれば良いのだろうか…。

    DL に関してはどの様にしようか。
    使用箇所を確認すると ble/canvas/put-dl.draw からしか使っていない。
    そして ble/canvas/put-dl.draw は複数の箇所から使われている。
    うーん。ble/canvas/put-dl.draw のレベルで何か修正はできるだろうか。
    つまり正しい DL の振る舞いをそれ単体で模倣する事ができるか、という事。

    うーん。DLする前にDLされる予定の行を消去しておけば良いのでは。。
    つまり EL を実行してしまえば良いのである。と思ったが EL は行数指定による消去ではない。
    つまり、各行に移動して EL を実行しなければならないので面倒である。
    範囲を消去する制御機能は他にあったろうか。他には CSI J (ED) ぐらいしかない。
    然し、これは全消去的になってしまうので駄目。

    各行に移動するとしても cygwin の \e[B 等の移動は勝手にスクロールを引き起こしてしまう。
    と思ったが却って都合が良いのかもしれない。
    同じ回数 \e[A を呼び出せばちゃんと戻ってくるという事だから。

2019-07-18

  * blehook: zsh の add-zsh-hook で提供している物を提供できるのではないか [#D1142]
    https://qiita.com/mollifier/items/558712f1a93ee07e22e2

    zsh の chpwd について試してみたが cd を実行する度に実行される様だ。
    つまりコマンド実行中にN回ディレクトリを移動すればN回実行される。
    正直便利なのかよく分からない。中で cd して処理をしてまた元のディレクトリに戻る、
    という様なシェル関数を書いたりすると、例えば chpwd に ls を仕掛けていたりすると
    何度も ls が表示されて悲しい事になってしまうのではないか。

    それよりはまたプロンプトに戻ってきた時に chpwd が呼び出される方が便利である。
    他に addhistory 及び periodic が存在する。後者は存在意義が不明。

    * done: trap_exit は exit に改名して良い気がする。対応した。

    * done: ユーザ向けと内部向けの hook が混ざって分かりにくいので
      ユーザ向けの hook は大文字で提供する事にした。

    * done: zshaddhistory は履歴に追加するかしないかを終了ステータスで指定するらしい。
      →対応した。と思ったが思うように動いていない。と思ったら
      blehook/invoke するのを大文字にするのを忘れていた。

    * ok: periodic については対応しない事にした。
      対応したければ各自で時刻を記録すれば良い。

  * 2019-07-09 global: 148 と 147 の区別をしたい [#D1141]
    現在の実装では広範に亘って 148 が用いられているが、
    実は 148 は二種類あって has-input の時と、
    或いは唯単にユーザの入力を待つ状態というのがある。
    更に 148 の中でも実際に read で読み取れる状態と、
    或いは ble.sh の枠組みの中に未処理のデータが残っている場合がある。

    % というか async で呼び出すのは idle.do の中からだけなので、
    % 実は ble-decode/has-input ではなくて ble/util/is-stdin-ready を使うべきでは。
    % と思って ble/util/idle を調べてみると ble/util/idle/IS_IDLE を使っている。
    % ble/util/idle/IS_IDLE は decode.sh で上書きされていて、
    % 其処の説明によると decode 途中の状態の場合にはすぐに続きのバイトが来るはず、
    % という論理になっている様だ。うーん。何だか分からないが取り敢えず
    % ble/util/idle/IS_IDLE を使っておくのが綺麗の様に思う。

    取り敢えず、idle 処理の中でどのようにするかというと。
    ble/util/idle/IS_IDLE じゃなくなったら return 148 するという事。
    それ以外の理由で一旦処理を停止するという時には return 147 するという事。

    また ble/util/idle/IS_IDLE は decode に於いて
    has-input で上書きされているがこれが妥当なのかについても考察の必要がある。
    そもそも ble/util/idle.do が呼び出された時点で中途半端な状態で
    入力がずっと来ないという事はないのではないかと思われるのである。
    これは ble/util/idle.do の呼び出し箇所を一つ一つ確認していく必要がある。

    [変更に関して]

    - decode.sh では実は 148 か 147 かというのはチェックしていない。
    - vi.sh における 148 は全てユーザーの次の入力を待つ為の物だから
      実は全て 147 である。
    - 逆に complete.sh における 148 は全て中断の為の物だからそのままで良さそう。
      ble/complete/menu#start に関してだけは 147 の様な気がする。
      但し現状ではこの関数は誰も使っていない。
      ble/complete/sabbrev/expand も 147 である。
    - history.sh の中は全て 148 である。
    - vim-surround.sh は全部 147
    - edit.sh は検索関連は 148 で他は 147 だった。
    - util.sh は idle/fiberchain は 148 で、CPR request は 147 である。

  * highlight: / で区切られた関数名の着色 [#D1140]
    / より前の部分をディレクトリ名と解釈しようとして、
    然しディレクトリが存在しないので黒色になってしまう。
    これは簡単な修正だった。

  * history 移行: blehook の枠組みを整える? [#D1139]
    bleopt と同様に。既存の hook に関しては変数名を変更する等して移行する。
    _ble_decode_char_hook 等に関しては揮発性の hook で少し性質が異なるので関係ない。

    取り敢えず雑多の hook を統一的に扱える様にした。

    * blehook の引数の指定の仕方は将来の事を考えると
      bleopt や ble-sabbrev と同じ様にした方が良いのでは。
      変更する事にした。対応した。

  * highlight: declare の引数でブレース展開が着色されていない [#D1138]
    解析の途中状態を確認してみると ARGVR になっている。

    * どうもこれは check-brace-expansion の実装が悪い気がする。
      inactive になる条件として文脈値が以下の何れかという事になっているが。

        CTX_CONDI CTX_CONDQ CTX_RDRS CTX_VRHS
        CTX_ARGVR CTX_ARGER CTX_VALR

      今試してみると declare a={a,b,c} でも a=([0]={a,b,c}) でも
      ブレース展開は実施される様だ。更に eval a={x,y,z} でもブレース展開が実施される。
      興味深い事に a=([0]={a,b,c}) でブレース展開が実施されると要素 0 に対する代入ではなくて、
      '[0]=a' '[0]=b' '[0]=c' という三つの要素を持った配列が初期化される。
      因みに a=([0]=a [0]=b [0]=c) とやるとちゃんと要素 0 に対する代入になっている。
      a=([{0..10}]=c) とするとちゃんと 11 個の要素の全てに c を代入するという意味になる。
      値の側でブレース展開を実行した時にだけ変な事になるのだ。

      取り敢えず上記の文脈値の内の最後の三つに関してはブレース展開無効化を解除する。

    * もう一つの疑問は declare -p ble_{a,b,c}_ とすると、
      = も来ていないのに何故か { から右辺になってしまうという事である。
      うーん。ARGER の時や VALR の時にはちゃんと判断できているという事を思うと、
      ARGVR の時にすぐに ARGVR になってしまうのは意図的な物だろうか。
      例えば着色を変数の色ではなくて黒色に変えるという事を目的とした。

      ble/syntax:bash/check-variable-assignment の以下の部分が原因である。
      確かにこれは何かの理由があってこの様にした記憶がある。
      記録には残っているだろうか。うーん。見つからない。

      | if ((ctx==CTX_ARGVI||ctx==CTX_ARGEI)); then
      |   suffix="$suffix|\[?"

      試しにこの部分を除いてみると今度は単語着色が為されなくなる。
      この部分が書かれたのは 1823c540 で 2017-11-27 23:46:09 である。
      確認すると #D0636 で ARGVR の導入について書かれている。

      うーん。試しに ARGVR ではなくて ARGVI の儘になるようにしてみたが、
      着色としては余り変わっていない。a{1..3}b=10 とした時に
      b の位置まで変数として着色するのかどうかというのが問題である。
      因みに a{1..3}b=~ とした時にはチルダ展開とは見做されなかった。
      つまり a{1..3}b=~ は bash の構文解析としては変数代入ではないのだ。
      その様に考えると a までで ARGVR に変化してしまうという振る舞いでも
      まあ矛盾はないのかなという気はする。寧ろ b まで着色して
      = 以降を右辺として扱うという事だとチルダ展開が有効になってしまう。
      (チルダ展開が有効でない = の右辺) の様な文脈を無駄には作りたくない。
      従って即座に ARGVI は ARGVX に変換するというので良い気がする。

      結局これに関しては現状のままという事にする。

2019-07-17

  * history: PREFIX_history_onleave -> _ble_history_onleave [#D1137]
    vi.sh は onleave_hook に登録しているがこれは
    [[ ! $_ble_history_prefix ]] の時にしか対応していないのではないか。
    観察した。実は全ての prefix の場合にこれを実行しても良い気がする。
    というかそもそも PREFIX_history_onleave を PREFIX 毎にする理由は何か。
    実は全体に対して登録して良い気がする。そして、
    PREFIX 毎の操作をしたければ PREFIX を調べれば良いのである。
    この修正もそんなに難しくなかった。簡単である。

  * 2019-07-09 history 移行: 検索機能だとか、或いは他の履歴の管理などに関しては [#D1136]
    追々 history.sh に移行する事にしようと考える。
    取り敢えず、今回の移行では bash history との接続部分だけにしておく。

    Bash のコマンド履歴と、その他の独立な履歴の管理について。
    移行するにしても名前を分かりやすくしたい。
    Bash のコマンド履歴を ble/history と名付けてしまっている。
    一方で、その他の独立した履歴およびそれらを統合的に扱う仕組みをどう名付けるか。
    同じ様に ble/history という名前にしてしまうと両者が混ざってしまって厄介である。

    コマンド履歴と同期した物を ble/history のままにして、
    新しい枠組みを ble/hist, ble/history/general 等の別名か子として定義するか。
    或いは、コマンド履歴と同期した物を ble/history:edit だとか、
    或いは ble/history:bash 等のようにするか。これが良さそう。

    さて移動するとしてもどの関数を移動したら良いだろうか。

    - 先ず履歴検索ルーチンに関しては移動しなければならない。
      と思って調べてみたが実は関数二個だけで閉じていた。238行しかない。
    - 他に prefix 関連の操作を移動する事にした。

    やってみると意外と簡単にできた。ちゃんと疎結合になっていたので
    多少書き換えるだけで簡単に分離する事が可能だった。

    x fixed: bash:history にしたら無限にエラーメッセージが表示される様になってしまった。
      これは ble/util/idle に登録するコマンド名に : を使えないという事だろう…。

    x 更に実は履歴が全く動かなくなっていた。うーん。
      どうも set-index がちゃんと動いていないという事?
      OK これも修正した。

  * decode: DA1 応答の読み取りに失敗して変な文字列が入力される (reported by miba072) [#D1135]
    https://github.com/akinomyoga/ble.sh/issues/28

    どうも DA2 に対して DA1 応答が為されている様である。DA1 に応答する様に修正した。

    後、よく考えたら認識できないキーシーケンスはその時点で破棄するべきでは。
    と思ったがデフォルトで破棄する設定になっている様な…。
    或いは ble-0.3 の時点では状況が違っただろうか。
    どうも調べると 0.3 では CSI seq に関してはちゃんと処理していない様だ。
    うーん。色々修正しなければならなそう。

    念の為、以前 0.4 で何処で修正したのかを確認する。
    2019-04-01 ab1b8b0 である。#D1056 だ。
    うーん。ab1b8b0 を覗いたら別に他に影響も無さそうなので cherry-pick してしまう事にした。

2019-07-16

  * highlight: ファイル名のディレクトリ部分の着色で、 [#D1134]
    ディレクトリ名にパス名展開があると正しく着色されない。
    と思ったら理由が分かった…。

    * fixed: 一番最初に一致した物がディレクトリ名でないという事なのだ。
      ディレクトリまたはシンボリックリンクだった時にのみ着色をしているのが行けないのである。
      うーん。これに対処する為には / も含めて展開する必要があるのではないか。
      つまり単語の区切れ目を / の直前ではなくて / の直後にする必要があるのである。
      然し今の振る舞いになっている理由があった筈である。
      という事を考えるとオプションで制御する様にする?

    x fixed: 今度は */a.txt について */a.t 等の様に途中まで入力した状態では
      全体がエラー着色されてしまうという事が分かった。
      と思ったが、これは実は failglob による問題である。
      failglob であっても途中のディレクトリ名まで一致している時には
      ディレクトリ名を着色しても良いのではないだろうか。

    x supported: 更にコマンド名の時にもディレクトリ部分に着色がされていない。
      これについても対応した。

  * highlight: コマンド名は : で区切った着色をしても仕方がないのでは [#D1133]
    現状では例えば : を含む関数名をクォートなしで入力するとエラー着色になる。

    ? ok: そもそも : を含むコマンド名を補完する事は可能だったか
      →確認したところ、補完に関しては : があってもちゃんと動作する様だ。
      : 以降の文字列に基づいた補完が起動するという事もなくて、
      始めから全体に対する補完が試みられているので問題ない。

    着色をするコードが何処にあったのかを確認する。
    これは ble/highlight/layer:syntax/word/.update-attributes/.proc の中で
    取り敢えず単語の種類に依らずに単語の開始位置をずらしているのが良くない。
    特に、ble/syntax:bash/simple-word/locate-filename "$wtxt" を呼び出して処理している箇所。
    これは文脈依存で実行する様にしなければならない。

    更にコマンド名の補完の場合には : による区切りは有効でない。
    従って : まで escape する必要性は実はない。
    core-complete の中を調べて見ると quote-insert の中で殆どは escape を実行している。
    その他の箇所では common-prefix で曖昧一致をした時に escape をしている。
    曖昧一致の時は流石にエスケープしても仕方がないと認める事にする。

    取り敢えず quote-insert の方を調べる。quote-insert の呼び出し元を探すと、
    結局全て action:action/initialize の中からである。
    特に action:command の時に関しては直接 quote-insert を呼び出している。

2019-07-14

  * edit: BUG bash-3.2 で "echo \改行" と入力するとエラーメッセージが出る [#D1132]
    bash-3.2: syntax error near unexpected token `"${@:2}"' というメッセージ。
    然し、その様な物が書かれている箇所は限られている。

    [問題位置特定]

    一つの場所は以下の所。何が文法的な問題が起こるとも思われない。
    実際にここを &>/dev/null して見たが何も変化はなかった。
    というかよく考えたらこれは bash-3.0 用のコードなので関係ない。

    function ble/util/sprintf {
      local -a args; args=("${@:2}")
      ble/util/assign "$1" 'builtin printf "${args[@]}"'
    }

    その次の箇所は ble/util/fiberchain#resume/.core の中である。
    これも同様に配列の初期化をしているだけなので文法的にどうという
    事がある用には思われない。実際に &>/dev/null してもメッセージに変化はない。

    他は decode 関係しか無いので多分関係はないだろう。

    では何処から ${@:2} という文字列が出てきたのだろう。
    $ grep -E '"\$\{@:2\}"' ~/.bash_history としても結果は
    echo "${@:2}" という1行だけである。これはこのデバグの為に実行したコマンドだ。

    仕方がないので次の方策として絞り込みをかける事にする。
    先ず auto-complete と menu-filter を切る…と思ったが、
    よく考えたら bash-3.2 なのでそもそも切られている。

    振る舞いを見るとちょうど "echo \改行" の状態の時にのみ発生する様である。
    続きを記述するとそのメッセージは発生しなくなる。更にカーソル移動では発生しない。
    ble_debug=1 で見ても文法構造的に何か偏という事はない気がする。

    ble/syntax/parse &>/dev/null してもメッセージは表示されたので parse は関係ない。
    ble/textarea#update-text-buffer &>/dev/null で何もでなくなったのでこの中である。
    ble/highlight/layer/update "$text" の中である。
    "ble/highlight/layer:$layer/update" "$text" "$player" の中で起こっている。
    LEVEL=1 である。syntax だった。
    ble/highlight/layer:syntax/update-word-table &>/dev/null の中だった。
    ble/highlight/layer:syntax/word/.update-attributes &>/dev/null の中である。
    ble/syntax:bash/simple-word/evaluate-path-spec "$wtxt" / "$opts" の中だ。
    ble/array#push spec "$s" なんとこれが駄目だ…。type で出力すると以下の通り。

    ble/array#push ()
    {
        builtin eval "$1+=(\"\${@:2}\")"
    }。

    不思議だ。bash-3.2 で色々動かして見るが似たような例が駄目に場合は見当たらない。
    以下の様にしてもエラーを出力せずに実行できる。
    ff() { b=(); builtin eval '\''b+=("${@:2}")'\''; declare -p b; }; ff 111 222 333 444 555
    ff() { local b=1; builtin eval '\''b+=("${@:2}")'\''; declare -p b; }; ff 111 222 333 444 555
    うーん。不思議な事に ble/debug/print-variables s が何も出力しない…。

    再現性は謎だが少なくとも ble/syntax:bash/simple-word/evaluate-path-spec $'\\\n' を実行すれば再現する。
    $ ble/array#push spec $'\\\n' としても再現性はない。

    うーん。ble-detach した状態でも再現はする。

    [原因解明]

    仕方がないので ble/syntax:bash/simple-word/evaluate-path-spec を少しずつ縮めて行った結果、
    以下の形にまで縮小する事ができた。B と C の間でエラーになる。
    どうも bash-3.2 eval は前に評価した時の途中状態を残して構文解析するらしい?
    然し、コマンドの実行に関しては前回の途中状態からではなくて、
    今回読み取られた新しい単語をコマンドとして読み取る様である。

    function debug1 {
      echo A
      builtin eval $': \\\n'
      echo B
      builtin eval 'B=()'
      echo C
    }

    他の bash はどうだろうか。ファイルに問題のスクリプトを記述して試してみる。
      builtin eval $': \\\n'
      builtin eval 'B=()'
    だと再現しない。
      builtin eval $': \\\n'; builtin eval 'B=()'
    で再現する。つまり途中に実行の区切れがあれば eval 状態はクリアされるという事。
    これで試すと bash-3.1 及び bash-3.2 で問題になる。bash-3.0 はOK

    [解決方法]

    これに対してどの様に対処したら良いだろうか。
    変な物を eval した後は eval -- ':' とかやっておけば良いのだろうか。

  * edit: exec:exec の枠組みは削除する事にする [#D1131]
    #D1130 の対応が面倒になってしまう為。
    更に全くテストしていないので他にも様々な問題が在るだろう。単に削除する。

  * main: BUG ble.sh セッションで source ble.sh --attach=none すると固まる [#D1130]

    [症状]
    ble.sh をロードした状態で source ble.sh --attach をすると固まってしまう。
    一方で source ble.sh --attach=attach としても固まらない。この違いは何だろうか。
    どうも調べてみると単に --attach とすると
    --attach=none という意味になり、そうすると固まる様である。
    --attach=none で再現する事を確認した。--noattach でも再現するのだろう。

    もしかしてこれは source ~/.bashrc で問題になるのではないだろうか。
    と思ったが、もし --noattach を指定していたとしても、
    bashrc の末尾で ble-attach を呼び出している筈だから大丈夫の筈なのである。

    試しに ble/base/unload-for-reload を呼び出してみるとその場で固まった。
    ble-detach/impl を実行してみてもやはり固まった。何が悪いのだろうか。
    どうも固まると言っても C-d によるログアウトはできる様である。

    [原因解明]

    C-f や C-g に ble.sh の枠組みでログアウトを登録しても何も起こらなかった。
    つまり C-d によるログアウトを支配しているのは bash の枠組みの方である気がする。
    実際に bind -p を出力したところ bind は復元されている様子であった。
    では標準出力等が繋がっている先がおかしな事になっているという事だろうか。

    la /proc/self/fd を実行してみたところ 0 と 2 は普通だが 1 は変な所に繋がっている。
    と思ったが、これは元からそうである様である。普通に実行しても pipe:[...] になっている。
    普通に ble-detach してその上で実行してもやはり pipe:[...] になっている。
    なので接続先がおかしくなっているとかそういう事ではないのだろうという気がする。

    * 2019-07-14 うーん。そもそもキー入力を受信しているのかどうかから調べる事にする。
      どうもキー入力を受信してはいない様である。次に bind の状態を調べてみたい。
      うーん。bind は通常の bash になっている気がする。

      その直後に PROMPT_COMMAND 経由で hook が実行されているのだろうか…。
      試しに PROMPT_COMMAND= を付けてみてもやはり反応がなくなる問題は継続している。
      うーん。ble-attach を直後に実行しておけば操作できなくなる事はない。
      因みに ble-attach の直後の builtin bind -p は何も出力されない…。
      何が起こっているのだろうか。と思ったが ble-attach の直後は出力は抑制されるのだった。
      ファイルに書き出してみた所 builtin bind -p によって期待通りに、
      何にも束縛されていない結果が出力される事を確かめた。

      うーん。source out/ble.sh --noattach の直後に stty sane をしても効果はなかった。
      というかそもそも stty sane を実行したとしても epilogue が走るのではあるまいか。。
      epilogue がどうなっているのかについて確かめて置きたい。

      成る程…分かった気がする。detach された時には
      ble-edit/exec:gexec/.end で本来チェックに引っ掛かって、
      bind/tail が呼び出されないという仕組みになっている筈だが、
      ble-reload をした場合にはそれがチェックされないという事の様だ。

    [修正]

    問題の箇所を修正したら完全に固まるという事はなくなった。
    然し依然として状態はおかしい。stty sane は実行して置かなければならないし、
    更に PS1 などが消滅してしまっている。どうやらコマンドを実行中は
    PS1 は消えていないので、その後で消滅しているという事の様である。

    うーん。調べてみると ble-detach/impl の後に PS1 の類が復元されている様である。
    これはどの様に対処したら良いだろうか。_ble_attached の状態で unload が起こったら…。
    detach のタイミングを遅延させて後で detach するという事にするか?
    然し、その場で unload しないと変な事になってしまう…。
    更に、attach が始まってしまう。或いは別の手として、
    _ble_edit_detach_flag == reload になっていたら
    その場で強制的に ble-attach してしまうという可能性?

    と思ったが既に PS1 等が破壊されている状態で
    ble-attach すると余計に変な事になってしまう。

    結局、そのまま detach する事は許して、
    然し、状態をちゃんと復元するという事にした。
    通常の detach の場合には epilogue の外で detach/impl するから問題なかったのが、
    今回の場合は prologue-epilogue の中で detach/impl して、
    その後で epilogue が実行されて内部状態に入ってしまうのが駄目だった。
    従って再び prologue を呼び出して誤魔化す事にした。
    面倒なので exec:gexec の枠組みの方の prologue を呼び出してしまう事にする。

    * というか exec:exec はちゃんとメンテナンスされているのだろうか…。

      うーん。一応 ble-edit/attach/.detach という関数があって、
      それでちゃんと処理をするという事になっているが、
      reload の時にはそれが後で覆されてしまう。
      しかし、ble-edit が保持している _ble_edit_attached 変数に記録されてしまっているので、
      再度この関数を呼び出しても意味はない。
      その様な事を考えると、実際汚いが prologue を呼び出して誤魔化すしかないのである。

      時に、ecec:gexec の prologue でなければならない。
      exec:exec は PS1, IGNOREEOF は local で被覆されていると仮定して
      復元処理をスキップしている為である。
      と思ったが restore-PS1 の枠組み自体が調整済みかそうでないかを記録しているのでは。
      exec:exec を利用している時にはそもそも adjust-PS1 を呼び出していないので、
      この時に破壊されてしまう気がする…と思ったが、よく考えたら exec:exec の場合には
      そもそも PS1= にしていないから問題にならないのであるという事か?
      否、exec:exec であっても起動時に adjust している。
      reload 時に restore して (しかし local PS1 に対して restore してしまう)
      その後で exec:exec/epilogue では adjust されない為に、
      改めて restore を実行したとしても復元されないという事になる。

      exec:exec に対する対応は複雑になってしまう。
      うーん。というか exec:exec はメンテナンスされていないし、
      今後使う事があるとも思われないのでこの際削除してしまって良い気がする。
      削除する事にした。

  * history: BUG #D1126 について対応したと思っていたら駄目だ [#D1129]

    % ble-reload した直後に C-d で終了すると履歴が書き込まれない。
    % 何かコマンドを実行した後だと書き込まれる。
    % 但し、":" の様な単純なコマンドだと書き込まれなかった。
    % "echo" でも駄目だった。どういう事なんだろう…。
    % また調べ直す必要がある。
    %
    % 終了するのに exit を実行した場合には問題は再現しない。
    % やはり C-d を実行すると行けないのだろうか。
    % というかそもそもちゃんと C-d を受信できているのだろうか。
    % 実は Bash の枠組みの側で C-d が受信されている可能性はあるだろうか。
    % そして Bash の機能としてログアウトが実行されている。
    %
    % 調べてみると何と ble/history/TRAPEXIT は実行されている。
    % つまり、問題は何かが呼び出されていないとかそういう事ではなくて、
    % ble.sh の中での skip の管理の方であると思われる。
    %
    % 気づいた事は、実は履歴の項目数が上限に達しているという事。
    % 更に history -a で全ての履歴が書き出されてしまっているという事。
    % wskip なのに何故だろう…。うーん。結局履歴が増殖するのも分からないし、
    % 更に、あー。何だか分かった気がする。履歴が初期化されるタイミングが色々なんだ。

    問題を切り分ける必要がある。今発生している問題は。
    1. ble-reload をするとコマンドが記録されない。
    2. ble-reload をした後にコマンドを実行して終了すると
      履歴が倍加してしまうという減少が発生していた。

    取り敢えず 2. が今も再現するのかどうかについて確認する。
    再現した。bash RET ble-reload RET echo RET C-d で再現する。

    取り敢えず 1. について調べる事にする。
    どうも ble/builtin/history/.check-uncontrolled-change が悪さをしている様子である。
    ここでは一体どういう判断をしていただろうか。
    max!=_ble_builtin_history_prevmax だった時に
    _ble_builtin_history_wskip を更新している。
    というか _ble_builtin_history_prevmax や
    _ble_builtin_history_wskip がクリアされているのがいけないんだ。
    ちゃんと初期化されない様にしたら治った。

    2. の問題も一緒に治ってしまった。考えてみれば当たり前の気がする。
    そもそも reload さえしなければ変な事は起こっていなかったのでこれは気にしない事にする。

  * [棄却] decode: BUG bind -sS が効いていない気がする [#D1128]
    →確認してみた所、わざわざ ble.sh の設定を解除してから
    出力する様になっていた。つまりこれは意図的な動作である。
    よく見ると -pP 等の場合にも復元する様になっている。
    確かに実行してみると復元した後の状態が出力されている様である。

2019-07-11

  * main: --prompt で attach するとプロンプト表示までに時間がかかる気がする [#D1127]
    と思ったが今試してみると再現しない。というより、
    padparadscha の bashrc を変更したら治ってしまった気もする。

    うーん。今 Cygwin で試してみると再現する。
    Cygwin の上と Linux の上で振る舞いが違うという事なのだろうか。
    一応 cygwin は bash 4.4.12 で linux は bash 4.4.23 である。
    linux 上の bash 4.3.48 でも再現はしない。4.2.53 でも再現しない。
    Cygwin の上でどのタイミングでプロンプトが表示されるのか調べる事にする。

    どうやら vi.sh の初期化がプロンプトの初期化よりも先に実施されている?
    というより ble-attach よりも先に実行されている様である。
    分かった。inputrc の読み込みのために初期化が実行されている。
    つまり inputrc がある環境では vi.sh 等の初期化が先に走ってしまうという事。
    後気付いた事だが、通常の bash の場合には bashrc で set -o 等をした後に
    inputrc が読み込まれるのではないだろうか。つまり、
    ble.sh をロードした時点では未だ inputrc を読み込んでは行けないのではないか。

    inputrc の初期化タイミングについて調べる必要がある。

    実際に調べてみると inputrc は bashrc の中で set -o vi とした後に
    読み込まれている様である。set -o vi より前に bind '' を実行すると
    その時点で読み込まれる様になる様である。
    何と bind 'set editing-mode vi' とした場合には、
    vi mode に変更するよりも前に inputrc が読み込まれてしまう様である。

    これについて対応する為には ble.sh での
    inputrc の読み込みタイミングを考える必要がある。
    - 'bind' を呼び出した時に inputrc の初期化を実行する。
    - 'bind' が一度も呼び出されなかった時には attach の時点で inputrc の初期化を実行する。

    修正したのに未だ駄目だ…。と思ったら分かった。blerc の中で bind を実行している。
    その瞬間に inputrc を読み込んでいるんだ。

    % 実は、bind を呼び出した瞬間には inputrc は読み込まなくても良いのではないか。
    % 特に set* を実行している場合には inputrc を遅延させても良い気がする…。
    % と思ったがやはり駄目だ。inputrc を読み込んでから、その inputrc の設定を
    % 上書きする様に振る舞う必要がある。という事は inputrc を先に読み込んで置く必要がある。

    これは取り敢えず対応完了と考えて良い事にする。

  * history: ble-reload するとそれ以前の履歴が bash_history に書き込まれない [#D1126]
    これは ble/builtin/history/.initialize がもう一度呼び出される為である。
    ここで _ble_builtin_history_wskip が reload した瞬間の値に書き換えられてしまう。

    a _ble_builtin_history_initialized が既に設定されている時にはクリアしない様にする?

    と思ったが問題はそれだけではない。例えば途中まで素の bash で操作していて、
    途中から ble.sh に切り替えたとする。するとやはり ble.sh をロードする以前の
    履歴の内容が bash_history に書き込まれないという事になってしまう。
    従って、ble.sh をロードした瞬間に残っているデータに関しては、
    その時点で何処かに書き出して置く必要があるのである。

    既にその仕組は整っている。fetch である。

    b うーん。histapp=$_ble_base_run/$$.history.app に history -a してしまえば良い?

      と思ったが本当に大丈夫だろうか。例えば history -a && history -c && history -r
      を実行しているという場合には history -r した内容が
      history -a で書き出されてしまうのではあるまいか。

      今試してみると history -cr; history -r した後で
      history -a x.txt で全ての履歴が書き出されてしまっている。
      と思ってもう一度試してみたがこれは再現しない。どういう事だろう。
      よく分からないが幻だったという事にする。

      取り敢えず他で history -r だとかしていたとしても
      履歴が倍化してしまうなどの現象は起こらないのではないかと予想する。
      然し、念の為対応した後に変な事が起こらないか確認する事にする。

    - 実装中に気になった事。/dev/stdin, /dev/stdout 等は POSIX にないのだろうか。
      http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap10.html
      を見ると /dev/null 及び /dev/tty しか定義されていない。
      他に /dev/console という目慣れない物がある。これはよく分からない。
      システムのエラーメッセージを出力する端末に繋がっている?

    - うーん。builtin history -a で大丈夫なのだろうか。
      一回 load した後だと bash の中で記録している index が
      色々と狂ってしまっているのではないか。
      その様に考えると a と b の対策の両方をしておくのが懸命と思われる。

  * history: ble-detach してそれから ble-attach すると [#D1125]
    bash: kill: (9952) - そのようなプロセスはありません
    と言った様なメッセージが表示される。何処の kill かを先ず特定する必要がある。
    →これは最近追加した history の bgpid の kill であった。
      前回使用した background-worker の情報が残っていて、
      それを kill しようとしているのである。

      何故 kill するのかというと、clear-background で再度
      background 処理がやり直しになった時に古い bgworker によって
      ファイルが上書きされると困るからであった。
      従ってファイルが完成した時点で bgpid をクリアしてしまえば良いのである。
      ファイルが完成した時点で bgworker が再びファイルを上書きしてしまうという心配はない。

2019-07-10

  * 2019-07-02 [不要] 現在 bashrc を実行中かどうかを判定する方法? [#D1124]

    以前 bashrc の中にいるかどうかを判定できたら良いという話があった。

    実は以下の条件で bashrc の中にいるかどうかを判定できるのではないだろうか。
    [[ $(builtin history -s -- echo; HISTTIMEFORMAT=X builtin history 1) == *'??'* ]]
    と思ったがこの方法が使えるのは bash-4.3 以降であった。
    というよりも寧ろ HISTTIMEFORMAT が動かなくなってしまうのは bash-4.3 以降のバグだろうと思われる。
    何れにしても実現する為にはもっと別の方法を模索する必要がある。

    何処で bashrc の中にいるかどうかの判定ができたら良いという話だったろうか。

    * 見つかった。#D0737 である。しかし、読んでみると結局 trap -- RETURN は、
      bashrc の末尾では呼び出されないとの事で、
      bashrc の中にいるかどうかの判定ができても意味がないという結論になっていた。
    * 或いは ble.pp のスタートアップの判断の時に何か使えるかもしれない。
      と思ったがやはり特に使えそうな物はない様な気もした。
      もし使えるとしたら $ source ble.sh した時はその場で attach して、
      bashrc の中で source ble.sh した時には manual attach という可能性があったが、
      どうせ manual attach をユーザに書かせるのであれば
      明示的に noattach を指定させた方が混乱がない。
      更にもし PROMPT_COMMAND を使うのであれば実はわざわざ場合分けする必要もなかった。
      というより今確認したら既に attach=prompt がデフォルトになっていたので、
      bashrc の中で単に source ble.sh を記述しただけでも
      PROMPT_COMMAND を上書きしない限りは動くには動く。
    * 対話シェル以外で起動した時に警告を発するかどうかを
      bashrc の中にいるかどうかで切り替えていた。
      然し、そもそも対話シェル以外の時には履歴が無効になっているので、
      上記で挙げた様な方法は使えないのであった。

    というか今や noattach を指定しなくても prompt で取り敢えず設定しておいて、
    もし末尾で manual attach されなかったら PROMPT_COMMAND 経由で attach を試みるというので良いのでは。
    実際に試してみるとそれで動作している気がするのでOK

    もしかすると知られた方法があるかもしれないと思って検索したが見つからない。
    というかどのようなキーワードで検索したら良いのかがよく分からない。

  * history: vi.sh は _ble_history の上で動作する事を前提としている様に見える [#D1123]
    然し、実際には read 等を用いた時に _ble_history 以外の上で動作する。
    ちゃんと _ble_edit_history_prefix を参照して動作する様に書き換える必要があるのではないか。

    或いは read で動作する時には local で _ble_history を被覆していたりするのだろうか…。
    と思ったが履歴を読み込んだりする時にやはり問題に為る気がする。
    →確認してみたが実は _ble_history_ind を参照しているだけだったのでそんなに問題ではない。
      これは全て get-index に置き換えて実装する事にした。

    * done: それより read での新しい編集モードに入る時に初期化するべき変数の一覧など。
      うーん。history prefix が変われば以下の様な変数は待避したりしなければならないのでは。。
      _ble_keymap_vi_mark_local=()
      _ble_keymap_vi_mark_global=()
      _ble_keymap_vi_mark_history=()

      以下の配列を用意してここに textarea 固有のデータを登録させる事にした。
      _ble_textarea_local_VARNAMES
      _ble_textarea_local_ARRNAMES

      適当にその辺りにある変数も登録しておく事にした。
      或いは、全ての textarea で退避する変数を一つの配列に入れようかとも思ったが、
      例えば ble/syntax や ble/textmap は独立して使う事もあるかもしれないので、
      やはり幾つかの配列に分けて置くというのは有効である。
      undo だけは _ble_textarea_local_VARNAMES に登録する事にした。

2019-07-09

  * history.mlfix: Bash-3.* でエラーメッセージが出る [#D1122]
    bash-3 系列では ble/util/idle を使えないのだった。
    必要になった時にロードする様に変更した。

  * history (resolve-multiline): 開始時に引っかかる [#D1121]
    どうも引っ掛かると思ったら .search-history-light だとか、
    或いは magic-space だとかが history -p を呼び出していて、
    その経由で resolve-multiline init が実行される様だ。
    仕方がないので history -p に関しては resolve-multiline を待たない事にした。
    一応現実的な速度で動いている様な気がする。

    他には特に問題は起こっていない気がする。

  * history: 複数行モードの履歴展開 (reported by cmplstofB) [#D1120]
    https://github.com/akinomyoga/ble.sh/issues/26

    これは前から問題があるなあと常々思っていて放置していたものである。
    既知の問題と書いてはいたが memo.txt には明記はしていなかった様に思う。

    履歴展開を自前で再実装するという様な愚は犯したくない。
    従ってできるだけ bash の枠組みの中で解決したい。
    目的は二つ。複数行コマンドの履歴をそのままの形で保持する。
    それから履歴展開も正しく実行される様に工夫する。

    履歴展開が正しく実行される様にする為には
    history には複数行コマンドを登録するという事は必須である。
    そして bash_history に登録された複数行に亘るコマンドを
    ちゃんと分断せずに読み取らせる方法は存在していない事から、
    bash_history への記録を行う場合には eval -- $'' の形式に変換する必要がある。
    history に複数行コマンドを登録する為には自前で history を再構築しなければならない。
    この再構築に一番時間がかかると予想される。

    | 試しに history -s -- '' の羅列を出力させて、
    | 更にそれを source するスクリプトを書いてみた。
    | chatoyancy の上では 5000 行を読み取るのに 0.033s であったが、
    | padparadscha では 47k 項目を読み取るのに 1.895s かかってしまう。
    | どのタイミングで再構築するのかによるが 1.895s は時間がかかり過ぎである。
    |
    | history -r でまとめて読み取る様にしたらどうなるだろうか。
    | chatoyancy 上で 0.012s にまで短くなった。
    |
    | * history -r でまとめて読み取るにしても例えばまとまりが単一行の場合には
    |   history -r に置き換えて却って遅くなるのではないかと思われる。
    |   次に何個のファイルであれば history -r が history -s * N に勝つのか調べる。
    |   計測結果は以下の通り
    |
    |   |     9.30 usec/eval: _read_r 1 (x10000)
    |   |    26.20 usec/eval: _read_s 1 (x5000)
    |   |     9.20 usec/eval: _read_r 2 (x10000)
    |   |    31.20 usec/eval: _read_s 2 (x5000)
    |   |    10.20 usec/eval: _read_r 5 (x10000)
    |   |    45.50 usec/eval: _read_s 5 (x2000)
    |   |    10.90 usec/eval: _read_r 10 (x10000)
    |   |    69.00 usec/eval: _read_s 10 (x2000)
    |   |    12.60 usec/eval: _read_r 20 (x10000)
    |   |   114.00 usec/eval: _read_s 20 (x1000)
    |   |    21.20 usec/eval: _read_r 50 (x5000)
    |   |   257.00 usec/eval: _read_s 50 (x500)
    |   |    32.20 usec/eval: _read_r 100 (x5000)
    |   |   489.00 usec/eval: _read_s 100 (x500)
    |   |
    |   | 何というか、始めから -r が勝っている気がする。
    |   | source の分が抜けているからであろう。
    |   | source の分を一致させて計測してみたがやはり _read_r の方が高速だ…。
    |   |    30.60 usec/eval: _read_r 1 (x5000)
    |   |    35.00 usec/eval: _read_s 1 (x5000)
    |   |    31.20 usec/eval: _read_r 2 (x5000)
    |   |    41.40 usec/eval: _read_s 2 (x5000)
    |   |    31.20 usec/eval: _read_r 5 (x5000)
    |   |    60.50 usec/eval: _read_s 5 (x2000)
    |   |    32.20 usec/eval: _read_r 10 (x5000)
    |   |    89.50 usec/eval: _read_s 10 (x2000)
    |   |    34.60 usec/eval: _read_r 20 (x5000)
    |   |   153.00 usec/eval: _read_s 20 (x1000)
    |   |    44.00 usec/eval: _read_r 50 (x5000)
    |   |   331.00 usec/eval: _read_s 50 (x500)
    |   |    55.50 usec/eval: _read_r 100 (x2000)
    |   |   625.00 usec/eval: _read_s 100 (x200)
    |   |
    |   | 然し、よく考えてみたら _read_r の方はファイル作成について考えていなかった。
    |   | つまり here string を使っているとその場でファイルを作成・削除する筈なのだ。
    |   |    59.00 usec/eval: _read_r 1 (x2000)
    |   |    34.60 usec/eval: _read_s 1 (x5000)
    |   |    62.00 usec/eval: _read_r 2 (x2000)
    |   |    41.20 usec/eval: _read_s 2 (x5000)
    |   |    70.00 usec/eval: _read_r 5 (x2000)
    |   |    60.00 usec/eval: _read_s 5 (x2000)
    |   |    82.50 usec/eval: _read_r 10 (x2000)
    |   |    89.50 usec/eval: _read_s 10 (x2000)
    |   |   105.00 usec/eval: _read_r 20 (x1000)
    |   |   155.00 usec/eval: _read_s 20 (x1000)
    |   |   176.00 usec/eval: _read_r 50 (x1000)
    |   |   331.00 usec/eval: _read_s 50 (x500)
    |   |   293.00 usec/eval: _read_r 100 (x500)
    |   |   625.00 usec/eval: _read_s 100 (x200)
    |   |
    |   | 漸く単一行では history -s の方が早いという結果になった。
    |   | N=1-10 でもう少し詳しく見てみる事にする。
    |   |    62.50 usec/eval: _read_r 2 (x2000)
    |   |    41.40 usec/eval: _read_s 2 (x5000)
    |   |    65.00 usec/eval: _read_r 3 (x2000)
    |   |    47.00 usec/eval: _read_s 3 (x2000)
    |   |    67.00 usec/eval: _read_r 4 (x2000)
    |   |    54.50 usec/eval: _read_s 4 (x2000)
    |   |    70.00 usec/eval: _read_r 5 (x2000)
    |   |    60.50 usec/eval: _read_s 5 (x2000)
    |   |    72.00 usec/eval: _read_r 6 (x2000)
    |   |    66.00 usec/eval: _read_s 6 (x2000)
    |   |    75.50 usec/eval: _read_r 7 (x2000)
    |   |    71.50 usec/eval: _read_s 7 (x2000)
    |   |    77.50 usec/eval: _read_r 8 (x2000)
    |   |    82.00 usec/eval: _read_s 8 (x2000)
    |   |    79.50 usec/eval: _read_r 9 (x2000)
    |   |    83.50 usec/eval: _read_s 9 (x2000)
    |   |    81.00 usec/eval: _read_r 10 (x2000)
    |   |    89.50 usec/eval: _read_s 10 (x2000)
    |   |
    |   | N=7,8辺りが怪しい? 何回か測ったがやはり N=7,8 が境目の様である。
    |
    | history -r にまとめる事の最適化を行って、
    | しかしそれでも 47k 項目の再構築をするのに padparadscha では 1.250s かかっている。
    | 30% ぐらいは高速化したがそれでも高速とは言い難いのである。
    |
    | a すると次に試みるのは history の再構築自体を分断して少しずつ実行するという事である。
    |   うーん。何というか段々と複雑になって行く…。本当に他に方法はないのだろうか。
    |   或いは、自前で履歴展開を実装するという方向性に行くのだろうか…。
    |   自前で履歴展開を実装するという方向性になると
    |   その細かな文法 (クォートの負い方) 等にも気を配らなければならない。
    |   Bash の振る舞いを完全に再現する必要があるのではないだろうか。
    |   それは面倒だし無為な気がする。
    |
    |   やはり idle 中に history が実行されないという前提で、
    |   history の再構築を実施するしかないのだろうか。。
    |   その為には先ず履歴に関連するコードを整理して置きたい。
    |
    |   history/initialize で history の再構築まで実施してしまうのが良いだろうか。
    |   と思ったが独立な処理だし history/initialize を呼び出す処理では必ずしも
    |   history 複数行再構築が必要とは限らないし、また history 複数行再構築が
    |   必要な文脈では必ずしも _ble_history 初期化を必要とはしない。
    |   従って、それぞれ独立に処理すれば良いという気がするのである。
    |
    |   他に気になるのは history -r で読み取った時に、
    |   追加業だけでなく全ての行に関して再度 history 複数行再構築が
    |   全体に対して必要になってしまうのではないかという事。
    |   うーん。history -r で読み取るという処理自体を止める必要があるだろうか。
    |   history -r で読み取るのではなくて source する方式にする必要がある。
    |   然し、それだと ' について追跡をする必要が出てくるなど、
    |   やはり処理が遅くなってしまう原因である。
    |
    |   然し、完全な対応をする為には避けて通れない処理であるし、
    |   まあ、仕方がないのかなという気はする。
    |
    | b 実は複数の一時ファイルを作ってしまう事を許せばもっと高速になるのでは。
    |   処理が遅くなるのは '...' の対応を取る処理を bash が行うからなのではないかと仮定。
    |   だとすれば始めからファイルに書き出してしまえば別に遅くはならないのではないか。
    |
    |   うーん。これは爆速である…。chatoyancy で 2ms になった。
    |   padparadscha でも 47k 項目で 79ms になった。
    |   これは十分な速度である。但し、その前処理の awk で1秒近くかかっている。

    結局 b の方法で history の書き換えを実行する事にした。
    然し、それでも前準備の awk の処理に時間がかかるという事は否めない。
    history -r でファイルから読み取る度に全て再構築するというのは現実的でない。

    うーん。history -r で読み取るのはやめて全部自前で読み取る様にするべきなんだろうか。
    というか builtin history -r を実行している場所を置き換えてしまえば良いのである。

    * done: Bash に history に書き込ませない様に修正する。
      これは EXIT で history -a /dev/null とかやっておけば良いだろうか。
      もし EXIT が正しく呼び出されなかった暁には Bash が history を書き込むという仕組み。
      というか history -a tmpfile; < tmpfile awk >> histfile とすれば良い気がする。
      うーん。然し、そうとなると histappend に依存した振る舞いにしなければならないのでは…。
      histappend が設定されている時とされていない時で実装を分ける様にする。

      後、EXIT trap に既に ble/base/unload が住んでいる。
      ble/base/unload の中で histfile に書き込むのは変な気がする
      (例えば ble-reload や ble-update でも呼ばれる物である) ので、
      やはり別に EXIT trap のハンドラを作って、
      其処から EXIT trap を実行する様にするのが良いだろう。

      というか実は EXIT で ble/builtin/history -aw を呼び出せば良いだけだった。
      これを実行してしまえば bash が自前で書き込むという事もないだろう。
      また history -w は中身をちゃんとクリアしてくれるので自前でクリアする必要もない。

      取り敢えず動作確認だけはしておく。
      →OKちゃんと重複なく書き込まれている事も確認した。

    * done: 起動時の history 複数行書き換えを実装する。
      書き換え中は history を編集させない様にする必要がある。
      実は ble/history/load と同じなので clear-background-load で一緒に補正すれば良い気がする。
      取り敢えず ble-dev で試していた物を持ってくる事にする。

      取り敢えず非同期実行を実装した。
      本当に動くのかどうか怪しいが試してみる事にする。
      そもそも起動していない様だ…。と思ったがこれは違った。
      単に clear-background が走っていただけだった。
      タイミングが分からないので出力してみる事にする。
      どうもちゃんと動いている様である。
      但し、一瞬で処理が終了してしまうので非同期がちゃんとなっているかは不明。
      何れにしても既に実装してある ble/history/load を参考にしたのでそんなに間違ってはいないだろう。

    * ok: bash-3.0 に関しては history -s が使い物にならないので、
      複数行の履歴項目を history に入れる事はそもそも不可能である。
      従って bash-3.0 に関しては履歴展開は諦める物とする。

    * done: bash history に登録する箇所では複数行エスケープはせずに登録する。
      但し bash-3.0 では複数行エスケープを実施する。

    * done: builtin history -r を実行している場所を置き換えてしまう。
      それで良い筈。実装の順番はどうしたら良いだろうか。
      というか同時に実装すれば良いのだろうか。
      と思ったが一旦どちらかを実装してそれを汎用化する形にした方が見通しは良いだろう。
      その時には history -c は外側で実行する様にするべきである。

    * done: 履歴項目が読み込まれるまでは (bashrc の外に出るまでは)
      待っていた方が良いのではないだろうかと思われる。
      或いは、履歴項目が前回から変化していたら全て初期化し直す。

    取り敢えず実装した気がする。実際に動かしてみる。

    x fixed: 自前で書き込んでいる筈なのにちゃんと改行が \n になっていない…。
      少なくとも eval -- $'' で囲まれているので自前の書き込みは実行されている。
      と思ったら ble/builtin/history/.write のエスケープが間違っていた。
      text という変数の中身を書き換えるべきなのに現在行を書き換えていただけだった。

    x fixed: 直したと思ったら今度は末尾に無駄な ' が挿入されている…。
      どうやら gawk で /\'/ というのを使うと文字列の末端に一致してしまう様だ。
      つまり /'/ としなければならなかった。
      或いは gsub(/['\\]/, "\\\\&", text) とするべきだった。後者の方法に修正した。

  * history: 履歴に関連するコードの整理 [#D1119]

    特に新しいファイル src/history.sh に移動する事で整理を行いたい。
    先ず、どの部分を edit.sh から独立させる事ができるかについて考察する必要がある。

    ble/builtin/history の部分に関しては大体は大丈夫だが
    _ble_edit_history に関連する部分は一緒に移動しなければならないと思われる。

    * done: ble-edit/info を呼び出している場所もある。
      これに関しても適当な hook を用意すれば問題ないだろうという気がする。
      というか bleopt と同様に hook 専用の枠組みを整えても良いのかもしれない。
      例えば blehook_ で始まる変数名を予約してしまうなど。。
      まあそれに関してはまた別項目として後々で対応する事にすれば良い。

    * done: ble-edit/history/initialize に関しては
      _ble_edit_history_prefix をチェックする版とチェックしない版に分ける。

    * ok: うーん。実は _ble_edit_history_ind はやはり
      history の方で管理した方が良いのではないか。
      というのも履歴の種類毎に *_history_ind という変数が存在している。
      寧ろ _ble_edit_history_ind が変更された時に
      その事を通知する様にした方が良いのではないのかという事。

    * fixed: うーん。ble/builtin/history/option:d の中で ble-edit/history/goto を呼び出している…。
      % →これに関しては _ble_builtin_history_delete_hook の中で実行すれば良いのではないか。
      %   基本的に _ble_edit_history_ind に関連する処理と
      %   _ble_edit_history_prefix に関連する処理は hook の中で処理すれば良いのではないか。

      _ble_history_ind はやはり ble/history 側に属しているとして処理する事にした。
      この時、どの様に ble-edit/history/goto を処理するべきだろうか。
      →結局 _ble_history_ind の補正は呼び出し元で行って、
        それとは別に履歴項目の移動に関しては delete hook で処理する事にした。

    x fixed: 書き換えていたら初期の _ble_history_ind が 0 になってしまっている気がする。
      何故だろう。_ble_history_load_done=1 になった瞬間での値を出力してみたらちゃんと有限の値になっている。
      get-index で見張ってみると3回問い合わせがあって初回が 0 になっている…。
      →これは ble/history/update-count が正しく動作していなかったのが原因であった。直した。

    x fixed: 後、async の途中で history/initialize の要求があって sync load が要求された時に、
      loading... のメッセージが表示されない状態になっている。これは表示する様に修正した。

    x fixed: どうも background load が動いていない様な気がする。
      最初にアクセスしようとした瞬間に読み込まれている様な気がする。
      async で呼び出すとどうも 148 で終了してしまっている気がする。
      うーん。どうしてだろう。。調べてみると恐らく idle.wait-condition が働いていない?
      どうも結局 148 を戻していたのがいけない様だ。148 を返すというのは
      ble/util/idle の枠組みに於いては入力があったという事を示している。
      従って、直後に再び ble/util/idle が呼ばれるという事を予期している。
      然し、実際には呼ばれない、という事によって問題になっている。
      では入力がないけれども制御を戻すという事の為の専用の戻り値はあるだろうか。

      取り敢えず 147 を返す事にした。148/147 のもっと詳しい考察については別の項目で行う事にする。

2019-07-05

  * sabbrev: メニュー絞り込み中に静的略語展開すると [#D1118]
    メニュー絞り込み状態が残存してしまう。そして何だか変な状態になる。
    と思ったが再現しない。再現した。

    "fi " で一旦補完候補を出しておいて其処で \L として SP をすると再現する。

    - 不思議な事に \date 等では再現しない。展開後の内容が "less" だと再現しない。
      展開後の内容が "| less" だと発生する。"| less -r" でも発生する。
    - "echo " の場合にも再現した。

    どうも menu-filter の編集範囲を抽出する時に "| less" 等が挿入されると
    simple-word ではなくなって、その事により menu-filter の更新が止まってしまう様だ。
    本来であれば is-never-word の判定で単語ではないという事になって、
    それによって menu 絞り込みがキャンセルされる筈だが、
    何故か is-never-word が反応していない。

    is-never-word の正規表現を修正した。
    最初から非単語文字が存在している場合に対応していなかった。

  * sabbrev: 複合コマンド直後で展開されない (reported by cmplstofB) [#D1117]
    https://github.com/akinomyoga/ble.sh/issues/25

    例えば ble-sabbrev '\L=| less' として、
    fi \L \L とすると1つ目の\Lは展開されない。2つ目の\Lは展開される。
    [[ ]] \L \L の場合にも同様になる。

    調べてみると sabbrev は補完候補の生成を用いて単語範囲を決定している。
    エラー単語の場合にはそもそも補完が存在しないので駄目なのである。
    % 実際に動かしてみるととちゃんと両方の場合で argument が補完源として動作している。
    この argument の補完源はその場で新しく引数を始めるという補完源であった。
    つまり、\L 全体を囲むような prefix の補完という訳ではないのである。

    代わりに単語として不正な物であっても良いので
    何らかの補完 source を生成する様にしたいのである。
    具体的に見てみると CMDXE 及び ARGX0 について補完源を生成すれば良い?

    取り敢えず実装してみた。動いた。と思ったが少し整理したら動かなくなった。

    x fixed: "fi \comm" まで入力して補完を開始すると末尾から補完が開始してしまう。
    o "fi \commit" 及び "[[ ]] \commit" は動く様になった。
    x fixed: "[[ ]] " の直後で補完候補が生成されない。
      調べてみると "[[ ]] " という単語が prefix になってしまっている。
      と思ったら単に completion-context/.add に第二引数を渡し忘れていた。
      それを修正したら動く様になった。

2019-07-02

  * highlight: 何故か空文字列に展開される引数がエラー着色されている [#D1116]
    これはファイル名着色が有効になってしまっているからと思われる。

    ファイル名が問題なのかと思って調べてみたらそもそもファイル名着色のコードに入っていない?
    然し ble_debug=1 で確認すると確かに単語着色で実装されている。
    詳しく調べてみると ble/syntax:bash/simple-word/evaluate-path-spec
    の時点で失敗しているという事が分かった。

  * history: ble-detach 時の ble/builtin/history の振る舞いについて [#D1115]
    history -na 等の操作がずれてしまうと困るので detach している状態でも、
    ble.sh の実装を用いる事にする。但し、_ble_edit_history 等に対する操作は
    detach している時には実行しない様にする必要がある。

  * 2019-06-28 history: history -d で現在編集の項目が削除された時 [#D1114]
    現在の実装ではどの様に動くだろうか。
    編集中の文字列は現在編集の項目がそのまま残る。
    この状態で移動を行うと、別の項目の edit として
    現在編集中の内容が記録されてしまって、
    元々其処にあった項目の内容が見えなくなってしまう。
    削除後の index に明示的に移動するべきなのではないか。

    然し、そうすると現在編集中の文字列が失われてしまう。
    或いは index を最新の履歴項目(未登録)の位置に移動するのが良いか。
    と思ったがそうすると最新の履歴項目で編集中の内容があった場合に、
    やはりそれが失われてしまう。

    そもそも現在の項目を削除するという事なのだから、
    現在編集中の文字列が失われるのは仕方のない事なのではないだろうか。
    なので現在編集の文字列は捨てて削除後の位置の項目をロードする事にする。

2019-07-01

  * history: HISTFILE を削除すると awk が警告メッセージを出す [#D1113]
    読み取るべきファイルが存在していない場合には単に無視するべきである。

  * history: 履歴に変化がない時 history -r で履歴データが同期されない [#D1112]
    これは ble-edit/history/load の問題だった。

  * history: 履歴ファイルが存在しない時、警告が出る [#D1111]
    これは wc の警告を殺すことにした。
    ファイルが存在しない時 wc の結果は空になるが算術式では空は 0 になるので気にしない事にする

  * history: PROMPT_COMMAND で history -cr すると履歴が倍化する (reported by cmplstofB) [#D1110]

    これは ble-attach した時に内部で初回の PROMPT_COMMAND を評価する時に
    history -a && history -c && history -r を実行するとなるという事の様である。

    色々実行しても倍加するタイミングが分からないのでもっと詳しく調べてみる。

    | ble/textarea#render ble/textarea#redraw ble-attach source                                                                                                                                                         ~
    | -rw-------. 1 murase murase 2994 2019-07-01 16:59:01 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-attach source
    | -rw-------. 1 murase murase 2994 2019-07-01 16:59:01 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-decode/EPILOGUE ble-decode/.hook
    | -rw-------. 1 murase murase 5988 2019-07-01 16:59:15 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-decode/EPILOGUE ble-decode/.hook
    | -rw-------. 1 murase murase 5988 2019-07-01 16:59:15 /home/murase/A.bash

    どうも最初の epilogue の呼び出しの瞬間になる様である。
    うーん。history -a で倍加しているのだろうか。
    history -a は wskip を基準にしている。調べてみる。
    と思ったら wskip に関しては history 1 の出力と同期している様子である。

    | ble/textarea#render ble/textarea#redraw ble-attach source
    | # Note: history 1 で何も出力されない
    | wskip=0
    | -rw-------. 1 murase murase 12010 2019-07-01 17:13:32 /home/murase/A.bash
    | -rw-------. 1 murase murase 12010 2019-07-01 17:13:32 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-attach source
    |  1088  bash
    | wskip=1088
    | -rw-------. 1 murase murase 12010 2019-07-01 17:13:32 /home/murase/A.bash
    | -rw-------. 1 murase murase 12010 2019-07-01 17:13:32 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-decode/EPILOGUE ble-decode/.hook
    |  2176  bash
    | wskip=1088
    | -rw-------. 1 murase murase 12010 2019-07-01 17:13:32 /home/murase/A.bash
    | -rw-------. 1 murase murase 24020 2019-07-01 17:13:35 /home/murase/A.bash

    したがってこれは関係ない。先に history のリストの方が倍加している。
    という事は読み取りの方が問題になっているのだろうか。

    | ble/textarea#render ble/textarea#redraw ble-attach source
    | history 1:declare -A _ble_builtin_history_rskip_dict=()
    | wskip=0
    | -rw-------. 1 murase murase 48051 2019-07-01 17:19:00 /home/murase/A.bash
    | -rw-------. 1 murase murase 48051 2019-07-01 17:19:00 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-attach source
    | history 1: 4355  bash
    | declare -A _ble_builtin_history_rskip_dict=([/home/murase/A.bash]="4355" )
    | wskip=4355
    | -rw-------. 1 murase murase 48051 2019-07-01 17:19:00 /home/murase/A.bash
    | -rw-------. 1 murase murase 48051 2019-07-01 17:19:00 /home/murase/A.bash
    | ble/textarea#render ble-edit/bind/.tail ble-decode/EPILOGUE ble-decode/.hook
    | history 1: 8710  bash
    | declare -A _ble_builtin_history_rskip_dict=([/home/murase/A.bash]="4355" )
    | wskip=4355
    | -rw-------. 1 murase murase 48051 2019-07-01 17:19:00 /home/murase/A.bash
    | -rw-------. 1 murase murase 96102 2019-07-01 17:19:01 /home/murase/A.bash

    と思って rskip の方を出力してみるがこちらも問題ない。
    というかやはり history のリストが倍加している…。
    分かった気がする…。bashrc の中で history -r を呼び出すと、X行読み込まれて、
    更に最初の bind 呼び出しまでに更にデフォルトの動作として X 行が読み込まれる事になる。

    大分特定できた。そもそもの原因は history -r を bashrc の中で呼び出すと、
    実際に対話モードに入った時に項目が二倍になってしまっているという事。
    うーん。最初に bind を受信した時に項目の数を rskip/wskip に記録するべきなのだろうか。
    しかし、そうしたとしても履歴ファイルの倍化が防げるだけであって、
    history や _ble_edit_history が二倍になってしまうという問題を防ぐことはできない。

    a だとすれば bashrc の中での history に対する操作は全てキャッシュしておいて、
      その場では発動しない様にしておくという事が必要になるのだろうか。うーん。

    b うーん。或いは bashrc の中で呼び出した ble-attach の場合には最後に history -c を実行してしまう?
      それと同時に ble/builtin/history/initialize に関してもデータを消去してしまう。
      うーん。対症療法的である…。実際にユーザが意図的に特別な履歴項目を予め読み込んで置きたいという時に問題になる。

    c 或いは ble/builtin/history/initialize は具体的に履歴が読み込まれている時にのみ実行して、
      そうでない時には初期化せずに放置しておく事にする? と思ったが、それは解決にならない。
      結局 history -r よりも後に更に何らかの別の history -r を実行するとずれてしまう。

      初回の bind の時に wskip を再設定するという事にするのが良いのかもしれない。
      うーん。綺麗な解決方法が見つからない。ble/builtin/history/.initialize が
      呼び出された後に Bash による history -r が暗黙で走る、という事が問題になっている。

    d それならば history が呼び出される度に履歴項目の数を監視しておいて、
      勝手に増えたらそれは何らかの別の枠組みによって履歴項目が増えた物として、
      その分だけ wskip を増加させるという事にしてはどうだろうか。
      今 wskip が変化するのは read/write/delete の時だけである。

      その様に実装するのであれば埒外の builtin history
      による履歴項目の変化は全て追跡する必要がある。

2019-06-27

  * 2019-06-19 history: clipboard が全く効かなくなっている [#D1109]
    これは HISTSIZE を小さな値にすると発生する様子である。
    最近の変更が悪い訳ではない様に思う。
    emacs mode の時には問題は発生していない? と思ったら
    vi mode でも再現しない。うーん。発生条件がわからない。

    これは .get-count の計算がずれるからだろうか。
    取り敢えず .get-count に関しては修正する事にして、
    それから .get-count を修正する事にする。

    これは再現しないし、また HISTSIZE の取り扱いについて #D1108 で修正を行ったので、
    それにより解決した可能性もある。再度発現した時に対処する事にする。

  * 2018-08-29 history: HISTSIZE に達した時の動作? [#D1108]

    今気づいたが HISTSIZE に達した時、何が起こるだろうか。
    何かがずれるのではないだろうか…。
    と思ったが history コマンドを使うのは初期化時と履歴展開だけである。
    実は大した影響はないのではないかという気がしてきた…。

    また、実は bash-4.3 以降では HIST{FILE,}SIZE に負の値を設定できる様だ。
    更に、それ以前から単に空文字列にしておけば無制限なのだそうだ。

    →2019-06-19 実際に動作を確認してみた所、

      % HISTSIZE に達しても履歴への登録が止まったり、
      % 古いものから順に削除されていくなどの動作はしない様だ。
      % だとすればそもそもHISTSIZEとは何だったのか…。
      % うーん。不思議だ。或いは初期化時の HISTSIZE に意味があるのだろうか。

      と思ったら…。実は HISTSIZE に達すると番号を保持したまま
      先頭部分が削れていくという事の様だ…。

    * fixed: だとすれば今までの history 1 による count の計測なども誤っていた事になる。
      うーん。修正するとすれば history に登録されている最初の項目の番号が必要になる。
      最初の項目の番号を取得する最も速い方法は何だろうか。
      history | head -1 だと 3 fork 必要になる。
      history を変数に入れると計算時間がかかる。
      と思ったが 13k 項目で 0.017s だった @chatoyancy
      それ程には時間はかからない。
      しかし history | head -1 の方が 0.007s と速い。

      history 1 は4箇所で使用している。
      うーん。history | head をする位であれば
      history | wc -l で取得した方が速い。

    * fixed: HISTSIZE に関連して history -p '!1' も危ないのではないか

    先頭が削れた時に _ble_edit_history 等はどうしたら良いのか…。
    実は _ble_edit_history と builtin history は内容が異なっても良い?
    うーん。微妙である。例えば ble/builtin/history/option:d の実装は
    history の番号と _ble_edit_history の番号が一致している事を想定している。
    他にも考察が必要な箇所が幾らか見られる。

    そもそも _ble_edit_history の内容をどの様にするかの可能性が幾つかある。

    a history の番号と同じインデックスに記録する。

      x 然し、これだと ble.sh をロードした時から history の offset が有限である場合に、
        offset までを空文字列で初期化しなければならない。

    b history の内容と同期する。つまり HISTSIZE に達して先頭が削れた場合、
      _ble_edit_history も一緒に shift を実行する様にする。
      この実装の為には、現在の _ble_edit_history の先頭の項目の
      history における対応する番号を一緒に記録しておく必要がある。

      x HISTSIZE に達すると毎回 shift が起こって効率が悪い。
        hook も毎回呼ばれる事になる。

      そもそも大量にメモリを使用しているし、
      履歴によって多少メモリを追加で食らっても問題ない気がする。
      なので HISTSIZE に構わず現在までの履歴を全て記録しても良いのでは。

    c history とは独立に _ble_edit_history の開始番号を記録する。

      x 然し、これだと history -r で HISTSIZE よりも多い行数を読み取った時に、
        その上で読み取った行数の一部だけが _ble_edit_history に追記される。
        この時、_ble_edit_history に記録される項目の番号は連続でなくなる。
        つまりずれが生じてしまう。

    d 或いは、末端からの行数で対応関係を取る事にする。
      つまり、history に於ける末端から N 番目の項目は
      _ble_edit_history に於ける末端から N 番目の要素と解釈する。
      この様にしておけば少なくとも history に現在ある項目に関しては、
      _ble_edit_history に於ける項目と正しく対応が取れる筈である。

    取り敢えず d の方策で問題なく実装できるかについて確認する。

    - option:d に関しては history の offset/count を取得して、
      削除範囲を限定する。そしてその後で対応する
      _ble_edit_history を削除する事にすれば良い。

    うーん。取り敢えず ble/builtin/history に関しては対応した気がする。
    他に対応するべき箇所はあるだろうか。。。
    ble-edit/history/load は特に対応を取っている訳ではないので関係ない。

  * 2016-07-07 history: HISTCONTROL=erasedups の時 ble-edit/history/add が遅いかもしれない [#D1107]

    重複する項目がないかぎりはそんなに遅くないのではないかと思われる。
    何れにしても bash 配列において何が遅くて何が速いのかについて計測する必要がある。
    filter 部分の操作とそれから truncate の部分について。
    →benchmark-array.sh で filter を実装して試してみたが、
      実装の仕方でそんなに速度が変化するということはなかった。
      もっと巨大な配列の場合などでしか効かないという事だろうか。
    →しかし何れにしても実測してみたところによると
      重複する項目がある時はかなり重くなるという事が予想される。

    というか unset して再度 arr=("${arr[@]}") したら速い気がする。
    →その方針で再実装した。遅い場合には 0.800 程度かかるのが
    0.120 程度に抑えられる事を確認した。もしかすると、
    項目数がもっとずっと大きい場合にはそれでも問題になるかもしれないが、
    従来の実装で遅くなるよりは格段に増しになっている筈である。

  * 2019-02-07 history: history -nr [filename] に関しては履歴を idle で再初期化する? [#D1106]

    特に追加項目の数が大量にある場合には background で初期化しても良いのかもしれない。
    これは bash 4.0 以降に於いて ble-edit/reset-history を呼び出せば良い。

    では追加項目の数が何個以上の時に background で初期化を実行するべきか。
    % 取り敢えず delta>=_ble_edit_history_count/2 で判定する事にした。
    やはり delta>=10000 で判定する事にした。

  * 2019-06-18 history: ble/builtin/history -r に時間がかかる [#D1105]

    調べてみると eval に時間がかかっている。
    やはり mapfile 等を用いてロードし直した方が早いという事か。
    5000項目ロードするのに20秒かかっている。
    1秒で250項目である。0.1秒で25項目である。
    うーん。

    結局、既存の ble-edit/history/load を拡張して、
    追加の項目を初期化できる様に変更した。
    動いている。

  * 2019-06-19 history: ble/keymap:vi/mark/history-delete.hook の動作テスト [#D1104]
    一応動いている様な気がする。

    x ずれが見られた…。試しに以下を実行してみると
      declare -a fire=([5]="B" [6]="C") となるべき所が
      declare -a fire=([0]="B" [1]="C") となってしまう。

      $ fire[7]=1
      $ fire[9]=A
      $ fire[10]=B
      $ fire[11]=C
      $ declare -p fire
      $ ble/builtin/history/array#delete-hindex fire 5-10
      $ declare -p fire

      調べてみた所 local shift=0 を宣言するのを忘れて shift を使っていた。
      前回の shift の値が使われていたという事だった。直した。
      取り敢えず一番最初にずれを見つけた例でも試して直っている事を確かめた。

    まあ、これに関しては動いていると見做して良いという事にする。

2019-06-19

  * 2019-02-07 history コマンドで出力される内容と、 [#D1103]
    ble.sh で管理している内容がずれてしまうという問題はある。
    ただ、それは現実的な問題になるだろうか。
    履歴展開を確認する場合には何れにしても history を使って番号を取得する。
    従って、内部の番号を参照する事になるはずである。

    一方で history -d や history -r 等の操作を実行した時に、
    どの様に ble.sh の方を更新するのかという問題はある。
    通常の bash では確かにコマンドライン編集時に辿れる履歴も一緒に変更されている。

    history の変更に際して何を修正するべきか。

    * done: vi.sh において履歴項目ごとに記録している内容

      | history に変化が現れた時の hook という物があった筈である。
      | それは何で何処から参照されていたか。
      | _ble_edit_history_onleave という配列がある。
      | これは onleave.fire で参照されている。
      | 去る直前に何らかの状態を記録するのに使われている。
      | 新しい行き先の情報は参照していない様である。
      | これを使っているのは ble/keymap:vi/mark/history-onleave.hook だけである。
      | そして ble/keymap:vi/mark/update-mark-history を呼び出している。
      | 特に _ble_keymap_vi_mark_history と _ble_keymap_vi_mark_global の中身を更新する必要がある様に思う。
      | その他の箇所で hindex を使用している箇所はあるだろうか。
      | history/get-index で検索すると他には ble/widget/vi-command/search.impl で使っているが、
      | これは移動したかどうかなどを判定する為に使っているだけで履歴に関する情報を記録するのには使っていない。

      - _ble_keymap_vi_mark_history
      - _ble_keymap_vi_mark_global

      _ble_keymap_vi_mark_global に関しては探索する必要があるので、
      やはり hook は削除範囲で指定する様にしたい。
      →ble/keymap:vi/mark/history-delete.hook に実装した。
        動作テストは一度も行っていない。適当な実装なのでテストは是非に行うべきである。

    * done: edit.sh

      以下の配列に対して作用すれば良さそう。
      - _ble_edit_history=()
      - _ble_edit_history_edit=()
      - _ble_edit_history_dirt=()
      - _ble_edit_undo_history=()
      最初の3つに関しては履歴をロードしている時にのみ更新する。
      最後の物に関しては履歴をロードしているかどうかに拘らず更新する。

      _ble_edit_history 及び _ble_edit_history_edit に関しては対応しているが
      _ble_edit_history_dirt に関しては対応していない。

    * ok: core-complete.sh

      他に history/get-index を参照しているのは core-complete.sh だけである。
      dabbrev で履歴を遡るために使用している。
      履歴を遡っている最中に history によって履歴が書き換わる事はない筈なので、
      これについては気にしなくても良いだろう。

    | history の操作としてどの様な物があるだろうか。
    |
    | * history -c は中身をクリアする
    | * history -d は項目を削除する
    | * history -n [filename] は追加行を読み込む
    | * history -r [filename] は履歴ファイルを読み込み直す
    | * history -aw [filename] は履歴データには変化なし
    | * history -p args... は一部の bash のバージョンで補正が必要
    | * history -s args... は項目を追加する
    |
    | 結構対応は面倒そうである。

    * done: 2017-12-03 の項目も対応する必要がある
    * 2016-07-07/3 についても確認が必要

    [実装]

    * clear.hook も追加した。
    * 取り敢えず実装した様な気がする。

  * 2017-12-03 keymap/vi (mark): BUG erasedup 等のときに履歴番号がずれるのではないか? [#D1102]

    これは ble-edit/history/add/.command-history 辺りで callback
    を呼び出す様にするなどの方法にしなければならない。

    ble/keymap:vi/mark/update-mark-history の仕様を観察すれば、
    erasedups 等に際してどの様に更新すれば良いかが分かる筈…。
    _ble_keymap_vi_mark_history の index をずらす。
    それから _ble_keymap_vi_mark_hindex を書き換える。
    -1 にでもすればよいか。

2019-06-18

  * 2015-08-11 history コマンドで操作を実行したときにそれが ble の履歴情報に反映されない [#D1101]
    history コマンド自体を上書きするなどするとまたややこしいことになるので、
    ble-history 等のコマンドを用意してそちらを使ってもらうようにした方がよい。

    或いは、もっと interactive に history 操作を実行できるようにしたい所である。
    →これは新しい項目で立てる事にする。

    builtin history を置き換える。取り敢えず実装した様な気がする。
    動作確認はしていない。→うーん。history -r を実行すると時間がとてもかかる。

  * 2019-06-11 history: ble/builtin/history/option:n の Bash 3.0 対策 [#D1100]
    そもそも history -r を用いると history -n の位置が変わってしまって変な事になる。
    history -r を使わずに履歴項目を何とかする方法はあるだろうか。。ない気がする。
    では history -n を使っても変な事が起こらない様にする方法?
    うーん。history -n を完全に自前で実装するというぐらいしか思い浮かばない。

    或いは history -r $histfile 等として history -n の開始位置を再設定できないか。
    サブシェルに閉じ込めて history -r "$tmp" とすると本体には反映されない。
    history -r とすると大量の行が追加されてしまうのでそれらを削除しなければならない。
    history -d は一つずつ削除しなければならないので大変である。
    history -cr とすると再度全体に対する初期化を実行しなければならないので遅い。

    a 或いは bleopt_history_share が設定されている時には history -n で読み取って、
      設定されていない時には history -r で読み取るという様にするか。
      しかし、そうすると bleopt_history_share が設定されていない状態から
      設定されている状態に変化した時に history -n で大量の行が追加されるという事になる。
      或いは bleopt_history_share の設定が変更される時に検出して
      bash 3.0 の時には再初期化を実行する事にするか。

    というよりそもそも何故 Bash 3.0 では history -s が使えないのだったか。
    記録を探してみると #D0233 に議論が残っている。
    history -s をしても一番上の項目が入れ替わるだけなのだという。うーん。

    改めて幾つか試してみる事にする。
    一つの bind -x の中で複数回 history -s をしてもやはり駄目だった。
    一番最後に実行した内容が登録されるだけだった。
    というかそもそも普通にコマンドを実行していても history -s は
    一番上にある履歴項目を置き換えるという動作しかしない様である…。

    b やはり history -n の実装を置き換えるしかないのだろうか。
      history -n の実装を置き換える為に何が必要だろうか。
      先ず、次の読み取り位置を記録して置かなければならない。
      一番最初は初期化時の history count で良い。
      history -n を実行する度に行数を調べる。
      history -a を実行する度にインクリメントする。

      要するに history -anrw を完全に ble.sh の物で
      置き換えてしまうという算段である。

    * というより Bash 3.0 でなかったとしても、
      history -n の結果が history -r の影響を受けて変化するのは望ましくない。
      やはり Bash 3.0 かどうかに関係なく全て自分で処理してしまうという手の方が良いだろうか。
      つまり前回の history -n の際の行数を覚えておく。
      しかしどうやって記録するのだろうか。wc で数えるのだろうか。
      更に読み取る時には tail awk を用いて読み取る事になる。
      まあ、そういう実装でも良いのかもしれない。どうせ awk を起動するのだから
      余分に幾つかのプロセスを走らせてもそんなに大変ではないだろう。

      もしくは awk で全て処理してしまうというのも手である。
      数を数えるという所から追加の行を配列に登録する所まで。

      ? 一番最初のカウントはどうするのだろうか。
        もし bashrc でロードしているのであれば
        その時の bash_history の行数で問題ない。
        然しもし ble-attach によって後でアタッチしたのであれば、
        最後に読み取った位置というのは非自明である。

        というより history を上書きするのは
        ble-attach ではなくて ble.sh をロードした瞬間である。
        ロードした瞬間に history -n で読み取ってしまうというのが手の様な気がする。

        サブシェルで history -n で読み取られた内容をファイルに書き出して置く等。
        次に読み取る時には先に書き出して置いた内容を読み出して、
        その後で新しく追加された行を読み取る様にする。

      連想配列の算術式に於ける展開について確認→OK
        $ tip='1]+a[1'
        $ declare -A arr=()
        $ arr[$tip]=12345
        $ arr[1]=10 a[1]=10
        $ echo $((arr[$tip]))
        20
        $ echo $((arr[\$tip]))
        12345

    [実装]

    * done: _ble_builtin_history_wskip
      ble.sh をロードした時に初期化するべき。
      その瞬間の histfile の行数にするか、
      或いはその瞬間の history 1 で得られる履歴項目の数か。
      これはその瞬間の histfile の行数と history 1 で得られる履歴項目の数 (0 より大きい時) で、
      より小さい方を採用するのが良い様に思われる。

    * done: _ble_builtin_history_rskip[histfile]
      これも ble.sh をロードした時に初期化するべきである。
      これは $_ble_builtin_history_wskip と同じ行数で良い気がする。

      うーん。ユーザが HISTFILE を設定し直す可能性もあるので、
      ble.sh をロードした時というよりは最初に ble-attach を実行した時だろうか。
      或いは、最初に ble/builtin/history にアクセスした時に初期化を実行するというのが良いだろうか。
      うーん。ble/builtin/history で最初に history 1 が有限の値を返した時にするか。
      これにするべき気がする。

    * done: _ble_builtin_history_wskip
      履歴を削除したり erasedups で履歴項目が消滅したりした時に修正する必要がある。
      erasedups で項目が変更される場合については対応した。
      履歴を削除する場合に関しては。。これは history -d だけだろうか。
      history/option:d を実装した。history/option:c に於いても
      _ble_builtin_history_wskip=0 を実行するべきではないか。

      現在の実装では _ble_builtin_history_wskip は項目が減った分だけ減らすという実装になっているが、
      本当にそれで良いのだろうか。
      wskip の位置が削除末端以降である場合にはそれで良いが、
      wskip の位置が削除開始位置以前にある場合には変化しない。
      また wskip の位置が削除範囲の内部にある場合には削除開始位置に移動する。
      →history/option:d と erasedups の処理でちゃんと wskip を処理する様に修正した。

    x fixed: 依然として Bash 3.0 で .bash_history に追加された内容が重複して読み取られてしまう問題は残っている。
      うーん。試してみると Bash 4.4 でも同様に発生している。option:n で wskip をずらすのに失敗しているのか?
      そもそもちゃんとずらしていなかった。というより読み込んだ時に wskip　を何処に設定するのかが非自明である。
      取り敢えず未書き込みの内容を histapp というファイルに記録しておいて、
      後の本当の write の際に書き込むことにした。
      →どうもちゃんと動いている気がする。

2019-06-10

  * 2019-05-27 edit: .bash_history と常に同期する設定を ble.sh で提供しても良いのではないか [#D1099]

    新しく追加された行を毎回読み込む様にする。

    a 具体的には巷にある設定と同様にして history -r すれば良いのではないか。
      とも思ったが少し微妙かもしれない。巷にある設定だと history -c してから history -r している様な…。
      それだと ble.sh を実行している場合には毎回履歴を初期化しなければならなくなって面倒である。
      もっとコストの低い方法を考えても良いのではないかという気がする。

    b 或いは、コマンドを実行する前に新しい項目が追加されていないかチェックする、という具合で良いのでは。
      新しい項目が追加されていたら追加分を履歴に反映させる様にする。

    コマンドを実行する前というよりは newline を入れる度にという様にする方が良いかもしれない。
    或いはユーザ入力がある度に? もしくは履歴を参照しようとする度に?
    履歴を参照しようとする度にというのが最も妥当な更新のタイミングである。

    ble.sh 独自の履歴ファイルを作ってしまうというのが一つの手の気がする。
    コマンドを実行する度にそのファイルに追記する。
    新しい履歴がある事をどのように他の bash に伝達するか。

    a 一つの手は全ての Bash インスタンスに対して *.history_add.txt 的なファイルを用意して、
      或る Bash がコマンドを実行する時に *.history_add.txt に履歴を書き込むという物。
    b 或いは履歴ファイルの長さを覚えておいて増えた分を追加するという物。
      これを実行する為には mapfile -s などで読み飛ばす必要がある。
      mapfile のない古い Bash の場合には tail 等を使って切り出す必要がある。
      もしくは全て読みだした後で切り取るか…。
      何れにしても履歴が長大になってくると結局時間がかかってしまう気がする。
    c というか history -a, history -n で良いのでは?
      これだとうまく動かない等あるのだろうか。

      history -a を実行するとちゃんと記録されている気がする。
      ちゃんと行数も増えている。次に history -n を調べる。
      うーん。hist_uniq.sh を実行した後で bash_history が縮まっている場合には読み込んでくれない。
      つまり Bash は前回の history の行番号を覚えているという事なのだろう。
      再度他の bash で history -a してから history -n すると読み込まれたので、
      前回の bash_history の長さというのは実際に読み込みが発生しなくても更新される。
      また bash_history が短くなっていたとしても現在の履歴が短くなるという事はない。

      history -na の順番と動作についても確認する必要がある。
      どちらを先に実行したとしても Bash の実装が単純だと変な事になる気がする。

      | * 例えば先に -n で新しい項目を読み込んでそれから -a で書き込むと、
      |   どの範囲のコマンドが bash_history に書き込まれるのだろうか。
      |   -n を実行すると新しく追加された行が history の末尾に読み込まれる。
      |   うーん。色々試した所、以下の様な事が分かった。
      |
      |   (1) Bash は最後に書き込みをしてから何個のコマンドを実行したかを記録している。
      |   (2) history -n で読み取るのは最後に読み取った時の行数以降の行である。
      |     この時に (1) で記録している情報の更新は行わない。
      |
      |   これによって何が起こるかというと、
      |   A個コマンドを実行した後に、history -n で N 個新しい履歴が読み取って、
      |   次に history -a する時と、history -n で読み取ったN個の項目と、
      |   (A-N)個の自分で実行したコマンドが記録される事になる。
      |   つまり、N個の自分で実行したコマンドが履歴に記録されずに終わる。
      |
      | * 或いは先に history -a して置いてそれから history -n で読み込むと何が起こるか。
      |   →これは特に何も起こらなかった。つまり history -n では何も読み取られない。
      |   →然し history -a する前に他の Bash プロセスから履歴項目が追加されている時には
      |   また変な事が起こった。つまり、history -n で自分の追加したコマンドが重複して読み取られている。
      |   つまり history -a で書き出す時に history -n の開始点がA個ずらされるという事の様に思われる。
      |
      | * Bash の動作は以下の様になっている?
      |
      |   | var number_of_new_commands;
      |   | var history_next_index;
      |   | history -a
      |   |   history[-number_of_new_commands..$] を HISTFILE に書き出す。
      |   |   history_next_index += number_of_new_commands
      |   |   number_of_new_commands = 0;
      |   | history -n
      |   |   HISTFILE[history_next_index..$] を history に読み出す。
      |   |   history_next_index += count;
      |
      |   書き換えると以下に等価である。
      |   | var history_write_index;
      |   | var history_read_index;
      |   | history -a
      |   |   history[history_write_index..$] を HISTFILE に書き出す。
      |   |   history_read_index += count
      |   |   history_write_index = += count
      |   | history -n
      |   |   HISTFILE[history_read_index..$] を history に読み出す。
      |   |   history_read_index += count
      |   |   history_write_index = += count
      |
      |   常に同じだけずれるのだとすれば。。
      |   実は最初の history と HISTFILE の差だけ記録しておけば良い事になる?
      |   と思ったが、少なくともどちらかの変数は記録して置かなければならなくて、
      |   それに加えて差を記録するという事になるので結局2つの変数を使う。余り意味ない。
      |
      | * 因みに history -an としたらどうなるのかと思って試してみたら、
      |   history -anrw は何れか一つしか同時に使用できないというエラーメッセージになる。

      動作に関しては #M0013 にまとめた。
      この動作を踏まえて history -a, history -n を上手に使って同期を実行する事は可能だろうか。

      a 例えば必ず history -s の直前に history -n を実行する様にしたらどうだろう。
        そしてその直後に history -a を実行する。
        未書き込みのコマンドが存在しない状態で history -n を実行した場合には特に何も問題は起こらない。
        その上で history -s を実行して history -a を実行すると history -s した内容が書き込まれる。
        それで良い様な気がする。

        また新しい履歴項目を追加する訳ではないが、
        新しい履歴項目が書かれていないかチェックする為には単に history -n とすれば良い。

    * 次に HISTCONTROL に変な値が設定されていた時に history -n がどの様に動作するのかという事である。
      HISTOCONTROL=erasedups が設定されている時にコマンド command を実行すると、
      その時点で履歴の中に含まれている command が全て削除される。
      その他の重複するコマンドに関してはそのままである。
      history -n で読み取った場合は過去の一致するコマンドは削除されない、という事が分かった。
      単に追記されるだけである。という事であれば割合対応は簡単なのだろうという気がする。

    * 他にチェックしなければならない項目として
      history -r 他ファイル を実行した後の history -n がどうなるかである。
      →うーん。履歴項目が倍化してしまっている…。
      つまり history -r を用いて履歴項目を増やす作戦は実は駄目。
      その後の history -n で駄目な事になってしまう。

      history -r は Bash 3.0 で history -s が使えないのを補うのに使っている。
      その他の方法で history -s に相当する機能を実装するか、
      或いは history -n 以外の方法で新しい行を読み取る様にする必要がある。

      うーん。Bash 3.0 では別の方法で history -n を実現する様にするか…。
      しかし、別の方法で実現するにしても history に関連する全てのコマンドを上書きしないと
      history -n で読み取り始める位置を特定する事ができない。
      うーん。結局毎回読み取る事になるのではないか…。
      →Bash 3.0 の時には history -n; histrory -a 戦略ではなくて、
      echo command >> "$histfile"; history -cr "$histfile" 戦略で行く事にする。
      と思ったがそうすると erasedups 等の設定で変更された履歴が全て消滅するので、
      結局改めて全ての履歴を読み出す事になってしまうのではないか。
      そしてそれは Bash 3.0 ではとても重いので避けたい操作である。

    取り敢えずは c (history -na) を用いて実装する事にする。
    その他のタイミングでの同期に関しては別の項目で改めて実装する事にする。
    と思ったが早速実装が汚くなってしまう気がする…。

    更に HISTINDEX_NEXT という物もあってこれも処理しなければならないのでは…。
    と思ったが、これに関しては history -n で項目が増えるだけである事を考えれば気にしなくても良い。

    取り敢えずの所は Bash-3.0 の事は無視した実装で区切りをつける事にした。
    一応動いてはいる様である。しかし、やはり同期のタイミングが
    新しい行に移った時というのが分かりにくい。

2019-06-09

  * 2019-06-07 progcomp: どうも bash は \= は COMP_WORDBREAKS の対象ではない様である [#D1098]
    確かにその様に動作するのが自然に思われる。

    * 更に、これが意味する所は挿入時に COMP_WORDBREAKS
      に含まれる文字もエスケープする必要があるという事でもある。

    現在の実装はどうなっているか。完全にクォート等を除去した上で処理している。
    処理を行っているのは以下の部分である。
    ble/complete/source:argument/.compvar-generate-subwords
    ble/complete/source:argument/.compvar-perform-wordbreaks

    クォートをせずに裸で存在している COMP_WORBREAKS だけについて
    分割をするようにするにはどうしたら良いか。
    というより既に存在している関数でその様な物はあるだろうか。

    うーん。評価まで一気にしてしまう実装ならば evaluate-path-spec に存在している。
    実のところ評価まで実行してしまっても問題ないのではないかという気もする。
    と思ったが各部分について評価を実行したいという事と noglob という事には注意する。
    notilde に関してはどの様に伝達すれば良いだろうか。

    実際に実装を初めてみるとどうしたら良いのか分からなくなる。

    * 先ず初めにパス名展開は起こすのか起こさないのかという事である。
      元の実装の場合にはパス名展開を起こした後に分割を行っていた。
      しかし元の単語の状態で分割を行うとすればパス名展開を起こす訳には行かない。

      →これに関しては元の単語が単語分割の対象になっていればパス名展開を起こし、
        元の単語が単語片に分割されていればパス名展開は起こさないという方針にする。

        或いは一番最後の単語片に関してだけパス名展開を実行する事にするか?

    * 次の問題は補完開始点の対応をどの様に取るのかという事である。

      古い実装に依ると補完開始点までの文字列を展開した結果から、
      新しい位置の補完開始点を算出するという事をしている。
      しかし、パス名展開が絡んでくるとこの方法で正確に対応を取る事ができるのかは怪しい。
      つまり、従来の方法でも既に問題はあったという事になる。

      新しい実装ではどの様に実装するのが良いだろうか。
      取り敢えず一から考えてみる事にすると…。

      そもそもパス名展開が起こるとしてもカーソルよりも後の位置に依存してはならない。
      という事を考えればパス名展開を考えるにしてもカーソルよりも後の位置は展開に関与してはならない。

      1. カーソルが単語内部に存在している場合には、
        先ず初めにカーソルよりも左の部分と右の部分に分ける。
        これを left と right とする事にする。
      2. left と right のそれぞれについて COMP_WORDBREAKS を適用する。
        left が単語分割された時はそれぞれの単語片に対して eval-noglob を適用する。
        left が単一の単語片の時には eval を適用する。
        right に関してはそれぞれ eval-noglob を適用する。
        left と right を結合する。left の最後の単語片と right の最初の単語片は結合する。
      3. カーソル位置に関しては left/right を結合する時に、
        どの単語片のどの位置に対応するかが計算できる。
      4. 更に登録する際に quote があるとその分のカーソル位置補正が入る事に注意する。

      何だか汚い実装だが仕方がない事だろうか。
      全体を作り直すという事も考えたが、
      処理として汚いかどうかではなく一つ一つの関数の機能として、
      分かりやすいかどうかが優先されるべきである。

  * menu_complete: C-g でキャンセルすると何故か展開が実行されてしまう [#D1097]
    因みに確定をした時にはちゃんと前の展開が保持される。

    更にエスケープ等も消えてしまう。
    調べてみると ble/complete/menu-complete.class/onselect で
    local insert=$_ble_complete_menu_common_part としているのが原因である。
    ここは menu_common_part ではなくて元々の文字列を指定するべきなのでは。

    _ble_complete_menu0_comp を見たら良いだろうか?
    と思ったがこれは候補を一番始めに表示した時の値が入っていて、
    その後の補完や入力に依る絞り込みの状態を判定していない。
    _ble_complete_menu_comp を観察してみるとそれらしい値が入っている気がする。

    menu_common_part に代入している部分を遡ってみると何れも COMPV を代入している。
    従って COMPV の代わりに COMPS を使う様にすれば良い筈である。
    そしてそれは ${_ble_complete_menu_comp[2]} に入っている気がする。

    と思ったが本来 menu_complete を開始する時に元々の文字列を記録しているべきなのではないか。
    と思って調べてみると _ble_complete_menu_original にちゃんと記録してある。
    これを使うべきなのである。と思ったが menu-complete.class は必ずしも
    menu_complete の中からだけ呼び出されるとは限らない様だ…。

  * 2015-06-28 color: --prefix=filename の filename 部分 (ref #D0839, #D0840, #D1095) [#D1096]
    単語に対して部分的な着色をする場合、現在の単語毎の着色ではない方法を考えるべき。
    → #D1095 で完全に対応した。

  * 2019-04-21 syntax: ファイル名の着色でディレクトリ部分の着色を別にする事が可能なのではないか [#D1095]
    特に simple-word に於いて / で区切られる場合について
    各 pathspec に対しての展開を既に実装していた気がする。
    これを利用すればディレクトリ部分を切り離して着色する事が可能なのではないか。

    また単語の途中で着色を変更する枠組みも既に用意してあった筈。

    * 確か = または : の後だけファイル名着色する時に使っていた。
      と思ったら = または : の後にある単語の着色は有効になっていない…。
      これは 2015-06-28 から todo にずっと残っている項目である。

    取り敢えず着色を行っている箇所を調べる事にする。
    実装は ble/highlight/layer:syntax/word/.update-attributes/.proc で行われている。
    単語着色の中でもファイル名の着色は特に ble/syntax/highlight/filetype を呼び出した後に行われている。

    * fixed: ble/syntax:bash/simple-word/evaluate-path-spec の実装を確認する。
      glob がある時に failglob で全然駄目になる様な気がする…。
      取り敢えず修正してみる事にする。
      試してみたところやはり駄目だった。修正が必要である。
      修正した。動いている気がする。OK

    * done: 一応単語の中に = や : が存在する時にはそれ以降をファイル名と解釈する様にした。

    x resolved: しかしこれだとチルダ展開が起こらない文脈でもチルダ展開を前提とした着色になってしまいややこしい。
      →途中からの着色の場合 ATTR_TILDE が設定されていなければチルダ展開を抑制する事にした。

    x fixed: 何故かチルダ展開を抑制しているのにチルダが着色される。
      というか echo '~' としてもチルダ展開が内部で実行されている気がする…。
      調べてみると filetype の中で明示的に ~ を処理している様だ。
      これは恐らく昔展開を実行する前のコードなので今は消して良いだろうと思われる。
      念の為呼び出し元を一つずつ確認していく事にする。

      - core-complete.sh からの呼び出しでは CAND を渡している。
        CAND にはファイル名が入っていると考えている。
        チルダに置換して短縮した名前は INSERT の方に入っている筈である。
      - 他に core-syntax.sh ble/syntax/highlight/getg-from-filename
        からの呼び出しがある。これはやはり core-complete.sh から CAND
        を渡して処理する物である。
      - 他は現在の実装部分だけである。

    x fixed: a= の形式の補完でディレクトリ名の後に / が挿入されないのは不便だ
      →うーん。原因が分かった。cand/yield file で a= の部分も一緒に渡すので、
      tail 設定のためのファイル名・ディレクトリ名判定が働かないのである。
      いや、yield というより最後の complete の時の処理である。
      これに関しては取り敢えず新しい action:file_rhs を追加して実装する事にした。

    x filename/aaaa とした時に filename/ までが着色されてしまう。
      ファイル名はディレクトリとして取り扱えないのでこれは不自然。
      前置部分の着色をする時にはディレクトリかどうかのチェックを実行する事にした。

2019-06-05

  * complete: = が含まれるファイル名について補完すると = より前の部分が重複する [#D1094]

    例えば hello= という状態で補完しようとすると hellohello=... という
    候補が生成されてしまう。complete -r とすると治るので、
    これは bash-completion を呼び出す時の問題である。

    | function ble/complete/minimal1 {
    |   ble/debug/print-variables COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY COMP_WORDS >>/dev/pts/14
    |   _minimal "$@"
    |   ble/debug/print-variables COMPREPLY >>/dev/pts/14
    | }
    | complete -F ble/complete/minimal1 echo

    先ずは bash のプログラム補完で呼び出した時の結果。

      COMP_LINE='echo b=' COMP_POINT='7' COMP_CWORD='2' COMP_TYPE='9' COMP_KEY='9' COMP_WORDS=('echo' 'b' '=')
      COMPREPLY=('b=hello1' 'b=hello2' 'b=hello3' 'b=hello4' 'b=hello5' 'b=hello6' 'b=hello7' 'b=hello8' 'b=hello9')

    ble.sh の枠組みで呼び出した時にはどうなるかというと。

      COMP_LINE='echo b=' COMP_POINT='7' COMP_CWORD='2' COMP_TYPE='9' COMP_KEY='9' COMP_WORDS=('echo' 'b' '=')
      COMPREPLY=('b=hello1' 'b=hello2' 'b=hello3' 'b=hello4' 'b=hello5' 'b=hello6' 'b=hello7' 'b=hello8' 'b=hello9')

    うーん。全く同じ結果になっている。という事は COMPREPLY を読み出して処理する側に問題がある。
    うーん。その後の処理でもやはり b=hello1 的な候補がちゃんと生成されている。
    これは挿入時の問題である様に思われる。

    調べてみると progcomp_prefix が
    ble/complete/source:argument/.compvar-initialize で設定されている。

    これに対して bash はどの様に動くのだろうか…。
    と思ったら変な動き方をしている。b=b\=hello という具合に補完されている。
    つまりどういう事かというと bash-completion の動作の方がおかしい。
    一方で = に対して b=hello という候補を生成している時に、
    ble.sh は = を b=hello に置き換える様に動作するが、
    bash は = の続きに "b=hello" を追記する様に動作している気がする。
    これに対する対策は必要になるだろうか、というか bash の振る舞いがどういう事なのか確認したい。
    例えば生成した候補が = で始まる場合にも = が重複して挿入されるのだろうか。。
    うーん。どうやら = が重複して挿入される様子である。

    うーん。COMP_CWORD 及び COMP_WORDS を確認する限りは生成候補は '=' の補完に使われる様に見える。
    然し、実際には = の更に次に新しい単語があるとして補完が実行されている気がする。
    うーん。bash-5.0 も bash-3.2 も同様の動作である。

    * done: 試していて気付いたが bash は連続する : や = を繋いで一つの単語としている。
      ble.sh では : や = を 1 文字ずつ全部分解して取り扱っている。
      ble.sh でも : や = を繋げて一つの単語片として取り扱う事にした。

    取り敢えず bash-completion が動く様にするかどうかについては置いておく事にして、
    = や : がある場合にはその直後から補完を開始する様にする事にする。
    その為に空の単語片を登録する事にして、更にカーソルを偶数番目の単語片に属させる事とした。

    以下にテストに用いた補完設定を残す。

    | function ble/complete/minimal1 {
    |   ble/debug/print-variables COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY COMP_WORDS >>/dev/pts/14
    |   COMPREPLY=('b=world')
    | }
    | complete -F ble/complete/minimal1 echo

2019-05-28

  * bash-3.0 で  ^V^V^V^? を入力すると stackdump が出る [#D1093]
    bash-3.1 以降では再現しない。

    stackdump: X1 0 <= beg:1 <= end:2 <= iN:1, beg:1 <= end0:1 (shift=1 text=)
      @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:9125 (ble/syntax/parse)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4 (ble-edit/content/update-syntax)
      @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:3954 (ble/highlight/layer:syntax/update)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:5 (ble/highlight/layer/update)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:9855 (ble/textarea#update-text-buffer)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7295 (ble/textarea#render)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3705 (ble-edit/bind/.tail)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:58 (ble-decode/EPILOGUE)
      @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble-decode/.hook)

    どうやら文字列の長さが 1 になってしまっている様子である。
    本来期待するのは ^V^? という内容である。うーん。
    $ ble/util/c2s 127; v=^V$ret; echo "${#v}"
    の結果はちゃんと 2 になっているので本質的に対応が難しいという訳ではなさそう。
    quoted insert について調べる。

    どうも edit.sh ble-edit/content/update-syntax で ble/syntax/parse を呼び出す時に、
    末尾にある ^? が消滅してしまうという問題が発生している様である。

    $ bash-3.0
    $ function f1 { a=$'\177'; b=a$a; f2 "$b"; }; function f2 { echo "${#1}"; }; f1
    1
    $ bash-3.1
    $ function f1 { a=$'\177'; b=a$a; f2 "$b"; }; function f2 { echo "${#1}"; }; f1
    2

    うーん。つまり bash-3.0 では全般に引数として ^? で終わる物を渡す事ができないという事になる。
    workaround について試してみたが、"$b""" としても"""$b""" としても駄目であった。
    $b と裸で引数に渡してみたら大丈夫だったが、これだと空白類やグロブ文字を含んでいる時に駄目である。

    a 代替手段として ^? を入力したい場合には
      bash 3.0 では別の Unicode 文字を入れるという手もあるかもしれない。
      実行する時にだけ ^? に置換して実行を行う。
      うーん。可也汚い方法ではあるが動かない事はないのではという気がする。
      面倒なのは文字幅や表示を ^? に変換するという処理が必要な事。

      x 然し、そうしたとしても bash_history に記録されている ^? もある。
        これも全て変換するとするととても面倒である。
      x また、入力文字列以外のあらゆるユーティリティ関数についても
        ^? に対する処理に問題があるという事になり、
        これは入力された文字列の表現を変更してもどうにもならない。
      x 代替文字に対して s2c を実行した時の振る舞いも変更しなければならない。

    b 或いは bash-3.0 では単に ^? の入力を無効にするか。
      元々 ^@ は入力できないのだからそれと似たような意味の
      ^? も入力できなくて仕方がないのではないか。

    中途半端な対応をしても仕方がない気がする。
    一応単純な対策として b を採用する事にする。。

2019-05-27

  * 2019-05-24 edit: 実は rlvar bind-tty-special-chars で C-u C-v C-w の bind の振る舞いが変わる? [#D1092]
    http://lists.gnu.org/archive/html/bug-bash/2019-05/msg00069.html

    →これに対する workaround は既に @decode.bind.uvw で実行している。
    既にこの rlvar の設定がどうなっていたとしても動作する様になっているので、
    わざわざ現在の workaround を bind-tty-special-chars の設定に置き換える必要はない。
    然し、この rlvar の動作については確認しておく必要がある。

    一応 rlvar bind-tty-special-chars の設定を変更した時の振る舞いについて調べて、
    (設定を変更した時にこの workaround が不要になるのかどうか、
    また設定を変更した時の現在の workaround が動作しなくなったりしないか)
    それで問題がなければ注記として残してこの項目は解決した事にすれば良い。

    | うーん。今確認すると manual attach にしてもしなくても uvw の対策無しで動いて見える。
    | % uvw の中で builtin bind -X | grep '[UVW?]' を実行してみると bind されていない。
    | % 対策を施した直後でも bind されていない。これはどういう事か。
    | % 実は UVW? では捕まえられない?→ grep 'C-[uvw?]' にしたらちゃんと取れた。
    | % 何れの場合でも少なくとも表面上は取れている。
    |
    | bind 'set bind-tty-special-chars on' にしても off にしても bind の変化はない。
    | どうも bind-tty-special-chars が追加されたのは bash-3.1 の様である。
    | 然し bash 3.0 で試しても特に問題が発生している様子は見られない。
    |
    | #D0003 を確認すると別の関数に配置した時点で問題が発生しなくなったという様に書かれている。
    | つまり現在の実装では実は問題になっていない、という事なのだろうか。
    | しかし #D0329 を確認してみると問題が発生していた様である。
    | Bash 4.3 で再現した。Bash 4.4 でも再現した。
    |
    | builtin bind -X は一度 bind されると xmap に情報が残ってしまうので確認には使えなかった。
    | 実際には bind -p を使って確認する必要があったのである。

    試してみたところ set bind-tty-special-chars on の時には ^U ^V ^W ^? の上書きが必要になった。
    つまり self-insert が勝手に設定されている。
    set bind-tty-special-chars off の時には特に必要ない様である。
    何れにしてもこの設定の変更によって何か問題が起こることはないようだ。

  * 2019-05-09 edit: source ble.sh (--attach=prompt) だと source に使ったコマンドの履歴が残らない? [#D1091]
    というかコマンド履歴が一切無効化されている気がする?

    うーん。そのセッションのコマンド履歴は全て消える。
    --attach=none にして ble-attach しても再現する。
    --attach=none にしてそのまま抜ければ記録される。

    bashrc からロードしてその上で ble-reload しても大丈夫。

    attach 処理の中のどの時点で問題が発生する様になっているのか特定して、
    それで原因を探し当てるのが最初にするべきことの様に思われる。

    * 試しに ble-edit/reset-history の中の ble/util/idle.push 'ble-edit/history/load async'
      という部分を無効化してみたが変化はなかった。やはりコマンド履歴に記録されない。
    * 以前 HISTSIZE 関連で変な workaround を実行していた様な気がしたので調べてみたが、
      今回の場合には関係なさそうである。該当コードは ble-edit/history/load/.background-initialize
      でありコメントに色々と書かれている (#D0702, #D0732) が結局、様々の問題の為に
      サブシェルで履歴項目の処理を行う事にして HISTSIZE は弄らない方針に変更されたのであった。
    * そもそも履歴に登録されているのだろうか。という事を調べる必要がある。
      色々 history | tail を実行してみるとこの時点で振る舞いがおかしいという事が分かった。
      履歴項目が消滅している気がする…。

      | $ bash --norc
      | $ source out/ble.sh --attach=none
      | $ history | tail
      | 14370  screen -ls
      | 14371  screen -dr
      | 14372  bind -v
      | 14373  echo hello1234
      | 14374  echo world4321
      | 14375  history | tail
      | 14376  echo test1234
      | 14377  history | tail
      | 14378  source out/ble.sh --attach=none
      | 14379  history | tail
      | $ echo 1234
      | $ echo 4321
      | $ echo 1111
      | $ history | tail
      | 14374  echo world4321
      | 14375  history | tail
      | 14376  echo test1234
      | 14377  history | tail
      | 14378  source out/ble.sh --attach=none
      | 14379  history | tail
      | 14380  echo 1234
      | 14381  echo 4321
      | 14382  echo 1111
      | 14383  history | tail
      | $ ble-attach
      | $ history | tail
      | 14373  echo hello1234
      | 14374  echo world4321
      | 14375  history | tail
      | 14376  echo test1234
      | 14377  history | tail
      | 14378  source out/ble.sh --attach=none
      | 14379  history | tail
      | 14380  echo 1234
      | 14381  echo 4321
      | 14382  echo 1111
      | $ echo 9999
      | $ history | tail
      | 14365  bind -x '"\C-@": "echo abc"'
      | 14366  command
      | 14367  screen -ls
      | 14368  screen -dr
      | 14369  screen -dr
      | 14370  screen -ls
      | 14371  screen -dr
      | 14372  bind -v
      | 14373  echo 9999
      | 14374  history | tail

      この時点で 14372 番目まで履歴が削れてしまっている。
      特に 14373--14377 は bash_history から読み取った物の筈である。
      これ以降に実行したコマンドは普通に登録される様である。

      うーん。history -s -- "$cmd" をコメントアウトしたら余計に酷い事になった。
      どんどん履歴が削れてなくなっていく…。
      前に似たような事があった。と思って調べると bash-3.1 以下の時の
      ble/edit/hist_expanded/.core で対策が書かれている。
      試しに bash 3.1 以降での処理をサブシェルにしてみた所、
      問題は起こらなくなった。履歴もちゃんと記録されている。
      つまり Bash-4.4 でも Bash 3.0 と同様の問題が起こるという事。

      % Bash 5.0 では再現するだろうか。と思って試したら再現しない。
      % というか Bash 4.4 でも再現しなくなった。
      % 何か特別な履歴項目の数などがあるのだろうか。。
      % screen の記録を探ると以下の .bash_history の内容で再現していた筈。
      %
      % $ tail ~/.bash_history                                                                                                                                                                    ble.sh master (2e6f44c)
      % screen -dr
      % screen -dr
      % screen -ls
      % screen -dr
      % bind -v
      % echo hello1234
      % echo world4321
      % history | tail
      % echo test1234
      % history | tail
      %
      % .bash_history の内容を削って再度試してみる事にする。
      % うーん。再現しない。と思ったら history の内容が追記されて増えていた。
      % また減らして調べる必要がある。減らしてみたら再現した。
      %
      % うーん。複数の要素が絡み合っているので再現するかどうか判定する為には
      % 一時的に history -s を無効にしておかなければならない。
      % というか寧ろ history 1 を繰り返し実行しても変化しないという事こそが
      % 再現しているという事の証拠になっているのでは? とも思ったがよく分からない。

      Bash-3.1 -- 5.0 の全てで再現する事を確認した。
      結局 Bash 3.0 で使っていたのと同じ workaround で
      問題が解決できる事が分かったのでそれを使う事にする。

    うーん。履歴項目が消滅する問題については解決されたが、
    履歴が保存されないという問題に関しては未だ残っている。
    というより、今迄問題なかったのが新しく問題になっている気がする。
    改めて調べる。history -r を使って履歴項目を追加したのは
    Bash 3.0 が history -s を持っていない (or 動かない) 為であろう。
    history -s -- "$cmd" をしている箇所でも Bash 3.0 は特別扱いしている。

    今回の workaround でも Bash 3.0 以外では history -s で項目を追加する事にした。
    Bash 3.0 に関しては history -r してもどうせ自分で histfile に記入するので問題にならない。
    実際に動かしてみた。問題なく動いている。OK

2019-05-09

  * main: bashrc から起動すると read が使えたり使えなかったりする [#D1090]
    具体的には vbell を表示するタイミングで read が終了してしまう。

    - bashrc から起動すると --attach=prompt, none に関係なく駄目。
    - bash --norc で起動してから source すると大丈夫。
      --attach=prompt, --attach=none に関係なく大丈夫。
    - ble-reload を実行すると治る。

    調べてみると ble/util/visible-bell の内部で死んでいる。
    うーん。再現性が分かった。一度でも外側で vbell を呼び出していれば問題は起こらない。

    うーん。failglob っぽい。どうもサブシェルの中だと failglob を eval で防げない様だ…。
    サブシェルの中では shopt -u failglob してしまう事にする。

  * edit: うーん。リサイズした後のカーソルの位置がおかしい [#D1089]
    ちゃんとテストしておくべきだった。何度も似たような修正を繰り返している…。

    所で read の方の TRAPWINCH は大丈夫だったのか。
    確認すると大丈夫の様な気がする。所で vim mode の時の read はどういう振る舞いをするのだったか。

  * edit: 後気付いたのはプロンプトの途中で改行が起こっている時に座標計算が正しくない [#D1088]
    これについても本来対応しているつもりだったが何かを間違えているのだろう。
    座標計算がどの様にされているか確認する。

    うーん。COLUMNS が 20 であるのにも関わらず x が 30 になっている…。
    分かった…。結果がキャッシュされていた。座標計算をする時には COLUMNS の幅も影響するので、
    それも一緒に比較するべきだった。

    うーん。考えた末に COLUMNS を version の一部に含めれば良いだけだと気付いた。修正する。
    と思ったが効果はなかった。チェックが二段階になっている。先ず version が同じだったらスキップする。
    更に expanded の値が同じだったらスキップする。

    これを修正したら色々と他にも直った。今まではリサイズした後の rps1 の位置が
    なにかコマンドを実行するまでおかしかったのがちゃんと再計算される様になった。

  * edit: read -e でベルを鳴らした後に C-c で終わると [#D1087]
    ref #D1000

    沢山のジョブ終了通知が現れる。というより C-c でなくても終了すると現れる。
    そもそも普通の状態ではベルをどの様に抑制していたのだったか。

    うーん。結局 ( ... & ) の形にすれば大丈夫と思っていたのが、
    $() の中で更にそれを実行すると駄目になってしまうという事か。
    read の $() の中でジョブ管理を無効にしたらどうなるか。
    と思って確認したら既に無効にする行が書かれていた。set +m である。

    % うーん。read は寧ろ bell が発生すると終了する様になってしまっている。
    % 0.4.0-devel1+ab8dad2 である。一方で動いている version は…
    % 0.4.0-devel1+ab8dad2 である。変だ。書き換えたのは WINCH だけである…。
    % もしかすると BLE_VERSION の抽出を間違えたのかもしれない。
    % 0.4.0-devel1+b52da28
    % 0.4.0-devel1+799f6d3
    % 0.4.0-devel1+467b7a4
    %
    % 直前までやはりちゃんと動いていた。新しく起動すると駄目になるのだろうか。
    % →何と新しく起動した ble-0.3.0 でも動かなくなっている。
    % という事は何か設定項目の変更が関係しているという事だろうか。
    % うーん。ble-dev で checkout して source すると変な事は起こらない。
    % キャッシュが破壊されているという事なのだろうか。。
    %
    % うーん。bash --norc してから source ble.sh しても動いている。
    % つまり、attach 戦略が行けないという事なのだろうか…。
    % どうも --attach=prompt で attach すると駄目という事の様だ。
    % 何故だろうか。

    まとめると。症状は bashrc から --attach=prompt で ble.sh に入ると
    read -e をした時に visible-bell を実行しようとした時点で終了してしまう。
    % 取り敢えずこの問題は別の問題であるので manual attach を使って
    % 先に簡単そうな問題の方を片付ける事にする。
    と思ったら駄目だった。普通に ble-attach で attach しても駄目になった。。
    再現性がよく分からない。不安定である。

    何れにしても source ble.sh した場合には問題が発生しないので、
    それで試してみると set -m でも +m でも関係なくメッセージは表示される。
    もう面倒なので visible-bell のタスクに関しては個別に判定して表示しない、
    という様にしてしまう事にする。

    % その様に書き換えたが全く検出できていない。何故?
    % →実は ble.sh/out/ble.sh ではなくて ble-dev のをロードして試していた。
    %   ちゃんと正しいのをロードして試したら検出できている。

    * reject: うーん。というか実は disown してしまえば良いのでは?
      と思ったが前回検討した時に disown は試した様な気もする。
      と思って調べると #D1000 に記録があって今回の問題と同じ問題について議論していた。
      何故解決されていないのかと思って見ると、長いメッセージを短くしただけで満足していた。
      完全に表示されなくするのは諦めていたのである。

      % うーん。disown してみたら表示はされない様になった。
      % 実は visible-bell の側で特別の判定をする必要はなくなった。
      と思ったらジョブ名の判定方法が誤っていて全てのジョブを表示しなくなっていただけだった。
      改めて試してみたら disown はまるで効果がないようだと分かったので使わない事にする。

    * resolved: 然し、別の問題として入力を完了しても visible-bell の
      子プロセスが終了するまではプロンプトが戻るまで待たされる。
      これは disown してもしなくても再現する。うーん。

      % この遅延時間をなくすにはどうしたら良いのか。
      % 子プロセスの pid を記録しておいて一気に kill するのか。
      % 然し、それだと子プロセスの pid と同じ pid の新しい関係ない
      % プロセスを殺してしまうかもしれない。
      %
      % kill に負の PID を指定すればまとめて消してくれるのではなかったかと思って調べたが、
      % これは PGID を同じくする物を全て殺すようだ。そしてサブシェルを同期的に動かしている内は
      % 親と同じ PGID になっているので使えない。もし使えたとしても、
      %
      % 或いは調べると ps を使って自分で子プロセスを列挙して kill するという手があった。
      % ps は posix のコマンドではない気がする。と思ったらあった…。
      %
      % ps -o ppid,pid 等として探し出せば良いのだろうか。。
      %
      % 調べると ppid が 1 になっているプロセスたちがいる。これらを殺せば良いという事だろうか。
      % と思ったが、それだと別の disown になっているプロセスたちを殺してしまうのではないか。
      % さて確認してみた所 disown していなくてもサブシェルから & で立ち上げたプロセスの親は 1
      % になっている。そして新しい PGID を形成しているという事も分かった。
      % これはなぜかというと ( ... & ) で起動している為に外側の () が先に消滅するからである。
      % という事を考えると、うーん。検出方法が分からない。( ... & ) をやめるのは面倒である。
      %
      % ? yes: というか、これは本当に visible-bell 関係の遅延なのだろうか。
      %   →確認してみた所 vbell がない時にはちゃんと一瞬で read が終了している。
      %
      % ? というか kill を実行したとしても SIGTERM だと sleep しているので届かないのでは。
      %   SIGKILL する必要があるのでは。色々問題が在る。
      %
      % ? no: 実は普通にログアウトする時にもそういう遅延があるのではないか?
      %   試してみたらログアウトする時には遅延はなかった。
      %
      % どういう構造になっているのか。
      %
      % result=$(sleep 10 & echo hello) でブロックされてしまうという事を確認した。
      % それで検索してみると似たような質問が見つかった。
      % https://stackoverflow.com/questions/16874043/bash-command-substitution-forcing-process-to-foreground
      % うーん。成る程… $() は標準出力が消えるのを待っていて、
      % sleep 10 が標準出力を保持し続けるのが悪いという事。

      標準出力を $() が待ち続けるのが悪いということが分かった。visible-bell は
      全て >&2 に対して実行しているので 1 は閉じてしまって問題ない。

2019-05-06

  * 2019-04-21 decode: key code の更新が実行されていない。うーん [#D1086]
    これは単にバグのあったバージョンを使っていた所為かもしれないと思ったが、
    修正直後のバージョンを使っている様だった。うーん。
    今後は強制的に全て更新する様に調整した方が良いのかもしれない。
    あるいは、init-cmap で全て更新する様に調整する。
    一応 touch vi.sh emacs.sh init-cmap.sh としたら動く様になった。

    やはり問題が発生する。更新のタイミングが悪いのかと思って
    $_ble_edit_cache の中のファイルと init-cmap.sh のタイムスタンプを確認する。
    ちゃんと正しい順序で更新されている様に見える。
    という事は問題になっているのは keyname2code の変換をしている関数の
    キャッシュが残っている等の事なのだろうか。

    うーん。分かった。配列を初期化する時にちゃんと空にしておかなければならなかったのだ。

  * edit: ウィンドウをリサイズした時に info が消えたままになる [#D1085]

2019-05-04

  * decode: mouse が有効になっていると大量のシーケンスが送られてくる [#D1084]
    完全に対応はしなくても少なくともデコードはしなければならない。
    そもそも mouse を keyseq の一員と見做して処理して良いのだろうか。
    例えば C-x まで入力してその瞬間にマウスに触ってしまって mouse move が起きた時に、
    シーケンスがなかった事になって良いのだろうか。

    一方で、シーケンスの途中として使いたいという場合も実はあるのではないか。
    例えば vim の normal mode で y としてそれからマウスで行き先の位置をクリックして、
    其処までをコピーするという動作として取り扱っても良いのではないだろうか。など。
    然し、何だか分かりにくい。やはりそういう変なのはやめた方が良いのでは。

    一方で、keyseq を入力している途中でマウス等により編集位置が変化した時、
    果たして keyseq は有効のまま続きを入力できても良いのかというのも分からない。
    うーん。まあ続きが入力できても良い気もする。
    或いは、入力途中の keyseq は消去してしまっても良い気もする。

    うーん。望ましい動作は、
    (1) マウスの移動に際しては keyseq と独立に処理する。
    (2) マウスの押下や解放や選択やドラッグに関しては、
      既存の keyseq を消去して処理する。という事。

    ? yes: 一般のアプリケーションでも上が望ましい動作だろうか。
      然し、本当にそうだろうか。現状ではマウスを使って操作するという状況が分からない。
      まあ、編集位置の移動や選択ぐらいである。本当にマウスを使って効果があるのは、
      もっと GUI っぽいアプリケーションなどを作成した時なのではないだろうか。
      例えば life game を実装したとする。クリックした位置に新しく点を打ったり、
      ドラッグした範囲を乱数で初期化したりなどができると面白いと感じる。
      そういう状況に於いての望ましい動作はラインエディタとしての望ましい動作と同じだろうか。
      マウスの移動に関して独立に処理するのもそうだろうと思うし、
      また、マウスの押下や解放があった場合にそれまでの keyseq を棄却するというのも良い気がする。
      →結論: つまり、その他の一般の用途であっても上記の様な動作で良いという様に思われる。

    それを踏まえて考えるとやはり mouse という単純なキーではなくて、
    mouse mouse_up(m) mouse_drag(32) mouse_select(t) mouse_move(35) wheel(64)
    ぐらいの区別はあって欲しいように思われるのである。

    取り敢えずドラッグ・移動に関しては独立に処理する事にした。
    うーん。(2) の既存の keyseq の消去に関しては対応していないが、
    まあ、mouse up/down/select/wheel ぐらいはそんなに沢山送られてくる物でもないので気にしない。
    後は具体的にこれを利用したものを書く機会があった時に、
    その需要に合わせて調整すれば良い。

2019-05-02

  * decode: S8C1T かつ DECCKM の時のキーシーケンスに対応 [#D1083]
    contra の fuzzing で生じた状態でキー入力ができなくなったので。
    確かに CSI シーケンスの時は C1 を解釈していたが、
    個別に登録しているシーケンスに関しては 8bit C1 を解釈していなかった。
    ちゃんと 8bit 表現も一緒に登録する様に修正した。

2019-05-01

  * syntax: 何と、fi の直後のコマンドは改行を隔ててもエラーのまま… [#D1082]
    CTX_CMDXE がずっと生きている様だ。
    試してみると ble-0.2 でも再現している。
    つまり、ずっとバグがありながら気づいていなかったという事になる。
    ble-0.1 では再現しない。ble-0.3 では当然再現する。
    実は CTX_CMDXE に対応した瞬間からずっとバグが残っていたという事なのか?
    取り敢えず修正した。すぐに問題の箇所は見つかった。
    また他の文脈値に関しては大丈夫そうに思われる。

  * main: ble-update で更新の必要がなかった時の終了ステータス (suggested by cmplstofB) [#D1081]

    https://twitter.com/cmplstofB/status/1123552437963329537
    > @akinomyoga こんばんわ。PRする程でもない提案なので，Twitterで失礼します。
    > bleshのble-updateコマンドは何も更新が無い時に終了値1で〝失敗〟しますが，
    > 個人的にこの挙動に違和感を覚えます。例えばdnfコマンドは，`dnf upgrade`と
    > 実行したときにパッケージの更新が無くても失敗しません。

    確かに dnf も git pull も更新の必要がなかった時には成功する。
    そして ble-update が明示的に失敗するのは repository が見つからなかった場合や
    その他、失敗しないと想定している操作が失敗した時のみである。
    なので、更新の必要がなかった場合には成功する事にする。

  * complete: cygwin で存在しないコマンド名を打つと遅い [#D1080]
    以前何か修正した筈なのに何故なのかと思って調べたら異なる原因だった。
    Cygwin では compgen -c -- '' 自体が物凄く遅い。2.6s かかっている。
    遅い計算機ではもっと遅くなるだろう。更に曖昧補完の場合には、
    no_empty_command_completion による予防もすり抜けてしまう。

    先ず、no_empty_command_completion を設定する事にして、
    更に no_empty_command_completion がなくても遅くならない様に修正する事にした。

2019-04-29

  * main: うーん。ble-update したら駄目な事になった [#D1079]
    (#D1077 に対する修正)

    keymap=auto のロードに失敗する。
    誤った代入ですというエラーメッセージが先ず表示される。

    取り敢えず keymap.emacs を削除して実行すると問題が発生する事は確認した。

    * done: 先ず "safe" keymap を使います、というエラーメッセージが表示を乱している。
      取り敢えずエラーメッセージが表示されても表示が乱れない様に修正した。

      と思ったが端末の画面の一番下の行にいる時に正しく領域を確保する事ができていない。
      本来は高さを設定する時に LF で領域を増やさなければならないのではないか。
      と思って調べたがこれは ble/util/buffer の flush の都合だった。直した。

    * それから何故失敗するのかについても調べる必要がある。
      _ble_decode_keymap_list に vi_imap が登録されていないという事の様に見える。
      何と $_ble_decode_keymap_list を確認してみると :vi_digraph だけしか登録されていない…。

  * bash-5.0 で reload を 2 回実行すると以下の様なエラーメッセージが出る [#D1078]

    $ source out/ble.sh
    readline: "\C-\\\": self-insert: no closing `"' in key binding
    readline: "\C-\": self-insert: no closing `"' in key binding

    Bash-4.4 では再現していない。確認すると
    /tmp/blesh/1000/16071.bind.save の中身が変になっている。
    内容を生成しているのは ble/decode/attach/.generate-source-to-unbind-default/.process である。
    食わせるデータを出しているのは ble/decode/attach/.generate-source-to-unbind-default (#2) である。
    #2 に対して介入してどの様なデータが出力されているかを調べる事にする。

    うーん。何と Bash-5.0 の bind -p 時点で何故か "\C-\\\" や "\C-\" という内容を出力している。。
    うーん。bind '"\C-\\": set-mark' を試してみた所、"\C-\\\" は再現した。
    "\C-\" がどうやって現れるのかについては分からない。まあ、何れにしても bash-5.0 が悪いのだ。
    更に言うと何故 self-insert なのかも不明である…。と思ったがこれは恐らく vi mode だからだろう。
    vi mode で実行したら再現した。

      $ bash-5.0 --norc
      $ bind -p | grep '"\\C-\\'
      $ bind '"\C-\\": self-insert'
      $ bind -p | grep '"\\C-\\'
      "\C-\\\": self-insert

      $ bash-5.0 --norc
      $ set -o vi
      $ bind -p | grep '"\\C-\\'
      "\C-\\": self-insert
      $ bind '"\C-\\": self-insert'
      $ bind -p | grep '"\\C-\\'
      "\C-\\\": self-insert
      "\C-\": self-insert

      $ bash-4.4 --norc
      $ bind -p | grep '"\\C-\\'
      $ bind '"\C-\\": self-insert'
      $ bind -p | grep '"\\C-\\'
      "\C-\\": self-insert

      $ bash-4.4 --norc
      $ set -o vi
      $ bind -p | grep '"\\C-\\'
      "\C-\\": self-insert
      $ bind '"\C-\\": self-insert'
      $ bind -p | grep '"\\C-\\'
      "\C-\\": self-insert

    一応 ble.sh 側で対策はしておく事にする。修正した。エラーメッセージは出なくなった。

  * decode: うーん reload した後に無限ループになって落ちるバグがある [#D1077]
    以前に起こった時には偶にしか起こらないと思っていたが2回目である。
    しかし、そう思って実行してみると再現しない。
    過去の特定のバージョンから最新のにアップデートした時になるという可能性もある。。

    また再現した。今度は --attach=prompt にしていたがそれで固まった。
    うーん。よく分からない。やはり再度試しても再現しない。
    やはり古い ble.sh をロードした状態で reload すると死ぬのだろうか。

    % うーん。再現した。ble-0.3 をロードしてから実行すると無限ループになる。
    % これは修正しておいた方が良い気がする。もう手遅れかもしれないが。
    % 無限ループになるのだからどの時点で無限ループになるのかは調べられる。
    % 少なくとも1文字入力した後で無限ループになっている。.hook から迫る事にする。
    % と思って改めて ble-0.3 をロードしてから新しい ble をロードしたが再現しない…。

    少なくとも分かった事は一定時間経たないと再現しないとかそういう事はなくて、
    source ble-0.3 してから source ble してもちゃんと再現する事があるという事。

    再現する迄は .hook に文字列を埋め込んで処理するか…。

    * あー。再現した。EPILOGUE の中で発生している。
    * 再現する条件が分かった気がする。補完を使って入力して、
      その直後に source を実行すると無限ループになる。
      また、古い ble-0.3 の中で新しい ble を source した時に発生する。
    * 更に、ble/util/idle.do の中で発生している。
      タスクが無限に繰り返されているのかと思ったが、
      そうではなくて ble/complete/auto-complete.idle が制御を返さない。

      うーん。不思議な事に ble/complete/auto-complete/.check-history の中から、
      ble/complete/auto-complete.idle が改めて呼び出されている様子である。
      しかも idle を経由した呼び出しではなくて。
      然し、検索しても auto-complete.idle を呼び出している箇所は他にはない。

      何かメモリでも破壊しているという事なのか?
      うーん。bash-5.0 でも再現する。

      更に遡っていくと ble-decode-key があった。これだ…。
      この中で更に idle.do が呼び出されるという事なのだろう。
      と思ったが、それも何だかおかしい。idle.do に入ったのだったら
      idle.do からメッセージが来るのではないのか。

      うーん。ble-decode-key auto_complete_enter が問題なのは分かったが。
      古い ble-0.3 からのときだけ問題になるのは何故だろうと思って、
      unkbd してみたが特に keycode がずれているとかそういう原因ではない様だ。

      と思ったら分かった。ble/widget/auto-complete-enter という関数の中で
      ble/complete/auto-complete.impl sync が呼び出されている。。
      そして無限ループになっているのだった。
      しかし ble/widget/auto-complete-enter は auto_complete keymap
      では存在しない筈では?
      実際に ble/widget/auto_complete/notify-enter が登録されている筈である。
      古い ble-0.3 の方では nop が呼び出されている。

      どうやら keycode の変化によって一回 cancel-default に行って、
      更にその後で auto-complete-enter が呼び出されているという事の様である。
      keycode が 114158 から 114159 に変化している。
      auto_complete keymap を再初期化する様にしなければならないのであった。
      最初期化を促す為にはどのようにすれば良かったか。reload のコードを辿る。

      ble-edit/bind/clear-keymap-definition-loader が怪しい。
      見てみると此処で unset -f ble-edit/bind/load-keymap-definition:* というのを実行している。
      うーん。keymap の読み込みの手順が何だか分からなくなった。
      ble-decode/keymap:auto_complete/define という関数だけ用意しておけば自動で読み込まれるのは何故か。
      →ble-decode/keymap/load という関数でこの関数名を探索して読み込んでいた。
        しかし、此処を見て分かる事は、ble-decode/keymap/is-keymap "$1" で始めに判定していて、
        ここで keymap が存在していると判定されると再読込がされないという事である。

      うーん。何故これをそのままにして放置したのだったか。
      ユーザの設定を保持する為だった様な気がする。
      しかし、ユーザの設定を保持する理由もよく分からない。
      reload の際に結局 blerc を読み込むのではなかったか。
      という事を考えると、やはり一旦消去してしまうのが良い。

    [修正]

    _ble_decode_kmaps に登録されている keymap を全て削除する事にした。
    と思ったら全然駄目だ。_ble_decode_kmaps に登録されていない…。
    仕方がないので _ble_decode_*_kmap_ という名前の変数名を全て探して削除する事にした。
    また、色々と keymap 関連の関数を整理する事にした。

    もっと大幅に整理しても良いかもしれないとも思ったが面倒なので止めておく。

  * 実は attach=prompt ならば普通に source からでも bashrc からでも使えるのでは [#D1076]
    実際に試してみると何事もなく実行することができた。
    うーん。何も引数を指定しなかった時には --attach=prompt を使う事にしよう。

  * 2019-04-21 [無関係] contra: stty? contra ./impl3 を実行した直後の状態が変である [#D1075]
    rm を実行しようとするとファイルのクローズに失敗しましたと表示されて終わる。
    cat を実行している途中に失敗する。ble.sh ではなくて bash --norc の中から
    ./impl3 を実行して抜けた場合には変な状態にはならない。
    一旦 bash --norc を実行して抜ければ元の状態に戻る。
    stty -a で出力される内容には変化はない。

    →./impl3 がこれは fcntl(STDIN_FILENO, F_SETFL, flags) で O_NONBLOCK
      を立てたまま終了していたのが悪かった。終了する時に元に戻す様にした。
      然し、こういった状態をコマンドから操作する事は可能なのだろうか。

2019-04-19

  * edit: プロンプト評価時の $? の値 [#D1074]

    https://qiita.com/kxn4t/items/bd85397914a22e69cefd
    この記事を見て思ったのだが PS1 の中に含まれているコマンド置換から見ると、
    直前に実行したコマンドの終了ステータスを $? を参照する事ができる。
    そして実際にプロンプトの表示を切り替える為にその値を参照するというのは需要がある。

    https://superuser.com/questions/301353/escape-non-printing-characters-in-a-function-for-a-bash-prompt
    更に Bash は \[ \] を ^A ^B に変換して処理を実行するそうだ…。知らなかった…。
    ble.sh の内部では \e[99s \e[99u に変換して処理を実行している。
    まあ、結局似たような事をしているという事に違いはない。
    ^A ^B に変換して処理をする様に変更する必要があるが、まあ大した変更ではないのである。

    両方共実装してみた。テストの為に上記 Qiita の記事に書かれている物を設定してみる事にする。
    まあ、ちゃんと動いている。但し、上の記事では add_line というので変な改行を出力している様にしているので、
    それによって vim-mode の表示が乱れてしまっているが、まあそれは気にしなくて良い。
    うーん。頬の罰印の表示に使われている文字の文字幅の計算が誤っている。
    west east emacs 等を試してみると何れの場合でも c2w は 2 になっている。
    一方で、screen 等の表示は 1 で処理している様に見える。
    screen が一方的に悪いという事だろうか。うーん。Qiita 記事を見ると半角で表示されている様子である。
    つまり、これは c2w の幅テーブルが誤っているという事を意味する。
    問題の文字は U+2716 の様である。そして ble/util/c2w/.determine-unambiguous によると ambiguous になっている。
    ble/util/is-emoji によると emoji と判定されている…。bleopt emoji_width= としたら良いのかもしれない。
    まあ、これは設定の問題である様な気がしてきたので気にしない事にする。

2019-04-15

  * decode: RLogin で delete が何故か効かない問題 [#D1073]
    delete を一回押しても無視される。他の文字を続けて入力するとそのまま素通りする。
    delete を2,3回押すと unbound keyseq のエラーが発生する。
    因みに別の Function Keys については特に問題も発生していない気がする。
    全く受信されないという訳でもなく、何が起こっているのかよく分からない。
    実際に受け取っているバイト・デコードされた結果などを観察してみる必要がある。

    dyna の上で実行してみると今度は insert が効かない。
    これは全く効かない。連続で押しても何のエラーも発生しないし、
    続いて他の入力をしても何事もなく操作する事ができる。
    これは RLogin の側の設定だろうか。設定を探したが何も見つからない。

    受信しているバイト列について確認を行う。
    どうもちゃんと受信できている気がする。
    デコード結果についても確認する。insert の decode に失敗している様だ。
    ESC [ 2 ~ は unrecognized csi sequence という事になっている。何故だろうか。
    ble-bind -P | grep csi とするとちゃんと insert で 2~ に登録されている。
    他の home end prior next delete も同様である。それなのに insert だけ動かない。

    うーん。変だ。ent に何も入って来ないのである。
    _ble_decode_cmap__... の配列を見ると変な物しか登録されていない。
    という事は何を意味するのかというと、CSI ... ~ は一つも登録されていないという事。
    うーん。もしかして別の所に登録されていただろうか。
    と思ったら insert が登録されているのは _ble_decode_csimap_tilde の方であった。

    うーん。ちゃんと hit している気がする…。と思ったら…。
    もしかして insert の kcode と error の kcode が衝突している?
    つまり、正しくキャッシュがクリアされていなかった事が問題なのである。

    - reject: というかキャッシュをクリアする為の関数を作っても良いのかもしれない。
      とも思ったがこれは全て ble.sh の内部実装の欠陥による物なので、
      ユーザにそれを実行してもらう為に作るというよりはデバグの為に作るべきである。
      という事を考えると、自分で使うのに必要でなければわざわざこれを作る必要はない。

2019-04-04

  * complete: menu-filter の途中で確定して実行すると自動補完前の状態に戻ってしまう [#D1072]
    これは一体何が起こっているのか…。恐らく layer が変な事をしている…。
    試しに layer:menu_filter を除外してみたら変な事を起こらなくなった。

2019-04-02

  * [考察] main: bash-it との組み合わせについて考える [#D1071]

    https://github.com/Bash-it/bash-it/issues/894 に投稿してみたが、
    投稿直後に一人反応した以外は何も反応はない。
    というか 340 も Watch していてそもそもサイトに訪れたのが1人である。
    余りアクティブなので結局皆見ていないという事なのかもしれない。
    しかし、メンテナーらしき nwinkler という人ぐらいは見てくれても良さそうだが。
    土日だから見ていないという事なのかもしれない。
    GitHub ユーザには土日にしか対応しない人と平日にしか対応しない人の二種類の人がいる。

    bash-it の初期化内容を idle.do で実行できる様にするのが良いのではないだろうか。
    或いは bash_it.sh を書き換える様に pull request を出すというのでも良い。
    しかし、下手に bash-it を刺激すると、ble.sh が bash-it の付属物であるかの様に広まったりしないだろうか。
    つまり、ble.sh を入れる為には取り敢えず bash-it を入れよう、という具合になってしまうという事。
    うーん。それは微妙な気がするが、まあ、すぐにそういう事になるとも思えないので気にしなくて良い。

    bash-it のコードを観察してみたが、余り質の良いものではない。
    沢山の人がコミットしているからなのかと思いきや、
    コアとなる部分のコードも微妙である。
    そもそも何故 local を使わない? と思われる箇所が沢山ある。
    というか local で宣言した物を他の関数から参照できるという事を知らない?
    或いは知ってはいるがそれは bash のデザインが悪いからと言う様に考えていて、
    積極的には使用しないよという方針なのかもしれない。

    * 2019-03-12 Traffic を見ると GitHub 経由でやって来る人が結構いる。
      それから検索経由でやって来る人も結構いる。
      これはつまり、GitHub 経由でやってきて、その後で名前を覚えてくれて、
      それから検索を使って到達してくれるという事なのだろうという気がする。

      では GitHub 経由というのは具体的に何だろうか。
      この bash-it に書いたコメントなのだろうか。
      しかし、これは閉じられた Issue なので余り見る人が多くいるとも思われない。
      或いは、自分の Profile を見て一番上にあるからと思って見に来るのだろうか。
      何だかそれが一番多いということの様に思われてきた。

  * [考察] main: oh-my-bash との相性についても調べておく [#D1070]

    | oh-my-bash は勝手に .bashrc を丸ごと変えてしまう。
    | bash-it にしろ oh-my-bash にしろ、
    | これらはツールというよりは .bashrc を丸ごと提供する「設定」である。
    | さて oh-my-bash の中についても確認したが、
    | これも PS1 と completion と alias を設定するぐらいで大した設定ではない。
    |
    | ble.sh との相性も別に問題はなさそうな気がする。が、念の為両方ロードしてみる。
    | ちゃんと動いている。但し、bash-it 程ではないがやはり遅い気がする。
    | やはり git コマンドを呼び出すのは遅いという事なのである。
    | 直接 .git の構造を探索して現在のブランチ名を取り出すぐらいしないと駄目である。
    | うーん。後、意味不明な alias が大量に定義されている…。
    | 一文字の alias は勝手に定義しないで欲しいものである。

    問題なし

  * [自然解消] 2015-03-01 ble-edit: 対応する物がない readline 関数 [#D1069]

    - done: history-expand-line magic-space
    - done: delete-horizontal-space
    - done: history-search-forward/backward
    - done: yank-nth-arg yank-last-arg insert-last-argument
    - done: shell-expand-line alias-expand-line
    - done: tilde-expand history-and-alias-expand-line
    - done: edit-and-execute-command
    - done: transpose-words upcase-word downcase-word capitalize-word
    - done: kill-whole-line
    - done: complete関連
    - done: redo, undo
    - done: yank-pop これはkill-ringを正しく実装する必要がある
    - done: digit-argument universal-argument 入力しやすい様に?

  * [自然解消] 2013-06-01以前 デフォルトで bind されている readline 関数の一覧をチェック [#D1068]

  * [自然解消] 2013-06-05 bashfc [#D1067]
    ref #D1050

  * [解消] 2019-03-21 emacs: readline 関数を少しずつ実装して行く事にする [#D1066]
    ref #D1059 取り敢えず全て実装した気がする。

  * 2018-08-19 highlight: シェル変数 auto_resume? [#D1065]
    一語の単純コマンドでありかつジョブの名前に一致する場合にジョブ名と解釈する。

    | 先ず初めに一語の単純コマンドとはどういう条件であるかを調べる必要がある。
    | value=less; $value でも成立するのだろうか。
    | →成立した…。更に "echo; $value" とやってもちゃんと実行される。うーん。
    | "一語から成る" というのは難しい条件であるが、
    | 何も考えずに単体のコマンドとして着色しても良いのかもしれない。
    |
    | うーん。よく分からない。$value だとできるが \less や 'less' だとできない。
    | "$value" 等もできない。\ や "' が含まれていると駄目という事なのか。
    | 何と $(echo less) でもできる。$(echo "less") でもできる…。
    | `echo less` はできない。
    | うーん。ble.sh では \"'` が含まれていなければ OK という事にしようか…。
    |
    | 調べてみると alias の方が優先される。function よりはこちらの方が優先される。

    ble.sh の仕様としては (1) 一語のコマンドかどうかの判定は諦める。
    (2) 単純コマンドかどうかは展開前に \'"` 等の文字が含まれていない事とする。
    (3) alias が優先されその次にジョブ名と解釈できるかどうかを判定する。

  * blerc: 設定に関する質問が来たので取り敢えず blerc に記述する事にした [#D1064]
    https://github.com/akinomyoga/ble.sh/issues/23

  * 2019-04-02 decode: ble/builtin/bind/rlfunc2widget が遅い [#D1063]
    呼び出し回数がそんなになければ良いが inputrc に沢山の項目が書かれていると、
    その項目の数だけ awk を fork しなければならない。
    特に Cygwin で重くなってしまうのである。実際に Cygwin 上で確認すると重い…。
    awk を使わない実装に切り替える事にした。実際に試してみたがそんなに改善していない。
    うーん。元々遅かったという事なのかもしれない。
    少なくとも多少は早くなったと思うので気にしない事にする。

  * decode: 起動時に error_cseq_vbell で変なエラーメッセージが出る様になった… [#D1062]
    と思ったらこれは inputrc の decode で発生している様だ。
    成る程、decode で visible-bell が表示されては困る。

    (1) 先ず始めに ble/builtin/bind/.decode-chars の中で
      エラーが発生しても無視する様にする。
    (2) 更に ble/decode/read-inputrc を実行する前に
      cmap を初期化する必要がある。
      ble-decode-bind/cmap/initialize で初期化を実行している。
      これは ble-decode/initialize から呼び出されている。
      ble-decode/initialize は ble.pp の中から呼び出されている。

2019-04-01

  * [解消] 2018-02-12 emacs: kill-ring [#D1061]
    ref #D1059

    M-y にも対応したい。C-y の引数に対応する。
    然し、今の所は vim-mode 対応の方を優先させるので、これは後回しにする。

  * [解消] 2017-12-04 keymap/emacs: 引き数: ble/widget/yank [#D1060]
    ref #D1059

    引き数の解釈がよく分からない。
    1 以外の引き数を指定すると rotate するのだろうか。
    どうもその様に思われる。
    しかし、現在の枠組みではそもそも kill_ring に対応していない。
    従って、急には対応できない。取り敢えずの所は clear-arg しておく。

  * emacs: yank-pop [#D1059]

    これは kill-ring の実装等も同時に考えなければならない。
    現在の変数は _ble_edit_kill_ring にある。
    及び _ble_edit_kill_type にある。

    取り敢えずこれを配列にする所から始める。
    直接触っている箇所について確認する。

    * 先ずは vi.sh 以外の場所について。登録している箇所が殆どであって、
      それらは push-kill-ring という名前の関数経由で設定する事にした。
      参照している箇所は yank のみである。

    * vi.sh はたくさん使っているが、
      これらは今まで通りに一番上の項目だけ使う様にすれば良い気がする。
      つまり、特に処置は必要ない。
      一応、emacs モードとの互換性も考えて登録する時には
      push-kill-ring を使って登録して、ring を参照できる様にする。

    取り敢えずコードは整理した。
    登録は push-kill-ring から行っている。
    使用は yank から行っている。これらの二箇所さえ修正すればOKなのでは?
    但し、yank が一体どの様に振る舞うのかによって実装の仕方が変わるかもしれない。
    先に振る舞いについて確認しておきたい。

    うーん。yank で引数を指定すると回転するのかと思ったがそうでもない様だ。
    f1 v kill-ring RET で kill ring の内容を確認する事ができるが、
    やはりいちばん最近に追加した物が一番上にあるままであった。

    引数1を指定すると位置は変わらない。
    引数0を指定すると一つ次の内容に移動する。
    引数2を指定すると一つ前の内容に移動する。
    次の内容が存在しない時には cyclic に移動する。
    新しい内容を kill すると先頭に戻る。

    こんな振る舞いで良いのだろうか。
    というか、項目の最大数を設定しなくても大丈夫だろうか。
    後、bash の振る舞いも emacs と同じと思って良いのだろうか。
    と思ったら bash は全然 ring になっていない気がする。うーん。
    あー。これは。。yank-pop を使った時にのみ ring にアクセスできる。
    然も、yank-pop は引数を認識していない様子である。

    a ううーん。yank 直後も何か特別な keymap にいるという事にしようか。

    b 或いは LASTWIDGET を用いて処理しようか。正直な所 LASTWIDGET は余り働いていない。
      引数を追加する widget や auto-complete 等が間に勝手に入っても良いからである。
      然し、そうは言っても C-w を連続で使用した時の積算や
      up down による移動の列の保持など、そういう操作で使いたい気もする。

      うーん。auto-complete やら引数 widget で "LASTWIDGET に影響しない"
      という事を明示する様にしてやれば良いのだろうか。。。これは実は可能である。
      _ble_decode_widget_last=$LASTWIDGET という具合に上書きしてしまえば良い。
      →その為の関数 ble/decode/widget/skip-lastwidget を新しく定義した。
        取り敢えず redispatch と引数追加が起こる時にはこれを呼び出す事にした。
        実際に auto-complete を起こしてみて調べてみる。
        nop が走っている。これは auto_complete_enter によって引き起こされている。
        auto_complete_enter では auto_complete/notify-enter というのを呼び出す事にした。
        その中で skip-lastwidget を実行する事にする。

      然し、LASTWIDGET を用いて処理するにしても
      置換がどんどん起こっていく時の置換範囲というのは分かりやすい方が良い。
      そう思うとやはり特別の keymap を作成した方が良いのではという気になる。
      実は yank の直後の yank-pop をした時点で keymap に入るのが良いのでは。

    ? 所でいきなり yank-pop を実行した時の bash の振る舞いは何だろうか。
      調べてみた所 bell が鳴るだけなのであった。

    取り敢えず実装してみた。

    x fixed: 置き換え範囲が変である。yank でちゃんと設定できていない?
      確認した所 mark の設定に失敗していた。修正した。

    x fixed: push-kill-ring を未だ真面目に実装していなかった。
      取り敢えず実装した。未だ動作は未確認である。
      ちゃんと動いている様に思われる。

    これで対応は終わっただろうか、と思ったが yank の引数の動作を確認していない。
    確認した。まあ、動いている様に思う。OK

  * [自然解消] 2017-09-23 ble-edit: yank-last-arg [#D1058]

    | 続けて入力するとどんどん遡っていく。
    | どの位置から置き換えを行うかは mark に記録されている様子だ。
    | また、前回実行された関数が yank-last-arg だった時にのみ遡る。
    |
    | 前回実行されたコマンドを記録する仕組みを整える必要がある。
    | 難しい点は marked/nomarked をどの様に取り扱うかである。
    | そう考えると呼び出し元 (ble-decode) で記録するのは難しいかもしれない。
    | かと言って呼び出される側 (ble-edit) の各 widget で記録するのも面倒である。
    |
    | うーん。取り敢えず ble-decode の側で最後に呼び出したコマンド文字列を記録するぐらいはできるし、
    | その程度の機能ぐらいはあってしかるべきと思うので実装する。
    | marked/nomarked などの無駄な文字列は、記録した文字列を使用する側で何とかする仕組みにすれば良い。

    これは #D1051 で実装された。

  * edit: universal-argument [#D1057]

    これの実装は面倒である。
    C-u が入った状態は + で始まるという事にしようか。

    うーん。arg=+ の時は M-C-u が入った状態とする。
    この時点で何か数字を入れると通常の状態になる。
    更にここで M-C-u を押すと +数字 という状態になる。
    この状態の時には M-C-u から抜けた状態になっていると考える。

    実装してみた。動いている様に見える。これで良いという事にする。

  * edit: skip-csi-sequence は ble.sh では bleopt の [#D1056]
    decode_error_char_discard か decode_error_kseq_discard
    に対応していると思ったが、調べてみると前者は誤ったバイト列の時で、
    後者は誤ったキーの列の時であった。

    これは入り組みそうなので別の項目として処理する事にする。
    csistat で IGNORE を返す様にすれば良い気がする。
    csi/consume の側では、登録されている cseq が存在しているかもしれないので、
    その場ではエラーになるかどうか判定する事ができない。
    一方で、ここで IGNORE を返してしまうと正しく認識できた上で IGNORE として
    返る CSI シーケンスとの区別がつかなくなる。

    結局 IGNORE (__ignore__) ではなく ERROR (__error__) というキーを新規作成する事にした。
    登録されている cseq の探索コードとの両方を統合する箇所でエラーを判定して、
    その上で vbell, abell の処理をすれば良いだろう。
    というか discard に関してもここで判定した方が見通しが良いのではないだろうか。

    取り敢えず bleopt decode_error_cseq_{abell,vbell,discard} を追加した。

  * edit: transpose-words [#D1055]

    単語の切り出しがどの様に起こるのかについて調べる。
    調べてみると bash と emacs で振る舞いが異なる。
    というか bash の振る舞いは物凄く分かりにくい。
    emacs の振る舞いに倣う事にする。

      echo hello_world

    echo hello world this is a pen
    echo+hello*world-this=is@a:pen

    1. 単語の先頭にいる時はその前の単語を移動
    2. 単語の二文字目以降にいる時は後の単語と交換
    3. 引数を指定した時は後のN単語を一まとまりと見て
      交換する。つまり word1+(word2-word3-word4)
      を (word2-word3-word4)+word1 にするという具合。

    開始点は locate-backward で b を拾えば良い。

    echo+hello*world-this=is@a:pen
    echo+hello*world-this=is@a:pen
    echo+hello*world-this=is@a:pen

    4. 引数0を指定した時は mark の位置の単語と、
      現在位置の単語を交換する。
      交換する単語は何れも前方に検索する。
      skip-forward, skip-backward して特定する。

    5. 負の引数を指定した時には
      1.2. と同様に移動単語を決定し、
      そして更に負の方向に単語を探索する。

    取り敢えず実装してみた。動いている。良しとする。

    * tty-status は呼び出しても何も起こらない気がする。
      stty raw として見て tty-status を呼び出しても状態が治るとか、
      現在の状態が変である事を示す表示が出るとかそういう事はない様だ。
      もちろん、元の振る舞い (C-t) も上書きしているので起こらない。
      bash-5.0 の man を見ても何も説明はない。
      これはよく分からないので無視する方向で行く。

  * edit: shell-expand-line [#D1054]

    * これの実装をする為には、先ずどの様な展開が実行されるのかを調べる必要がある。
      エイリアスの展開は実行される。チルダ展開は実行されない。
      パス名展開は実行されない。コマンド置換は実行される。
      パラメータ展開は実行される。算術式展開は実行される。
      何とクォート除去も実行されてしまう…。プロセス置換すら実行されてしまう…。

      - 履歴展開
      - コマンド置換・パラメータ展開・算術式展開
      - プロセス置換
      - エイリアス展開
      - クォート除去
      - 単語分割
      x チルダ展開・パス名展開

      因みにコマンド置換・クォート除去の後にエイリアス展開が起こるという事はない。
      コマンド置換の後にクォート除去が起こるという事もない。
      つまり、複数の展開が一気に起こるという事はないのである。

      然し、履歴展開によって現れた内容に対してコマンド置換は適用される様である…。
      というかそのコマンド置換でエラーが生じたところ bash が落ちる。
      と思ったが勘違いか? 再度試したら落ちなかった。

    * カーソルの位置は末尾に移動する? と思ったら、dirty range の前に居る場合は dirty range 直前に、
      dirty range の中にいる場合は dirty 末尾に、dirty range の後に居る場合は
      文字列の末尾に移動するという事になっている様だ。

      これは既に実装しているエイリアス展開の実装を参考にして実装するのが良さそう。
      但し、どうせ展開されるので nest の中の実行はしなくても良い。

      というか今の実装では .replace-range を使っているので自動的にカーソルが計算される。
      寧ろ、.replace-range に任せる方が良いのではないかという気がする。
      唯、振る舞いの違いは .replace-range だと置換範囲の末尾ではなくて、
      できるだけカーソルが移動しない様になっているという事である。
      →.replace-range のカーソル移動の仕様に関しては特に意味がなかった様な気がするので、
        振る舞いを変更してしまう事にする。mark, ind が変更に巻き込まれる時、
        mark は 変更範囲の先頭に、ind は変更範囲の末尾に移動する。
      * .replace-range を使っている箇所を一応確認する。
        大抵は _ble_edit_ind を設定している。
        多くは operator の中で使われているが、operator の場合は
        呼び出し元で位置を設定するはずなので気にしていないのだろう。
        他に変更範囲外の時には曖昧なく移動が起こるという事を仮定している
        様に思われる箇所はあった。確かにこれは妥当な仮定である。
        そしてこれは新しい振る舞いでも保たれる。
      .replace-range の振る舞いは変更する事にした。

    というかそれぞれの単語について展開を実行すれば良いのでは?

    * うーん。どの様にしたら展開対象の単語の文脈を網羅する事ができるだろうか。
      単語を閉じる時に検査など行っていなかっただろうか。

      ble/syntax:bash/ctx-command/check-word-end を確認したがチェックはない。
      ble/syntax:bash/ctx-command/.check-word-begin にコードがあった。
      _ble_syntax_bash_command_BeginCtx というテーブルを使って単語の wtype に変換している。
      確認できる物は以下の通りである。

        CTX_CMDI
        CTX_ARGI CTX_ARGEI CTX_ARGVI
        CTX_FARGI1 CTX_FARGI2 CTX_FARGI3
        CTX_TARGI1 CTX_TARGI2
        CTX_CARGI1 CTX_CARGI2

      然し、実際に確認できる物はこれよりも少ない。実は、もっと後で更に変換をしている気がする。
      と思ったが実装をよく見るとテーブルで変換した後の値を wtype にしているのではなくて、
      その前の文脈値を wtype にしている様だ。
      と思ったらちゃんとコメントに説明が書かれている _ble_syntax_bash_command_EndWtype で
      更に最後に変換が行われるという事が述べられている。このテーブルによると以下の値が確認できる。

        CTX_CMDI
        CTX_ARGI CTX_ARGVI CTX_ARGEI
        CTX_CARGI2 CTX_FARGI2

      CARGI2 FARGI2 は in というキーワードなので展開の対象ではない。
      他に試していると CTX_VALI という物も確認することができる。
      うーん。ctx.def を観察する CTX_CONDI は対象である。
      RDRI というのもあるがこれは展開の対象ではない。

    * fixed: うーん。eval-noglob としているのにパス名展開が実行されている…。
      と思ったら、eval-noglob では変数代入の右辺にする事で
      パス名展開を免れていたのであった。
      今は単純単語以外も許すために、
      配列代入で単語を展開しているのでパス名展開が有効になってしまっている。修正した。

    チルダ展開についても一緒に実装する事にする。
    チルダ展開についても alias-expand-line と同様に tree-enumerate で実行しようと考えたが、
    よく考えてみるとチルダ展開は tree に登録していない。
    というか内部構造がなくて単に syntax の解析の時点で特定できているから、
    _ble_syntax_attr だけ確認して置換すればよいのではないか。
    簡単に実装してみた。動かしてみる。動いている気がする。良しとする。

2019-03-31

  * emacs: history-nsearch-{for,back}ward-again [#D1053]
    again の実装は簡単である。と思ったが nsearch 自体の振る舞いが変だ。

    x fixed: 検索文字列として有限の物を入力していても `' not found というメッセージが出る。
      これは一番端に達した時に needle をロードしていなかったのが原因。
      何れにしても local needle=$_ble_edit_nsearch_needle を実行する様にした。

    x fixed: 同じ履歴内容の物に一致すると範囲着色が為されない?
      調べてみるとちゃんと mark_active 及び mark ind は設定されている。
      それなのに描画している時に着色が適用されないという状態。
      これは一体何が起こっているのだろうか…。

      reset-and-check-dirty で変更が起こらないとちゃんと着色されないという事なのか。
      うーん。ble/textarea#render まで行ったが
      其処でもちゃんと mark_active mark ind は設定されている。
      それなのに着色される時とされない時がある。

      x fixed: というより、そもそも何故か2回ずつ render が呼び出されている。
        これはどういう事だろうか。何故2回呼び出す必要がある。
        設計上は1回呼び出すだけの筈なのではないのか…。
        不思議だ…。.hook が2回呼び出されているのか?
        DEL は一文字で受信できる筈だし、もしそうだとしても状態が変化しない筈なので
        textarea#render が2回実行される事はない筈なのである…。

        調べるとどうも EPILOGUE は 1回しか呼び出されていない。
        ble/bind/.tail の中で複数回 textarea#render が呼び出されている。
        中を確認すると idle.do を実行した後にもう一度 textarea#render を呼び出している。
        つまり、2回 textarea#render が呼び出される所までは良い。

        問題は何故何も操作をしていない筈なのに dirty が立つのかという事。
        あー。これは caret_state がちゃんと初期化されない制御パスがある…。
        直した c7599a2

      さてそれでも着色が為されない場合というのが存在している。
      もしかすると layer 側の問題だろうか…。
      うーん。layer:region/update を観察する。selection の取得まではできている。

      あー。分かった。変更点がなかった場合に PREV_BUFF を更新する必要があったのだった。
      直した 23796bc

    x fixed: 更に途中で何故か操作不能になるという現象も発生していたはず…。
      今再度試してみたらやはり再現する。これは何だろう。
      一度 C-r してから C-s で端まで到達すると上にも下にも動けなくなる。

      検索範囲が狭められている…。
      これはどうも start の初期化の問題の様である。
      直した 3b2237e 動くようになった。

  * emacs: menu-complete-backward [#D1052]
    これは簡単である。

  * emacs: insert-last-argument [#D1051]

    取り敢えず実装してみたは良いが Bash のマニュアルを見ると
    yank-nth-arg だとか yank-last-arg だとかがあって、
    引数に対する取り扱いが全く異なる。
    更に、挿入内容は !n や !$ を使って展開されるという話。

    うーん。再実装の必要の予感…。と思ったが、
    editted entry からという事を考えると、
    やはり自分で履歴項目を取り出して処理する必要があるのではないだろうか。
    うーん。サブシェル内で評価する。
    builtin history -s -- "$cmd" で登録してから !!:$ 等で単語を切り出す。

    以下は再実装前の実装。

    | ## @var _ble_edit_lastarg_index
    | ##   最後に挿入した最終引数の履歴番号です。
    | ## @var _ble_edit_lastarg_arg
    | ##   最後に挿入した時の編集関数の引数です。
    | ##   次に編集関数を引数無しで呼び出した時の
    | ##   既定の方向を決定するのに使われます。
    | _ble_edit_lastarg_index=
    | _ble_edit_lastarg_arg=
    | function ble/widget/insert-last-argument {
    |   local arg; ble-edit/content/get-arg ''
    |
    |   # current position
    |   local beg=$_ble_edit_ind end=$_ble_edit_ind index=
    |   if [[ ${LASTWIDGET%%' '*} == ble/widget/insert-last-argument && $_ble_edit_lastarg_index ]]; then
    |     beg=$_ble_edit_mark
    |     index=$_ble_edit_lastarg_index
    |     [[ $arg ]] || ((arg=_ble_edit_lastarg_arg>=0?1:-1))
    |   else
    |     ble-edit/history/get-index
    |     [[ $arg ]] || arg=1
    |   fi
    |
    |   # next position
    |   local index2=$((index-arg))
    |   if ((arg<0)); then
    |     local count; ble-edit/history/get-count
    |     ((index2>=count&&(index2=count-1)))
    |   else
    |     ((index2<0&&(index2=0)))
    |   fi
    |   if ((index==index2)); then
    |     ble/widget/.bell
    |     _ble_edit_lastarg_index=$index2
    |     _ble_edit_lastarg_arg=$arg
    |     return 1
    |   fi
    |
    |   while :; do
    |     local entry; ble-edit/history/get-editted-entry "$index2"
    |     local wordbreaks; ble/complete/get-wordbreaks
    |     local rex='([^'$wordbreaks']+)['$wordbreaks']*$'
    |     if [[ $entry =~ $rex ]]; then
    |       local rematch1=${BASH_REMATCH[1]}
    |       ble-edit/content/replace "$beg" "$end" "$rematch1"
    |       ((_ble_edit_mark=beg,_ble_edit_ind=beg+${#remtach1}))
    |       _ble_edit_mark_active=menu_complete
    |       break
    |     elif ((arg<0)); then
    |       ((++index2>=count)) && break
    |     else
    |       ((--index2<0)) && break
    |     fi
    |   done
    |   _ble_edit_lastarg_index=$index2
    |   _ble_edit_lastarg_arg=$arg
    | }

  * emacs: edit-and-execute-command [#D1050]

    以前以下に書いた https://ja.stackoverflow.com/questions/8808 の実装は参考になるだろうか。
    結局エディタで編集した結果を accept-line と同様に実行すれば良いのである。

    エディタの中に記述した履歴展開はちゃんと展開されるのだろうか。
    どうやら履歴展開は無効になっている様だ。

    うーん。まあ動いている気がする。

    ? ok: bash の edit-and-execute の場合 LINENO が増えない
      bash の振る舞いは変である。ble.sh では LINENO はちゃんと増える事にする。
      それどころか bash では CMD も増えない…。ble.sh では増える事にする。

    ? ok: gexec/.begin, prologue, epilogue, end 等は呼び出さなくて良いのか。
      うーん。$_ だとか $? だとか $BASH_REMATCH を保存するかどうかも関係してくる。
      面倒なので呼び出さなくても良いという事にする。
      エディタコマンドであればそれぞれに勝手に stty してくれるだろう。

  * 何故か menu-complete に入って C-g すると入力済み部分が消える様になっている… [#D1049]
    これは修正した。

  * complete: dynamic-complete-history とは何だろう [#D1048]

    実際に実行してみた所、履歴の中から単語を切り出して、
    更にその単語を候補として利用する物の様である。

    しかも適当に試してみるとちゃんと引用符も認識している様な…。
    これは対応が難しい。

    というか以前にも考察した様な気がする。
    dynamic-complete-history は memo.txt を検索しても当たらない。
    → #D0820 に議論が残っていた。dabbrev-expand の振る舞いについてだった。
    恐らく dabbrev-expand は dynamic-complete-history の menu-complete 版だ。
    逆に言えば、dabbrev-expand の実装を調べれば良い?
    議論によると COMP_WORDBREAKS によって区切っている。

    dabbrev-expand の実装を調べようとしたらこれは incremental である。
    どの様に判定しているかだけ確認して実装し直す事にする。
    dabbrev で条件判定に使う正規表現などを構築しているのは以下。

      local ret; ble/string#escape-for-extended-regex "$original"
      local needle='(^|['$wordbreaks'])'$ret

    まあ sed 辺りで実装する事にする。というか grep -o が良い。
    HISTTIMEFORMAT= builtin history | ble/bin/grep -o "$needle" という具合にする。
    実装した。一応動いてはいる。

  * 2019-03-28 complete (insert_braces): 遡って書き換わる場合に対応できているか謎 [#D1047]
    特にちゃんと前方が置き換わらない様に全候補が調整されているかどうかで振る舞いが変わる。
    やはり common-prefix を真面目に求めてから処理する方が良いのかもしれない。

    うーん。或いは完全に置き換えてしまうのでも良いのかもしれない…
    と思ったが何故それをしないのかというと候補を生成した時点で、
    その引用符を前提とした挿入文字列を構築してしまっているからである。
    それを braces に変換する為には結局その様な操作が必要になる。

    然し、common-prefix を真面目に求めたとしても、
    単語の途中で quote の種類が変わる様な場合もある訳だし、
    考えれば考える程難しい気がしてきた。
    うーん。common-prefix よりも後は CAND から再度クォートして復元するという手もある。
    それが候補生成の時に意図した事なのかどうかは分からないが、
    まあブレース展開として挿入するという場合には妥協しても良い気がする。
    何れにしても CAND は絞り込みなどに使うので物凄く離れた物にはなり得ない。

    2019-03-31 determine-common-prefix の実装を確認すると色々微妙である。
    曖昧補完の時には色々と複雑な処理をするが、
    これはブレース展開による挿入にそぐうだろうか。
    そもそも曖昧補完に対してブレース展開による挿入を起こして良いのだろうか。
    まあ、候補を確認した上で挿入を起こすというのは考えうる。

    然し、曖昧補完の時の determine-common-prefix が返す値は
    common-prefix ではなくて common subsequence になっている。
    つまりブレース展開を実行する時の前方部分としては使えない事になる。

    ではこれとは別に実装すれば良いだろうか。
    共通部分を特定して共通部分以降をブレース展開に変換する。
    然し、共通部分以降が特定のクォート方法だけで表現されているとは限らない。
    今の awk の実装では '...' か $'...' か "..." $"..." しか対応していない。

    1 うーん。結局全ての候補が COMPS を共有していれば OK

    2 そうでなければ COMPS を遡って書き換える事にする。
      特に中途半端に遡っても quote の状態が分からないので、
      諦めて全部遡る事にする。

      と思ったが、determine-common-prefix の partial comps では何をしていただろうか。
      これは ble/complete/candidates/determine-common-prefix/.apply-partial-comps で実装される。
      最長一致部分と COMPS を比較する事によって比較を行っている。

      うーん。ble/complete/candidates/determine-common-prefix/.apply-partial-comps
      を使えるだろうかと思ったが微妙な気がしてきた。
      何れにしても遡って書き換えが起こる場合には INSERT ではなくて
      CAND の方から再度クォートも含めて再構築する必要があるのではないだろうか。

      何だか実装が汚くなった気がするが、まあ動いている。

    面倒なので determine-common-prefix に関しても awk で実装する?
    →これは駄目。ble/syntax:bash/simple-word を使いたいので。

  * 2019-03-28 complete (insert_braces): 末尾で close-quotation するとやはり空の引用符ができてしまう [#D1046]

    これは最後に空文字列を除去する所で close-quotation の処理をする事にした。
    close-quotation の時に文字列が空ならば始まりの引用符を除去する。

  * 2019-03-28 complete (insert_braces): 引用符を閉じてすぐ開くというのを除去したい [#D1045]

    これに対応する為にはどの様にしたら良いだろうか。

    | a 現在の候補がクォートを必要としているのかしていないのかについての情報を別の方法で保持する
    |   特に現在の候補の右側と左側でクォートの状態が異なりうるという事は注意しておくべきである。
    |   例えば {a..z}'xx という時には左側は quote が要るけれども右側は要らない。
    |
    | b 現在の候補の内容に基づいて引用符の中にいるかいないかを自動的に判定する。
    |   これは曖昧性はないだろうか。現在の実装だと引用符の外にいる状態というのは
    |   {...} となっている場合しかない気がする。
    |   と思ったが、実際に本当の文字列が {} を含んでいる場合には、
    |   それがそのままになっていると駄目である。
    |
    | c うーん。実は最初に候補を register する時点で quote してしまう?
    |   と思ったがそれはそれで取扱が難しい。range detection だとか
    |   共通部分括り出しの時のクォート除外の処理が増えてしまう。
    |
    |   やはりよく分からなくなった。現在の処理の手順はどうなっているだろうか。
    |   一番最初に登録する時にはクォートの中の状態という事になっている。
    |   その後で reduce する時にクォートの中の状態と外の状態が混ざり合う事になる。
    |
    |   その文字列を観察した時にクォートの中か外化というのを判定するにはどうしたら良いだろうか。
    |   例えば、逆に必ずクォートの中にいる状態にとして記録する事にして、
    |   端に引用符があればそれを除去する事によってクォートを外せる事にする、等。
    |   然し、端に引用符があったとしてもそれがエスケープされた物なのか、
    |   そうでないのかについては連続する \ を数えなければならない。

    うーん。上で提示した手法たちは考えが甘い。
    状況が整理できてきたので改めて手法について具体的に考える。

    | a 現在の候補が引用符の中にあるのかないのかの情報を
    |   本体の文字列とは別に記録する事にする。
    |   因みに引用符の中にあるのかないのかは右端と左端で独立である。
    |
    |   x '{a..z}' という文字列と {a..z} というブレース展開は
    |     両方共本体の文字列で {a..z} として記録されてしまう。
    |     共通部分の括り出しで両者は結合されてしまう。
    |     かと言って共通部分の括り出しの処理で引用符の状態まで含める様にするのは
    |     実装が複雑になってしまう。
    |
    | b 現在の候補が引用符の中にあるのかないのかを自動判定する。
    |
    |   x これは a と同様の問題がある。
    |     というより区別できない事例があるので余計に深刻である。
    |
    | c 最初に登録する時に引用符の中に入れてしまう。
    |   つまり常に引用符の外側にいる状態で比較などを行う。
    |
    |   x これも共通部分の括りだしを行う時に何だか面倒な事になる気がする。
    |     うーん。或いは、単純な引用符の場合には問題にならないのだろうか。
    |
    |     然し、現状で既に引用符を外す場所などで
    |     to_atoms が変な振る舞いをしないかどうか危ない。
    |     というか、引用符の中にある {} で問題が発生する気がする…。
    |
    | d 記録する時は全て引用符の中にいる様にする (つまり今と同じ)
    |   結合する時に端に引用符があればそれを対消滅させる。
    |
    |   x この方法の問題はエスケープが絡んできた時に、
    |     右端の引用符が対消滅できる物かそうでないか判定する為に、
    |     エスケープも考慮に入れなければならないという事。
    |
    |   x 引用符の種類によって実装を行わなければならない

    問題の切り分けを行う。

    問題は (1) どの様に表現するのかという事と、
    (2) 引用符が本質的に除去可能かどうか別に記録する
    必要があるのかどうかという事である。

    - (1) に関しては A 全て引用符の外側と仮定した表現とするか、
      B 全て引用符の内側と仮定した表現とするか、
      或いは C 引用符の外側でも内側でも良いので最短となる様にするかの選択肢がある。

    - (2) に関しては C の時は確実に必要である。
      A は一致の処理が面倒になる。というか B でも to_atoms に修正が必要。
      然し、to_atoms がちゃんと動作する為には
      "クォートの外のパターン" を限る必要があるのでは。
      '{' '}' 及び ',' と '{a..z}' である。
      然し、そうなると下手に空文字列を消去できない。

    うーん。最後の最後に空文字列を除去するのが自然に思われて来た…。
    →その様に実装した。

    * done: 更に引用符がある時の {...} を atom として取り扱う様に修正した。

  * 2019-03-28 complete (insert_braces): range detection のコードはもっとまともな物に書き換えたい [#D1044]
    例えば a b c 1 2 3 を {{a..c},{1..3}} 等に縮約するなどできると嬉しい。
    これは配列の要素を部分的に書き換える等の方法で実装する事ができるだろうか。
    始めの要素に対して負の方向と正の方向に拡張する形で探索するなど。
    問題は zpadding に合致する物を探すという事だが、
    これは実装し始めれば丁度その実装に合った方法が自ずと分かるだろう。

    a 取り敢えず [{type, begin, end}, ...] の形式のデータを
      一個候補が現れる度に更新するという方法で実装しかけたが、
      これだと、例えば a,b,c,c,d,e (順不同) の時に、
      {{a..e},c} ではなく {{a..c},{c..e}} 等になってしまう可能性がある。
      できるだけ長い列を取り出すのが自然に思われる。
      従って、この実装方針は諦める事にした。
      実装途中のコードを以下に残しておく。

      function range_extend(type, value, width, _, irange) {
        for (irange = 0; irange < nrange; irange++) {
          if (range[irange, "t"] != type) continue;
          if (width != "" && range[irange, "w"] != width) continue;
          if (value == range[irange, "b"] - 1) {
            range[irange, "b"]--;
            for (jrange = irange + 1; jrange < nrange; jrange++) {
              if (range[jrange, "t"] != type) continue;
              if (width != "" && range[jrange, "w"] != width) continue;
              if (value == range[jrange, "e"] + 1) {
                range[jrange, "t"] = "";
                range[irange, "b"] = range[jrange, "b"];
              }
            }
            return 1;
          } else if (value == range[irange, "e"] + 1) {
            range[irange, "e"]++;
            for (jrange = irange + 1; jrange < nrange; jrange++) {
              if (range[jrange, "t"] != type) continue;
              if (width != "" && range[jrange, "w"] != width) continue;
              if (value == range[jrange, "b"] - 1) {
                range[jrange, "t"] = "";
                range[irange, "e"] = range[jrange, "e"];
              }
            }
            return 1;
          }
        }
        return 0;
      }

      function range_register_alpha(ialpha, _, irange) {
        if (range_extend("A", ialpha, "")) return;

        range[nrange, "t"] = "A";
        range[nrange, "b"] = ialpha;
        range[nrange, "e"] = ialpha;
        nrange++;
      }
      function range_register_number(value, _, irange) {
        width = length(value);
        value = 0 + value;

        if (range_extend("N", value, "")) return;
        if (range_extend("Z", value, width)) return;

        range[nrange, "t"] = "N";
        range[nrange, "b"] = value;
        range[nrange, "e"] = value;
        nrange++;
      }
      function range_register_znumber(value, _, irange) {
        width = length(value);
        value = 0 + value;

        if (range_extend("Z", value, "")) return;
        if (range_extend("N", value, width)) return;

        range[nrange, "t"] = "N";
        range[nrange, "b"] = value;
        range[nrange, "e"] = value;
        nrange++;
      }
      function simple_range(arr, len, _, iother, i, alpha, value, beg, end) {
        alpha = "abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        iother = 0;
        for (i = 0; i < len; i++) {
          value = arr[i];
          if (value ~ /^(0|-?[1-9][0-9]*)$/) {
            range_register_number(value);
          } else if (value ~ /^(0+|-?0+[1-9][0-9]*)$/) {
            range_register_znumber(value);
          } else if (value ~ /^[a-zA-Z]$/) {
            r = index(alpha, value);
            range_register_alpha(r);
          } else {
            other[iother++] = value;
          }
        }

        len = 0;

        for (i = 0; i < nrange; i++) {
          if (range[i, "t"] == "A") {
            beg = substr(alpha, range[i, "b"], 1);
            end = substr(alpha, range[i, "e"], 1);
            value = del_close "{" beg ".." end "}" del_open;
          } else if (range[i, "t"] == "N") {
            beg = range[i, "b"];
            end = range[i, "e"];
          } else if (range[i, "t"] == "Z") {
            beg = zpad(range[i, "b"], range[i, "w"]);
            end = zpad(range[i, "e"], range[i, "w"]);
          } else continue;
          arr[len++] = del_close "{" beg ".." end "}" del_open;
        }

        for (i = 0; i < iother; i++) arr[len++] = other[i];

        return len;
      }

    b また別の方針で実装してみる事にする。
      実装した。動いている気がする。前のコードは削除する。

2019-03-28

  * complete: complete-into-braces に対応する [#D1043]

    候補をどの様に braces に変換するのかという事が重要になる。
    後、上限の文字数という物を決めておかないと大変な事になる気がする。

    | braces にする為には…。実は色々なやり方が考えられるとは思うが、
    | 取り敢えず前方から一致させるとどうなるだろうか。
    |
    | bash がどの様に振る舞うかについて一応確認しておく。
    | $ touch hello{a..c}{1..3}.txt
    | $ echo hello{a{1.txt,2.txt,3.txt},b{1.txt,2.txt,3.txt},c{1.txt,2.txt,3.txt}}
    |
    | 成る程。つまり、前方の一致だけしかまとめてくれない。
    | ではそうだとしても {a..z} の様な形式にまとめてくれたりするだろうか。
    | $ touch world{1..10}
    | $ echo world{1{,0},2,3,4,5,6,7,8,9}
    | $ touch check{1..9}
    | $ echo check{1,2,3,4,5,6,7,8,9}
    | この結果を見ると a..z の形式には対応していない様子である。
    | 全て , によってまとめられてしまう。
    |
    | 取り敢えず最短にするなどの事は考えずに挿入すれば良いだろうか。
    | 取り敢えずクォートは勝手に外す事にする。
    |
    | 処理は bash でやるよりも awk 等に投げてしまった方が楽そうである。
    |
    | - 実装としては漸化式的に考えれば良い。
    |   今までに確定した部分と、確定していない部分。
    |   一つ前の文字列と較べてどこまで一致しているかで処理が変わる。
    |
    | - POSIX awk はちゃんと SUBSEP に対応していて、
    |   多次元配列 arr[a, b] がちゃんと使える。
    |   ちゃんと各要素の長さを別に管理すればちゃんと使える。
    |
    | - いざ {} を閉じる時に末尾からの brace expansion 取り込みを実行すると良い。
    |   そして最後に {a..z} 等の様なパターンに一致しないかというのをチェックする。
    |
    | - 複数の箇所に brace 展開が現れない限りは、
    |   最後に残る物は '^[0-9]+$' か '^[a-z]$' の時だけ {a..z} にまとめられないか
    |   チェックするだけで十分の筈である。
    |
    | うーん。この様に実装すれば bash の braces にまとめる機能よりも強力に
    | すっきりと brace expansion にまとめる事ができる。凄い。
    |
    | 取り敢えず、始めは欲張らずに先頭からの一致について実装を試みるのが良い。
    | うーん。クォートとかはどうしたら良いのだろうか。
    | これも多分どうにかなるので取り敢えずは実装する事にする。
    |
    | →いろいろバグを出したが取り敢えず動いている様な気がする。
    |   また後で実装を確認してみる事にする。

    一度実装してみて何となく分かったので再度上の議論を整理する。

    * done: 改行を含む候補に対応する為には環境変数を使うしかないだろうか。
      と思ったが環境変数のサイズこそ制限があるはずである。
      大量のデータを環境を経由して渡すのは非現実的である。

      他の方法としては \0 で区切って渡すという物だが、
      RS = "" の時の振る舞いは POSIX で "空行" で record を区切るという物の様である。
      一方で RS = "\0" は gawk は認識するが可搬ではない。
      従ってこの方法も取りづらい。

      或いは ASCII か Unicode の特別な文字を使って分離するという手もある。
      特に制御文字で (^0 以外の) 誰も使いそうにない物を使う。
      意味的には FS などを使いたくなるが誰かが使いそうな気もする。
      伝送制御 DLE 等は誰も使いそうにない気がする。
      DEL だとかは意味的には NUL に近いので使いたくなる気もするが、
      こういった有名な物はやはり誰かが使いそうな気がするので避けたい。

      完全な答えではないが DLE を使うのが一つの手である。
      C1 の文字を使うてもあるとも思ったが、
      本当に文字コードに依存しないのかどうか怪しいので止めておく。
      うーん。しかし C0 文字というのは実は Ctrl-X に対応しているので、
      制御文字としては使われなくてもキーボード操作として使われる事はあるのではないだろうか。
      やはり ^@ を使って分割したい気がする。

      或いは初期化時に備え付けの awk の特性を調べておくというのも手かもしれない。
      或いは起動が遅くなるのは嫌なので一番最初の実行時で良い。
      2回目以降の呼び出しではキャッシュした内容を使用する。
      % と思って gawk で試してみたが RS = "\0" を認識していない…。
      % stackoverflow の記事に騙された…?
      % https://stackoverflow.com/questions/9170119/could-sed-or-awk-use-nul-character-as-record-separator
      % の最初の回答の最初のコメントによると確かにそう書かれている様に見える。
      % https://www.gnu.org/software/gawk/manual/html_node/gawk-split-records.html#gawk-split-records
      % にもその様に書かれている。
      あー。<<< $'a\0b' だと bash の側で \0 以降を消去してしまうのであった…。
      printf 'a\0b\0c' で流し込んだら実行できた。OK。
      gawk ではなくて awk の名前で起動してもちゃんと認識している。

      一応対応した。動いている。

    * done: 先ず候補は sort -n 的な方法で sort して置きたい。
      そうしないと {1..10} の様な場合に対応する事ができない。
      sort を呼び出すにしても改行区切りでないと辛いのでは。

      調べてみると sort には -z オプションがある。NUL で区切れる。
      と思って POSIX に行くと -z は廃止されたと書かれている。駄目だ。

      或いは落ち着いて考えてみると {1..10} の様な場合については、
      順番が変わっても (どうせ sort という作戦を取ろうとしていたのだし)
      良いので連番になっているかどうかをチェックする、というので良い気がする。

    * done: クォート等に関しては現在の実装の to_atoms を場合に応じて
      適切に選択する事で対応できる気がする。
      というかそもそも引用符は外さないとブレース展開を有効にできない。
      或いは、ブレース展開の周辺だけ引用符を外すという手もあるのかもしれない。
      何れにしても文脈に応じた to_atoms と出力を実施したい。

      to_atoms だけではなくて quote を閉じたり開いたりするのも実行しなければならない…。
      取り敢えずそれも実装した。本当にこれで良いのだろうか…。
      うーん。前方まで置き換わる場合など考えると不完全な気がする…。

      無駄に沢山の引用符が挿入されてしまうなど課題は残っている気がするが、
      それはまた別の項目を立てて考察するのが良い気がする。

    また現状の振る舞いが変なので修正をしなければならない。

    x fixed: どうも rfrag[-1] がクリアされていないのが問題の様である。
      というかそもそも rfrag[-1] を使うという事自体が変である。
      →修正した。前よりもすっきりしたコードになった。

    x fixed: {1..10} の様な物に対応したと思ったが、
      その前に前方括り出しで 1{,0} 2 3 4 ... に変換されてしまうので、
      {1..10} にはならないという事が分かってしまった。

      | これはどの様に対処すれば良いだろうか。例えば、
      | 数字の連続に関しては atom として取り扱う等?
      | そうしても問題ないだろうか。例えば 120 110 150 を
      | 1{2,1,5}0 ではなくて {120,110,150} にするという事。
      | うーん。数字の連続は atom にした方が分かりやすそうだ。
      | とも思ったが、これが物凄く沢山数字が並んでいて末尾の数字だけ違う等だと大変。
      | 然し、二桁以上の数字の場合には必ずこの様に分解される事は必定。

      従って、やはり数値は atom として取り扱うべきなのである。

      数値を atom にしても動かない。
      前の番号が w1 の時 w10 が来たとすると w1 まで一致しているので、
      0 以降を atom で分解する様にしようとしている。
      うーん。これは get_matching_depth を修正する必要がある。

      修正した。適当に修正したら何だか完全に動く様になった気がする。
      これで気にしない事にする。

2019-03-25

  * main: 今や inputrc を勝手に読み込んでも良いのではないか [#D1042]

    後、inputrc を読み込まない様にする設定も欲しい。
    然し、bleopt を呼び出すのは blerc の中か ble.sh を source した後である。
    然し、その時には既に inputrc は読み込まれている。

    * fixed: うーん。所で .inputrc の中で set editing-mode vi 等とした時に、
      ちゃんと keymap が正しいものに選択されるのだろうか。
      opt_keymap に使われる既定の文字列は空文字列にしている。
      という事を考えたが辿ってみると、ちゃんと空の時には、
      ble-decode/DEFAULT_KEYMAP → bleopt/get:default_keymap
      という経由で正しい物が選択される様になっている。
      但し、 ble-decode/DEFAULT_KEYMAP は edit.sh 側で上書きされた物でなければならない。

      うーん。decode.sh の ble-decode/DEFAULT_KEYMAP の時点で
      ちゃんと切り替わる様になっているべきなのではないか。
      →最初からその様になるように実装し直した。

    * ok: 後、read-inputrc の中で呼び出している bind は…。
      勝手に二重に起動されていたりはしないだろうか。
      →大丈夫。ble/builtin/bind/.process しか呼び出していない。
        そして ble/builtin/bind/.process が呼び出しているのは
        オプションを指定した時の builtin bind だけである。

    * fixed: 万が一 - で始まる内容が inputrc の中に含まれていたとしても、
      それをオプションとしてではなく束縛の設定として解釈させるために、
      -- をつける必要があるのではないか→つけた。動く事を確認した。

    inputrc を読み込まない為の設定として
    ble.pp に --noinputrc というオプションを追加した。
    これを指定していない限りは .inputrc を読みに行く事にする。

    * done: bleopt_internal_suppress_bash_output に対応する機能も
      引数から指定できる様にするべきなのでは。
      というかそもそも bleopt_internal_suppress_bash_output= は動作するのだろうか。
      今試してみた所、一応ちゃんと動いてはいる様である。
      オプションの名前を考える事にする。

      --debug-enable-bash-output
      --debug-keep-bash-stdout
      --debug-keep-bash-output
      --debug-no-interrupt-bash-output
      --debug-free-bash-output
      --debug-full-bash-output

      うーん。keep が良い気がする。debug という prefix は必要だろうか。
      まあ、debug 用の機能という事が分かる様に debug はつけるべきである。
      或いは debug が動詞だと考えるのであれば、

      --debug-bash-output

      でも良いのではないだろうか。うーん。これが良い気がする。

    * done: --help にも対応するべきなのでは
      うーん。引数を解析するのは実は全ての初期化を終わった後である。
      然し、--help や --version を表示する為だけに全部ロードするというのは変である。
      その様に考えると最初に引数の解析は終わらせて置くべきなのだろうか。

      因みに version を解析する箇所は check-environment の後である。
      version だけは一番最初に初期化してしまっても良い気がする。

      うーん。--help や --version は実はシェルに依存せずに動作して欲しいのではないだろうか。
      その様に考えると、実は引数の解析は sh 準拠で実装しなければならないという事になるだろうか。

      対応した。簡単な対応なので --rcfile --help 等の指定があっても反応してしまうが、
      面倒なので妥協する事にしようと思う。sh で解析するのは面倒である。

  * emacs: insert-comment に対応する [#D1041]

    x fixed: 実行している途中で落ちると思ったら
      redispatch の実装を誤っていて無限ループになっていた。
      decompose-meta で修正した物に置き換えている積もりが、
      元と同じキーシーケンスを食わせていた為であった。修正した。

    対応した。動いている様に見える。
    元の bash では先頭にしか # を入れないが、
    ble.sh の実装では各行に挿入する事にした。

  * emacs: character-search{,-backward} に対応する [#D1040]

    これは文字を一つ受け取って実施する所も含めて vi の f と同様の機能である。
    但し、key を受け取るのではなくて本当に char を受け取る。
    つまり、quoted-insert と同様という事である。

    delete-forward-char-or-list も実装が簡単だったので一緒に実装した。

2019-03-24

  * emacs: readline-dump-{functions,macros,variables} に対応する [#D1039]
    これはとても簡単だった。本来は ble-bind の設定を出力するべきなのではないか、
    と思わないでもないが面倒なのでこれで良い。

    もし実装するとしたら dump-macros については
    ble-bind -P | grep 'ble-bind -m [^ ]+ -s ' 等として出力するしかない。
    また dump-functions の様な逆引き機能を提供するのは難しい。
    真面目にやろうと思うと全ての widget について keymap を検索しなければならないので非効率的である。
    dump-variables はそのまま readline の変数を出力してしまえば問題ない。
    何れにしても余り必要性を感じないので現段階では ble-bind 版は提供しない事にする。

  * edit: re-read-init-file に対応する [#D1038]
    既に decode.sh で ble/decode/read-inputrc を実装しているから簡単だと思ったが、
    よく考えたら本当にそうだろうか。
    set keymap に応じて現在の keymap を切り替える必要があるのではあるまいか。
    これは以前 ble/decode/read-inputrc を実装した時の手落ちである。

    [調査]

    opt_keymap が空の時には set keymap で指定した所から読み出す必要がある。
    うーん。本当だろうか。実はこれが有効なのは inputrc の中だけだったりはしないだろうか。
    振る舞いを調べなければならない。

    | 実際に set keymap をすると完全に keymap が切り替わってしまう。
    | うーん。これはどの様に処理したら良いのだろうか。
    | 要するに bind の呼び出しを跨いで "現在の keymap" という物が存在するという事になる。
    | これはグローバル変数にでも記録しておくしかないだろうか。
    | 然し、グローバル変数に記録した "現在の keymap" というのをクリアするタイミングというのは何か。
    | 例えば bash の場合にはコマンドを実行する度に keymap はリセットされる様である。
    | 然し、コマンドが実行されない限りはリセットされずに保持されている。
    | 本当だろうか。と思ったが、コマンドが実行されてもリセットされずに保持されている。
    | そして bind の適用対象は相変わらず set keymap で指定した keymap になっている。
    |
    | - done: $include を跨いでも持続するのかどうか → yes
    | - done: bind -f を跨いでも持続するのかどうか → yes
    |   D1038.test1.* を用いて調べた。結果は
    |   $ source D1038.test1.0.sh
    |   # keymap emacs
    |   "A": "from 0.sh"
    |   # keymap vi-insert
    |   "B": "from 1.inputrc"
    |   # keymap vi-command
    |   "C": "from 2.inputrc"
    |   "D": "from 1.inputrc"
    |   "E": "from 0.sh"
    |   set keymap vi
    |
    |   内部で設定した keymap が外側にも残っているという事が分かる。
    |   つまり $include を使っても bind -f を使っても設定は持続する。
    |
    | - 因みに bind -f はそれを記述しているソースファイルからの相対パスではなく
    |   現在のディレクトリからの相対パスとして解釈される。
    |   一方で $include に関しては、それを記述している inputrc ファイルからの相対パスで行ける。
    |   と思ったら勘違いだった。現在のディレクトリからの相対パスでなければならない。
    |   ファイルが見つからなかった場合には何もエラーメッセージがなく失敗する。
    |
    | - done: re-read-init-file (inputrc) を跨いでも持続するのか
    |   →抜ける時に既定の物になる(入る前の状態に復元する訳ではなく editing mode に固有の keymap に矯正される)
    |
    |   これはどの様に調べれば良いか。C-xC-r で re-read-init-file を呼び出す事ができる。
    |     INPUTRC=D1038.test1.1.inputrc
    |     \C-x\C-r
    |   という具合にすれば良いだろうか。
    |   うーん。 D1038.test1.0.sh の中身で bind -f の行の部分だけ
    |     INPUTRC=D1038.test1.1.inputrc
    |     \C-x\C-r
    |   に置き換えて実行すれば良い気がする。
    |   うーん。そもそも C-xC-r で読み込まれていない気がする。
    |
    |   実際に試してみると re-read-init-file の中で設定した keymap は見えない様である。
    |   というか re-read-init-file を実行すると keymap はリセットされる様子である。
    |   また、re-read-init-file の中では外側で設定されていた keymap は見えるのだろうか。
    |   確認してみた所外側で設定されていた keymap が保持されている様である。

    まとめ

    * set keymap をすると本当に編集に用いている keymap が切り替わる。
      当然 bind の既定の対象も切り替わる。
      * コマンド実行を跨いでもその効果は持続している。
      * bind -f や $include の中で行った切り替えも外側に影響を与える。
      * 外側の設定は re-read-init-file の中で見えるが、
        re-read-init-file が終わる時に既定の keymap に強制的に戻る。
    * bind -f filename 及び $include filename は現在のディレクトリからの相対パスである。
      これらのコマンドを記述しているスクリプト・初期化ファイルからの相対パスではない。
      (ble.sh ではファイルからの相対パスに対応しているが余計な機能だったかもしれない)

    [実装]

    * fixed: うーん。何と現在の editing mode と関係なく keymap を切り替える事ができて、
      しかも切り替えるとその editing mode でコマンドラインが編集できるという状況である。
      これは微妙である。ble.sh が動かなくなってしまう原因なので、修正する必要がある。
      因みに set -o emacs もしくは bind 'set editing-mode emacs' を明示的に呼び出せば、
      既定の keymap に自動的に戻る様子である。つまり、ble-decode/attach する直前に
      set -o emacs もしくは set -o vi を呼び出せば良いという事になる。

    * fixed: うーん。ユーザのコマンドによって keymap が勝手に切り替えられてしまうという事はあるだろうか。
      そういう事があった場合でも ble.sh は動作を停止してしまう事になる。
      その様な場合への対策として、やはりコマンドを実行した後に keymap を復元する必要がある。
      実際に試してみた所、確かに一時的に変な状態になってしまうが RET を押すと治る。
      恐らくコマンドを一つ実行すれば元の keymap になって動作が戻るという事なのだろう。

    * done: 現在の bind の対象の keymap を _ble_builtin_bind_keymap に保持する事にした

    * ok: bind -f 及び $include は現在のパスからの相対パスを優先させる?
      うーん。普通に考えたらファイルパスからの相対パスを優先させる方が自然である。
      なので、bash の振る舞いと変わってしまう所ではあるが現在の振る舞いを保持する事にする。

    まあ、これで多分大丈夫だろうという気がする。動作チェックは面倒なのでしない。
    試しに source D1038.test1.0.sh を実行してみた所、ちゃんと動いていた。
    但し、bind -s は代わりに ble-bind -P | grep ' -s ' としなければならない。
    re-read-init-file についても動作確認してみた。

    * fixed: ble-bind のエラーメッセージに ble edit function という語句が含まれている
    * fixed: bind 'set editing-mode' の時に keymap はクリアするべきではないのか。

  * edit: kill-while-line に対応する物があったのではないかと思ったが [#D1037]
    そういう物は実装されていない様だった。kill-forward-line (C-k) 及び
    kill-backward-line (C-u) に倣って実装しようと思ったが、
    それぞれ logical/graphical の二種類があって、
    更に引数の有り無しで改行も一緒に消すかどうかの動作まで切り替わる様で、
    何だか複雑だったので最初から実装し直す事にした。
    最初から実装し直したらすっきりとした実装になった。

  * menu-complete: 現在 "表示" されているメニュー項目から候補を生成している? [#D1036]
    ble/complete/menu/generate-candidates-from-menu の実装を見て思った。
    menu-filter した後の menu_items ではなくて、
    更にその後に表示を行っている menu_icons から読み取っている気がする。

  * global: builtin echo を関数に置き換えるというのはどうだろうか [#D1035]

    実際に benchmark-201903-builtin-echo.sh というスクリプトで試してみる。
     7.37 usec/eval: echo.normal (x10000) (echo)
     7.70 usec/eval: echo.builtin (x10000) (builtin echo)
    10.97 usec/eval: echo.function1 (x10000) (関数内で builtin echo)
    12.37 usec/eval: echo.function2 (x10000) (printf %s\n による実装)

    まあ、誤差の範囲内である。
    ふと思って &>/dev/null の繋ぎ変えを削除して実行してみる。

    3.22 usec/eval: echo.normal (x20000)
    3.63 usec/eval: echo.builtin (x20000)
    6.75 usec/eval: echo.function1 (x10000) ble/builtin/echo1
    7.67 usec/eval: echo.function2 (x10000) ble/builtin/echo2

    うーん。実は二倍ぐらいの時間がかかっているという事か。
    echo の呼び出しと、関数呼び出しと、&>/dev/null の時間は大体同じぐらいという事。
    然し、ユーザで echo を置き換えてやろうという事を考える人は本当にいるだろうか。
    例えば、echo の振る舞いを標準化してやろうとして echo を置き換えたいという人はいるかもしれない。

    6.35 usec/eval: echo.functionS (x10000) ble/print
    6.29 usec/eval: echo.functiont (x10000) ble/p

    うーん。やはり関数名は短い方が高速に動作する様子である。

    a ble/print 的な関数を作ってしまっても良いのかもしれない。

    b ble/p でも良い? 然し汚い感じがする。
      というか其処まで速度を気にする必要はない筈である。

    c ble/builtin/echo という事にしようか。
      しかし ble/builtin/* は builtin を置き換える関数の為の名前だった気がする。
      従って、やはり別の名前の方が良いのではないか。
      本当に builtin の関数を呼び出したければ builtin echo とする。とそういう物。

    d ble/bin/echo は大丈夫だろうか。
      ble/bin は command として実行する為に置き換えられてしまうのではないか。
      と思って調べてみたが、別に明示的に指定しない限りは特に置き換えは起こらない様である。
      考えてみれば当たり前である。わざわざ呼び出される度に検査する訳ではないので、
      勝手な置き換えは起こらない。

      問題は ble/bin/echo だと command 版が呼び出される様に錯覚してしまう事である。
      うーん。やはりコマンド版が呼び出されると勘違いしそうなので良くない。

    e 或いは ble/util/print でやはり良いのでは。。ble/util/p とか。
      と思ったが -n に対する処理を考えるとやはり echo が良い。

    f そう思うと ble/util/echo という手もある。

    うーん。考えるのが面倒になったので、取り敢えず ble/bin/echo という事にする。

  * vbell: menu complete でページを移動している時に [#D1034]
    ページ番号が短くなった時に前の表示を消しきれていない。

    うーん。persistent だったとしても前の表示を消して良い筈。
    と思ったが、persistent の時にはすぐに終了してしまう?
    そして終了してしまうともう表示されていないのではないかと判定されてしまう。
    workerfile を空にせずに終了すれば良いのではないか。
    そうすれば未だ表示されている内容があるという事の意思表示になる。

    問題になっていたのは worker が生きているのにも拘わらず、
    workerfile の中身が空になって、他の worker の為に同じ
    workerfile が使われてしまうという事だった。
    従って、worker だけが生き続けて workerfile が有限の内容を持ったまま残るというのは問題ないのでは。

    x と思ったのだが、よく考えたらそうでもない。これだとその workerfile はずっと残り続けてしまう。
      うーん。worker が終了したらやはり消去するべきなのである。

    * 所で worker が予期せず終了して workerfile をクリアしなかったらどうなるのだろうか。
      その様な場合にも workerfile が残り続けてしまうが、
      そういった事故はそんなには起こらない筈なので多少残っていても問題はない。

    結局、思っていたよりも様々な状態があるという事。

    - 次の表示が始まっていて既に表示は消えている状態
      これは ftime と有限サイズ workerfile のタイムスタンプを比較して判定できる。
    - 未だ表示されていてそして worker も生きているという状態
      これは workerfile が有限の大きさを持っている事によって判定できる。
    - 表示が消されていて worker も消えているという状態
      これは workerfile が空になっている事で確認する事ができる。

    if [[ -s $workerfile && $workerfile -ot $ftime ]]; then
      # worker は生きているが、既に消去済み
    elif [[ -s $workerfile ]]; then
      # worker は生きていて、表示も消されていない。
    else
      # worker は死んでいる。workerfile は再利用可能。
    fi

    これに加えて表示は未だされているが worker は死んでいるという状態がある。。
    これはどう判定したら良いのだろうか…。
    実は単純にダミーの workerfile を作れば良いという事になるだろうか。
    "死んでいて動いていない worker" の workerfile として *.Z というのを作る。
    これは .erase-previous-visible-bell の判定に入るのでこれで動く筈。

    動作確認した。ちゃんと動く様になっている。

  * menu: 取り敢えず menu 選択機能だけは実装する [#D1033]

    * done: iloop をもっと別の名前にする
      →これは主に menu#construct の中だけで使われている。menu_iloop にした。
      更に complete 中に使う判定ではなくて menu 専用の判定に切り替えた。

    * linewise に項目番号を表示する機能をつけても良いのではないか
      或いは > だとかそういう装飾を設定できる様な自由度があって良いと思う。

      考えてみたがどういう自由度を持たせるのかというのは難しい。
      項目番号だけしか提供しないのであればそれで良いのかもしれないが、
      例えば複数選択時に選択されているかどうかの表示を含めるとか、
      或いは何かの文字を表示するとか、番号に応じて色を変えるだとか、
      或いは番号を二種類表示するとかそういう事があったらどうするのだろう。

      例えば PS1 の様に \? という形式で指定できる様にするとしても、
      フォーマットをどの様に指定するかが問題である。
      printf の様に %d 等の形式にするとすると、
      フィールドの順序と数は固定しなければならなくなってしまう。
      然し、現実的な事を考えれば複数選択時には別の枠組みで表示するべきだし
      (ユーザの設定によって表示されたりされなかったりというのは不便である)、
      番号の他に表示するべき項目などはあるだろうか。

      その様に考えるとやはり printf と %d を用いた形式で
      指定できる様にするのが現実的な感じがする。
      問題はどの様に外部から指定するのかという事。
      bleopt で指定する仕組みにすると (一時的な変数だとしても)
      何だか global な設定を指定している様な感じがして変である。
      或いは menu_style 変数に引数を指定できる様にするか。
      うーん。やはり bleopt で指定できる様にするのが良い気がしてきた。

      変数名はどの様な物が良いだろうか。
        bleopt menu_linewise_number_format
        bleopt menu_linewise_ps
        bleopt menu_linewise_fmt
        bleopt menu_linewise_bullet_format
        bleopt menu_linewise_prefix
      長いのも何だか面倒なので最後のにしようか。
      然し、prefix は乱用しすぎて何だかわからない。

      * reject: 或いは bleopt menu_linewise_format='%d %s'等にして、
        番号と項目の両方を指定させてしまうという手もあるかもしれない。

        x うーん。幅がずれたりするのを調整するのが面倒である。
          しかし、幅という事で言えば %3d 等とした時点で
          予想外の数の候補が来た時には何れにしてもずれる事になる。
        ? 後は、%s に何を指定するのかという事もある。
          %s に指定するのは SGR も含めた文字列だろうか。
          だとすると printf を適用するのは SGR の処理の後である。
          従って番号の着色は指定する事ができない。
        x というか項目の選択範囲の計算がこれだとできないから駄目。

      まあ、取り敢えず最後の物を使うことにする。
      取り敢えず実装してみた。動いている。

    実装はしてみたが何の役に立つのかよく分からなくなってきた。
    もっと高機能になってから具体的な用途を持って使わないとインターフェイスが定まらない。
    これ以上編集するとごちゃごちゃしそうなので取り敢えず commit する事にする。

    そもそも現在の menu#start という関数は適切なのだろうか。
    menu_style は決め打ちだし、menu.class も決め打ちである。
    そして、引数に与えた文字列を選択できるだけという物である。
    また、気になるのはこれを widget の中で使う分には良いが、
    通常のコマンドとして実行してしまうと、
    すぐに終了して読み取り待機状態になるので表示が乱れてしまうという事。

    うーん。vi_cmap と同様に新しいプロンプトを出して処理するとか、
    そういう事が必要になるのではないか等。
    然し、現状では使い道がないのでサンプル実装として menu#start を置いて置く事にする。
    これに依存したコードは未だ書かない様に注意する必要がある。

  * menu: \commit での menu の項目の着色が消えている? [#D1032]
    調べてみると comp_type が空になっていて着色が無効になっていた。何故だろうか。
    →これは sabbrev では comp_type が空のままだからであった。
      readline variables の読み取りを sabbrev でも行う様にした。

    更に選択するとやはり着色が無効になっていた。
    これも選択の度に comp_type が空になっているのが原因であった。
    comp_type を初期化する様に修正した。

    readline variables の読み取りの箇所は comp_type を宣言した所であるべきでは。
    と思ったが別に現状で良い気がしてきた。menu から読み取る場合には
    結局以前使った comp_type を復元するのだから、
    実際に候補を生成する場所で comp_type を作れば良いのである。
    その様に考えると現在の場所で問題ない様に思われる。

  * menu: desc の説明が取得できなくなっている… [#D1031]
    これは local desc としてしまっていたのが問題だった。直した。

  * decode: charlog/keylog に関して再考 [#D1030]

    うーん。menu_complete/exit-default 等は redispatch でなくても本当に良いのか。
    改めて考えてみる事にする。入れ子の呼び出しの場合には keylog は記録されない。

    x fixed: また、ble-decode-char の _ble_decode_keylog_chars に登録する場所で

      | _ble_decode_keylog_depth のチェックが本当に効いているのかというと怪しい。
      | というのも ble-decode-char は入れ子の呼び出しの場合には、
      | 実際の実行を呼び出し元に任せてすぐに抜けるからである。
      | つまり、常に一番外側でしか char を処理しないので、
      | _ble_decode_keylog_depth は常に 0 になっている。
      | 従って、入れ子の呼び出しによって再度 ble-decode-char を処理する、
      | というような場合にも全て処理した文字が登録されてしまう事になる。
      |
      | これを正しく処理する為にはどの様にしたら良いだろうか。
      | 例えば ble-decode-char を呼び出す際に charlog に記録されている内容を pop するなど?
      | どういう箇所で ble-decode-char が呼び出されているだろうか。確認する。
      | - マクロ再生の箇所2箇所 (vi, emacs)
      | - ble/builtin/read のループ
      |
      | うーん。逆にこの箇所に於いて charlog の suppress を明示的に指定すれば、
      | 他は全て charlog に記録されてしまっても問題ないのでは。。
      | と思ったが、此処で明示的に suppress を指定したとしても、
      | 結局処理が遅延されるのであれば suppress が効果を発揮しない。
      | (char buffer に登録する時に suppress の情報も一緒に記録する、
      | というようにするのは無駄に処理が複雑になるので余り考えたくない。)
      |
      | 逆に再生中は記録状態にはないと考えて、
      | そのまま記録させてしまうというのでも良いのかもしれない。
      | 或いは、再生に用いた文字を pop して、
      | 再生内容で置き換えるという様に考える。
      | そちらの方が現実的の様な気がしてきた。
      |
      | と思ったが本当だろうか。やはり "再生" という処理をしたというのは
      | 記録に残っても良いのではないかという気もする。うーん。
      |
      | うーん。何故こんなにも複雑になってしまうのか。
      | 本来はもっと簡単な事ではないのか。
      | 例えば、ユーザから入力された文字については記録するけれども、
      | マクロ再生などによって入ってきた文字については記録しないという具合に。
      | 問題は何処にあるのかというと。処理の順番にある。
      | 処理の遅延を考えないのだとしたら、
      | 普通にユーザから入力された文字を受け取った時点で記録すれば良い。
      | マクロ再生などの場合には記録せずに処理を行えば良い。
      | 然し、処理を遅延させている場合には、単に記録すれば良い訳ではない。
      | 例えばマクロの記録をしている時には、
      | マクロの終了が呼び出された段階での charlog の内容を見ると問題になる。
      | charlog には未だ処理されていないが既に受信した文字などが全て入っているからである。
      | 従って、charlog には実際に処理した文字を追加するという様にしなければならない。
      |
      | うーん。現在エラー文字に関しては特別のフラグを立てて処理している。
      | 結局、同様に特別なフラグを立てて charlog に入れないという様にするのが良さそうである。
      | depth のチェックは意味をなしていないので削除する。

      結局 buffering を行う ble-decode-char に於いて
      自動的に charlog に登録するかしないかを判定するのは困難であるという結論。
      従って、ble-decode-char に文字を渡す時点で、
      文字にフラグを設定して charlog に登録しない事を明示する事にした。

    改めて exit-default における redispatch について考える。

    * resolved: charlog に関してはこれで多分問題ないと思われる。本当か。

      | 具体的に動作を考えてみる。
      |
      | 1. exit-default が呼ばれる
      | 2. ble-decode-key で改めてキーが処理される
      |   然し、charlog は通過しないので勝手に新しい文字が増える事はない。
      | 3a. (2) の結果として例えば普通のコマンドが選択されたとする。
      |   この場合にはやはり charlog に対しては何も起こらない。
      |   また、この呼出は入れ子の呼び出しになっている為、
      |   _ble_decode_keylog_depth が多い。従って charlog のクリアも起こらない。
      | 3b. (2) の結果として end-keyboard-macro が呼び出されたとする。
      |   この場合には charlog#pop が呼び出されて
      |   元々の exit-default 呼び出しに要した文字の列が削除される。
      |
      |   うーん。この動作は本当に大丈夫なのだろうか。
      |   考えてみれば end-keyboard-macro が複数回呼び出される様な事があると、
      |   charlog#pop が複数回呼び出されて変な事になる気がする。
      |   従って、charlog#pop に相当する操作は配列を得た後で行うべきなのでは。
      |   もしくは charlog#end-without-current-call 的な物。
      |   charlog#end-exclusive という名前にする。
      |
      |   と思ってよく考えてみたらどうせ #pop した後に #end して
      |   中身は空になるので複数回呼び出しても余り問題はなかった気もする。
      |   然し、設計としてはこちらの方が自然なのでそれで良い。
      |
      | 4. ble-decode-key が終わったら exit-default に戻る。
      |   そして exit-default を抜けると keylog_chars_count がクリアされる。

      charlog#pop & charlog#end ではなくて、
      charlog#end-exclusive という関数で取り出した後に削る事にした。
      これで良い気がする。

      うーん。よく考えたら駄目な気がして来た。
      というのも、再生した時には exit-default までを実行したいはずなのでは。
      然し、現在の記録方法だと exit-default も exclude されてしまう。
      とは言っても、一方だけを exclude するのは不可能である。
      うーん。入れ子の呼び出しの時には exclude しないという事にするか。
      →charlog#end-exclusive-depth1 というのを実装した。

    * resolved: keylog に関しては真面目に考え直す。現状使っていないとは言え。

      | 例えば次の様に動作をする事にする。
      |
      | 1. exit-default を呼び出す (KEY が記録される)
      | 2. 中で ble-decode-key を呼び出す。
      |   この時 _ble_decode_keylog_depth の効果により、
      |   KEY が重複して記録されるという事はない。
      | 3a. これで呼び出されるのが通常コマンドの時は何も問題はない。
      | 3b. もし呼び出されるのが keylog#end を利用する物だったら。
      |   keylog#pop & keylog#end をしてそれまでの記録を取得する。
      |   この時 ${#KEYS[*]} は本当に正しいのだろうか。これはとても怪しい。
      |   うーん。_ble_decode_keylog_chars_count と同様に処理するべきなのでは。
      |   →_ble_decode_keylog_keys_count を導入した。
      | 4. ble-decode-key, exit-default を抜けると終わる。問題はない。
      |
      | keylog を用いてマクロを実装するとしたら、
      | charlog#end-exclusive-depth1 と同様の事をしなければならない。
      | 因みに vi.sh の qx...q の側でも迷い込んだ q は無視する様に既になっていた。

      _ble_decode_keylog_keys_count を導入した。
      今後 keylog によるマクロを実装する場合には、
      charlog#end-exclusive-depth1 と同様に処理する。

      他にも keylog に干渉するパターンがある。decompose-meta の類である。
      この場合には既に入力されたと思っているデータを書き換える目的がある。
      従って、redispatch の様な操作が必要になるのである。

    * ok: auto-complete は本当に redispatch が必要なのか。

      | これは勝手に起動した auto-complete を終了する為のキーとして記録が行われて、
      | 更にその時点で _ble_decode_keylog_keys_count がクリアされてしまうのが問題。
      |
      | 然し、それだと charlog の方もちゃんと対策が必要なのではないか。
      | と思ったが、よく考えたら depth=0 としている事によってそれを免れていたのだった。
      | なので、現状ではちゃんと期待通りに動いているのである。

      →つまり必要であるという結論になる。

    * 然し、そうすると menu-complete 等の exit-default の場合にも必要ではないかと思われてくる。
      これもまた抜けるのに使ったキーが其処で記録されて中途半端に記録が終了してしまう。
      然し、だからと言って redispatch するとその記録自体が exclusive-depth1 で消えてしまい、
      再生した時には exit-default の exit 部分自体も実行されずに終わるという事になる。
      だからといって exit-default -> end-keyboard-macro を検出できるかは謎である。
      直ぐに呼び出される場合には良いが、end-keyboard-macro を呼び出すための
      1文字目だけが exit-default で処理されたとすると、
      実際に再生を行った時に 1 文字目だけが中途半端に入力された状態で

      再生が終了するという事になる。その様な事になるぐらいであれば、
      そもそも exit-default も呼び出さないか、或いは end-keyboard-macro まで呼び出す。
      end-keyboard-macro まで呼び出すかどうかを判定するのは難しい。
      というかそもそも end-keyboard-macro を呼び出す為に使ったシーケンスなのであれば、
      exit-default の exit を起こすのが目的ではなかったと思われて、
      その場合には exit-default が再生で呼び出されなくても良いのではないか…。

      うーん。面倒なので menu-complete の exit-default の場合にも redispatch で処理する事にする。

    * では ble/widget/auto_complete/accept-line 等の ble-decode-key 13 はどうするのか。
      これも redispatch で処理するべきなのだろうか。
      原理的には 13 が end-keyboard-macro を呼び出すキーシーケンスの最初の文字になっている可能性はある。
      然し、一方で accept-line を呼び出すのに別のキーを使った可能性もあって、
      その場合には 13 に redispatch してしまうとそもそも accept-line が再現されなくなる可能性もある。
      うーん。これに関しては accept-line を呼び出すのに使ったキーが消滅するのは嫌なので、
      redispatch は実行しない事にする。

2019-03-23

  * complete: menu の枠組みの分離 [#D1029]
    実は menu の枠組みは他に流用できるのではないだろうか。
    補完とは切り離して利用できる様になると便利である。

    うーん。menu の表示部分と補完の処理部分の分離を試みる。

    * done: desc の説明取得部分は未だ分離できていない

    * done: 現在 menu_onselect だとか menu_item_renderer だとかで
      外部から振る舞いを変更できる様にしているが、
      どんどんと外部からの振る舞いが追加されていくと辛い。
      menu_class menu_param という二つの変数で制御できないだろうか。

        menu_class=ble/complete/menu-complete
        menu_param=object-id

      として置いて

        menu_param=$menu_param "$menu_class"/render-item

      の様にして呼び出してもらう事にする。

    * self-insert をどの様に取り扱うか。
      これは二種類の keymap を用意しても良いのではないかという気がする。
      特に積極的に filtering を行うモードの場合には、
      自由に keymap を弄り回したい気がするので。

      というか現在の menu_complete keymap はそのままにして、
      menu keymap としてその様な物を提供すれば良い気がしてきた。

    * accept だとか exit だとか cancel についても callback にする?
      これは具体的に menu の機能を利用する機能が出てきたら考える。

  * emacs: kbd-macro に対応する [#D1028]

    [実装案]

    既に vi の側で類似の機能を提供しているのだから何も考えずにそれを実装すれば良いのでは。
    vi での実装は ble/widget/vi_nmap/record-register にある。
    _ble_decode_key__hook="ble/widget/vi_nmap/record-register.hook" を設定して、
    ble/widget/vi_nmap/record-register.hook で記録先のレジスタの番号を取得すると、
    其処から記録を開始する。結局、実際に行っている処理は以下の通りである。

    | _ble_keymap_vi_reg_record=$reg
    | _ble_keymap_vi_reg_record_char=$ret
    | ble-decode/keylog/start
    | ble/keymap:vi/update-mode-name
    | return 0

    - さて何処に実装するのが良いのか。
      どんどんと emacs モードではなくて本体の edit.sh の方に機能を実装している気がするが、
      それで良いのだろうか。考えるに readline の機能は両方で使う可能性があるので、
      edit.sh に記録したいという気分である。一方で、emacs.sh に定義しておいて、
      vi 側から使いたい時には autoload で呼び出すという考えもある。

      うーん。所でマクロに関しては vi 側では qx...q があるので、
      その機能との混線を避ける事を考えれば vi 側では実行できない様にするべきなのでは。
      その様に考えるとやはり emacs.sh に実装したほうが良い気がする。

      一方で、そもそも混線しない様に設計するべきなのではないかという話もある。
      うーん。取り敢えず edit.sh に実装する事にする。

    - 記録の形態はキーの列で行う事にする。
      bash の振る舞いを見ると (print-last-kbd-macro で出力すると)
      文字単位で記録されている様に見える。
      然し、特殊キーなどを端末依存で記録するのも嫌なので、
      ble.sh の実装では、キーの列として記録して、
      print を求められた時には vi の記録と同様に内部形式で文字列に戻す事にする。

    - うーん。やはり文字列に変換して表示するのは分かりにくいだけで意味がないので、
      unkbd で戻した結果を表示することにするのが良い

    - [棄却] ble-decode-key abort/buffering 機能?

      然しキーの列として処理させようとして気づいたが、
      現在の枠組みでは byte または char に対して abort は効くが、
      key に対する abort は効かない。前回対応した時には char を buffering する様にしたが、
      文字に関しては buffering する様にはしていないのである。
      key についても同様に buffering する様にする必要があるだろうか。

      ? 然し、そうすると実は char に対する buffering は必要なかったのではないかとも
        思われてしまう。何故ならば char->key の処理は byte->char にも増して軽い気がするからである。
        まあ、実際にどうかは分からない。色々なシーケンスの検査をするので、
        実は char->key の方が重いような気もする。
        そのまま通過する char も多いと言いつつ、それは byte->char の時にも同様である。
        実測してみれば良い。

      ? 次に気になるのは _ble_decode_char_hook だとか、
        _ble_decode_key_hook の処理の順序が乱れないのか、という事である。
        例えば或る widget が _ble_decode_char_hook を要求したとして、
        実は既に後続の文字が ble-decode-key に全部吸収されている場合、
        _ble_decode_char_hook を通過せずに全部キー入力になってしまっている。

        従って、ble-decode-key の側で完全に処理しきらないまま
        ble-decode-char に戻してしまうと処理の順序が変わってしまう事になる。

        しかし本当にそうだろうか…。実はユーザからの入力が来た場合には、
        ble-decode-char が中断して ble-decode-key も中断して、
        という具合になって中途半端な事は起こらない、という事になったりはしないか。
        真面目に考えてみる。ユーザからの入力が大量に来るとする。
        ble-decode-char に文字が大量に現れる。
        ble-decode-key は key が来る度に真面目に処理をする。
        処理の途中で追加のユーザの入力が現れるとする。
        この時 ble-decode-key は制御を戻す。
        ble-decode-char も制御を戻す。
        ble-decode/.hook に於いて abort のチェックが行われる。
        abort があれば処理中の ble-decode-char/key の列は廃棄される。
        もし abort でなければ ble-decode-char の待ち行列に追加される。
        さて、処理は続きから実行される事になる。
        ble-decode-char に入り、もしこの時点で hook が定義されていればそれを実行する。
        そうでなければ ble-decode-key に入る。
        うーん。ble-decode-key の中で無駄に buffering していない限りは大丈夫の気がする。

        →実際に vi の実装で試してみたら問題になっている。駄目だ。
        vi は keylog ではなくて char レベルの記録 charlog に実装を切り替えた。
        従って emacs でも charlog にしないという手はないだろう。

    [実装]

    * done: 引数に対する仕様を確認する
      →再生時には繰り返し回数になる。記録時には何も意味しないだろう。対応した。

    * done: keylog が混線しないように現在の処理にタグを付けるなどする。
      →これは対策した。

    x fixed: 何故か再生がその場では成されない。
      一番外側の ble-decode-char ではないからだろう。
      これは ble-decode-char のループを修正した。

    x fixed: vi のマクロ再生時に必ず bell が鳴る。
      記録されている内容を見ると別に何か変な物が混入している訳でもない。
      →実は register#play の戻り値は意味があって、
      マクロの再生ができなかった時に失敗を返すのだった。

      では ble-decode-char が失敗を返しているのは何故だろうという話になるが、
      これは調べてみた所、入れ子の ble-decode-char はその場で登録するだけで、
      処理は外側の ble-decode-char に任せるからなのであった。

    * fixed: emacs の mode name に現在記録中である事を表す記号を表示する。
      →これは対応したはずだが何故か動いていない。
      これは footprint で変更がなければ更新しない様になっていたのが原因だった。直した。

  * edit: vi_cmap に於いて rps1 が表示されている [#D1027]
    read -e の時には抑制していた筈である。と思ったら抑制していなかった。
    read -e でも rps1 が表示されている。うーん。これはこのままで良いのだろうか…。
    read -e に関してはユーザ側で適当に rps1 を設定してもらえば良い話である。
    一方で、vi_cmap についてはやはり抑制した方が良い様な気がするが…。

    どの様に抑制するのが正しいのだろうか。
    例えば _ble_textarea_panel==0 の時にだけ表示する等?
    read に関して言えば元々 _ble_textarea_panel==0 で起動するのでこれだと消えない。
    一方で編集関数の中などから使った時には 1 で起動するので表示されない。
    ユーザが普通に使った時はユーザが自由に設定できて良い筈なので残しておいて良い気がして来た。
    従って、_ble_textarea_panel==0 の時だけ rps1 を処理する事にした。

  * vi: q によるマクロの記録で、quoted-insert 等が正しく記録されない [#D1026]
    実は quoted-insert 等 char hook を用いている機能は
    すり抜けているのではないか…。試してみる。
    →うわー。すり抜けている…。これは設計を考え直す必要がある。。。
    本来実行するべきは keylog ではなくて charlog なのではあるまいか。。

    * 取り敢えず ble/decode/charlog を実装する事にした。
      ble-decode/keylog をそのままコピーすれば良いだろう。
      と思ったのだが、微妙である。
      ble-decode/keylog/pop に対応する機能の実現方法が分からない。
      或いは、ble/decode/charlog を使う側で適当に処理すれば良いのだろうか。
      然し、widget は自分を呼び出すのに使った char をどの様に検出すれば良いのだろうか。

      a widget を呼び出す度にクリアする char の buffer を用意する
        もしくは char の count を用意する。
        うーん。ble-decode/charlog の記録をすると同時に count すれば良い気がする。

      b reject: KEYS に倣って CHARS の様な配列を用いて、
        その widget が呼び出されるに至った文字の列を提供する。
        これはそもそも有用なのか分からないし、実装が複雑そうだし重そう。

      c reject: keymap の __before_widget__, __after_widget__ 辺りで文字数を計る。
        うーん。これは実装として汚いし重そうである。

      然し、そんなに大げさなことをする必要があるのだろうか。
      もっと綺麗な解決方法はあったりしないのだろうか。

      - 因みに keylog/pop は既に vi の2箇所で使われている。一つは record-register であるが、
        もう一つは vi-command の decompose-meta (これは __default__ で処理される) に於いて、
        ble-decode-key を改めて再発行する時に分解前の記録を抹消する為に用いている。
        実は、これに関しては keylog 機能を削除すれば気にしなくて良くなるのではないか…。
        従って、keylog/pop に関しては record-register だけから用いられると考えて良い。

      d reject: 或いは charlog/end に至る文字の列を予め登録しておいて、
        それが来たら hook を呼び出させるという手もあるかもしれない。
        然し、それはそれで C-x ) 等の場合を考えると複数の文字の列の場合を考えなければならないし、
        また別のキー列の部分に現れる C-x ) に反応されても困るとか色々問題がある。

      うーん。良い案が思い浮かばないので charlog と一緒に count する作戦 (a) で行く事にする。

    * さて。文字ベースでの記録に変更した事によって 0 をどうやって記録するのかが問題になる。
      0 は結局、必ず C-@ に変換されると思ってよいのだろうか…。
      と思ったが、よく考えたら _ble_decode_char__hook 経由の場合には、
      変換されずに 0 として出力される事になる。
      従って、やはり 0 は 0 として記録しなければならない。
      例えば整数値の列として記録したら良いのだろうか。
      然し乍ら、register は元々文字列である。
      更に編集文字列中の部分文字列をそのまま貼り付けたいという需要もある。
      編集文字列中には ble.sh では C-@ は存在できないが、
      然しキーボードの操作としては C-@ があっても良いのである。
      従って C-@ もちゃんと記録できる様にしたい。

      うーん。C-@ だけ別の文字に変換して記録するのか…。
      うーん。既に isolated ESC は U+07FF という未割り当て文字に対応させている。
      その事を思えば、実は C-@ を U+07FE 辺りに適当に割り当てても大丈夫なのではないか?

      その様に実装した。:reg で表示した時に C-@ だけ何だか変な表示になってしまうが、
      まあ仕方のない事である。少なくとも今までの keylog による記録よりは綺麗である。
      様々な自動的に発動されるキーだとか修飾キーだとかが綺麗になっている。
      端末依存の表記になってしまっている部分はあるかもしれないが、
      差異(というかコンフリクト)はそんなにないだろうし、
      まあこちらの方が実際に受け取った文字の列なので見やすい。

  * isearch: どうも編集前の文字列に対して一致している気がする [#D1025]
    と思ったがそうでもないようだ。
    と思ったら履歴を移動した先で削除を行って、
    その場で検索を開始するとその場で一致している気がする。

    うーん。現在の項目で何故一致する事ができるのか…。

    分かった append になっていると現在の項目から next-history.fib が始まる。
    そして現在の項目は未だ edit に格納されていない。

2019-03-22

  * edit: alias-expand-line 実装 [#D1024]

    これを実装するにはどうしたら良いだろうか。
    知る限りをこれを実行する様な機能は bash では提供されていない。

    a 従って自前で実装するなどしなければならない。

    b 或いは readline に食わせて処理させる事など可能だろうか。
      例えば DA2 応答等を無理やり返答させて、続きを処理させるなど。
      つまり一旦抜けてから次の端末からの送信メッセージで
      alias-expand-line を実行させて、
      更にその次の文字を受信した時に続きの処理を実行する事にする。
      然し、端末が必ずしも応答を返してくれるとは限らない。

      やはり汚い事を実行するよりは自前で実装するのが良い気がする。
      環境に依存せず動くので安心である。

    自前実装する事にする。ble_debug=1 で観察した限りだと、
    コマンド名に相当する部分は必ず CMDI の単語になっている。
    キーワードや組み込みコマンド等の区別はない。
    どうも [[ ですら CMDI という事になっている。
    と、ここで alias '[[' を定義したら ble.sh が動かなくなるという問題…。直した #D1023

    CMDI なる全ての単語について alias を確認すれば良いという事だろうか。
    結局 tree-enumerate を用いて実装する事にした。
    何故ならば直接 _ble_syntax_tree を弄ろうかとも思ったが、
    そうすると _ble_syntax_tree の仕様変更があった時に問題になる。

    実際に回してみるとちゃんと動く。内部に単語がある場合には alias 展開は試さなくて良いだろう。
    alias があるかどうかの確認は cmdtype で実装している筈。
    と思ったが cmdtype で確認しているのは type -t を用いて alias かどうかを確認しているだけだった。
    alias の展開を実行しているのは ble/syntax:bash/ctx-command/check-word-end であった。
    展開している部分を ble/util/expand-alias として分離する。

    動いている。実装してみれば意外と呆気ない物である。

  * edit: alias '[['=hello とすると [[ と入力した時点でエラーメッセージが大量に出る [#D1023]
    と思ったら、どうやら ble.sh の処理に使っている [[ が全て hello に置換されている様だ。
    これは凶悪である。unset -f をやっているのと同じ箇所で unalias も実行しておくべきであろう。

  * 2013-06-04 説明書に注意点を書く [#D1022]
    + 問題点: 既存の bind を上書きする事
    + 問題点: 既存の trap を上書きする事
    →これらは説明書にその様に書いておけば問題ない

  * edit: {kill,copy,delete}-region-or の引数に [#D1021]
    {kill,copy,delete}- を付加して実行するのは分かりにくいのでやめる

  * 2017-12-04 emacs: 引き数: 単語関連 [#D1020]

    todo: ble/widget/単語関連
    現状では取り敢えず clear-arg する。後で仕様の確定も含めて対応する。

    2019-03-21 capitalize-word の類の実装と同時に実装する事にした。
    負の引数を与えた時の振る舞いはどうするのか…→適当に実装した。
    負の引数を与えた時の振る舞いの確認を行う。
    forward/backward-word は動いている。
    kill-forward-word も動いている。まあ問題ないだろう。
    delete-forward-word も動いている。

    x fixed: どうも forward-word が変である。
      恐らく一番最後に修正した skip-forward,backward が問題なのではないか。

  * emacs: rlfunc capitalize-word, downcase-word, upcase-word [#D1019]
    対応した。一緒に単語関係の widget の実装を整理した。

2019-03-21

  * decode: rosaterm で起動すると "no previous search" というメッセージが表示される [#D1018]
    何か変な物を受信している?

    調べると vi mode の search.impl で n または N の時に表示される。
    もしくは / ? # * でも表示される事がある?
    何れにしても最初に何か変な物を受信しているのが原因である事には違いない。
    うーん。やはり ble-decode/.hook 経由で呼び出されている。

    うーん。調べてみるとなんと rosaterm は CPR を "CSI Pn ; Pn n" で返す様だ。
    むう。因みに n は private sequence という訳でもない。というか DSR である。
    これは仕方がないので対策する事にした。

  * emacs: rlfunc forward-byte, backward-byte [#D1017]

    これらはどの様に振る舞うべきなのか。
    中途半端な位置に移動してしまって良いのだろうか…。
    類似の例として vim mode の nth-byte という物がある。
    これは文字内部には移動しない様に実装している。
    二分法によって適切な文字境界に移動する。
    逆に言えば forward-byte 及び backward-byte は、
    引数を指定した時にそのバイトまで移動するという様に実装できないだろうか。

    取り敢えず振る舞いに関する提案はさておき、
    readline で具体的にどの様に動くかについては確認しておいて良い気がする。
    →実際に以下の様にして日本語を入力してカーソルを移動して入力してみた所、表示が乱れた。
      $ bind '"\C-f": forward-byte'
      $ bind '"\C-b": backward-byte'
    つまり、readline の振る舞いとしては変な位置にカーソルを移動するという事になる。

    ble.sh の振る舞いとしてはどの様にしたら良いだろうか。
    中途半端な位置に移動した場合には次の文字境界まで移動するという事にしたい。
    然し、どの様にして文字境界を判定したら良いだろうか。
    一つの方法は vim mode の nth-byte と同じ様に二分法で位置を決定する。
    他にあるだろうか。1文字ずつ移動してバイト数を超えたら終わる?

    取り敢えず実装した。動作確認した。まあ、大丈夫だろう。

  * rps1: checkwinsize の時に rprompt が再描画されていない気がする [#D1016]
    と思って落ち着いて調べてみた所、再描画はされているけれども、
    元々あった内容の消去ができていない、という事の様である。
    サイズが変わったら el2 を使って全て消してしまうほうが良いのかもしれない。
    と思ったらページ内容を消去するのは ED (\e[J) であった。
    _ble_term_ed を定義して再描画時にそれを出力する様にした。直った。OK

  * complete: ブレース展開の中ではファイル名の直後に ' ' ではなくて ',' を入れたい [#D1015]
    もしくは何も入れない。
    取り敢えず , を入れる事にした。これは簡単に実装できた。

  * complete: 曖昧補完であっても既存の部分が一致している場合には置換しなくて良いのでは [#D1014]
    例えば chat 上で ~/.in に対する補完で再現している。
    inputrc がなかったので別のファイルに曖昧一致しているが、
    その時に ~/ が /home/murase/ に無駄に置換されてしまっている。
    うーん。これは変だ。補完候補生成の段階で /home/murase は ~ に置き換えられる筈なのである。

    調べてみて分かった。"既存の部分" は "/home/murase/.in" なので、
    "/home/murase" の部分だけが一致していても仕方がないのであった。

    a 候補生成側での COMPS への置き換えをもっと細かく実行する案

      ではディレクトリ毎に一致しているかどうか確かめれば良いのか、というと、
      COMPV のディレクトリの区切りが COMPS のどの部分に対応するかは非自明なのであった。
      かと言って COMPS を適当に切断しながら評価していくというのも大変である。

      % うーん。理由は分からないが候補生成側で共通部分に対する置換を実行する事にする。
      % 問題は先頭一致部分をどの様に修正するのかということである。

      うーん。曖昧補完の時には実は COMPV は信用できない。
      何故ならば候補生成時に COMPV を書き換えて短くする等している為である。
      ファイル名の場合には自前で処理する為に COMPV の書き換えを実行していないが、
      一般の枠組みとして考えるとやはり共通部分を決めてから
      COMPS に一部戻すなどの事が必要なのではないか。
      しかしどの様にして戻すのかというのは難しい問題である。
      例えば、不一致部分が特殊文字を含まず裸であれば、
      COMPS の末尾からその文字数分だけ削って、
      共通部分を置き換えるという様にすれば良い。

      然し、ファイル名の処理の時にだけ / 区切りで一致部分を探すというのも現在の枠組みでは面倒だ。
      現在は COMPS への置き換えは quote-insert を通じて行っているが、
      この quote-insert は全ての source から共通して使われる関数である。
      或いは、あらゆる場合について / または : または = による区切りで共通部分を確認するとしても良いのかもしれない。
      然し、これを全ての候補に対して実行していると処理時間が長くなってしまう。
      その様に考えると、実は置換を実行する側で共通部分の評価結果が同じであれば、
      COMPS に置き換えてしまうというのを実装しても良いのかもしれない。

    b 曖昧補完の共通部分決定の後で COMPS への置き換えを考える案

      曖昧補完の挿入の側で共通部分を勝手に抽出しても良いのだろうか。
      というかそもそも何故補完候補生成側で共通部分を置換していたのだったか。
      或いは、特別なキーワード等の場合の為にその様にしていたのかもしれない。
      とも思ったが特別なキーワードであったならばそもそも
      展開後の内容で補完候補を生成するべきではない。

      確認してみると実は曖昧補完の場合には
      既に COMPS を参照して共通部分の決定を実行している。
      従って、COMPS を共通部分決定の際に参照する事を避ける理由は実はない気がする。

      共通部分を置き換える事が可能である条件は何だろう。
      先ず始めに置き換える部分は、COMPS の方も common の方も simple-word でなければならない。
      クォートを閉じれば simple にできる等ではなくて、何もしなくても完全でなければならない。
      そうしないと文脈が変化してしまうからである。或いは、common の方さえ simple であれば、
      COMPS の方のクォートを閉じれば良い気もするが分からない。

      更に共通部分をどの様に判定するのかの方法についてもどの様にするのが良いか考えたい。
      結局 COMPS の方も common の方も展開が必要になるという事なのだとすれば。
      うーん。:/= 区切りで評価するというのを実装するのが良いのだろうか。

      うーん。まあ取り敢えず実装してみた。一応動いてはいる。

    さて、動いてはいるが、メニュー補完の中に入ると結局補完前の状態になってしまう。
    然し、全ての候補について置き換えを実行するとなるとやはり処理時間が気になる。
    うーん。或いは、挿入時に挿入内容を書き換える仕組みがあっても良いのではないか、
    とおも思ったが挿入時に書き換える仕組みになっていると共通部分探索の意味がなくなってしまうのでは。
    やはり候補を生成する時に挿入内容は確定させて置かなければならない気がする。

    まあ、面倒なのでメニュー補完の場合にはそのメニューが提供する内容に
    置換してしまって仕方がないという事にする。

  * 2019-02-10 decode: 組み込みコマンド bind 上書き実装で未対応の事柄 [#D1013]

    * reject: ble-bind -s で bell が呼ばれた時にマクロ実行を中断する?
      bind -s の場合にはその様な実装になっているが
      ble.sh では取り敢えずはその振る舞いは実装しない事にした。

      2019-03-20 ユーザによる中断の要求に対しては #D0998 で実装された
      decode_abort_char で中断できる様になった。
      ble-bind -s の場合には ble-decode-char を用いてマクロを実行しているので、
      特に意識しなくても中断を実行する事ができるのである。

      一方でマクロの文字列の中に含まれている C-g 等の文字に関しては
      マクロを中断する機能はない。というか、それがマクロを中断する能力を
      持っていて良いのかという疑問も残る。
      % 然し、decode_abort_char がその機能を持っている限りはやはり、
      % decode_abort_char がマクロを中断する機能を持ってしまう。
      % と思ったが調べてみると decode_abort_char は .hook で受信した時のみ
      % 検査される様なのでこれに関しては問題ない。

      →この実装ではマクロ中に含まれている C-g (bell) も
      C-\ (decode_abort_char) も特別な処理を実行しない、
      という実装で良い事にする。

    * done: 現状では bind -lpsPSX は元の readline の情報を出力している。
      ble.sh における情報を出力するように修正しても良いのかもしれない。
      ble.sh の bind は元の bind の振る舞いを変更しないままそれに対して介入して
      ble.sh の設定に反映させるというのが目的である。
      bind 自体の振る舞いを ble.sh に変更するのが目的ではなかった。
      更に ble.sh の設定を確認したいのであれば ble-bind 経由で調べれば良い。
      その様に考えれば bind -lpsPSX で ble.sh の設定を出力する事に意義はない。

      と思ったが、attach している間は bind -lpsPSX の内容は滅茶苦茶な内容になっている。
      なのでそのまま出力しても仕方のない状態になっている。

      a その事を思えば ble-bind の内容を bind 風に整形した内容を出力するべきなのではあるまいか。
      b 或いは、サブシェルの中で binding を復元して出力しても良いのかもしれないが…。

      ここは b の方針で修正する事にした。bind 風の出力をしても再利用できないので仕方がないし、
      かと言って ble.sh の内部で使用している binding を出力してもやはり仕方がない。修正した。

    * done: bind -q function には対応していない
      これに関しても元の bind の設定を出力させれば良いのではないか。
      bind -psPSX と同様に元の状態を復元してから呼び出す事にした。

      -q function がある度にちゃんと出力する様にした。
      元の builtin bind の場合には最後に指定した -q function しか処理しない。

    * done: bind -u function には対応していない
      →実装した。これは ble.sh の bindings を変更する様にする。
      実際に試してみた。動いている様に見える。

    * done: bind -f filename には対応していない。
      $if 等のディレクティブ以外は既に対応している機能を用いれば良い。
      ディレクティブに関しては何とかして実装する必要がある気がする。
      或いは bash のコマンドに置換して後で全体を eval するというのでも良いかもしれない。

      更に言うと .inputrc についても本当は読み取ると良いのかもしれない。

      うーん。bash と readline version の対応が分からない。
      外部 readline を利用している場合には対応していないが、
      ldd で何とか分かるかもしれない。しかし major version しか分からない可能性もある。
      組み込まれている readline に関しては以下の日付から推測する事ができる。
      https://ftp.gnu.org/gnu/bash/
      https://ftp.gnu.org/gnu/readline/

      Bash 3.0 - Readline 5.0
      Bash 3.1 - Readline 5.1
      Bash 3.2 - Readline 5.2
      Bash 4.0 - Readline 6.0
      Bash 4.1 - Readline 6.1
      Bash 4.2 - Readline 6.2
      Bash 4.3 - Readline 6.3
      Bash 4.4 - Readline 7.0
      Bash 5.0 - Readline 8.0

      取り敢えず対応した。動作確認をする。

      - 取り敢えず動作テストした。動いている気がする。
      - $if $endif $include は動く事を確認した。
      - 後は $if の条件がちゃんと動いているかである。
        application, mode, term, version, rlvars の何れも動作確認した。

2019-03-20

  * vi_imap 及び vi_nmap に於ける rlfunc <--> widget 対応表の記入 [#D1012]
    vi_imap に関しては多少埋めた。完全ではない。 55cfa22
    vi_nmap に関しても編集する。

    * done: vi_nmap に関連して単語関連の操作が沢山あって違いが分からない。

      vi-next-word        vi-end-word     vi-prev-word
      vi-fword            vi-eword        vi-bword
      vi-fWord            vi-eWord        vi-bWord
      vi-forward-word     -               vi-backward-word
      vi-forward-bigword  vi-end-bigword  vi-backward-bigword

      どうやら vi-next-word/vi-end-word/vi-prev-word は入力された文字に応じて
      動作を変更する物になっているという気がする。
      試しに eword eWord を e, E に設定してみたが両方共 E の動きしかしない気がする。
      end-word 及び end-bigword はちゃんと期待通りに動いている気がする。
      但し end-word は大文字か小文字かで動作を変える。end-bigword は変わらない。
      うーん。謎である。よく分からないが、取り敢えず憶測で割り当てる事にする。

      もう少し真面目に調べてみる。
      先ず bigword は実は bWord eWord fWord に等価である。
      同様に backward-word は bword で、end-word は eword で、
      forward-word は fword である。なので現在の方針は正しい。
      更に気になるのは vi-next-word, vi-end-word, vi-prev-word である。
      実際に vi-prev-word の実装を見てみると、
      現在の ble.sh の実装と同じ様に文字が大文字かどうかで判定して
      bword, bWord に分岐している。

      | int rl_vi_prev_word (int count, int key) {
      |   if (count < 0)
      |     return (rl_vi_next_word (-count, key));
      |   if (rl_point == 0) {
      |     rl_ding ();
      |     return (0);
      |   }
      |   if (_rl_uppercase_p (key))
      |     rl_vi_bWord (count, key);
      |   else
      |     rl_vi_bword (count, key);
      |   return (0);
      | }

    * vi_nmap において以下の物は .dispatch を作る必要がある。
      done: vi-search       (/ or ?)
      done: vi-search-again (N or n)
      done: vi-subst        (S or s)
      done: 更に operator 達も d D y Y c C は動作が区別されている気がする。

    未だまだ不完全の気がするが細かく対応し始めると
    widget を色々と新しく作る必要が出てくる。
    emacs でもちゃんと対応しきれていない。
    これはこの項目の中でするべき事ではなくて、
    個別の機能について考察するべきである。という訳でこの辺りで止めておく事にする。

  * 2019-02-05 char_width_mode=auto? [#D1011]

    既に起動時に DA2 要求と応答の読み取りを実施している。
    序でにカーソル位置を用いて文字幅の判定を実行してよいのではないだろうか。

    実装した。まあ、動いているのではないだろうか。

    - done: 幅が 1 または 2 以外の時には失敗しているので既定の幅を用いる。
      →幅が1以外の時は全て 2 という事にする事にした。
      幅が1以外の時には常に折り返しの可能性があるので。

    - done: check において変更を検出する。変更時に更新を行う。
      画面の左上か右下を用いる。画面の左上で RI を使うのが良いのでは。
      画面の右上で実行する事にした。

    x fixed: s-A-f3 という謎の文字が受信される様になった。
      然し、文字幅判定自体はちゃんと動いている。
      % 調べてみると CSI >83;40301;0 c という謎のシーケンスが送られて来ている。
      % これは何だろう…。と思ったが、これは DA2 応答なので関係ない。
      →分かった。CPR の処理をした後に return をしていなかった。直した。

    x fixed: bleopt char_width_mode=auto を実行するとカーソル位置がずれる。
      これは RI を実行しない様にする事で対処する事にした。

2019-03-19

  * vbell: 長いメッセージを表示した直後に短いメッセージを表示すると消去時に文字列が残る [#D1010]
    更に、短いメッセージが長いメッセージの上に表示されて内容が混ざる。
    新しいメッセージを表示する時に前のメッセージを消去する必要がある。

    現在はファイルの時刻に基づいた判定になっているが、
    メッセージ毎のファイルを使用する事にして、
    ファイルが空かどうかで判定できる様にするのが良い気がする。
    有限の内容のファイルが残っている場合には削除をその場で実行する。
    有限の内容のファイルには横幅を記録しておくなどすれば良い。

    と思ったが一種類のファイルでは管理できない気がしてきた。
    状態が三種類ある。現在表示中・削除済みだがworkerは動いている・削除済み。
    或いは worker の生死と表示の有無があるのである。
    ファイルに有限の内容があるかどうかだと、
    worker が未だ生きているかどうかを判定する事ができない。

    a 或いは vbell を実行した回数だけファイルを作成してしまうという手もあるのかもしれないが、
      それだとファイルが無限に増えていくので定期的に適度に削除しなければならない。
      然し、削除するにしても現在使用しているファイルを削除する訳には行かないので、
      一つ一つファイルスタンプを確認するとか、或いは定期的に何処までファイルが消えているかを
      確認して記録しておく必要がある。

    b その様に考えると rm 等使ってファイルを削除する等しても良いのではないかとも思われる。

    c 或いは $! を使って fork した worker を記録しておいて、それに対してシグナルを発する?
      と思ったが変にジョブ管理に登録されても嫌だし、それについて調べるのも面倒なので、
      ファイルを使って何とかする方法を模索したい。

    d ファイルの状態を使って何とかできないだろうか。
      現在は -s を使っている。ファイルを削除する為には外部コマンドを呼ぶしかない。
      -s 以外に何かシェルの組み込み機能だけで読み書きのできる属性はあるだろうか。
      -xwr に関しては読み取りはできるが変更はできない。
      umask を使えば最初に作成する時の属性の変更はできなくはない。

    e reject: [[ -N $file ]] を使う案。

      help test を見ていたら面白い機能が実装されている。使えないだろうか。
      -N で最後にアクセスしてから新しくなったかどうかを確認することができるようだ。
      と思ったら実はこの機能は bash-3.0 の時から既に存在している様である。
      然し、最後に読み込まれてから新しくなったかどうかというのの、
      最後に読み込まれてからというのはどのタイミングの事だろう。
      Bash が読み込んでからという事なのだろうか。
      或いはどのプロセスでも良いから読み込んでからという事なのだろうか。
      また -s や -N によってアクセスした場合には最後に読み込んだという事になるのだろうか。

      - 他のプロセスが読み込んでも最後に読み込んだと見なされる。
      - [[ -s $file ]] でアクセスしても最後に読み込んだとは見做されない。

      これはどうもファイルシステムに記録されている情報を使っている気がする。
      そして mtime と atime をそのシステムがどの様に更新するかに依存している。
      従って、この機能に依存して状態を管理するというのには不安が残る。

    f 各表示について2つずつファイルを作るのではなくて、
      一つは時刻か何かの制御に使って、残りを各 worker が active かどうかの管理に使う。
      というようにするのはどうだろうか。

      先ず始めに、vbell を表示する時には必ず "前回の表示" を削除する様にする。
      2回よりも前に表示した内容は既に削除している筈なので気にしなくて良い。

      既に削除したかどうかはファイルの内容の有無で管理する事にする。
      もしくは最後に表示した時刻を .time ファイルに記録しておいて、
      .time よりも古いものは全て削除済みなのだと解釈する事にする。

      worker が削除した時に本体の側に削除の必要がないことを伝達するにはどうすれば良いか。
      これも .time ファイルを触るという事にすれば良いのではないだろうか。

      具体的な手順について考える。
      .time より新しい .N ファイルがあったら前回の内容を削除する。
      .time を触る。新しい .N ファイルを触る。

      うーん。やはり worker が生きているかどうかは .N に有限の内容があるかどうかで保持し、
      表示を削除済みかどうかに関しては .time で管理するというのはどうだろうか。

    うーん。f で実装してみたが何回か実行してみると表示が残ってしまう事が結構ある。
    何が起こっているのだろう。workerfile と reference の読み書きについて
    動作確認する必要がある気がする。

    確認してみると多くの vbell が錯綜している時、
    何故か途中で .time を触っていないのにも拘わらず
    .3 が .time よりも新しくない、という事になっている。
    うーん。create してから deprecated1 する迄間に何もない、というのはどういう事か。

    何回か試して分かった。同じタイムスタンプになっているのである。
    これはファイルシステムの時間分解能の問題である。
    同じタイムスタンプの時には未だ deprecated になっていないという解釈にする事にした。
    色々試してみたがちゃんと動いている様に見える。

  * [自然解消] 2015-11-21 vbell の色 [#D1009]

  * [自然解消] 2016-06-20 ble-edit/exec:exec/process コマンド実行時に一時的に .ble-line-info を消す [#D1008]
    その他にも ble-line-info の使い方について全体的に見直しを行うと良い。

  * complete: rlvar mark-symlinked-directories, match-hidden-files 等の対応 [#D1007]

    * done: comp_type が段々と複雑になって来た。
      opts の様に名前で指定できる様にするべきではないか。

      x ok: しかし、比較速度の問題もある。
        - 確認してみた所、候補ループの中では使われていない。
        - 唯一使われているとすれば、メニュー表示の一致範囲の決定であるが、
          - 元々この部分は時間がかかる処理なので comp_type の検索時間はそれ程効かない筈である。
          - また、ループの外で判定結果を変数に入れてしまっても良い。
            と思ったが別にループがあるという訳でもなかった。
        →比較速度に関しては気にしなくて良いだろう。

    * done: 実装
      mark-symlinked-directories には対応した。
      match-hidden-files にも対応した。
      両者とも実際に動かして確かめてみた。

    * done: 動作チェック
      match-hidden-files に関しては絞り込みによって
      . が入力されても新しく生成されないというのが難点だが、
      まあ絞り込みと考えれば変な動作でもない。
      C-g によってキャンセルして改めて補完を実行すれば
      hidden-files もちゃんと生成される様になったのでOK

    * done: menu-complete-display-prefix にも対応した。

    * done: colored-*
      set colored-completion-prefix off
      set colored-stats off

      以上の物に関しては既に機能としては ble.sh で既定で有効になっているが、
      rl の既定では off になっているのでこの変数に対応するとしたら、
      ユーザに自分で設定を有効にしてもらう必要がある。
      もしくは勝手に ble.sh の側で有効にしてしまうという手も考えられるが…。
      結局対応してしまう事にした。
      a うーん。勝手に設定を on にする事にする。
        但し、遅延ロードで設定を on にすると bashrc で制御できないので、
        遅延ロードでない所で勝手に設定を on にする事にする。
        この振る舞いに関しては何処か説明書に書くと良いのかもしれない。
      b と思ったが off にする機能を残しておく必要はあるのだろうか。
        その様に考えると一応 on/off する仕組みを残して置きつつ、
        やはり強制的に on にするというのの方が良い気がしてきた。
        実は他にも沢山の設定項目が rlvar にはあって、
        それらを全て on にするというのは非現実的な感じがする。

2019-03-18

  * 2019-03-12 complete: source:sabbrev の候補表示に \ を入れたい [#D1006]

    menu の表示に使われる文字列と、絞り込みに使われる文字列を別々にしても良いのでは。
    という様に最初は考えたが、よく考えると menu の表示に使われる文字列を用いて、
    絞り込みやどのように絞り込まれたかの表示が為されるので、
    結局、絞り込みに使われる文字列で menu 表示が行われる事になる。

    然し、ファイル名候補の場合に末尾に * 等を追加するだとか、
    そういう可能性もあるから、prefix 及び suffix を取得する
    というのがあっても良いのかもしれない。
    そしてそれは getg と同時に行われるのが良い。

    * done: action:sabbrev の場合には其処で prefix を設定する。
      と思って途中まで実装してみたが、よく考えてみると、
      別に sabbrev は必ずしも \keyword の形をしている訳ではない。
      或いは各文字に対応する文字列がどれかを指定して eval する事は現実的だろうか。
      うーん。もしその様にしたとしてもどうやって construct-single-entry に伝達するのか。
      うーん。変数 show の内容を弄るという事になるのだろうか。
      そして変数の内容を弄った時には一致部分の着色は無効にしてしまうという事。

      show の内容を弄ってもらうという事にした。
      show の内容が元々の内容と同じであればその時に限り着色を実行する。

    * ok: まあ、その様にするのが自然の気がする。show という変数名は変更しても良い気がする。
      然し、元々の complete の実装で cand_show などだった事を考えれば、
      まあ、show のままでも良いような気がする。或いは別の変数名で良さそうな物はあるだろうか。
      →取り敢えず show のままで良いという事にした。

    * done: また visible-stats が有効の時に * や / を末尾に付加する機能があって良い気がする。
      毎回 visible-stats を問い合わせるのは大変なので、これは comp_type 等に入れると良いのだろうか。
      さて、此処で問題になるのは prefix, suffix に着色をするかしないかという事である。
      それが付加的なマークであると考えるのであれば着色しない。
      それが候補自体の見た目を整える為の物であれば着色する。
      まあ、見た目を整える為に prefix/suffix を使うというのは変な気がするので着色はしない事にする。

    * done: うーん。もし show の内容と filter_target の内容が一致していなかったとしても、
      show の内容に filter_target が部分文字列として含まれている場合には、
      その部分を対象として着色すれば良い気がする→その様に実装した。

    * done: getg という関数名は最早そぐわない。色々な機能を持っているからである。
      どの様な関数名が良いだろうか。menu item の見た目の調整である。
      うーん。decorate-menu-item とか。adjust-menu-item とか。
      get-menu-item でも良いのかもしれない。と思ったが、
      何もしなければ既定の表示がされるという事で必須ではないので get-menu-item は変。
      adjust-menu-item かもしくは setup-menu-item か。
      menu-item というより entry なのかもしれないとも思いつつ、
      menu_items という配列も使っているからやはり menu-item でも良いかもしれない。
      initialize-menu-item が良いかもしれない。或いは initialize-menu-entry か、
      initialize-menu-item-rendering だとか。うーん。init-menu-item が良い気がする。
      置換した。

    * done: 序でなので mark-directories にも対応する事にする。対応した。

    * mark-symlinked-directories や match-hidden-files にもこの際対応するべきなのではないか。
      と思ったが、そもそも sabbrev の為に修正を始めたのであって、色々手を出しすぎると収集が付かないので、
      取り敢えずここまでで commit してしまう事にする。別項目として立てる事にする。

  * 2019-03-13 rps1 の高さを PS1 と同じだけ確保しても良いのではないかという説 [#D1005]
    複数行の PS1 にしている人は rps1 も複数行にできる様にする。

    一方で、rps1 の方が PS1 よりも行数が多いというのは微妙なので止める。
    例えば、出力と被らない様にする為には rps1 の 2 行目以降を消去するか、
    コマンドの出力を rps1 の最終行の次の行からにするか、
    或いは、rps1 とコマンドの出力が被ってしまっても気にしないか。
    とそういう選択肢しかない。

    これは PS1 の高さが確定してから、その高さを用いて rps1 を初期化する様にする。

    x fixed: さて複数行の rps1 を許す様にして rps1 を削除するコードを書いてから、
      実際に rps1 を表示してみると一行になってしまっている。
      と思ったら prompt/.initialize で trace を呼び出す時に明示的に LINES=1
      を実行してしまっていた。そして、confine を指定していない PS1 の方については
      問題が発現していなかったというだけであった。

    x fixed: うーん。表示されるようになったが座標計算が誤っている。
      rps1 を表示してから y 座標を更新できていない気がする。
      座標計算も誤っていたし、更に PS1 の描画位置も誤っていた。修正した。

  * 2019-03-13 rps1: rps1_transient の時 _ble_term_el で最後の文字以降を全て消去しても良いのではないか [#D1004]
    実際に zsh の場合にはその様にしている様に見える。

    ただ複数行の時に各行に対して全て実行するというのは面倒である。
    或いは、一行目の時だけ改行の右側を空白で fill するという手もあると思ったが、
    2行目以降の改行が1行目に移動した時に問題が発生するので、
    それはやはり難しいのである。

    全ての改行位置を手早く取得する手法はあるだろうか。
    と思ったが、よく考えてみれば $'\n' を単に検索すれば良いのだった。
    その他に折り返しの場合もあるが、折返しは一番右側で起こると決まっているので、
    殊更に削除するべき空白などがあったりはしない。

    うーん。これについて試しに実装してみる事にするか…。
    rps1 を消去する時にどの場所で消去するのだろうか。

    1 先ず始めに幾何を更新する前に消去する。
    2 次に編集文字列の改行の位置より右側を削除する。

    2回削除しているので無駄の様な気もするが両方必要の様な気もする。
    というのも 1 がないと複数行プロンプトで複数行の rps1 に対応している時に
    rps1 が削除されないという事態になる。一方で 2 がないと空白が行末まで続いた状態になっていて
    コピー&ペーストする時に邪魔になってしまう。従って、この二種類の消去が必要になるのである。

    取り敢えず実装した。最後の行末も消す必要があった。修正した。

  * 2019-03-13 rps1: not rps1_transient でコマンドを入力してから次の行に進む時 [#D1003]
    rps1 が消去される。寧ろ transient の時は空白で埋められている。
    →これは条件式を誤っていた。修正した。

    また、何も入力せずに次の行に行く時の再描画についても修正した。
    次にユーザの入力が途切れるまで buffer.flush が実行されないので、
    明示的に buffer.flush を呼び出す事にした。

  * 2019-03-12 complete: completion-ignore-case の時に comp_type=i を設定しているが実際に使っていない [#D1002]
    うーん。各 source で本当に正しく実行できているかどうかは分からないが、
    そして compgen がいい感じに候補を生成してくれるのか分からないが、
    取り敢えず見て簡単に分かる所は更新した。簡単に実行して確かめてみる事にする。

    一意確定すれば動いている様な気がするが複数の候補がある時に全く補完できない。
    これは count-match-chars の実装が必要である。更に、common_part を求める時に、
    case の違いを許す様にして求める必要がある。

    色々工夫してみたは良いが、実は nocasematch というオプションが bash-3.1 以降には存在する様だ。

    * done: というより常に nocasematch は off にして置かないと別の場所で問題になるのではないか。
      実際に shopt -s nocasematch にすると IF true; THEN echo hello; FI が文法的に正しくなってしまう。
      実際に試してみるとそのように解釈されてしまっていて、しかも実行するとやはりエラーになる。
      うーん。面倒なのでこれはやはり全体の設定で解除しておくべきである。

    取り敢えず動かしてみる。

    x fixed: 前方部分を置き換えるために確定部分の挿入が起こらない。
      そもそも前方部分の置き換えに関しては曖昧補完の時にしか起こしていなかった。
      これを ignore case による補完の時にも起こる様に修正した。

    - 実は既に実装した部分に関しても nocasematch を使ったほうが高速化できるなどあるだろうか。
      問題は一致の init と finalize を作ったとして、
      その途中で nocasematch が別の操作に対して悪影響を与えないのかという事である。
      また、どうせ bash-3.0 では nocasematch に依らずに実装する必要があるので、
      わざわざ無駄にスイッチを作るというのは面倒である。

      determine-common-prefix でスイッチしてでも nocasematch を実施したのは、
      毎回 tolower を実行するのはコストが高いだろうと判断するからである。
      a 然し、そうは言っても [][] でパターンを生成するというのも、
        少しずつ短くしていかなければならないので毎回パターンを生成しなければならない。
      b もしくは構築時に長さを配列に記録して少しずつ短くするという手もある。
      c もしくはアルファベット以外の文字 x の場合にはダミーで [xx] というのを生成して、
        4文字ずつ切り出してパターンとして利用するという手もある。

      うーん。余り実装する意味はない様な気もするが、
      一方で bash-3.0 ではやはりこういう風に処理した方が速い気もする。
      一方で、余り実装手法を複雑にすると後でよく分からなくなる。

2019-03-12

  * syntax: "for a in 1; do done" が文法エラーになっていない [#D1001]
    現在の実装では do の後に任意のコマンドが来ても良い事になっている筈。
    然し、来ては行けないコマンドという物を指定する事はできない。
    それでもよく考えてみれば } や done 等の時には来ても良いコマンドを指定する事ができたのだから、
    それと同じ様に処理すれば良いのではないだろうか。} や done は CTX_CMDXE という文脈を生成する。
    一方で do は CTX_CMDX1 という文脈を生成する。
    CTX_CMDX1 になるのは他にも if while until then elif else { 等がある。

    他に case esac で esac を読み取る直前に CTX_CMDX1 を設定している箇所があったが、
    ここは別に CTX_CMDX で良いきがするのでこれはその様にした。
    この上で、CTX_CMDX1 の次には then elif else } done esac fi 等は消えてゃ行けないという制限をかけたい。
    CTX_CMDXE の特別の判定をしている箇所を探す。

    結局 'for' 等を処理している ctx-word-end に於いてやはり判定をしているのだった。
    実は wtype にその文脈に入った時の ctx が入っている。
    CTX_CMDXE に関しては _ble_syntax_bash_command_Expect による判定が使われていた。
    同じ箇所に手動での判定を書き加えることにした。動いている。

  * read -e で C-d を入力してから確定すると vbell のジョブメッセージが出る [#D1000]

    a set +m を用いてジョブ管理の状態を変更しても効果はなかった。
      ジョブを発動する瞬間に set +m でなければならないという事だろうか。
    b と思って set +m と set -m で囲んでみても効果がなかった。理由はよく分からない。
      或いはコマンドが終わった瞬間にジョブ管理が有効になっていると検出してしまうという事だろうか。
    c そう思って set +m にずっとしたままで実行してみても変わらない。

    もしかすると bind -x の中で実行している限りは状態が復元されてしまうという事なのかもしれない。
    というか、普通の visible-bell の時には検出できないのが何故 read -e の時にだけ検出できるのだろうか。
    うーん。よく分からないけれども。まあ余りきにしない事にする。

    visible-bell のサブシェルのコマンドは
    直接コマンドの羅列を記述していて長いので関数にする事にした。
    これで何か変なメッセージが表示されるとしても短くて済む。

    * edit: read -e 実は ble-0.2 の時点では変なメッセージなしに vbell が表示できていた。
      と思ったら気の所為だった。単に bleopt edit_vbell が off になっていただけなのだった。

  * read -e で謎の改行が入る [#D0999]
    これは第二の panel を使って入力をしているからである。
    その時に第一の panel の高さをクリアし忘れている。直した。

  * 2018-08-22 vi: マクロ再生の中断? [#D0998]
    ユーザから入力があったら中断する機能。
    すぐに中断するのではなくて時間を計測しても良い。

    Note: 現在はマクロの中で更にマクロが再生されるのは検知して阻止している筈。
      従って、中断できる様にする対象は履歴の検索等の元から時間がかかる処理である。

    2019-03-12 思うにこれは大量の入力をしてしまった時にも同様である。
    従って、vi マクロの側で処理するのではなくて、
    vi マクロの側は "大量の入力" として再生を decode 側に一任する。
    そして decode 側は "char" の列を何処かに記録して実行を行う。
    もし入力が現れた時にはそれを読んで例えば ^\ だったら記録されている列を削除する。

    * 再帰的に ble-decode-char を呼び出した場合には、
      記録されている列の "前" に新しい文字が挿入されるという事に注意する。
      また、普通にユーザの入力として ble-decode-char を呼び出した場合には、
      "後" に新しい文字が挿入されるという事にも注意する。

      では中途半端な位置に挿入される事が期待される場合はあるだろうか。
      うーん。今実行中の部分が原因で呼び出される場合には必ず "前" である。
      何故なら今実行中の文字の直後に処理されて欲しいから。
      ユーザからの入力の場合には必ず "後" である。
      現在処理中の物を全て処理した後に実行して欲しいから。
      しかし、それ以外の要因で char が追加されるという事があるだろうか。
      恐らくないと考えて良い。

    * 今似たような仕組みは ble-decode/.hook に存在している。
      これは byte を受け取る部分の側の仕組みである…。
      char を受け取る部分の側の仕組みで似たような事をしたい。
      しかし byte を受け取る部分との整合性も考えたい。

    * 実は ble-decode-key も直接呼び出されたりしているが、
      これに関してはまあ中断機能は及ばなくても良いだろう。
      後で簡単に拡張して対応できるし、
      現時点では ble-decode-key ベースのマクロ再生は存在していないので。
      もしかすると emacs モードでのマクロは key ベースになるかもしれないが、
      然し、マクロをプリントする機能などの事を考えると、
      やはり char ベースのマクロになるのではないかという気がする。

    [実装案]

    bytes = [ユーザからの入力の列] = _ble_decode_input_buffer
    chars = [デコーダからの入力の列]

    うーん。bytes は chars に末尾から追加する。
    それ以外の ble-decode-char は chars に前に追加する。
    bytes に C-\ が入ってきたら全て消去する。

    chars を実行している途中に has-input 状態になったら、
    今まで実行した chars の部分を消去して中断して抜ける。
    其処で bytes の末尾に byte が追加されるのである。
    そして bytes から ble-decode-char が呼び出されるが、
    その時の文字は chars の末尾に追加されて、
    ble-decode-char は溜まっている char からまた
    処理を再開するという流れになる。

    % - 前に追加するか後に追加するかは
    %   ble-decode-char の中から ble-decode-char
    %   を呼び出しているかどうかで判定する。
    %
    % - 因みにユーザがコマンドから呼び出す ble-decode-char は…。
    %   ble-decode-char の外側から呼び出される筈なので、
    %   溜まっている chars よりも先に実行されてしまう気がする。
    %   一方で、コマンドの全て処理が終わってからの様な気もするので、
    %   そういう意味では前も先もないのかもしれない。
    %   これは確認する必要がある。
    %
    % - 後、前に挿入する、という事だが、
    %   一つの処理の間に複数の ble-decode-char が呼び出される場合、
    %   順序が反転して記録されてしまうのではないだろうか。
    %   この辺りは工夫して buffer の管理を行えば回避できる気がする。
    %   例えば実行中は buffer は空にして置いて、
    %   去る時に未処理の文字たちを buffer の末尾に追加する。など。
    %   実は、その様にすれば前だとか後だとか気にせずに、
    %   常に後ろに追加するだけで良くなるのではないか。

    - done: ble/builtin/bind/.decode-chars の処理に関しては、
      ユーザからの入力があっても失敗しない様にする。
      もしくは 148 を返したら失敗と判定する事にする。
      多分、ユーザからの入力があっても中断しない様にするのが適切。

    - done: ble-decode-char で処理中は一旦ローカルの配列に移動する。
      但し、ローカルの配列に未だ中身があるという事をどうにかして、
      has-input で検出しなければならない。

      | 特に入れ子になって実行している時でも大丈夫だろうか。
      | 或いは入れ子になって実行している時には必ず push しかしない、
      | という様にするという手もある。
      | そうすれば入れ子で実行しているという事はないのだから、
      | そして実行しているとすれば必ずその関数の中から呼び出されているので、
      | ローカル変数は見えているという事になる。
      | 従って、has-input でそのローカル変数を参照すれば良い。
      |
      | と思ったが、本当にそれで大丈夫だろうか。
      |
      | ble-decode-char 自体はどの様に入れ子で処理しているか検出するのか。
      | やはりローカル変数で確認するという事になるのか。
      | そして ble-decode-char 自体が入れ子で処理している時に、
      | どの様にして引数を追加したら良いのだろうか。
      | ble-decode-char が呼び出されてユーザからの入力はないけれども、
      | ble-decode-char で未だ残りの文字が存在するという状況で、
      | その場で push して抜けるべきなのか、
      | それともその場で処理を続行するべきなのか。
      |
      | a 当初の計画ではその場で処理を続行するという物だった。
      |   そして、ユーザからの入力があったら push して抜けるという物。
      |   ユーザからの入力は一番上まで抜けなければならないから大丈夫。
      |   しかし、よく考えてみるとユーザからの入力は50回に1回しか確認しない。
      |
      | b 従って入れ子の ble-decode-char の場合には必ず失敗して、
      |   push してから上に抜けていくという状況になる。
      |   そして呼び出し元では毎回 _ble_decode_char_buffer に
      |   何か新しい処理が書き込まれていないか確認しなければならない。

      入れ子で ble-decode-char を呼び出した時は制御を戻し、
      外側で実行してもらう事にする。
      ble-decode-char で ble_decode_char_rest という変数を提供し、
      残りの文字数を分かるようにして、has-input ではそれを参照する事にした。

    - ok: ble-decode-char を呼び出す時は必ずしも
      その場で実行されるとは限らない事を確認する。
      特に ble-decode-char の後に処理が走っている場合には気を付ける。

    - done: ble-decode/.hook 経由で呼び出される encoding の
      ble-decode-char はどの様に処理すれば良いのか。
      ユーザからの入力があったからと言って中断していると、
      後続の処理が実行されてしまう。
      特に erase-progress が実行されてしまう。

      うーん。或いは実は寧ろそちらの方が良いのではないか。
      と思ったが、これが走っている時は必ず
      has-input が true になるので直ぐに終了してしまう。
      つまり、直ぐに末尾まで行って、その後で
      erase-progress が実行される。

      試しに実行してみたらやはりそうなった。
      decode だけを実施して最後まで行ってしまう。
      因みに動作自体はちゃんとしている。
      うーん。progress を ble-decode-char の側でも
      実行するべきなのかもしれない。表示する様にした。

    - done: うーん。builtin/read/.loop の処理に関しては、
      その場で最後まで処理し切るという様にしないと困る気がする。
      と思ったが、abort する事ができる様にする為には、
      やはりループを書き直す必要があるのではないだろうか。。

      何だか面倒なので試しに一回実行してみる事にした。
      すると実は一応動いている様な気がする。
      erase-progress だけは実行しておく事にした。

      然し、やはり has-input-for-char の動作は切り替えなければならない。
      取り敢えず _ble_decode_input_count は見えない様にマスクしておく事にする。
      ble/encoding:.../is-intermediate に関しては気にしない事にする。
      中途半端な状態でユーザが read を呼び出す様な事をすることはないとの仮定。

    さて、次に必要なのは C-\ (28) を受け取った時に中断する機能である。
    うーん。何れにしても is-stdin-ready の時には処理が一時中断される事を思えば、
    実は入り口の ble-decode/.hook で全て消去してしまえば良いのである。

2019-03-11

  * 2013-06-01 以前 vbell [#D0997]
    + スタイルを指定できる様にする
    + 位置を指定できる様にする

    設定 "bleopt vbell_align" を追加した。
    描画設定として vbell, vbell_flash, vbell_erase を追加した。

  * vi: imap に於ける undo がちゃんと記録されていないのでは [#D0996]
    特に補完のタイミングにおける記録もない。
    やっぱり undo/add が呼び出されていない。

    実装を見ると ble/widget/vi_imap/__before_widget__ 経由で、
    white でないコマンドを実行する直前に
    ble/keymap:vi/mark/end-edit-area が実行されて、
    そのタイミングで undo/add が呼び出される筈の気がするが…。

    と思ったが、実は DEL などは white と認識されている?
    うーん。vim の動作を調べると実は vim の場合は undo は
    挿入モード単位で行われている様だ。つまり、
    現在の様な記録方法で問題ないのである。

    しかし、やはりこれは分かりにくい。というか不便だ。
    オプションでもっと細かく undo を記録するモードをつけるか。
    その場合にはどの様に判定するのか。
    別に判定など考えずに undo を沢山呼び出せば良い様な気もする。

    - done: ble/util/invoke-hook _ble_complete_insert_hook は
      実際に挿入を行った後に呼び出す様に変更した。
      実装を見てみるとどちらで行っても良い様な実装になっていたので。

    - done: bleopt keymap_vi_imap_undo=more の時に細かく記録する事にした。
      新しく magic-space やら delete-backward-char やらの拡張を作るのが面倒になったので、
      結局 edit.sh の方の widget 本体を弄ってしまった。まあ、仕方がない。
      というか keymap 毎に widget の名前が微妙に違うというのも分かりにくいのでこれで良い気もする。

  * menu-complete: C-g でキャンセルできる様にしたい [#D0995]
    C-g は bell だったが。bell に何か hook する事は可能だろうか。
    拙速かもしれないが C-g でキャンセルする事ができる様にした。

    然し、layer:manu_filter による着色が解除されない。
    これに関しては明示的に invalidate するか dirty-range とするかする必要がある?
    取り敢えず invalidate してしまっているが、まあ面倒なので良いかという具合である。
    本当は caret_state に自由に外から追加できる様にするべきなのかもしれない。

  * 2019-02-28 complete: sabbrev に登録されている単語の補完もあっても良い気がする [#D0994]
    実装してみたがメニュー補完に於ける置換範囲が変である。
    先頭の \ が抜けている所為で二重に \ が挿入されてしまうのである。
    これは sabbrev の候補のみを生成した時でも再現する。

    うーん。成る程。初めから \ が除外された状態で補完が開始している気がする。
    というか。reconstruct-incomplete-word に於いて末尾の \ を除去するべきなのではないか。
    つまり reconstruct-incomplete-word による COMPV の構築に失敗して、
    fallback の位置で補完が開始しているという事になる。

    reconstruct-incomplete-word で \\ に対応する事にした。
    然し、いろいろ考えると対応していない物は沢山ある。
    "a\ で終わっている様な場合や "a${para で終わっている様な場合。
    まあ、それらは気になった時に実装していくというので良い気がする。

  * edit: bleopt rps1_transient 対応 [#D0993]
    非空文字列が設定されている時、右プロンプトを次の行に行く前に消す。

  * util (ble/util/openat): 入れ子の bash-3.1 で C-d を受信できない [#D0992]
    ref #D0857

    これは前に修正した物ではなかったか。
    実際に調べてみると子プロセスが起動していない。
    また再現するかどうかを見ると 3.0 3.1 3.2 の中で 3.1 を起動した時に起こる。
    前の時と全く同じ症状に見える。しかし、前の対策は有効である。
    exec を2つに分けて実行してみても駄目だった。

    うーん。子プロセスが起動していないというのは前にはなかった気がする。
    子プロセスを起動する部分を見たが特にエラーメッセージが出ている訳でもない。
    調べるとどうも起動した瞬間は起動している様である。
    その後で read に失敗して while ループを抜けている。

    openat でその pipe を開かない場合には失敗して終了する事はない様子である。
    つまり pipe を開くと read に失敗する。
    また openat_base をずらすと失敗して終了する事はない。

  * edit: RET を連打するとプロンプトの表示前に行頭にカーソルが滞在している [#D0991]
    これは何故だろうと思っていたが、よく考えたら has-input の時には、
    プロンプトを再描画せずに通過するのであった。
    そして次の RET が来て .insert-line した時に漸く新しい行が描画される。

    それなら新しい行を挿入した時点で textarea#render してしまえば良い。
    と思って render しようとしたら変な事になる。
    というのも新しい行を挿入した時点では新しい行の状態を指定していないので。
    従って、新しい行の状態を指定した上で再描画しないと行けない。
    特に ble/widget/* のレベルで再描画を指定するほうが良さそう。その様にした。

    x ble/util/joblist.bflush を呼び出しているが、
      keep-info の時にこれを呼び出すと info が消えてしまう。
      これについても対策した。

2019-03-10

  * menu-complete: 頁管理の枠組みを統一したい [#D0990]
    統一した。

  * util: bash-4.0 未満では物凄く遅くなるので曖昧補完は無効にしたい [#D0989]
    と思ったがこれは実は ble/util/array-assign が原因だったのかもしれない。
    また後で詳しく何が原因だったのか調べる必要がある。

    後、ble/util/array-assign は本当に高速なのか。
    後 ble/util/mapfile も遅そうである。
    というか split-lines が遅いのでは。
    図ってみたら確かに50倍ぐらい遅い。
    split-lines は while read で実装し直す事にした。

    それ以外でそんなに bash-3.2 と bash-4.0 に差があるとは思えないので、
    取り敢えず様子見して固まらない限りは気にしない事にする。

  * bash-3.1 以下で bleopt_rps1 が動いていない [#D0988]

    これは何だろう。全く動かないというのは不思議な事である。
    途中でクラッシュしているという訳でもないのだと思うが。
    trace の問題だとしたらもっと他の場所でも影響が出ているはずである。

    調べてみると何と measure-bbox の結果が変な事になっている。幅0という事に。
    しかも何故 bash-3.2 で動いて bash-3.1 で動かないのか。という事。
    他の実際の出力結果などはちゃんと動いている様に見える。
    最終的な位置に関してもちゃんと動いている。

    と思ったらこれも算術式のバグだった。
    bash-3.1 では三項条件式を全てカッコで囲まなければならないのだった。
    これを直したら呆気なく動く様になった。

  * bash-4.0 未満では menu-filter.idle に対応していないので、 [#D0987]
    layer:menu_filter は登録しない事にする。
    変な着色が実行されてよく分からない事になっている。

  * bash-3.2 以下で 関数名補完が変だ。というか絞り込みが働かないので [#D0986]
    menu 候補がいつまで経っても最初と同じ状態で駄目だ。
    これは menu-filter が働いていない時には menu-filter を手動で呼び出す様にした。

  * bash-3.2 以下で sabbrev が動いていない [#D0985]
    正規表現? と思ったがそもそも core-complete.sh が読み込まれていない。
    ble/complete/sabbrev/expand を autoload に追加しておく事にした。
    また、物凄く遅いが一応動いている様子である。

    然し、この遅さは何だろう。滅茶苦茶遅い…。
    もしかすると全ページを構築している?
    と思ったが次のページに行こうとするとやはり時間がかかるので、
    恐らく本当に動作が遅いという事なのだろう…。

    調べたら ble/util/assign-array に滅茶苦茶時間がかかっていた。
    変な split-lines のルーチンよりも while builtin read -r line の方が速いのだった。
    2m22s から 0.05s にまで短くなった。約 1000 行のファイルである。

  * ble/util/msleep の usleep を使う実装に於いて警告が表示されている [#D0984]
    deprecated だそうだ。取り敢えず &>/dev/null で警告を殺す。

  * bash-4.1 未満で visible-bell? もしくは menu-complete の頁描画がずれる [#D0983]
    そもそも1頁に表示されている項目の数が怪しい。
    ble-edit/info/.initialize-size の計算結果を見てみると、

      $ echo "$COLUMNS x $LINES / $cols x $lines" >>/dev/pts/4
      bash-4.4: 179 x 68 / 179 x 66
      bash-4.1: 179 x 68 / 179 x 67

    となっていて、この時点で計算が怪しい。
    ble/canvas/panel/layout/.get-available-height の中でどうなっているか確認。

      bash-4.4
      declare -a mins=([0]="1" [1]="0" [2]="1")
      declare -a maxs=([0]="1" [1]="0" [2]="66")
      declare -a heights=([0]="1" [1]="0" [2]="66")

      bash-4.1
      declare -a mins='([0]="1" [1]="0" [2]="1")'
      declare -a maxs='([0]="1" [1]="0" [2]="67")'
      declare -a heights='([0]="1" [1]="0" [2]="67")'

    うーん。ble/canvas/panel/layout/.extract-heights が悪いのかとも思ったが、
    ble/canvas/panel/layout/.determine-heights が怪しい気がしてきた。

      bash-4.4
      declare -- lines="67"
      declare -a mins=([0]="1" [1]="0" [2]="1")
      declare -a maxs=([0]="1" [1]="0" [2]="68")
      declare -a heights=([0]="1" [1]="0" [2]="66")
      lines=67 mins=(1 0 1) maxs=(1 0 68) heights=() max=69 min=2
      heights=(1 0 66)

      bash-4.1
      declare -- lines="67"
      declare -a mins='([0]="1" [1]="0" [2]="1")'
      declare -a maxs='([0]="1" [1]="0" [2]="67")'
      declare -a heights='([0]="1" [1]="0" [2]="67")'
      lines=67 mins=(1 0 1) maxs=(1 0 67) heights=() max=68 min=2
      lines=67 mins=(1 0 1) maxs=(1 0 68) heights=() max=69 min=2
      heights=(1 0 67)

    やはり変だ。入力が同じなのに結果が異なる。
    これは算術式のバグを踏んでいた。
    条件分岐の中に配列要素の参照があると常に処理されてしまう。

  * rosaterm で screen -dr を isearch する時に座標計算がずれている [#D0982]
    これは rps1 と関係している様子である。xenl の問題だろうか。
    これは xenl が入っていない時には更に cols-- する様にすれば良い。

  * menu-complete (desc-raw): 頁生成が遅い [#D0981]
    trace で nooverflow を指定していても文字列の末尾までスキャンしている気がする。
    更に言うと、ellipsis を付加する処理を何度でも実行してしまっている。
    特に ellipsis は余り頻繁に起こらないと思って遅い実装になっているが、
    今の実装だと ellipsis は全角文字の数だけ起こるのでとても非効率的である。

    trace は制御シーケンスを解釈するので一旦範囲外に行っても、
    また戻ってきて範囲内に文字列を出力する可能性がある。
    その為に文字列の末尾まで全てスキャンしているのであった。

    新しく ble/canvas/trace に truncate と confine の二種類を実装した。
    confine が今まで通り範囲外に行きそうになっても全て処理するもの。
    truncate は範囲外に行ったら其処で処理を終了するもの。

  * menu-complete: ページ番号を visible-bell で表示するのはどうだろうか [#D0980]

  * util: unicode 文字を使って出力を行うことの是非について [#D0979]

    現在 progress の表示及び trace.draw の ellipsis の表示に Unicode 文字を使用している。
    然し、output-encoding が unicode とかそういう環境でなければそれは面倒な事になるのでは。
    古い端末だと文字化けしてしまって変な見た目になってしまうかもしれない。
    その様に思うと * や ... を用いた代替を用意して置いた方が良いのではないだろうか。

    これは bleopt で設定しても良い気がする。
    オプション名は何にするのか。
    例えば output_encoding として置いて、
    output_encoding に Unicode 文字が使える場合にはそれを使う等。
    しかし、output_encoding は実のところ LC_CTYPE で制御されている。
    そういう風に考えれば、bleopt で指定しなくても LC_CTYPE を見て *.UTF-8 ならば
    unicode 文字を使うという風にして良いのではないかという気がする。

    →LC_CTYPEを使って ble/util/is-unicode-output を判定して、
    それを使って出力に使う文字を切り替える様に実装を変更した。

    その他の序での変更。

    - (ble-edit/info/show): rename ansi -> esc
    - (ble-edit/info/show): esc (現在の端末の解釈) に対応
    - (ble/canvas/trace): 関数追加
    - test/check-trace.sh: lib/test-canvas.sh にマージ
    - canvas: rename ble/canvas/rmoveto.draw -> ble/canvas/put-move.draw
    - canvas: rename ble/canvas/rmoveto-x.draw -> ble/canvas/put-move-x.draw
    - canvas: rename ble/canvas/rmoveto-y.draw -> ble/canvas/put-move-y.draw
    - ble/canvas/trace.draw: opts=terminfo に対応

  * 2018-03-14 info: progress の表示 [#D0978]

    history の background loading で一時 progress の表示をしていたが、
    その後に効率的な実装方法が分かった為に結局現在は使われていない。

    しかし、その時に残っていた課題が幾つかある。

    * info で progress を表示するための専用の仕組みを作る?

      一つは info で表示する事自体に 40ms 程度時間がかかっていた事である。
      これは progress を表示する事自体によって処理時間が長くなるという事を意味する。
      また info の表示を行う為に配列を使用しているので、
      外側のループで巨大配列を触っている時に、これも速度低下の原因となる。

      2019-03-10 何の為に info で progress を表示する専用の仕組みを作るのか分からなくなった。
      また、実際に progress bar を isearch の検索進捗状況の表示に使ってみたが、
      "固定文字列部分 プログレスバー 状態表示" の様になっているので、
      info で表示する為の専用の枠組みを作っても面倒なだけの様に思われる。
      それよりは各自でプログレスバーを生成した方が良い気がする。

    * ok: screen の文字幅判定のコードをチェックする。

      % また Unicode Block Characters を使って作成した progress bar で、
      % 文字幅の計算がずれてしまう。これは screen 上で Unicode Block Characters が幅2 なのに、
      % Poderosa 及び ble.sh で幅1で扱われているのが原因である。
      % 使用している screen は cjkwidth emacs で動作しているのに変である。

      これは確かめてみた所、そもそも padparadscha 上ではオリジナルの screen-4.1.0 を用いていた。
      改造した screen は screen-4.3.1 である。
      改造した repository を探してみたが padparadscha 上にはなくて magnate 上にあった。
      GitHub に登録することにした。
      また、git pull してみると 4.* 系列は既に 4.6.2 まで出ている様である。
      既存の改造を 4.6.2 に付け替える事にした。

      - Cygwin でコンパイルできない問題に関しては screen-v4 では直されていた。
        master の方では治っていない (依然として ut_div を用いている)。
      - SGR mouse (DECSET 1006) は 4.6.2 で対応した様である。
      - 結局、4.6.2 に対する改造は `cjkwidth emacs` のみである。
      - 他に Makefile.in の微妙な修正が含まれる。

      新しくした screen で試してみた所、ちゃんと文字幅 1 で計算されている様である。

  * complete (style:desc-raw): 範囲に入り切らない場合に末尾に … を表示する [#D0977]
    序に style:desc でも頁描画をキャッシュする事にした。

  * [自然解消] 2015-11-21 bug: 複数行編集でカーソルが一番上にない場合 vbell で編集内容が消される [#D0976]

    これは既に #D0878 で解決している。

    元々 vbell を実装した時は複数行になる事を想定していなかった (複数行にできなかった)。
    現在は複数行に対応したので特別の配慮が必要である。
    (ble-edit.sh から値を引っ張ってくる必要があるので interface を決めておく必要はあるが。)

  * menu-filter: 着色を改良 [#D0975]
    然し、使ってみると menu-filter の範囲の着色は分かりやすいのか分かりにくいのか謎。
    更に、何処が入力の開始点なのかも分からない。

    x 空文字列から補完を開始した時は、
      menu からの補完を行ってもそれを DEL で戻って修正できるが、
      有限の長さの文字列から補完を開始した問は、menu からの補完を行うと、
      補完した部分より前を修正すると menu-filter が終了してしまう。
      これは何が起こってるのだろうか。

      成る程。分かった。menu-source での更新は行われていない。
      というか、R を入力した時点で README まで確定しているから、
      メニューが一番始めに表示されたタイミングが README まで入力した状態だった。
      従って、其処から絞り込みが開始するというのは自然である。
      これは寧ろ着色の問題である。

  * menu-filter: 何故か関数名補完で一致する候補が消えても候補が menu-filter で消滅せずに残る [#D0974]
    うーん。これはあれだろうか。simple-word でなくなった時にそのままにしているのが悪いのか。
    simple-word でない時には着色だけ解除するという手もあるのかもしれない。
    或いは、そもそも simple-word でない時には menu-filter を使う気がないと判断するべき?

    うーん。或いは。"simple-word ではあり得ない" という判定を作るのが良いのではないか。
    →その様に実装した。ble/syntax:bash/simple-word/is-never-word と言う関数名にした。

  * 2013-06-01 以前 vbell: メッセージが長い場合に適度に長さを制限する [#D0973]

    trace を拡張して construct-text と同様の機能を持たせるか。
    或いは construct-text を trace に統合してしまうか。
    然し、現状で construct-text はそれなりに高速である。
    なので、trace に統合すると遅くなってしまう。
    ble-edit/info/.construct-text は ble/canvas/trace-text に改名する事にした。

    取り敢えず trace-text を利用する事にする。

  * menu-complete: menu-filter の後に menu-complete に突入する際に menu_style が保持されない [#D0972]
    これはメニューから候補を読み取る際に _ble_complete_menu_style から
    bleopt_complete_menu_style を local 復元するという様にする事にした。

  * menu-filter: コマンドを実行した時に着色が解除されない [#D0971]
    これは region の時と同じ様に _ble_complete_menu_active を解除すれば良いだろう。
    と思って試してみたら駄目だった。caret_state に反映されないので、
    _ble_complete_menu_active の変化を検出できていないのである。
    invalidate するか。或いは _ble_textarea_version なる変数を導入するか。導入した。
    ble/textarea#invalidate を拡張する事にした。

  * edit: rps1 を設定していると vi : 等によるサブコマンドラインの表示位置がずれる [#D0970]
    render_opts を空にしても同じ問題が生じているので、出力部分の問題である。
    実際に rps1 を put している所をコメントアウトしたら直った。
    と思ったら _ble_textarea_panel を _ble_text_area_panel と typo していた。修正した。

  * 2019-03-04 complete: menu-filter の編集領域を着色する案 [#D0969]

    編集領域 (get-active-range) を layer:region を用いて着色するのは微妙そうだ。
    auto-complete と同時に使いたい事もあって、layer:region は
    auto-complete で一時挿入された部分の着色にも用いられる為である。

    a reject: 実際に試しで実装してみたが region を使って着色するのは色々と微妙である。
      menu-filter は新しい keymap を導入するわけではないので、
      self-insert などがそのまま実行される。そうすると region が置換されて消滅してしまう。
      auto-complete や menu-complete や search の時に問題がなかったのは、
      特別に keymap を用意しているので self-insert などが region に作用しなかったからである。

      更に当然の事であるが auto-complete が走っている間はそちらを優先しているので着色されない。

    b reject: うーん。別の layer を使って着色を変更する事は可能だろうか。
      例えば overwrite_mode 及び disabled に関して。
      然し、着色順序が異なる。syntax の上で region の下に着色を行いたい。
      overwrite_mode は region と排他的なので、移動は可能かもしれないが、
      overwrite_mode 自体が self-insert の振る舞いを変更するのでこれは変えられない。

    c 振る舞いは変えないけれども表示だけ変わるというような新しい layer が必要である。
      更に状態を制御する変数として、caret_state のチェックに menu-filter が有効になっているかどうかも含める必要がある。
      _ble_complete_menu_* 変数の状態は caret_state として記録しなくても大丈夫だと思われる。
      というのもこれらが更新されるのは何れにしても _ble_edit_str か _ble_edit_ind が変更される時だからである。

    d 或いは disabled を逆に利用して編集領域以外を灰色で被せるなど?
      然し、その場合には overwrite_mode や region 等も同じ色で被せてしまう事になるので微妙である。

    やはりもし実現するとしたら新しい layer を作るのが現実的に思われる。
    現状では余り活性化しない layer が増えてもそんなに重さには影響しないはずである。
    更に、blink-matching-paren などの機能も考えると結局 layer は増やす事になる気がする。

    x fixed: menu-filter に入る時に何故か menu がクリアされてしまう様になっている。何故
      と思ったら、これは menu-filter.idle が menu-filter が失敗した時にメニューを削除するのだった。
      つまり、今回の変更で menu-filter の戻り値を変更したのが原因である。直した。

  * 2019-02-15 ble.sh で [ble: EOF] としている内容は zsh では PROMPT_EOL_MARK で設定できるそうだ [#D0968]
    https://qiita.com/2357gi/items/6d530820402ae776ca66

    ble.sh でもユーザが設定できる様にする? しかし、毎回座標計算するのは面倒である。
    というより現在の位置が分からなければ tab 等の座標計算ができないのではあるまいか。
    結局、現在位置を CPR で尋ねるという事をしなければならなくはないか…。

    事前に計算しておく事にするか? その場合には tab 等の文字が含まれていた場合に困る。
    と思ったが、tab の場合はスペースに変換するので問題ない。
    垂直タブやカーソル移動等が含まれる場合はサポート外とすれば良い。

    2019-03-09 これは trace.draw で nooverflow を実装したので
    一行に収まる様にして簡単に実装できる筈。

    →実際に現在の ble.sh の実装を確認してみたところ、
      実は EOL_MARK の大きさに関係なく動くような実装になっていた。
      % というか eol mark の途中で折返し改行が入った場合はどういう動作になるのか…。
      % 何だかよく分からなくなったがまあ動いているから良いのだろう。
      これは大丈夫。何れにしても次の行に行くという事。
      それからもし行頭に居た時には [ble: EOL] を削除するという事。
      正しく削除する為には eol mark はその行に収まっていなければならない。

  * [棄却] bleopt: openat_base -> internal_openat_base [#D0967]
    internal をつけるかどうかはユーザが触る可能性があるかないかである。
    特別な fd を使う時に触ってもらうかもしれないので internal_ は取り敢えず付けない事にする。
    (とは言いつつユーザがこのオプションに気づいてこれを活用する様になる事があるかは不明だが。)

  * menu_complete: support prior, next, home, end [#D0966]

2019-03-09

  * 2019-03-03 complete: desc の着色に対応する? [#D0965]

    これは trace を弄る必要がある。trace は多分、範囲の指定に対応していない。
    一応見てみると LINES 及び COLULMNS を読み取って使っているが…。
    行末の処理などが折り返し全体になっていたり、
    実際に改行を挿入してしまったりなどしているのではないかと思う。
    これは .construct-text と同様に nonewline 等に対応する必要がある。

    しかし、そもそも色のついた desc を生成する物がないので、
    実装する意義は今のところない。

    2019-03-09 #D0964 に於いて範囲をはみ出ない様な trace を実装した。
    なので実は実装しようと思えば簡単に実装する事ができる。
    →実際に .construct-text を置き換えてみたところ普通に動作している…。
    計算時間に関しても特に無駄にかかっているという様な印象はない。
    というか寧ろ高速だったりする事はあるかしらん。

    * trace.draw と .construct-text の速度に関して

      % 実際に計ってみると .construct-text よりも trace.draw の方が速い…
      勘違いだった測定する順序を間違えていた。逆だった。

        fa2a874 の上に居る時に .blerc (akinomyoga.dotfiles) の sabbrev \commit の表示で試した。
        for entry in "${measure[@]}"; do のループの実行時間を計測する。
        .construct-text による計算時間は:

        real    0m0.027s 1ページ目
        real    0m0.248s 最後の頁
        real    0m0.074s 最後から2番目の頁

        trace.draw による計算時間は:

        real    0m0.048s 1ページ目
        real    0m0.739s 最後の頁
        real    0m0.115s 最後から2番目の頁

      うーん。これを見た感じだと特に日本語の文字が連続している場合には 3 倍ぐらい時間がかかっている。
      やっぱり配列に大量に触ると遅いという事になるのだろうか。

      うーん。DRAW_BUFF を配列ではなく普通の変数にして見たが計算時間は全く変わらない。
      宣言部分を local DRAW_BUFF= に変えてみてもやはり速度は変わらない。
      というか本当に DRAW_BUFF は配列にする事によって速度が向上しているのだろうか。怪しい。
      JavaScript の場合には配列に入れておいて後で連結したほうが速かったが
      bash の場合はどうなんだろう。実際に計測してみる事にする。

        $ bash-5.0 benchmark-strbuff.sh
         4485.78 usec/eval: concat.str (x50)
         4493.09 usec/eval: concat.ret (x50)
         2177.40 usec/eval: concat.arr (x50)

      うーん。実際に計ってみると配列を連結したほうが速い様だ。

        5745.09 usec/eval: concatB.str (x20)
        5899.53 usec/eval: concatB.ret (x20)
        3574.55 usec/eval: concatB.arr (x50)

      途中で別の配列も一緒に触る様にしてもやはり配列の連結の方が速い。
      複数の配列を触って遅くなるのは物凄く長い配列の場合だけだろうか。
      Bash の version 毎に違いがないかも確かめたが違いはない様子である。

      まあ速度的には微々たる物の気がするので気にしない事にする。

      * 着色した場合の速度はどうだろうか。と思って調べたが
        30ms 程度の遅延が一様にかかる様である。まあ気にしなくて良い。

      * 切り替えられる様にした。desc-raw とした時に trace を用いる事にした。

  * 2019-03-08 canvas: ble/canvas/trace を大幅に書き換えようと思う [#D0964]

    complete: desc で色のついた説明を表示できる様にする事に関連して。

    1. 特に先ず初めに範囲内に収まらない場合に出力しない様に修正する。
    2. 改行などで移動している部分を相対位置の移動でもできるオプションを実装する。

    実装した。これで Window 的な物を実装する事はできる様になったのではないかという気がする。
    overlay が簡単に実現できる様になったかどうかについては微妙な所ではある。
    overlay は textarea/info の上でに overlay する事を考えれば、
    textarea/info それぞれに対して再描画等の処理が必要になる。
    それぞれに対して指定された範囲を再描画する関数を実装するか。

    * reject: 背景色を設定する場合を考えると。
      また改行を実行する際に現在位置の右をスペースで埋めるオプションは必要になるだろうか。
      と思ったが、\r を実行してから改行を実施する場合もあるし、難しい問題である。
      先にスペースで埋めてから描画するという具合にするしかないのではないか。

      % Note: ble/textmap#update に於いては、
      % #D0959 での考察により terminfo に ech がある場合にはそれを使い、
      % もしなければ半角空白で埋めるという事をする事にした。
      %
      % erase-eol (ech で消去する) fill-eol (半角空白で埋める) などの
      % オプションを用意しても良いのかもしれない。
      % と思ったが \r を実行してから改行を実行する場合も考えると対応は難しい。

      やはり何か枠の中に描画する際には始めに
      呼び出し元でその枠の中身を消去しておいてもらう必要がある。

    * done: RPROMPT の表示にも使うことができるかもしれない → #D0959 実装した

    * done: trace 中に最大で何処まで右に行ったかを記録したい。

      opts=measure-bbox として実装する事にした。
      これの実装は面倒そうだと思ったが意外と簡単だった。
      殆ど全ての動作は直線的に行われ、
      直線でないのは折返し操作が入る時だけなのであった。
      折返し操作が入る場合には 0-cols を範囲に含めれば良い。
      他の操作に関しては操作が終わってからの位置を見るだけで良い。

      →これを用いて rps1 の表示位置を決定する事にした。

      x fixed: と思ったら日本語を含む時に座標計算がずれている…。
        これは先日 trace を修正した時のバグだった。直した。直った。

    まあ、こんな物である。また本格的に Window System でも作る時に手を入れる
    必要が出てくるかもしれないが今はこれ以上の拡張は行わない事にする。

  * [自然解消] 2013-06-05 RPS1 [#D0963]
    zsh で試してみた所、そもそも RPS1 に改行を含めると RPS1 自体表示されない事が分かった。
    改行は含まれていないと仮定して表示してしまっても良いのかも知れない(2015-03-04)。

    2019-03-09 #D0959 で "bleopt rps1=" として実装した。

  * [自然解消] 2015-02-21 zsh にある機能で気になる物 [#D0962]

    menu 補完と言った物もあるようだ。
      選択肢の説明の表示もできる。
      考えつきそうな機能は一通り揃っているという事か。

    2018-09-23 メニュー補完は既に対応した。
    選択肢の説明は表示していない。
    menu_style で選択肢の説明を表示するモードも提供して良いかもしれない。

    2019-03-09 選択肢の説明に関しては #D0946 で対応した。

  * 2019-03-05 complete: "ble/complete/" の状態から menu-complete に入る事ができない [#D0961]
    これは後で調べる必要がある。

    調べてみると $_ble_complete_menu_active の値が auto になっているのが原因だった。
    では何故 _ble_complete_menu_active=auto の時には menu-complete に入らないのか。
    と思ったら、これは敢えてその様にしているのだった。二回 complete を押して漸く
    menu_complete に入れる様にというそういう配慮だった。
    しかし、今 auto-complete の所為で LASTWIDGET が変化しているので、
    LASTWIDGET による判定に頼る事ができない。

    よく考えてみたら今では footprint による判定を実行しているので、
    わざわざ _ble_complete_menu_active=auto 等の様な仕組みは用意しなくて良いのだった。

    実際に削除してみたら動作が変である。filter で一意確定になった状態で
    complete を実行しようとしても enter_menu になってしまう。
    うーん。filter で一意確定になる所までは良い。
    問題はその一意確定が唯の prefix として生成された物であって、
    実際には完全な候補ではないという事である。
    なので候補を再生成しなければならないが、
    現在 menu から候補を読み取る機能を実装してしまった為に、
    再生成が行われなくなったというのが問題点である。

  * complete: ~/ble 等と ~/ に続けて存在しないファイル名を入力すると物凄く処理に時間がかかる [#D0960]
    途中の処理中断が働いていないという事が考えられる。

    ble/complete/source:file/.construct-ambiguous-pathname-pattern が緩すぎて、
    /home/murase/ble に対して m (substr 一致) で /*/*/* が生成されていた。
    もっと厳しく判定する事にした。速くなった。

  * edit: bleopt rps1 に対応 (RPROMPT (RPS1) 実装) [#D0959]

    | ble/canvas/trace.draw の書き換えに
    | 類似の書換として、textarea の改行を入れる時に
    | 右側に表示されている内容を消すというのがあった。
    | これが RPROMPT の実装の際に問題になっている。
    | これを何か別の物に置き換えるという事は可能だろうか。
    | 例えば RPROMPT が設定されている時には、
    | textarea の幅が狭くなった状態になっている。

    結局 RPS1 に対応してみる事にした。

    a その時に右側を消すには文字数を指定した消去を使うことができる。ECH である。
      と思って infocmp を見てみたが ECH なる項目はない。
    b DCH と ICH の組み合わせで実装するしかない。
      然し DCH で全角文字がある場合にはどうなるのだろう。
      と思って実際に試してみた所 Poderosa でエラーが発生した。
      なのでこれを使う事はできない。
    c 実は此処は単に空白文字を出力するだけで良いのではないか。

    取り敢えず実装した。RPROMPT がある時には opts に
    relative を入れて実行すれば良いのではないか。
    実は、常に relative を入れても良いのかも知れない。

    実装した。

    x fixed: 何故か表示されないと思っていたら結果が記録されていなかった
    x fixed: PS1 を上書きしていると思ったら local ret するべきだった
    x fixed: 表示位置がずれている。一番右ではなく余白ができている。
      これは cols を rps1 を除いた長さに修正したことを忘れていた事による物だった。

    動いている気がする。

    * done: RPS1 は bleopt_edit_rps1 に変更する。
      →結局 bleopt_rps1 という名前にする事にした。変更した。

    * done: 次に文字を入力しても消去されない様にする必要がある。
      というより文字を入力した時に何処で消去が起こっているか調べる必要がある。

      * ble/textarea#render/.show-scroll-at-first-line
        先ず line... というのを表示する所で _ble_term_el を出力している。
        ここは rps1 が有効の時は relative にする。

      取り敢えず上は render_opts を参照して消去を行う様に修正した。
      然し、他に _ble_term_el を出力している箇所はない…。
      という事となるとやはり ble/canvas/trace.draw が末尾に el を出しているのだろうか。
      もしくは ble/textarea#slice-text-buffer の辺りか…。
      見つけた。ble/canvas/panel#clear-after.draw を呼び出している所である。

      動かしているが座標計算が誤っている。
      と思ったら ble/canvas/panel#goto.draw を呼び出すべきところを、
      ble/canvas/goto.draw を呼び出していた。直した。

    * done: _ble_term_ech 対応
      現在は空白を大量に出力するので効率が悪い。既存の端末の ech 対応状況を調べて、
      もし多くの端末で対応されているようであれば ech を用いた実装も準備する。
      dch と ich を用いた実装は poderosa が全角文字で火を吹くので駄目。

      RLogin 及び xterm は対応している。screen, mintty も対応している。
      Poderosa (myoga) は何故か引数の解釈が一つずれている?
      うーん。やはり ech は terminfo の中でも余りない為に動作が怪しい。
      terminfo に登録されていても使わない方が安心なのでは。
      しかし xterm に登録されている…。
      xterm を名乗りながらバグが有るのはその端末の責任である。
      なので、ble.sh の知ったことではない。寧ろバグの洗い出しになるだろう。

      Poderosa での ICH/DCH/ECH の実装について。
      % 例えば Poderosa-4.35b では (1) 引数の解釈がおかしい (1 少なく解釈される)。
      % (2) ECH で全角文字の途中まで消去すると変な文字が表示される。
      % (3) DCH で全角文字の途中まで消去しようとするとエラーメッセージが出る。
      実際にソースコードを見てみたところ自分の実装がおかしかっただけの気がしてきた。
      Poderosa で xterm の場合で動作確認したところ、
      DCH に関しては中途半端な文字が残ってしまうが、他の動作は普通だった。

      取り敢えず Poderosa の DCH を直した。ECH はどうも変な振る舞いは起こっていない。
      全角文字の途中までの消去でもちゃんとスペースになっている気がする。
      引数の解釈も問題ない気がする。修正した。後で更新する事にする。

    以下の項目はこれで実装完了とする。

    | + 2015-11-21 RPS1

2019-03-07

  * complete: menu の頁 [#D0958]

    現在の実装だと画面に収まる範囲でしか選択できない。
    commit id 等の場合には入力による絞り込みは難しいので、
    やはりどの項目も menu からアクセスできる様にしたい。
    そう考えると menu の頁に対応するのが良い気がする。
    その為には現在表示している項目の範囲を記録するという事、
    それから前に表示した頁の先頭位置を記録するという事。
    S-TAB で戻った時には計算が重くなるが、全頁について計算する。

    うーん。取り敢えず desc の場合にはページと項目番号の対応が自明なので、
    desc の場合にだけ対応してしまうというのも一つの手である。

    現状の実装について観察する。どうも construct-text が lines をはみ出ない様になっている為に、
    途中で内容が切れていても収まっていると判定されている…? それによって中途半端の項目が表示されている。
    更に中途半端の項目はメニュー選択で着色されたりされなかったりして振る舞いが一定していない気もする。
    今の所再現する条件については分かっていない。

    * done: 現在の表示の高さは最後の行に改行を出力する事前提で一行少なめになっている。
      末尾の改行を無駄に出力しない様にする事に出最後の行まで使い切る様に修正する。

    * fixed: 中途半端に表示されている項目は表示しない様に修正する。
      然し、中途半端になったかどうかについてどうやって判定すれば良いのだろうか。
      うーん。.construct-text の実装を調べるとまあ分からない。
      一番最後の位置に移動していれば丁度ぴったり収まったかはみ出たかのどちらかである。
      然し、やはりちゃんと収まったかどうかについて判定できる方が良い。

      はみ出たときにはそれを検知する様にするべきである。
      →はみ出た時には .construct-text は失敗する様にした。
        また同様に construct-single-entry についても失敗する様にした。

      戻り値を用いてはみ出た項目については出力しない様に修正した。
      但し、一番初めの候補の時点ではみ出てしまう場合にははみ出ても表示する。

    どの様に頁を変更・表示するのかについて考える。
    ble/widget/menu_complete/forward を観察すると
    _ble_complete_menu_selected が現在の頁の中の選択位置で、
    ${#_ble_complete_menu_items[@]} が現在の頁の中の項目の数である。
    これに加えて ${#_ble_complete_menu_pack[@]} も考慮に入れて再描画などして実行すると良いのではないか。

    * done: 先ず初めに menu/show に於いて開始位置を指定して表示できる様にする。
      _ble_complete_menu_offset という変数を用意して其処に offset を記録する事にした。

    * done: 実装した。動いている。

    但し頁切替時の offset の計算方法が適当である。

    a 或いは construct に統合しても良いのかもしれないとも思う。
      適当な場所から描画を始めて二分法的に開始位置を特定する。

      もし頁切替時の offset の計算を construct に統合するのだとすれば。
      その際には opts として offset=NUMBER ではなくて、
      bottom=NUMBER もしくは end=NUMBER 等を指定できる様にする?
      或いは scroll-up=NUMBER もしくは scroll-down=NUMBER でも良い。
      と思ったが、scroll-up/down の up/down は紙の話か枠の話かで分かりにくい。
      scroll=NUMBER にして現在の表示範囲と較べて自動で判定してもらうという手もある…。

    b 或いは全て計算を実行しきってしまうか。と思ったが、計算に時間が掛かるし、
      更に大抵の場合にはスクロールもしないで終了するので意味がない。

      やはり適当に計算を実行するしか無い気がする。

    c 或いは、一度表示した頁に関してはその情報を記録しておくという手がある。
      但し info の高さなどが変更になった場合にはその情報をクリアしなければならない。
      また遡った時には頁情報を利用することができないので、
      やはり中途半端な実装になってしまう。

      適当な見積もりで何とか誤魔化すしかないだろうか。

    d 或いは逆方向に rendering する事は可能なのだろうか。
      そちらの方が現実的な気がしてきた…。と思ったが、
      やはり逆方向に rendering しても元と完全に一致するかは分からないし、
      中途半端に実装しても非直観的な振る舞いになってしまう。

    二分法で当たりをつけるにしても最初の範囲はどの様に決定したら良いか。
    一番最初からにすると候補が増大した時に大変な事になる。
    1項目あたりの長さを見積もってそれで適当に予測を立てるしかないのだろうか。
    1項目あたりの長さに関しては bleopt_complete_menu_align で最大値が分かる。
    しかし実際にはもっと短いファイル名の場合などがあるのでもっと小さくなりうる。
    或いは最低の align という物を定めてしまっても良いのかもしれない。

    e うーん。やはりどうしても実装が汚くなってしまう。
      もし bash ではなくて十分に速度の出る言語だったらどの様に実装しただろうか。
      普通に考えて一番初めに全て計算しきってしまうだろう。

      或いは、その時に request した部分までを計算して、
      既に計算し終わった部分に関しては何処かに記録しておいて、
      未だ計算し終わっていない部分が必要になったらその時に計算を実行する。

    うーん。まあこの方法が一番まともな気がする。
    変に速度を気にしておかしな実装にするよりはずっと良い。
    問題は info の幅が変更になった時に再度計算し直しになるという事だが
    これは速い言語で実装する時にもそうなる筈なのだから気にしなくて良い。

    取り敢えず各項目が表示される頁は固定という事にしてしまう。
    そうしないと頁を跨る項目などが現れて面倒な事になるからである。
    また、offset=NUMBER の指定ではなくてどの項目を表示するかの指定を
    scroll=NUMBER で指定する様にする事にする。
    実装が複雑になりそうなので一旦 commit を作ってしまう事にする。

    * style:align に関して配置を計算しようとしたが厄介である。
      先ず始めに幅をどの様に決めるか。これは実際の項目の幅を全部見ていかなければ分からない。
      そして幅というのはページごとに計算するべきである。
      という事を考えればページごとに配置を計算していかなければならないという事になる。

      なのでループする時にも実際に途中まで計測を実行して頁配置を実際にして、
      そしてはみ出たところからまた項目の計測を行って頁配置を実際にして、
      というのを繰り返して計算を実行しなければならない。
      うーん。1から計算し直さなければならないのだろうか…。
      或いは計測した情報だけから何か有意に計算する事が可能だろうか。うーん。
      incremental に実際に取る幅を計算していく事ができるだろうか。
      取り敢えず考えてみる事にする。

      1. 仮定として全角文字は含まれないという事にする。
        つまり単語の任意の箇所で改行が実行できるという様に仮定する。
      2. max_wcell は cell の幅の最大値である。
      3. wcell は現在までの項目から決めた cell 幅という事にする。
         ncell は現在までの cell の数という事にする。

      wcell を大きくしなければならないという事が分かった時にどの様に更新するのかという事。
      先ず wcell->wcell+delta とする時に、一行に収まる cell の数が減少する。
      逆に増えるという事はありえない。これによって ncell_max が減少する。
      また一旦 wcell が max_wcell に達すると、それ以上に wcell が増大する事はなくなる。
      また align-nowrap に関しては、wrap が起こる様な場合というのは、
      必ず wcell が max_wcell に達した後になるので、これも wcell は固定されていると思って良い。

      まずはじめはキャッシュの形式などを考えることなく愚直に最後まで実装する事を考える。
      その後で途中で中断・再開する為に必要なデータの形式について考える事にする。
      というか正しく実装すれば実は一つのループで実装できてしまうのではないかとすら思われる。

      取り敢えず配置の見積もりの部分までは書いてみたが…。うーん。本当にこれで大丈夫なのだろうか。
      正確に測量できているだろうか。予想外の事によってやはり収まらないみたいな事はないのか。
      と思ったが、実際にそういう可能性がある。というのも、全角文字の途中で改行が起こって収まらない可能性があるから。
      その様に考えると頁を一つ処理する度に、一旦ループを抜けて実際の配置の構築を実施しなければならない筈である。
      一応、wcell <= max_wcell の時には途中で改行が入るなどの事はないと思われるが、
      実のところ場合分けしても仕方がないので前提として改行が入る可能性を考えてページごとにレンダリングを試す事にする。
      頁に収まらない項目に関しては計測が重複してしまう様な気もがするがそれは仕方がない。
      というかその部分をキャッシュすることにすれば良いという気もする。

      頁内容の構築の部分は今までのコードを流用すれば大丈夫のはずである。
      取り敢えず動作テストだけ実施してしまう事にする。

      x fixed: フリーズする→これはどうにかして直した。
      x fixed: 一列になってしまう→ncell の初期化をしていなかった。
      x fixed: TAB を連続で押すとフリーズする→これは check-cancel
        で終了したのに成功したとして処理していたのが悪かった。
      x fixed: 何故かもっと表示できるはずなのに余り表示されない。
        これは cols%wcell の余白に収まる候補が改行されないのが原因であった。
        余白に収まる場合には改行しないという事を考慮に入れた実装にしたい。

      まあ、取り敢えず style:align の頁は実装した。

    * style:dense は style:align よりは簡単だろう。
      というのも途中で wcell が幅を変えるだとか変則的な事は起こらないので。
      実装した。動いている。取り敢えずこれで良い気がする。

    * style:desc はもっと簡単である。
      動作確認する。動いている。OK

    最早 offset がどうのというコードは要らなくなったので削除する。

2019-03-04

  * complete: menu-filter が有効の時は auto-complete を無効にする? [#D0957]
    <kbd>C-g</kbd> で menu-filter をキャンセルする (menu を消す)?

    うーん。実際に試してみたけれども微妙な気がしてきた。
    編集領域の途中にカーソルがある時に勝手に auto-complete を挿入されると
    混乱の元になってしまうので抑制するというのは正しい気がする。

    然し、更に編集領域の末尾にカーソルがある時に
    auto-complete を抑制する事が果たして自然なのかは分からない。

    % というか、編集領域が "" の時に auto-complete を許していると、
    % その後の文字入力に対して編集領域が変化した時に auto-complete に食われてしまって
    % menu-filter が働かないのではないかという気がする。
    % →と思って実装を調べてみたら auto-complete の時には
    % menu-filter 側で特別の対策をしていて auto-complete
    % で挿入された部分をちゃんと取り除いてから処理している。

    うーん。こうなっているとすると、menu-filter の active range を
    layer:region (_ble_edit_mark_active) を用いて着色するという作戦は微妙?
    →これは独立した項目として議論する事にする。

  * complete: menu-complete に入る条件がやはり何かずれている [#D0956]

    三回目の TAB で漸く menu-complete に入るという状態になっている。

    echo pr [TAB] echo pro [TAB] echo pro [TAB] echo prog

    本当はこの様な時には2回目のTABで menu-complete に入って欲しい。
    具体的にどの様になっているかを調べてみるのが良い。
    特に footprint がどの様な状態になっているのかが一番怪しいので調べる。

    どうやら記録されている footprint の _ble_edit_mark の位置が異なるのが原因である。
    というか _ble_edit_mark の位置は auto-complete に依って書き換えられるのだから、
    異なっていても仕方がない。なので、_ble_edit_mark は footprint に含めない。
    もしくは _ble_edit_mark_active が設定されている時にだけ footprint に含める。

    直した。その他の場面でも前よりも違和感のない動作になった様な気がする。

2019-03-03

  * VARNAMES でブレース展開を使うのは良くない。refactoring の置換で変な事になる [#D0955]
    具体的には edit.sh の _ble_dirty_... など。手で展開した。

  * info: ble-edit/info/.construct-content raw は分かりにくい [#D0954]
    結局中で trace するので、raw ではなくて ANSI sequence である。
    これは ansi だとか esc だとかにするべきなのでは。esc が良い。
    幸いに raw という単語は他に殆ど使っていない様なので一括で置換できそう。

  * complete: desc を表示する為の単語候補は既定にしても良いのでは。。 [#D0953]
    対応した。

  * complete: menu-filter した後の menu-complete を確定すると / が付加される [#D0952]
    これは起こったり起こらなかったりする。LICENSE.md で起こる。
    うーん。必ず起こっている気がしてきた…。何故だろう…。

    また動作を調べてみる事にする。
    これは _ble_complete_menu_items (表示候補) からデータを取り出さなければならないところを、
    _ble_complete_menu_pack (全候補) からデータを取り出していたのが行けなかった。
    番号が全く異なるので別の候補 (ディレクトリ) を取り出して処理していた。
    今まで問題にならなかったのは menu-filter をした後に menu-complete に入る事がなかったので
    両者の番号が一致していたという所にある。

    これはちゃんと _ble_complete_menu_items からデータを取り出す様にしたら直った。

  * complete: menu-filter した後に TAB で menu-complete に入ろうとしても入れない [#D0951]
    どうも新しい補完が発動している様な気がするが…。
    しかし、menu-filter はクリアされていない様子である。

    これは ble/widget/complete の中で enter_menu になる条件の所を調べる必要がある。
    うーん。自動補完が関係している様な気もしている。

    具体的に再現する例は Makefile make_command.sh というファイルが存在して、
    その時に "echo @" で補完を開始して "echo ak" まで絞り込んだ時に、
    メニュー補完に入る事ができない。

    具体的に見てみる事にする。

    連続で素早く TAB を入力するとメニュー補完に入る事ができる。
    auto-complete が LASTWIDGET を書き換えてしまっているという事だろうか。
    調べるとたしかに書き換えてしまっている。
    しかし、別経路でメニュー補完に入るのもある。
    _ble_edit_str と _ble_complete_menu_str が一致している時である。
    今までは大体こちらの別経路の方でメニュー補完に入っていた様に思われる。
    今回これが効かなくなってしまったのは _ble_complete_menu_str の更新が変わったからである。
    今までだと _ble_complete_menu_str は最後に complete を実行した時の編集文字列だった。
    然し、現在では complete を実行したとしても必ずしも _ble_complete_menu_str は更新されない。
    従って、ここでの判定に _ble_complete_menu_str は使えない。

    というか _ble_complete_menu_str は元々 filtering の初期状態を残しておく為の物だった。

    a なので、この用途の為にはまた別の変数を用意するのが良い気がする。
      うーん。然し変数名はどうした物か。
      というか str,beg,end は何れも active-range の為の物なので menu を始めに表示した時の物である。
      str の名称を変えるのだとしたらそれに応じて beg,end も変えなくては変である。
      従って、str,beg,end の変数名は変えない事にして、
      最後に TAB で complete を呼び出した時の内容は別の変数名 str2 などに格納するのか。

    b 或いは LASTWIDGET が正しく動く様にするという手も考えられる。
      というか ble-decode-key を使っているのだから、LASTWIDGET が設定されても良いのでは?
      と思ったが cancel-default も LASTWIDGET を設定するし、
      ble-decode-key から呼び出された complete も LASTWIDGET を設定するし、
      という事になるので難しいし、今の振る舞いが変であると言うこともできない。

    c やはり変数に記録する方法が良いのだろうか。
      後、カーソル位置についても確認した方が良い気がする。

      うーん。ble/textarea#render の更新でチェックしている _ble_textarea_caret_state
      と似たような情報を調べたほうが良いだろうか。つまり、カーソル移動等があった後は、
      いきなりメニュー補完に入るのではなくて、一回は通常の補完を試みる。

      というか menu-filter の途中で auto-complete が起こるのは微妙である。
      うーん。menu-filter の途中では auto-complete が起こらない様にするか…。
      その様にした方が振る舞いとしてすっきりする気がする。
      また、auto-complete がなければ get-active-range の着色も region layer からできる。

    →結局 footprint という変数名にして _ble_edit_{ind,mark,mark_active,overwrite_mode,str} を記録する事にした。


  * complete: REPLACE の時の auto-complete と上書きされる文字の着色について [#D0950]
    auto-complete で一時的に挿入される内容が上書き対象として着色されてしまっている。

    これは以下の順序が問題である。
    _ble_highlight_layer__list=(plain syntax region overwrite_mode disabled)
    然し、この順番になっているのには理由があるのではあるまいか。
    例えば region で囲まれている時に overwrite だったら…。
    囲まれている時の self-insert は囲まれている部分を削除するのであって、overwrite は無効になる筈である。
    したがって、そもそも overwrite_mode は mark_active の時には着色しない?

    然し、mark_active= は色々な場合がある。単なる選択の場合から矩形選択だとか、云々。

      1 ... これは通常の選択 (選択範囲を置換)
      S ... これは shift による移動中 (選択範囲を置換)
      search ... これは検索中 (選択範囲を置換)
      menu_complete ... (範囲を削除した上で上書き)
      auto_complete ... (範囲を削除した上で上書き)
      vi_c?surround ... (入力待ちなので self-insert が起こる事はない筈)
      vi_{char,line,block}+? ...
        これは xmap の時には self-insert は起こらない。
        選択モードの時には選択範囲を置換する。というか、
        選択モードから抜けた時に REPLACE になる事はあるのだろうか。
      vi_search ... これは normal mode なので挿入は起こらない
      vi_filter ... これはコマンドを入力している間の話なので関係ない。

    この様に眺めてみると、実は overwrite_mode の着色は、
    menu_complete/auto_complete の時を除けば mark_active なら無効にして良い気がする。
    実際に動かしてみた。まあ、大丈夫である。

    menu_complete/auto_complete に関しては妥協する。
    将来的にオーバーレイかそれに類いする方法を実装した時には、
    auto_complete は region ではない方法で実装される様になるので、気にしなくて良い。
    menu_complete に関しては実際に挿入する事になりそうだが、
    その時に self-insert をした時に何処が上書きされるのか、を表示するのは結局面倒である。

    或いは、mark_active の種類毎に削除した上での overwrite かどうかを取得して、
    削除した上での overwrite だったら範囲の末尾で着色をするという事もできるのかもしれない…。
    然し、実装として汚くなるので妥協してそういう実装にはしない事にする。

    x ok: vi_nmap (`!!`): キャンセル時に vi_filter の色が残る。と思ったが勘違いだった。
      C-g ではキャンセルできないのだった。

    x fixed: xmap r での上書きの着色が見えなくなった。今までは上書きになるという事を示すべく、
      カーソル位置で色が水色になっていたが、それがなくなった。
      しかし、それはこのままでも良いような気がしてきた。
      というのも $ で行末に行っている時には結局水色にならないからである。

      _ble_edit_overwrite_mode=R の時には選択範囲の着色を変えるのが良いのではないかと思ったが、
      そうすると、vi_{char,line,block}+? のそれぞれに対してコピーを作成する必要があって不毛である。
      と思ったが、mark:vi_{char,line,block}/get-face の中で _ble_edit_overwrite_mode を参照すれば良いだけ?
      →その様に実装する事にした。動いている。

  * 2018-08-26 complete: 候補一覧にて曖昧一致に関しても一致部分を太字にすると便利ではないか? [#D0949]

    % これは処理が重くなるので取り敢えずは実装しない。
    %
    % うーん。awk による実装に切り替えたら現実的な速度で実装できるかもしれない。
    % awk による実装で問題になるのは getg を先に全項目に対して呼び出して置かなければならないという事。
    % シェルの実装だと画面の大きさに達したらそこまでで良かったが、awk の実装だとそういう訳には行かない。
    % と思ったが、まあ、文字数で数えて上限を設定すればそう問題でもない。
    %
    % 2019-02-08 更に配列を awk に渡すなどの際に色々面倒な事がある気がする。
    % とにかく実装が汚くなってしまう。何か簡単に一発で着色できる方法の様な物はないだろうか。
    % 或いは、部分一致だけ awk で処理して着色部分に関しては ble.sh 側で行うという手も考えられる。
    % 何れにしても bash が遅いのが問題なのである。
    %
    % 2018-09-05 ブレース展開の comps_ibrace による固定部分の処理には注意する。

    →これは結局 #D0948 の一環で実装した。awk 等は使わず結局 bash だけで実装する事になった。
    そもそも曖昧補完で沢山一致するという事が余り考えられないので速度は取り敢えず気にしない。

  * complete: menu-filter に於いて、候補がなくなった時の曖昧一致は [#D0948]

    1. 部分一致
    2. 先頭1文字と部分列一致
    3. 部分列一致

    の優先順位で試す事にしたい。というより普通の補完の時にも
    その様にして良いのかもしれない。但し、コマンド補完などの場合には
    大量の候補が生成されて処理に時間がかかってしまうので、
    部分列一致は無効にするなどの事はして良いのではないかと思う。

    menu-filter に関しては実装した。然し、通常の補完については実装していない。

    →取り敢えず簡単に実装してみたが、未だ候補生成部分を弄っていないので
    部分列一致に関しては不完全である。

    * done: 曖昧一致の種類が分かる様にする。comp_type を弄る。
      一応一通り書いた様な気がする。
      候補生成部分に関しても実装した。

    * fixed: source:glob の実装が怪しい。
      pattern* による補完が可能かどうかチェックする。
      これは今までの実装では動かなかったが修正して動く様になった。

    動作テストをしてみる。

    x ok: 何故だか menu-filter を実行した後に ble/widget/complete を呼び出しても、
      その場で補完が起こってしまって enter_menu にならない気がする。
      と思ったが、その動作で正しいのだった。
      もしかすると保管によって挿入できるかもしれないとして、
      メニューに入らずに TAB を押したいという事があるかもしれない為である。
      二回 TAB を押した時に限ってメニュー補完に入るのである。

    o 取り敢えず substr も subseq も動いている気がするので OK

    * done: 実装を整理する。つまり、menu-filter と最初の生成のルーチンを共通化する。

    * done: 曖昧一致によって menu 項目着色のルーチンを変更する

      現在の実装を確認してみると先頭一致の場合には途中で色を切り替えて、
      曖昧一致の時には全体をそのまま描画する様になっている。
      .construct-text を途中で呼び出しつつ処理している。

      どの様な実装にするのが良いだろうか。
      例えば、trace を呼び出してしまって計測するという手は?
      →その方法だと埋め込まれた制御シーケンスの切り出しなどが手間である。
      やはり .construct-text を自分で呼び出していく方が高速に動作する筈である。

      さて、どの様に実装するのが良いだろうか。
      例えば filter:substr/get-matches という形で配列に一致部分を格納する?
      或いは filter:substr/construct という関数で、自前で描画してもらう事にする?
      前者の実装の方が良い気がする。前者の方法で取り敢えず実装してみる事にする。

      - ble-complete/candidates/filter:hsubseq/match は何となく実装したが今ひとつ自信がない。
        →テストした。少し直した。
      - 更にこれを使って着色するコードを書いた。動いている。
      - substr の時の動作が変だったが直した。

    x fixed: 部分列一致を通常の補完でも実装したつもりなのに動いていない。
      progcomp が悪いのだろうか。然し、空の文字列の時にはちゃんと補完候補が現れている…。
      これは調べてみると progcomp の問題ではなくて、
      generate-with-filter の関数の戻り値の問題だった。曖昧補完が全く起動しなくなっていた。

    x fixed: 今度は補完した時に表示される筈の候補が一瞬しか表示されなくなってしまった。
      挿入が起こると消滅してしまう様子である。今までは動いていた。

      調べると候補一覧は if [[ $insert_flags == *m* ]]; then の中で表示している。
      実際に中にある menu/show を省略すると一瞬表示されていた物は全く表示されなくなった。
      問題は、誰かが表示を消しているという事である。

      うーん。不思議だ。ちゃんと menu/show は呼び出されている気がする。
      % しかも、一瞬だけ表示されていたと思ったものが全く表示されなくなってしまった。
      % と思ったらこれは勘違いだった。make できていなかっただけだった。

      うーん。誰が表示を消しているのだろうか…。ble-edit/info からも調べてみる事にする。
      何と調べてみると、menu-filter の中の get-active-range の中で menu/clear が呼び出されている…。何故?

      どうやら auto-complete で挿入されている内容がメニュー構築時に記録されて、
      その後で挿入が起こるとその内容が消えてしまった様に見える為に menu-filter 状態が解除されたと見なされている。
      今まで動いていたのは挿入が起こった場合には候補生成・メニュー構築を再実行していた為に、
      挿入後の内容で再度 menu-filter が初期化されるからである。
      現在ではメニューが残っている場合には、それを用いて menu-filter 状態を更新している為に、
      挿入で消えたものや吸収した文字列にずれが生じた事に対応できていない…。

      a menu/show で記録する時に auto-complete で一時的に挿入されている物を削除する。
        この作戦は使えない。というのも auto-complete がなくても挿入時に吸収される場合もあるからである。
        というかそもそも auto-complete で一時的に挿入されている物が記録されてしまうのも謎である。
        complete を実行している間は auto_complete keymap から抜けているので、
        auto-complete によって挿入されている文字列は _ble_edit_str には残っていないのでは…。変だ。
        何れにしてもこの方法だと駄目なのでもっと良い方法を考える。なので気にしない。

      b 挿入が起こった時には、挿入開始点はそのままにして、
        その後の状態を menu/show で記録するという様にすればよいのでは…。
        つまり、menu 項目を用いて補完して挿入された場合には、
        その場合専用の情報更新をすれば良い。

      うーん。よく分からない記録する部分を弄ろうとしたら全く通過しない。
      しかも考えてみたら menu から拾った候補でない時にも同じ現象が起こっている。
      先ずは、普通の時に動作する様に修正しなければならない。
      記録しているのは beg=$COMP1 end=$COMP2 …ああ、これだ。最近書き換えた…。
      これは修正した。そうしたら以前のとおりに動く様になった。

      しかし menu から拾った候補の場合には未だ問題が残っている。
      文字列を吸収した場合に対応できていない。
      →これは menu/show で、menu から候補を拾った時の特別な更新を追加して対応した。動いている。

  * complete: menu-filter で曖昧になった時に complete で補完すると [#D0947]
    comp_type に a が含まれない事になって、挿入結果にごみが残ってしまう。
    と思って修正してみたが症状は変わらない…。うーん。
    実際に調べてみると COMP1 と COMP2 が正しく設定されていない。
    というか COMP2 が正しく設定されていないのである。
    COMP2 が filter 前の状態になっている…。

    x fixed: これについては修正したが、今度はちゃんと補完できなくなった。
      実装を見てみると "既存部分を置換し、一意確定でない場合は挿入しない" という事になっている。
      その様にする理由は何だったろうか。文法構造を破壊してしまう可能性があるからだったろうか。
      どうも 41b8cbb の様である。調べると #D0897 である。
      #D0897 は既存の部分を置換する様にした一番最初の実装なので、大した意味はない様である。
      成る程。理由が分かった。既存の部分を置換してしまうと、
      共通部分が既存の部分の一部にしか一致していない場合に、
      既存部分の持っていた情報が失われてしまうという問題がある。

      これに正しく対応する為には、共通部分が完全に曖昧一致する場合は、
      既存部分の置換を起こしても良い事にする。しかし、それでも不完全である。
      もっとちゃんと言うと "共通部分の評価結果が含む既存部分を吸収する形で挿入する" というのが正しい。

      然し、もっとよく考えてみると曖昧一致の場合と、
      完全に置換する場合の二種類がある。
      完全に置換する場合には勝手に内容を書き換えてしまっては行けないので、
      今まで通りに一意確定の時以外には挿入を実行しないという事にする。
      曖昧一致の場合にはその様に置換する。
      しかし曖昧一致の種類に応じた処理が必要なのではないか…。

      * ble-complete/candidates/determine-common-prefix の comp_type の部分を真面目に実装する必要がある。
        ble/widget/complete の部分も真面目に実装する必要がある?
        或いは determine-common-prefix でちゃんと実装すれば実は気にしなくても大丈夫?

        取り敢えず実装する。determine-common-prefix において、eval する所までは良い。
        完全一致ではなくて部分一致の時はどの様に実装すれば良いのか。

        1 例えば部分列 (m) で考える事にする。
          この時は $common* が m に一致すれば良い。
          つまり $common == *m* か或いは、
          $common == *${m::some} という事になる。
          うーん。2つ目の条件は…。common-suffix-prefix という関数があったのでそれを使う事にした。

        2 部分列 (a) の時にはどうしたら良いだろうか。
          何文字目まで一致したのかという事を知らなければならない。
          正規表現を工夫する事を考えたが、よく考えたら正規表現にする意味がない。
          正規表現にするのは大量の候補を処理する時に高速だからである。
          しかし今回の場合は一回限りの判定なので正規表現を構築していたら却って遅い。
          自分で1文字ずつ処理するのが速い。

        取り敢えず実装した。動いている。
        ble/widget/complete の部分では特に処理をする必要はなかった。

2019-03-02

  * ble-sabbrev -m に於いて COMPREPLY で結果を戻す様にしているが [#D0946]
    この方法だと自由度に欠けるのではないか。
    それよりは yield を使って生成する等の方法を取った方が良いのかもしれない。
    或いは、自分で desc を追加する方法を提供するなど?

    というかそもそも現在の補完の仕組みでは各項目に対する desc を設定する事ができない。
    desc を記録するフィールドがそもそも無いからである。
    なので、これに対応するのは、少なくとも、補完において各項目の desc を表示できる様にしてからである。
    desc の表示はどの様に実装したら良いのだろうか。特に候補の幅と desc の幅をどう決めるのかという事。
    desc を一緒に表示するという事になると候補の数は最初に確定してしまうので、
    その中で最長の候補の長さを候補の表示に割り当てて、残りの幅を desc の表示に割り当てる事にすれば良さそう。
    desc に関しては入り切らない部分は其処で切るという事にする。

    * 取り敢えず COMPREPLY でも ble-complete/cand/yield でも
      どちらでも候補を生成する事ができる様にする事にした。

    * 生成する事が可能になった。
      更に、.blerc に blerc/sabbrev-git-commit として実装してみたが頗る便利である。

    * ble-sabbrev -m '\date'='ble/util/assign COMPREPLY "date +%F"'
      これは便利な感じがする。

  * complete: description の表示に対応する [#D0945]

    description を表示する時には各行に候補を表示する事にして、
    一番長い候補に合わせて候補の表示幅を決める。
    残りの部分を説明の表示に使う事にする。

    対応する為には先ず説明の情報を格納する方法について考える必要がある。
    当初の考えでは source または action 毎に DATA に必要な情報を格納してもらって、
    必要になった時に説明を生成するというものだった。
    説明の生成には時間がかかるかもしれないので、できるだけ説明の生成を遅延させるという事。
    もし説明の生成に必要な情報が候補生成時にしか得られないのだとしたら、
    そのまま説明のデータを DATA に格納してしまっても良いのである。

    DATA に必要な情報を格納するという方式にして置けば
    ble-complete/cand/yield をそのまま使う事ができる。
    action に対応した形式で必要な情報を DATA に格納する。

    先ずは desc がある時の配置・描画のコードを書く事にする。
    はみ出る候補や説明については切る事にする。
    調べてみると .construct-text は初めからそうなる様に実装されていた。
    更に、.construct-text は改行やタブは ^J や ^I としてくれる。
    なので候補が変に切られたり表示が滅茶苦茶になったりという事はない筈。

    cols 及び lines を弄る事によって幅を制限すれば良い。

    取り敢えず実装してみた所、表示はできている気がする。
    もの凄く長い物が含まれている場合等でも大丈夫か確認する。

    x fixed: 駄目である。と思ったら隔てる空白の分の x 座標移動を入れていなかった。入れた。

    x fixed: しかしそれでも未だ何かずれている。うーん。put-atomic で文字を出力してしまっている気がする。
      それも put-simple で切れた後にそれが起こっている。
      行末または範囲外に行ったらその時点で処理を中断する必要があるのでは。

      % また、丁度ぴったりの時にも put-atomic が起こらない様にする必要がある。
      % と思ったらちゃんと w による幅で収まるかどうかを判定している。
      % これは put-atomic の想定として "未だ範囲内にいる" と思っているのが行けない。
      % なので、これについては呼び出し元で処理する事にして put-atomic 側では何もしなくて良い。

      これについても修正した。

    x fixed: 後、丁度ぴったり末尾に収まった時に put-atomic が改行を出力してしまう気がする。
      put-simple の方も put-nl-if-eol というのを出力する様になっている。
      もしこれが発動してしまうと幅を計算するのに使う事ができなくなる。
      勝手に開業しない種類の construct-text が必要になるのではないか。
      これは construct-text の第二引数に opts でも受け取って処理することにすれば良いか。

      自動改行が起こらないオプションという事にする。
      これについても慎重に考えてみたが恐らく問題は起こらないという判断。

    x fixed: 改行などの特殊文字に色がついていない。
      これは .construct-text の呼び出し元で sgr1 sgr0 を用意しておく必要があった。対応した。

    x fixed: 座標計算が誤っている。直した。

    * done: また幾つかの action について get-desc を実装した。

    * done: メニューの形式を最初にメニューを表示した時点の物に固定する様にした。

  * vi_map N でコマンドが見つかりませんという表示が出る [#D0944]
    これは ble-edit/isearch/backward-search-history-blockwise に
    opts として progress をつけて呼び出しているのにも拘わらず、
    isearch_progress_callback を指定していないのが原因であった。
    ではそもそも何故 progress を付けたのだったか。
    そして、isearch_progress_callback は何故設定していないのか。
    既定値を使用する意図だったのかそもそも progress は表示しないつもりだったのか。
    実際に vi.sh を観察すると isearch_progress_callback は影も形もない。
    取り敢えず isearch で使っているのと同じ callback を用いる事にした。

2019-02-28

  * bash: 何と色々試している内に変な事を発見してしまった [#D0943]

    $ bash --norc
    $ shopt -s failglob
    $ a='\'
    $ echo $a'*'

    これで failglob が発動する。\* に一致するファイルは存在しませんという話。
    試しに bash-3.0 -- 5.0 まで調べてみるが全て同じ動作だった。
    うーん。まあ、変数に入った物は全て "" で囲むというルールを徹底していれば問題は起こらない。

    更に、これは決してファイルに一致しない様である。
    '\*' という名前のファイルにも一致しないし、'*' という名前のファイルにも一致しなかった。不思議だ。

    単語中の "" で囲まなければならないパラメータ展開は、
    展開後の結果に以下を含む物の時。

    1. (単語分割抑制) IFS に含まれる文字
    2. (パス名展開抑制) グロブ文字 *?[@!
    3. (パス名展開抑制) '\'
      これは a='\'; $a'*' 等に於いて * がパターンと見做されてしまう為。

  * ble-sabbrev でコマンド・関数を実行する機能? [#D0942]
    この記事を見て思った。https://qiita.com/kazuooooo/items/92bf3146cafeb8fd8673
    例えば \branch として展開を実行すると git のブランチ名の中から選択できる、など。
    これは peco だとか fzf だとかを呼び出さなくても menu-complete を呼び出しても良い。

    取り敢えず実装してみたが振る舞いが変である。

    x resolved: 先ず始めにメニューの最初の項目を選択した時点で選択されている文字列が表示されていない。
      最初の enter で何が起こっているのか調べる必要がある。

      ble-complete/menu-complete/enter の中の
      "ble-complete/menu-complete/select 0" という行が問題の行の筈である。
      中を辿る。(ble-edit/content/replace "$_ble_complete_menu_beg" "$_ble_edit_ind" "$value")
      という関数の呼び出しに関しては問題ない様である。ちゃんと 5-7 を最初の候補に置換している。
      という事は描画の問題なのだろうか…。或いはその後で _ble_edit_str が書き換えられてしまっている?

      →分かった。magic-space では sabbrev/expand の直後に空白が挿入されるのだ。
      148 を返した時には空白挿入をキャンセルするという様に修正する必要がある。
      直した動く様になった。

    x resolved: 更にメニューから選択をしてそれから確定すると元々在った文字列が削除されない。
      うーん。どうも yield した時点で追記されている気がする…。COMPV が空白のままなので、
      既存の内容が空白に相当すると勘違いされてそのまま挿入されているのである。

      a これが起こらない様に action 等を弄る事にしようか。
      b 或いは COMPS も COMPV に対応して空白にしてしまえば良いという事なのか。
      c または先に key に相当する部分は削除してしまう事にするか。
        削除してしまうとキャンセルする事ができなくなる。
        というか COMPS= とした場合にもキャンセルする事ができなくなる。
      d 実装を観察していて思ったが COMPV を評価するのに失敗した時でも
        ble-complete/action/util/quote-insert で $CAND == ""* ならば、
        既存の内容を残したままの挿入になってしまっている。
        この部分を修正すれば良い。

      結局 d で修正する事にした。これで挿入される文字列に関しては大丈夫になった。

    x resolved: やはりいきなり menu-complete に入るのは微妙である。
      先ずは menu を表示しておいてそれから menu-filter に任せるというのが適切である。
      これは単純に enter しないだけで大丈夫だろうか。
      →メニューを表示するだけという事にした。

    x ok: 絞り込みの際に候補がなくなったら曖昧一致させたい気がする。
      menu-filter ではどの様に処理していただろうか。
      うーん。実装を見ると曖昧一致が有効になる筈である。何故有効にならないのか。
      と思ったが、曖昧一致は曖昧一致でも先頭が一致していなければならないのだった。
      この辺りは変更しても良いのではないかという気がする。
      →これは独立した項目で処理する事にする。

    - done: 最後に機能の名称は ble-sabbrev -c で良いのだろうか。
      ble-sabbrev -m 等の方が分かりやすいのではないだろうか。
      メニューを表示するという意味において。
      寧ろ -c は直接編集コマンドを実行するという機能を将来的に実装した方が良いかも。
      という訳で -m に変更する事にする。

2019-02-27

  * syntax: 何と eval の引数として a=() の形式が許される様である [#D0941]
    eval a=(1) b=(2) c=(3) や eval declare a=(1 2 3) が動く。
    解析の方法を変えなければならないのではないか。
    或いは declare 等と同じ様に解析すれば良いのだろうか。
    しかしその場合には変数名の補完が起こらない様にする必要がある。

    うーん core-syntax-ctx.def の ARGVX ARGVI ARGVR 辺りを複製して
    eval 専用の ARGEX ARGEI ARGER 的な物を導入するのが早いだろうか。

    * ok: 補完はどの様に起こすのが良いのだろうか。
      これは通常のコマンドと同様に補完させるのが良い気がする。
      しかし、コマンドと同じ文脈にしてしまうと今度はコマンドとしての着色が発生して、
      コマンドが見つからない時にエラー着色になってしまう。
      コマンドが見つからない場合にはエラー着色ではなくて何も着色しない、
      というようにする必要がある。また、引数の着色はどの様にするのが良いだろうか。
      コマンドの抽出…うーん。

      よく考えたら declare と同様に適当な着色のままで良い気がしてきた。
      取り敢えずは特別な着色は考えずに現状の着色で行く事にした。

    * ok: 所で eval はキーワードではなくてコマンドである。
      通常のコマンドではあるが文法解釈を変えるというのは自然に実装できるだろうか。
      等と考えたが、改めて考えてみれば declare や typeset なども同様である。
      declare や typeset 等と同様に取り扱えば問題ない。
      そして declare や typeset に関してはやはり 'for' 等と同様の場所で処理していた。
      ここに eval を追加すれば良いのである。

    取り敢えず対応した。動いている。

  * complete: PROMPT_COMMAND に追記が在った時の対策 [#D0940]
    bash-it 等の場合には PROMPT_COMMAND に ';' で区切ってコマンドを追加してくる。
    また、別の枠組みで PROMPT_COMMAND を管理している事もある。
    その様な時には attach-from-PROMPT_COMMAND は呼び出されるけれども、
    PROMPT_COMMAND は別の文字列になっているという事が考えられる。

    その様な時には attach-from-PROMPT_COMMAND の中から PROMPT_COMMAND を
    書き換えると後に設定された PROMPT_COMMAND が削除されてしまって問題である。
    従って、後で設定された PROMPT_COMMAND はそのままにして置いて、
    attach-from-PROMPT_COMMAND の処理を二回目以降はスキップする、
    などと言った処理が必要になる。その様に実装した。

  * complete: C-x $ などで変数名候補が出ている状態で、 [#D0939]
    多少入力して menu-filter が働いて一意になったという時に
    TAB を押すと通常の補完が走って候補が消滅してしまう。
    menu に候補が表示されている時には TAB (complete) で、
    表示されている候補を使う様に修正するべきなのではないか。

    実はこの振る舞いは今までにも気になっていた物である。
    一回、メニューが表示されている時にはメニューの内容で補完する様に変更してみる事にする。
    変更してみた。動いている。何か見落としがあるような気がしないでもないが暫く使ってみる。

    x resolved: この状態で補完が起こると menu 項目が全てクリアされてしまうので、
      DEL をしても最後に補完で挿入した内容よりも前に戻る事ができない。
      これは、現在は menu から抽出した候補を用いているという情報を何処かに記録して、
      その場合には menu の情報の再設定は行わないという様に工夫する必要がある。

      menu の情報の記録は何処で行われているのだったか。
      どうも menu-filter の場合には ble-complete/menu/show filter を呼び出している。
      filter を指定して呼び出す事により menu の情報が消滅するのを避けているのである。
      →これも適当にやったら動いた。

    - ok: 然し、今までの補完だって続きを補完しようとしたら menu-filter
      で戻る為の情報は記録されないのではなかったか。
      と思ったが、今回の対応によってそのような場合でもちゃんと menu-filter
      で戻る事ができるようになったのではあるまいか…。
      うーん。やはりその様になっている気がする。

2019-02-26

  * main: --attach=prompt (bashrc) で reload すると PS1 が消滅する [#D0938]
    うーん。PROMPT_COMMAND の評価をする時に PS1 を復元していないから?
    と思ったが復元はしている筈なのである。これは後で調べる。

    改めて reload が起こる手順について確認する。
    うーん。source ble.sh するとその場で unload が実施される。
    この時点で PS1 などは復元されるのではないのかと思う。
    そして復元など一頻りした後に bashrc で PS1 が設定されて、
    その後に PROMPT_COMMAND が呼び出された時に PS1 が ble.sh 側に待避される。

    この何処かの段階で PS1 が失われるという事になる。
    うーん。調べてみると ble-attach の瞬間までは問題ない様である。
    ble-attach すると PS1= になるが、これは期待している動作である。

    →分かった。PROMPT_COMMAND が実行されているのは
    何と、ble.sh の枠組みの中なのであった。
    うーん。中にいる時には attach するとかしないとか。
    どの様にするのが良いだろうか。中で attach するが、
    PS1 等は弄らない様にするという動作にするのか…。

    うーん。結局 ble-detach を実行する時にも、
    ble-detach/impl を exec:gexec/.end から呼び出して、
    その後で再描画をして終了するという事になっている。
    という事を考えると、一旦 detach を完全に実行してから、
    その後の prompt の表示の際に attach するという様にするべきなのではあるまいか。

    うーん。駄目だ変な状態になる。そもそも detach された状態になっていない様な気が…。
    うーん。改めて調べてみると .check-detach 経由で detach した時には
    .check-detach が return 0 をして、それにより term/enter, bind/.tail 等の操作がスキップされる。
    unload の時にもその様に操作しなければならないのではないだろうか。。
    と思ったがその場で ble-attach するという場合には _ble_edit_detach_flag を設定すると都合が悪い。
    と思って ble-attach の実装を見てみると、ble-attach の実装では _ble_edit_detach_flag
    をちゃんとクリアする様になっていた。気にしなくて大丈夫そうだ。

    [実装]

    % % a _ble_attached で _ble_term_state == external で
    % %   unload を実行するのは .check-detach 経由でという事にする。
    % %   と思ったが ble-attach と ble-detach が相殺して結局何も起こらないという状況になってしまっては厄介だ。
    % %   やはり unload はその場で実行しなければならないという事になる。
    % %   unload が起こったという事だけ通知して .check-detach に return 0 させるという事にすれば良い。
    %
    % unload はするけれども detached を _ble_edit_detach_flag に設定する事にした。
    % しかしそれでも期待通りに動いていない。どういう事だろうか。
    % 調べてみるとそもそも .check-detach で _ble_edit_detach_flag の分岐に入っていない気がする。
    % 変数名を間違えているだろうか。と思ったら分かった。
    % ble.sh を初期化している時に _ble_edit_detach_flag= が設定されてしまうのである。
    %
    % さて、動く様にはなったがプロンプトが空文字列で更に、
    % 次にコマンドを実行する時まで PROMPT_COMMAND が呼び出されないという状況である。
    % うーん。つまりこの方針は使えないという事になる。別の方針を考える必要がある。

    b 別の方法は PROMPT_COMMAND が内部で実行されているという事を検出して、
      その場合には PS1 の取り扱いを特別にするという物である。
      しかし、特別にしなければならないのはそれだけだろうか。

      うーん。というか、そもそも実行中の関数を書き換えてしまった場合に
      一体どういう事が起こるのかというのも気になる事ではある。
      まあ、多分、ちゃんとやっているという事にして、
      これは実際に問題が発生した時に気にする事にすれば良い。

    c 或いは --attach=prompt であっても、
      内部から reload した時にはその場で attach するという様にするべきか。
      うーん。一応 PROMPT_COMMAND 経由で実行するという事になっているのだから、
      特に問題がない限りは PROMPT_COMMAND 経由で実行した方が良い気がする。

    d ble-edit/{adjust,restore}-PS1
      ble-attach の実装をよく見てみるとこの様な関数を経由して PS1 を待避している。
      もっと言うとちゃんと現在の状態が待避した状態かそうでないかを管理している。
      もしかするとこれを用いて PROMPT_COMMAND を呼び出せば解決する問題ではないのか。
      改めて考えてみる。

      通常は adjust 状態にある。
      reload をユーザが呼び出すとどうなるかというと、
      restore 状態で呼び出す事になる。
      a この時 ble-attach が即座に行われれば、
        adjust 状態になり正しく PS1 が記録される。
      b もし --attach=prompt の場合だと、
        PS1 は restore 状態のまま描画ルーチンに入る。
        1 そこで restore-PS1 が呼び出されるが何も変化は行わず、
        2 次に PROMPT_COMMAND が呼ばれて中で ble-attach を実行した時に adjust 状態になる。
        3 次に adjust-PS1 が呼び出される時には何も変化がない。
      これでちゃんと動くはずである。

    結局 d の方法で呆気なく動くようになった。

2019-02-25

  * 2019-02-15 bash-4.4 で reload を実行すると \ が入力できなくなる [#D0937]
    というより ble-detach, ble-attach しただけでも入力できない。
    うーん。初回はうまく行っているのに2回目以降で失敗するというのが分からない。
    ble-attach を観察してみると ble-decode/attach ble-decode/bind から、
    /home/murase/.mwg/src/ble/out/cache.d/1000/ble-decode-bind.40419.UTF-8.bind を
    source していて、このファイルの中身は特に変な事はない。

    エラーメッセージはコマンドのキーマップが存在しません、という事なので…。
    うーん。これは bash のソースを見ながら調べなければならないのだろうか。

    * set -o vi をせずに emacs モードで実行しても同様になる。
      つまり編集モード固有の問題ではない。
    * ble-detach/impl; _ble_attached=; ble-attach でも再現する。
    * ble-decode/detach; ble-decode/attach でも再現する
    * ble-decode/unbind; ble-decode/bind では再現しない
    * ble-decode/unbind; source $_ble_base_run/$$.bind.save; ble-decode/bind でも再現しない。
    * どうも builtin eval -- "$(ble-decode-bind/.generate-source-to-unbind-default)" を実行すると駄目の様だ。
      eval しているスクリプトを覗いてみる。怪しい項目として以下の様な物が見つかる。

      builtin bind -r '\\": '
      builtin bind -r '\C-x\C-\\": '
      builtin bind -r '\C-x\\": '
      builtin bind -r '\C-\\": '

      そもそもこの様な物が現れる原因は何だろうか。
      うーん。generate-source-to-unbind-default を覗くと bind -X の結果の処理が怪しい。
      特に2回目の attach で問題になるという事からこれが原因である事は明らかである。

    →うーん。あっさりと直ってしまった。結局 "..." を抜き出す部分のエスケープの取り扱いを誤った所為で、
      "..." の範囲の切り出しに失敗して、結果として変な bind -r が呼び出されていたのが悪かった。
      これにより変な keymap entry が構築されてよく分からない事になっていたのである。

  * 2017-11-22 syntax: 実は予約語も alias にできてしまう… [#D0936]

    $ alias end=fi
    $ if true; then if true; then echo; end end

    現状ではエラーとして検出してしまう。
    更に以下の様なこともできる。

    $ alias var=declare
    $ var arr=(echo 1 2 3)

    うーん。指定の単語が alias だった時は、
    毎回 alias を resolve するのだろうか。
    然し、alias の展開結果が複数の単語を含む場合に至っては、
    完全に追跡する事は不可能である。
    従って、alias までは考慮に入れなくて良いのではという気がする。
    寧ろ、中途半端に対応するよりは全然対応しない方が良いかもしれない。

    或いは単一の単語の時にだけ展開するという手もあるし、
    または最初の単語についてのみ alias の展開を実行するという手もある。

    $ alias begin='{'
    $ for ((i=1;i<=2;i++)) { echo hello; }
    $ for ((i=1;i<=2;i++)) begin echo hello; }
    bash: 予期しないトークン `begin' 周辺に構文エラーがあります
    $ for ((i=1;i<=2;i++)); begin echo hello; }

    for (()) の直後などの文脈では alias の展開は起こらない様だ。

    * 2019-02-25 関数定義 function キーワードも alias にできるのか?

      $ alias defun=function
      $ defun hello () { echo hello; }

      関数の定義も alias にする事ができる。

    * 2019-02-25 所で alias の展開を実行するコードは既にあったろうか。
      使っているとすれば ble/util/type 等の周りである。
      うーん。別に alias の展開を実行している訳ではないのである。
      alias だったら alias 色に着色するという事と、
      quote されていたら alias ではない type の評価を実行するという事。
      alias の中身が何であるかについては調べていない。
      では、実際に調べるとしたらどの様にすれば良いのだろうか。

      alias name とすると alias name='...' と表示される。
      ' は '\'' に置換されて出力される。もしこの方法を使うのだとしたら、
      alias ...= の部分だけを別のものに置き換えて eval すれば良い。

      type name とすると日本語で表示されてしまう。
      LANG=C type name とすると name is aliased to `...' と表示される。
      alias の文字列の中に ' が含まれている場合でもそのまま出力される。
      type --help によって使えそうなオプションがないか見たがなさそうである。

    * 何と alias 名として hello:world だとか A+B だとか指定できる様だ。
      ; や \ 等の文字を含める事はできなかった。当然 = も含められない筈である。

  * util: sleep coreutils check [#D0935]
    bash-3 以下で sleepenh もなく usleep もない時 /bin/sleep が使われるが、
    その sleep が整数しか対応していない時にはエラーが出てしまう事になる。
    適当に整数に調整してから呼び出す様にする必要がある。

    結局これも #D0934 と一緒に実装する事にした。

  * 2019-02-22 util: sleep で </dev/zero を使う可能性について [#D0934]
    Qiita についたコメントから。

    Note: 遅延は他の方法と較べても最も良い。
    Note: /dev/zero から読み取っている間 CPU は 100% になる。
    Note: /dev/zero は POSIX にはない。存在を確認してから使うというので良い気がする。
    Note: zsh の場合には </dev/zero を実行するとメモリを大量に食らってクラッシュする。

    とにかく cygwin の場合には現状では変な子プロセスが必要になっているので、
    read -t 0.001 </dev/zero の方式と sleep を組み合わせて使う様に変更したい。

    実は bash 5.0 以上では遅延を計測する事によって
    更に高精度の sleep を作る事ができるのではないか。

    うーん。やはり /dev/zero は CPU 100% になってしまうのが問題である。
    1秒以上の遅延がある場合に sleep を併用する事にしても、
    例えば bleopt idle_interval の既定の設定だとずっと CPU 100% になってしまう。
    →実際に試してみると task がない場合には idle.do 自体が終了するので、
    ずっと CPU 100% という事にはならない様に思われる。
    しかし、将来的に screen saver 等の仕組みを整えようと思うと、
    やはり CPU 100% になってしまうというのは良くない。
    やはり /dev/zero は使わない方針で実装するのか…。
    もし使うのだとしたらとても短い時間の遅延にだけ使うという事になるのだろうという気がする。

    そしてその為には様々な sleep の種類について遅延を計測するという事が必要になる。
    遅延の計測に関しては init の時に実行する事にして、毎回計測しなくて済む様にしても良い。
    ble.sh でもアップデートするタイミングで再計測するという事にすれば良い。
    また、計測自体は idle の中で実行するということにすれば良い。
    最初の計測の時に使う idle は遅延なしを仮定した sleep を用いる事にすれば良い。

    しかし、できるだけビジーウェイト (/dev/zero) を使わない方針にするとすると。
    他にどの様な短い遅延の sleep の方法が Cygwin で利用できるだろうか。
    うーん。udp は結構遅延が短いが余り長い時間接続していると udp の timeout が起こりそうで、
    長時間の sleep には使用できない。今の実装はそれに対応する為に複合型になっていると思われる。
    しかし、1秒以上の時間になるという事なのであれば、普通に sleep を呼び出しても問題ないのでは??

    集中力が切れている。何をするべきか決めてさっさと実装する事にする。
    或いは実装しない事に決定するか。実装しないという選択肢はない様な気がする。
    結局 sleep の性能を計測するより他はない。
    初回の sleep の実行の際に計測を実施するというので問題ないだろうか。
    しかし計測には結構時間がかかるので、初回の sleep というよりは、
    idle.do の中で実行するべきなのかもしれない。
    初期化前は遅延は 0 として計算する。

    一度に全ての補正を実装するのではなくて、一つずつ実装する事にする。
    また、計算自体にかかる時間も考慮に入れるべきなのではあるまいか。

    [実装]

    * done: msleep として実装する案

      うーん。まずはじめに sleep ではなくて msleep を実装するべきなのではないかという気がしてきた。
      実際に使用している箇所を調べてみると固定の値を用いているか、
      そうでなければ msec から sec への変換を実施している。
      どうせ呼び出し元で毎回 msec から sec へ変換するのであれば、
      msleep の側で変換をする様にした方が遅延などの補正も実行しやすい。

      取り敢えず少なくとも msleep を実装する事にする。
      元から少数に対応している sleep を使用する際には、
      実はもしかすると msleep よりも sleep の方が都合が良いかもしれないが、
      結局遅延の補正を実施するのだとしたら msleep の方が良いのではないか。

    * ok: 遅延自体の計算と小数への変換にかかる時間に関して。
      これは計測してみない事には分からない。
      これは cygwin で測ってみると 70usec 程度なので、
      msec オーダーの sleep の際には無視できる。
      _ble_measure_base=0 にしても 86usec 程度である。
      まあ delay は少なめに見積もるのが良い気がするので
      _ble_measure_base ありで良い気がする。

    * sleep が coreutils なのかのチェックもあった方が良いのでは。
      coreutils でない場合には小数の sleep は切り上げにするしかないのだろうか。
      1s 未満の場合には切り上げで、それ以上の場合は切り捨てで良いだろう。

      →これは別項目を立てる事にする。

      何だか収集がつかなくなってきた気がする。
      何も考えずに実装すると言いつつ色々考えてしまっている。

    * done: benchmark.sh を読み込む様に修正する必要がある。
      benchmark.sh は zsh でも動く様に設計してある。

    * ok: Cygwin で複数の方法を組み合わせるとしたらどの方法が良いか。

      | 遅延を修正する事ができるのだとしたら sleep を用いてしまって良いのではという気がする。
      | 流石に遅延が 1s に達する事は殆どないだろうという前提で。
      | 1s 以上については sleep を用いる事にして、
      | それより小さい物に関しては udp を用いる事にする。
      | 更に短いスケールでは /dev/zero を用いるのだ、
      | という事を考えては見たがよく考えてみると遅延を修正することができるのであれば、
      | /dev/zero に頼らなくても udp だけで事足りるのではあるまいか。
      |
      | 結局 /dev/zero を使う意義はやはり余りないだろうという事で、
      | 以下の /dev/zero を用いた実装は使わない事になった。
      |
      | if [[ $BASH_VERSION && -c /dev/zero ]]; then
      |   function ble/util/sleep {
      |     local sec=${1%%.*} msec=0
      |     if [[ $1 == *.* ]]; then
      |       msec=${1#*.}000; msec=${msec::3}
      |     fi
      |     local ext=0
      |     if ((10#$msec)); then
      |       builtin read -t "0.$msec" s < /dev/zero; ext=$?
      |     fi
      |     if ((sec)); then
      |       ble/bin/sleep "$sec"; ext=$?
      |     fi
      |     return "$ext"
      |   }
      | fi

      →read -t 0.001 udp と /bin/sleep を組み合わせる事にした

    * done: Cygwin で複数の方法を組み合わせる時に遅延に対する修正はどの様に行うのか

      まず、かかる時間に応じてどの様に分けるのかの遅延 (delay0) が存在する。
      そして ble/bin/sleep を起動するのにかかる時間 (delay2)、
      それから read -t 0.001 udp を呼び出すのにかかる時間 (delay1) が存在する。

      問題はどの長さの時に ble/bin/sleep を呼び出して、
      どの長さの時に呼び出さないのかという事である。
      ble/bin/sleep は必ず秒単位でしか呼び出さないという事にする。
      更に簡単の為に read -t 0.001 udp は必ず呼び出す事にする。

      ble/bin/sleep を呼び出す事にすると、
      必ず遅延として delay0+delay1+delay2 はかかる事になる。
      従って、delay0+delay1+delay2 より短い時には ble/bin/sleep は使わない。
      また、delay0+delay1+1秒より短い時にも ble/bin/sleep を使う理由がよく分からない。
      うーん。必ず delay0+delay1 は支払うのだとしたらば、
      delay0+delay1 を引き算した上で、残りが1秒+delay1 以上あるならば ble/bin/sleep を呼び出して、
      それより短いのであれば全て read -t に押し付けるという方法で行くのが良さそうである。

      その様に実装する事にする。特に delay0+delay1 はくっつけて考える事にする。
      取り敢えず実装して delay の計算部分も実装した。

    [まとめ]

    * sleep 自体にかかる時間を見積もって較正する機能を実装した
    * 較正のための計算が複雑になるので ble/util/msleep として実装することにした
    * 較正する機能を実装したので CPU 100% になる /dev/zero を敢えて使う必要はない
    * 従来の ble/util/sleep は便利かもしれないので ble/util/msleep を呼び出して実現する
    * Cygwin ではサブシェルのパイプではなく /bin/sleep で長時間 sleep を実装する事にした

2019-02-15

  * bleopt: ble.sh reload 時に failglob でエラーが出る (reported by cmplstofB) [#D0933]
    https://github.com/akinomyoga/ble.sh/issues/22

    ble-update の時にエラーメッセージが表示されるという話。再現した。
    普通に source ble.sh で reload した時にも再現する。
    どうも bleopt 関係である事は間違いない気がしているが、
    どのタイミングでエラーメッセージが現れているのかを調べる。

    と思っていたら調べる前に分かってしまった。
    これは : ${hello:=...} のイディオムが火を吹いている。
    さて : "${hello:=...}" とする事もできるが…。
    そうすると ... の部分がクォートされている場合にはどうするか。

    試しに "${hello:-$'\e[91mhello\e[m'}" というのを試してみた所、
    bash-3.0 で変な事になる。bash-3.1 以降では大丈夫。
    うーん。念の為 shopt -u extquote でも試してみる。
    →変化はない。extquote はこの場合には関係ないのだった。

    うーん。

    a bleopt に新しいオプションか指定方法を追加するか…。

      * もしその様にするとしたらどの様な形式が良いだろうか。
        空文字列を上書きする場合と、未設定変数を上書きする場合の二種類がある事に注意する。

        bleopt var::[default]
        bleopt var:[default]

        微妙。そもそも分かりやすいのかという話。
        更に default 値に [] が含まれる可能性もあるので、
        括弧の様な対応があるような物は余り使わない方が良いのでは。

          bleopt var:-default
          bleopt var-default
          bleopt var:~default
          bleopt var~default
          bleopt var:+default
          bleopt var+default
          bleopt var:?=default
          bleopt var?=default
          bleopt var:||=default
          bleopt var||=default
          bleopt var||=default
          bleopt var|=default

        うーん。まあ、最後の物が一番良い様な気はする。
        然し、どちらが || でどちらが | なのかは分かりにくい。

          bleopt var:|=default
          bleopt var|=default

        こう? しかし、これだと普通の var:=value var=value
        の区別と混同しそうな気もする。

      * 後もう一つの問題は bleopt 関数の定義より前に
        bleopt 変数の宣言を置く事ができないという事である。

        →実は最初の bleopt 変数の宣言は util.sh の中であり、
        更に bleopt 関数は他の関数に一切依存していないので、
        util.sh の先頭に持ってきても問題ない。

    b 或いはできるだけ : "${}" を使う事にするが、
      右辺に特別な値を入れたい時には何か別の方法を使うか、
      一次変数に規定値でも入れてから : "${}" を使う。

    c 手動で [[ ${var+set} ]] || var=... とするか。

    d bleopt とは独立に : ${var=value} を実行する関数を定義する?

      うーん。こちらの方が良い気がしてきた。
      或いは、bleopt専用の変数定義関数を作成するか。

    現状の候補は b または c である。うーん。
    d と a を折衷して bleopt を util.sh の先頭に持ってきて、
    bleopt/declare という関数を作成する事にした。

2019-02-13

  * M-\ が現在より右側にしか作用していない [#D0932]

    後、誰かが timeout か何かで止めている。screen?
    →screen を抜けて試してみたら問題なかったので screen が問題である。
    maptimeout は設定しているはずなので、それとは別の何かがあるのだろう。
    しかし不思議なのは emacs の中ではその様な事はないという事。
    やはり ble.sh の方で何か問題があるのだろうか…。後で確認する。

    →と思って再度試してみた所特に問題はなくなった。
    もしかすると今回のバグの所為で何らかの条件で
    問題が発生したりしなかったりしたのかもしれない。
    取り敢えず気にしないことにする。

  * syntax: ブレース展開は [[ $- == *B* ]] の時だけ有効にする [#D0931]
    これは実は ble-syntax:bash/check-brace-expansion の最初の条件を弄るだけなのでは。
    後で試して動作を確認してみる事にする。

    →試しにその様に実装してみた所、エラー着色になってしまった。
    改めて実装を読んでみると実は {fd}> 等のリダイレクトの読み取りとの兼ね合いもあるので単純ではない。
    というか幸いにして brace expansion が効かない文脈という物もあって、
    そういう文脈に対する処理も既に書かれていたので [[ $- != *B* ]] の時も
    brace expansion が効かない文脈に含めればよいのだった。
    まあ、動いている。気にしなくて良さそう。

  * set -e で ble.sh をロードしようとすると終了する。他 set -xv 対策 [#D0930]

    しかし、対話シェルで set -e にしているとタイプミスしただけで終了してしまう。
    本当にそんな設定で良いのかというのは疑問であるが、一応 ble.sh がロードできる様にして置きたい。
    特に、set -e を解除する迄生き長らえれば問題ない。
    実際に試してみると ble/base/adjust-bash-options を呼び出す所までは到達している様子である。
    結局、ble/base/adjust-bash-options を多少いじっただけで動く様になってしまった。
    本当にこれで大丈夫なのか…。

    [set -x について]

    他にも確認しておくべきオプションはないだろうか。
    set -x は物凄く沢山のデータを出力する。これは封じるべきだろうか。
    例えば以前の cmplstofB さんの報告では set -x による出力が提供された。
    しかし、実のところ余り役には立たない感じだった様にも思う。まあ、これは封じる事にする。

    * ok: 3>&2 大丈夫?

      実装している途中で { } 3>&2 などを用いた。
      此処で何だかよく分からなくなった。bash はどうやってこれを処理しているのだろう。
      一つのプロセスの中で複数の fd の体系を保持するのは困難である。
      或いは、fd の体系は実は単に模倣しているだけで、
      他のプロセスに exec する直前にだけ調整しているという事だったりするのか。
      丁度環境変数の処理と同じ様に。

      3>&2 としても外側で作った 3 が削除されない事を確認する為に実験する事にする。

      $ exec 3>p.txt
      $ echo hello >&3
      $ { echo true world; } 3>&2
      $ echo world >&3

      うーん。平気みたいだ。では中から見るとどういう事になっているのか。

      $ { ls -la /proc/self/fd; } 3>&2
      lrwx------ 1 murase murase 64 2019-02-13 21:44:57 3 -> /dev/pts/6
      $ { ls -la /proc/self/fd; }
      l-wx------ 1 murase murase 64 2019-02-13 21:45:19 3 -> /home/murase/prog/ble/p.txt

      他に変化はない…。つまり、何処か別の場所に fd を保存しているという訳でもない?
      もしかしてサブシェルになっているという事なのか…。

      $ echo +$a
      +
      $ { a=12345; } 3>&1
      $ echo +$a
      +12345

      否、ちゃんと同じシェルの中にいる。ではもしかして繋ぎ直したりしているのか?
      名前付きパイプで確かめてみる事にする。

      % mkfifo p.pipe
      % sed 's/^/[/;s/$/]/' p.pipe

      $ exec 3>p.pipe
      $ echo hello >&3
      $ echo world >&3
      $ { echo hello; } 3>&1
      hello
      $ echo running >&3
      $ exec 3>&-

      ちゃんと期待通りに動作する。途中で接続が切れる等の事は起こっていない。
      途中で別プロセスを起動 { ls -la /proc/self/fd; } 3>&2 してみても問題はなかった。
      うーん。中でどうやっているのかは謎だが気にしなくても良いのかもしれない。

      気にしない事にした。

    * ok: 所で着色が間違っている事に気づいてしまった
      { echo; } 3>&1 とすると 3 が赤いままである。
      多分、これは始め 3 が単語であると認識されてエラー着色されて、
      その後で単語が削除された後に色が残ってしまっているという物である。
      以前の配列の場合と同じである。これは以前の配列の着色の問題の項目に追記する事にする。

    [set -v について]

    set -v に関しては起動してから -v とした時には特に問題は起こらないが、
    起動する時から -v を指定していた場合にはずっと出力がされる。

    もしかして起動時に指定した -v は取り消す事ができないのだろうか。
    然し、実際に試してみた所、そんな事はないようである。
    更に、-v の時に定義した関数を呼び出すと verbose に出力されるのかと思いきや、
    そういう様子でもないらしい。一体何が起こっているのだろうか。
    もしかすると [[ -o verbose ]] では検出できないという事なのだろうか。
    →ちゃんと検出する事ができている。うーん。

    うーん。検出できるできない関係なく変である。
    set +v と明示的に入力して実行しているのにその効果が現れない、という事なのだから。

    source ble.sh の周りだけを set -v ... set +v で囲んだ場合でも変な事は起こらない。
    bash -v で起動するが set +v を source ble.sh の直前で実行した場合も大丈夫。
    set +v ... set -v で source.ble.sh を囲んだ場合は再現する。bash -v をしなくても再現した。
    実は prompt_command 及び bind -x の中での set -v はリセットされるという事なのか?
    prompt_command で attach しても bashrc の末尾で手動 attach しても再現する。
    と思ったら手動 attach の直前で set -v した場合には特に問題は起こらない様だ。

    ? ok: つまり、プロンプトを表示する瞬間に set -v だと、
      それ以降はどんなに bind -x の中で set +v をしても解除されない、という事なのか。
      どうも bind -x の中で set +v をすると一時的に +v になるが、
      bind -x を抜けた時には既に set -v になってしまっている様子である…。
      というのも {adjust,restore}-bash-options の処理を追跡してみた所、
      以下の様な具合になっていたからである。

        adjust: v->n
        restore: n->v
        adjust: v->n
        restore: v->v # ←最後に観測した時は n だった筈なのに勝手に v になっている
        adjust: v->n
        restore: v->v # ←
        adjust: v->n
        restore: v->v # ←
        adjust: v->n

      他に ble.sh の中で set -v だとか set +v だとか set -o verbose だとか
      そういった物を触っている箇所はない。なので bash が勝手に状態を戻しているというより他はない。

    ? ok: 更に言うと、bash の出力を抑制している筈なのに抑制できていないのは何故?
      何か特別の fd を使って出力しているという事なのだろうか…。
      或いは、表示する瞬間だけ内容が漏れているという事なのか。
      stdout.on,off はどのタイミングで行われるのだったか。
      実は、ble-decode/.hook の中の PROLOGUE EPILOGUE の中で on, off が行われるのだった。
      従って、ble.sh の機能が働いている間は殆ど stdout は on の状態になっている。

      なので抑制しているのに色々と出力されているというのは特に普通の事である。

    どのタイミングで set -v の状態が戻っているのか確認する為に、
    念の為 PROLOGUE と EPILOGUE で張って見る事にする。
    というか、張るべきなのは厳密には head と tail である。
    やはり、tail で +v だったとしても次の head の時には -v に戻っている…。
    これは何処で対策するべきだろうか。というか、ble-decode/.hook の先頭で set +v としても良い気がしてきた…。
    というのも ble-decode/.hook が呼び出される時点で adjust された状態の筈だから…。

    取り敢えず ble-decode/.hook で set +v を実行してみる様にしてみたら問題は発生しなくなった。
    この振る舞いについて何処かに記録しておくべきだろうか。記録する事にした。記録した。

    動作確認してみる。動いている。大丈夫。

  * [整理] 2013-06-10 ble-bind 以下の同値なキーに対する処理? [#D0929]
    ref #M0012, #D0752

    | + DEL を BS にマップする
    | + C-_ を C-BS にマップする
    | + C-m を RET にマップする
    | + C-i を TAB にマップする
    | + M-大文字 を M-S-小文字 にマップする? → これは CapsLock に依存するので止めておく
    | + DEL の bind している物を BS から bind する。
    | + C-_ の bind している物を C-BS から bind する。

    これは #D0752 で再考された。以下のものはキーマップ上で交換可能であるように注意深く束縛された。
    しかし、一方で自動的に変換してどれかだけ束縛すれば良い様に実装することも考えて良いかもしれない。

    - DEL C-?
    - BS C-h
    - NUL C-@ C-SP
    - RET C-m
    - TAB C-i
    - C-_ C-DEL C-BS

  * [整理] 2017-11-29 syntax: http://lists.gnu.org/archive/html/bug-bash/2017-11/msg00002.html [#D0928]

    "$(case *) ;; esac)" の問題が報告されて Chet が調べると言っている。
    もしかしてこれは将来的に修正されるのかもしれない。
    →2019-02-13 bash-5.0 で試してみたが全然直っていない。当面は直らないのだろう。

  * [整理] 2017-11-29 syntax: function @() { ...; } [#D0927]
    https://stackoverflow.com/questions/43117707/bashs-strange-behavior-on-a-function-named/
    http://lists.gnu.org/archive/html/bug-bash/2017-03/msg00220.html
    これで関数を定義しても関数は定義されない。

  * [整理] 2018-03-18 アニメーション gif を作る [#D0926]
    ref #M0004

    - 画面の幅や文字の大きさなどを調整しておく。

      mintty を使って撮影することにした。
      文字の幅は 56 にする。文字の大きさは 14 ぐらいで良かろう。

      うーん。本当はもっと文字を大きくして PS1
      も簡単なものにするべきかもしれない。
      というか '\s-\v\$ ' にするべきの気がして来た。
      そうすれば bash で動かしているという事が分かる。

    - 現在のキー入力を表示する機能を搭載する?
      →これはやはり何らかのソフトウェアを使うのが現実的だろう。

    - done: 黒背景の時の着色の調整を行う。
      コメント・disable の着色が暗い。
      算術式の色が暗い。

    3 どの様な順で操作をするのかまとめておく。

      元々の動画ではどの様にしていたかと言うと…。

      - echo hello world
      - printf hello
      - [[ a == b ]]
      - echo "hello $(echo bash $(echo world))"
      - # history search
      - echo 'select, copy and paste'
      - echo insert mode
      - echo lib/core-complete.sh ble-decode.sh make_command.sh
      - echo histexpand
      - cat <<EOF
        this is the $(echo multiline mode).
        EOF

      これにインストールの様子も加えると良いだろう。

      - git clone git@github.com:akinomyoga/ble.sh.git
        cd !$:t:r
        make
        make install

      然し、それとは別に現在出ているエラーを修正する必要がある。
      set -o vi した直後に出るのは何だろう?

  * [整理] 2018-05-24 bash-5.0 alpha が告知された [#D0925]

    気になる事を幾つか。

    - EPOCHSECONDS, EPOCHREALTIME ... これは sleep に応用できる可能性がある。
      と思ったが何れも単位は秒の様である。
      と思って EPOCHSECONDS と EPOCHREALTIME の違いを調べてみた所、
      EPOCHREALTIME は小数で結果が返ってくるのだった。

    - 今まで ++var++ という算術式が許されていた様だ。

    - 複数行履歴がちゃんと記録されるようになるらしい。
      従って eval -- $'...' という workaround はしなくてもよくなるかもしれない。

      →試してみたが何がどう変わったのかよく分からない。
        全然複数行履歴として記録されていない気がする。
        この情報は気にしない事にする。

    - %q は未だバグが残っていた様だ。

    - 自分の報告・修正した項目も含まれている:

      1. q. t. oooo. xxxx. ggggg.
        一つ抜けている気がしたが、よく考えたらそれは
        4.4 以降に埋め込まれて 5.0 前に直されたバグだった。

    - (4. a. vi-mode n, N) 正規表現ではなくてグロブパターンらしい。

    - (4. d. C-v) 負の引数 -N を指定すると、次の N 文字をそのまま挿入するらしい。

  * [整理] bash 4.0-4.4 で f() { declare -a x; declare -A x; }; f で segfault という報告がある [#D0924]

    知らなかった。これは危険である。
    http://lists.gnu.org/archive/html/bug-bash/2019-02/msg00047.html

    試してみると unset x; declare -A x とすれば大丈夫の様だ。
    declare -a A; f() { local -A A; }; f の場合も大丈夫の様だ。
    まあ、同じ関数内で配列として使っていた物を後になって連想配列にするという事も余りなかろう。

    というより。こういう情報を ToDo にどんどん入れているが、
    これらは ToDo ではなくて Memo か情報か、そういった物である。
    これを機に整理したら良いのではないだろうか。

  * 2017-02-27 PS1='$(echo "hello")' [#D0923]

    現在の実装では " で囲んでも大丈夫な様に一頻りエスケープしてから
    builtin eval "ps1esc=\"$ps1esc\"" を実行している。
    しかし、この実装だと $() の中にある " も全てエスケープされてしまう。

    これに対応するのは面倒である。
    正しく実装する為には $() の中と ${} の中を読み飛ばして無駄にエスケープしない様にする必要がある。
    それこそ構文解析をして $() や "" <() ${} の入れ子を追跡しなければならない。
    実は入れ子の追跡だけならば () と "" だけ追えば良いのではないか?
    しかし case esac があるとまた厄介になる…が、それに関してはシェル自体も対応していなかったりする。
    @() や +() 等に関しては必ずバランスする事が保証されているのでこれも一緒くたに追跡すれば良い。
    問題は quote されている () "" であるがそれらは… \? '...' `...` を飛ばすという対応で良いのではないか。
    と思ったが文脈によっては ' は quote にならなかったりする。文字列の中では quote にならないし、
    また $(('aa)) だとどうだろう。と思ったが、そもそもこれは算術式のエラーになる。
    実際に試してみた所、更にシェルの文法としてもエラーになる様子だ。つまり、切り出しはやはり '...' の組で行っている。

    うーん。因みに Bash はコマンド置換の中の \w 等についてもちゃんと展開してくれる。

    2017-11-12 改めて Bash の振る舞いについて調べる。

    | 先ず \w が展開された結果として $(...) が現れても
    | それはコマンド置換の対象ではない。
    |
    | ~$ mkdir '$(echo "hello")'
    | ~$ cd !$
    | $(echo "hello")$
    |
    | この状態で PS1 を設定してみる。と、エラーになった。
    | $(echo "hello")$ PS1='$(echo \w)'
    | bash: command substitution: 行 41: 予期しないトークン `(' 周辺に構文エラーがあります
    | bash: command substitution: 行 41: `echo ~/t/\$(echo \"hello\"))'
    | bash: command substitution: 行 1: 予期しないトークン `(' 周辺に構文エラーがあります
    | bash: command substitution: 行 1: `echo ~/t/\$(echo \"hello\")'
    |
    | うーん。どうやら Bash の実装では \w 等を展開した結果に $" が含まれている場合は
    | エスケープ付きに一回置き換える様だ。
    | 因みに ~ もエスケープされないので \w にしていても上記の PS1 では /home/... になってしまう。
    |
    | /home/..../tmkdir '\\\\'; cd '\\\\'
    | /home/..../t/\\\\
    |
    | どうやら、\ もちゃんとエスケープ付きに置換されている。
    | 因みに \w と違って \\ は単一の \ に置換されるようだ。
    | 従って、次の評価の時に数が半減してしまう。
    |
    | /home/....t/\\\\PS1='$(echo \\\\)\$ '
    | \$

    恐らくこういう実装になっている。

    1 最初に \w などの特別な指定を全て置換する。

      この時置換結果に $"\` が含まれている場合にはエスケープする。
      これは丁度 "" 引用符の中でエスケープが必要なものに合致する。
      (! はエスケープの対象ではない。)

      また \\ は \ になる。
      \" は \" のままの様だ。これは PS1='$(echo \\\"hello\\\") '
      とするとプロンプトが \hello\ になる事で確かめられる。

    2 次に文字列を評価する。コマンド置換やパラメータ展開を処理する。

      それも恰も "" で囲まれた環境であるかの様に展開を処理する。
      しかし " は引用符の終わりという意味を失って単なる文字になる。
      この部分が一筋縄では行かない難しい点である。

    " が引用符の終わりという意味を失いつつ、
    それでいてパラメータ展開やコマンド置換が有効な文脈は思い浮かばない。

    | a そう言えばヒアドキュメントはどうだろう。
    |
    |   o ヒアドキュメントは行末の空白は消えない。空白類はちゃんと保持される。
    |   o 最後に改行は付加される。
    |   x \" は \" のまま。これは問題である。
    |   o \$ は $ になる。\\ は \ になる。
    |
    |   うーん。しかし、厳密に bash と同じ振る舞いでなければならない訳ではない。
    |   例えば step 1 の段階で \" を " に縮め、
    |   また置換結果の " をエスケープしないというのも可能である。
    |
    |   この時 PS1='\\" ' の結果が Bash と異なることになるが仕方がない。
    |   Bash は \" にし、更にその後の評価で " になる。
    |   一方で、此処で提案した実装では初めに \" になる所までは同じだが、その後で \" のままになる。
    |   PS1='\\\" ' の場合はどうだろうか。Bash は \\" にし 更に \" になる。
    |   此処で提案した方法だと初めに \" になり次のステップでも \" に留まる。
    |   この時は (中の処理は異なるが) 結果は一致して見える。
    |
    |   % 更に言うと Bash の実装に従う必要も全然ないかもしれない。
    |   % 例えば、\w 等の置換結果は当たり障りの無い
    |   % 特殊 Unicode 文字 (私用領域など) に変換しておいて、
    |   % 最後に代入するという手法も考えられる。
    |   % この様にすれば変なディレクトリに入った時に Bash の文法とかち合うこともない。
    |   % 但し、これだと例えば \w のパスを加工して表示するという様な処理が期待通りに動かない。
    |   % 直観的でないのでやはりこの方法は避けた方が良い様に思われる。
    |
    |   x そういう意味で言えば Bash の振る舞いはコマンド置換の中で \w を使う場合でも
    |     取り敢えず "" で囲んでおけば問題は起こらないので、PS1 を正しく設計すれば大丈夫である。
    |     一方で、此処で提案したような「" はエスケープしない」という実装だと、
    |     二重引用符を含むような名前のディレクトリにいる時、"\w" の様に二重引用符で囲んでも駄目、
    |     ということになり問題が生じる。どんなディレクトリ名でも大丈夫にしようと思うと、
    |     ヒアドキュメントを更に内部で使用しなければならず、非現実的である。
    |
    |   そう考えるとやはりヒアドキュメントに頼らない方が良い気がする。
    |   というかヒアドキュメント自体が悪いのではなくて、
    |   ヒアドキュメントで \" が " にならないという仕様がたまたま今回の場合に合わないだけである。
    |
    | b 他に文脈はあるだろうか。ない気がする。
    |
    | c やはり正確に処理する為には地の文にある " だけを全て正確に \" に置き換えるしかない。
    |   そしてその為には $() ${} "" の入れ子の勘定が必要である。\? '...' `...` はスキップする。
    |   うーん。場合によっては ble-syntax を呼び出した方が賢明かもしれない。

    2019-02-12 c の実装を試してみる事にする。
    現在の実装を確認する事にする。1. の振る舞いについては現時点で既にその様になっているようだ。
    地の文の \" は " になる。また " は " のままである。
    それ以外のコマンド置換等の中の \" はその文脈で評価される。

    取り敢えず $(...) ${...} "..." の入れ子の対応は考える事にする。
    ${...} の中にある \" は " になる。これはそのまま放置で良い。
    ${...} の中にある生の " はエラーである。これはエスケープする。
    と思ったが、そういう事ではなかった。${...} の中では "..." が有効なのである。

    取り敢えず指の動く儘に実装してみた。色々動かしてみたが結構いい感じに動いている様子だ。
    何より不完全な状態で終わっている時の補完がちゃんと動いていて良い。
    具体的な例で試してみる事にする。

    o PS1='$(echo "hello")\$ '
    o 以下の物は bash と全く同じプロンプト・エラーメッセージになったのでOK
      $ mkdir '$(echo "hello")'
      $ cd !$
      $ PS1='$(echo \w)'
      $ cd ..; mkdir '\\\\'; cd '\\\\'
    o PS1='$(echo \)\$ '        → ')$ '
    o PS1='$(echo \\)\$ '       → ')$ '
    o PS1='$(echo \\\)\$ '      → '\$ '
    o PS1='$(echo \\\\)\$ '     → '\$ '
    o PS1='$(echo \\\\\)\$ '    → '\)$ '
    o PS1='$(echo \\\\\\)\$ '   → '\)$ '
    o PS1='$(echo \\\\\\\)\$ '  → '\\$ '
    o PS1='$(echo \\\\\\\\)\$ ' → '\\$ '
    o PS1='$(echo \\\"hello\\\") ' → '\hello\ '
    o PS1='" '        → '" '
    o PS1='\" '       → '" '
    o PS1='\\" '      → '" '
    o PS1='\\\" '     → '\" '
    o PS1='\\\\" '    → '\" '
    o PS1='\\\\\" '   → '\" '
    o PS1='\\\\\\" '  → '\" '
    o PS1='\\\\\\\" ' → '\\" '

    何も問題なく完璧に一致している。良かった。

2019-02-11

  * bash-dev で complete が識別式の関数名しか受け付けなくなった [#D0922]
    これは本当に意図した動作なのだろうか。
    と思ったら普通にバグである。これは流石に気づいて直しているだろう…。
    →これは 439b8c2 で直った。

  * 2018-07-19 bugbash: lib/readline/bind.c:397: [#D0921]

    ref #D0699

    | 以下の ic = UNMETA (ic); の行は if (map ...) の内側であるべきなのではないか。
    |
    |   if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
    |     {
    |       ic = UNMETA (ic);
    |       if (map[ESC].type == ISKMAP)
    |         {
    |           prevmap = map;
    |           map = FUNCTION_TO_KEYMAP (map, ESC);
    |         }
    |     }
    |
    | 然しこれは bind -m emacs-meta ... とした時の為にそうなっているとも考えられる。

    これは別の直し方をした。報告した。
    https://lists.gnu.org/archive/html/bug-bash/2019-02/msg00036.html

  * 2018-08-18 bugbash: #D0727 の報告をするか? [#D0920]
    一応 bash devel branch に対する修正の案も作ってある。

    検索してみたら似たような提案が行われた形跡があるが Chet は無視した。
    http://lists.gnu.org/archive/html/bug-bash/2014-06/msg00053.html

    報告した。
    https://lists.gnu.org/archive/html/bug-bash/2019-02/msg00035.html

  * keymap: `C-x C-g` や `C-M-g` にも cancel, bell を設定する? [#D0919]
    実は C-g は keymap によって様々な物が bind されている。

2019-02-10

  * builtin bind --help を実行すると標準出力が変になる… [#D0918]
    これは最近の実装が問題になっているのだろうか…。
    しかし builtin で問題になっているから別の問題かもしれない。
    ble-0.2 と ble-0.1 でも試してみる事にする。
    うーん。ble-0.1 でも再現する。

    ble-detach してから ble-attach すると直る。

    コマンドラインに内容が消されてしまうという事は、
    bleopt_internal_suppress_bash_output の関係だろう。
    と思って観察したが suppress_bash_output は最初のロード時に
    初期化するだけであって detach/attach に関係するとは思われない。

    set -o emacs で editing mode を変更すると
    ble-decode/{detach,attach} が呼び出されるはずである。
    と思って確認してみた所、set -o emacs では治らない。
    明示的に ble-detach して ble-attach すると確かに直る。

    また一度 ble-detach して ble-attach すると
    次に builtin bind --help しても問題は発生しない。
    stty の問題でもなさそうな気がする。
    念の為 stty -a を調べてみる事にする。
    discard が undef から ^O になっている。
    うーん。然し色々調べてみたがこれはやはり関係ない気がする。

    うーん。_ble_attached=; ble-detach/impl; stty sane; ble-attach
    というのを一気に実行したとしても症状は治らない。
    ble-detach して ble-attach すると直るのは何故だろう。

    また builtin bind --help が実装された bash-4.4 以降で起こる様になっている。

    ble/util/assign hello 'builtin bind --help' としても症状は発生する。
    (builtin bind --help) の様にすると症状は発生しない。
    うーん。bash の状態がおかしくなっている?
    bind の実装はどうなっているだろうか。うーん。分からない。
    これを見ると他の組み込みコマンドの時にも同様の問題が発生しても良い様に見える。
    或いはこの仕組を使って --help を表示しているコマンドは少ないという事なのか。
    何れにしても最新版の bash-dev で試してみる事にする。

    % bind.def の実装は変わっていない。complete.def と比べると、
    % bind の方は help を表示した後に未だ何か動作をしている。
    %
    % |   begin_unwind_frame ("bind_builtin");
    % |   builtin_usage ();
    % |   do { return_code = EX_USAGE; goto bind_exit; } while (0);
    % | bind_exit:
    % |   if (saved_keymap)
    % |     rl_set_keymap (saved_keymap);
    % |
    % |   run_unwind_frame ("bind_builtin");
    % |
    % |   return (sh_chkwrite (return_code));
    %
    % この時点で saved_keymap は NULL なので rl_set_keymap は実行されない。
    % run_unwind_frame は何をするのか…。どうも begin_unwind_frame と対になっている。
    %
    % 調べてみると sh_chkwrite を CASE_HELPOPT の後に呼び出しているのは bind のみである。
    % 他の builtin では直接に戻り値を返している。では sh_chkwrite とは何か。
    %
    % | // builtins/common.c
    % | int sh_chkwrite (int s) {
    % |   QUIT;
    % |   fflush (stdout);
    % |   QUIT;
    % |   if (ferror (stdout))
    % |     {
    % |       sh_wrerror ();
    % |       fpurge (stdout);
    % |       clearerr (stdout);
    % |       return (EXECUTION_FAILURE);
    % |     }
    % |   return (s);
    % | }
    % |
    % | // quit.h
    % | #define QUIT \
    % |   do { \
    % |     if (terminating_signal) termsig_handler (terminating_signal); \
    % |     if (interrupt_state) throw_to_top_level (); \
    % |   } while (0)
    %
    % うーん。これで振る舞いが変わる物とは思われない…。
    % 取り敢えず bash-dev で再現するかどうか試してから弄ってみる。
    % →bash-dev でも再現する。
    %   sh_chkwrite を呼び出さない様にしても再現する。
    %
    % というか、以下の部分が極めて怪しい。
    % 成る程、unwind_protect とはそういう使い方をする物なのか…。
    %
    % | unwind_protect_var (rl_outstream);
    % | rl_outstream = stdout;
    %
    % うーん。調べてみたがそもそも CASE_HELPOPT を通過していない。。
    % うーん。実は --help は CASE_HELPOPT ではなかった…。
    % これは変な引数などを指定した時に出るエラーだったのである。
    % そして、その場合には特に変な現象には悩まされていない。

    改めて。試してみると begin_unwind_frame を呼び出しているのに、
    run_unwind_frame が呼び出されない、という事になっている様子である。
    と思ったら…。CASE_HELPOPT はよく見たらラベルじゃなくて文だった…。

    CASE_HELPOPT の中を覗いたら return (EX_USAGE) している。
    これが犯人である。直した。

  * [自然解消] 2013-06-10 ble-bind キーボードマクロの定義に対応 [#D0917]
    ref #D0915

    % 2017-09-10 ble-decode.sh: キーボードマクロのためには _ble_decode_key__hook と似ているが、
    %
    % 1. 一回限りではなくて恒久的に処理する
    % 2. 既定の処理も行う
    % 3. 複数の物を登録して管理できる
    %
    % ような仕組みを取り付ける必要がある (3. に関しては不要かもしれない)。
    % ↑2019-02-10 これは C-x ( .. C-x ) C-x e によるマクロの考察では?

  * [自然解消] 2015-03-01 ble-edit: bind 模倣? [#D0916]
    ref #D0915

    bind -x や bind の機能を実装し、
    更に bind 関数を上書きしてその動作を模倣するという事?

  * 2015-02-23 bind の上書き [#D0915]

    未だ時期尚早である。先ず、readline の function を一通り実装しなければならない (expand 系が大変)。
    また、bind にある様々なオプションとそれらを組み合わせて使った時の振る舞いについて整理しなければならない。

    一応将来的な実装の為に、既存の bind の呼出に一通り builtin をつけた。

    * 2018-08-19 bind '"":""' の形式の振る舞いについて調べた。
      特に後半の文字列がどのように解釈されるか。

      - \C-? は解釈される。\C- の直後に日本語の文字があると1バイト目だけ切り取られて解釈される。
      - \C-@ があるとその場所でマクロが途切れる。
      - \ooo は解釈される。3文字まで。
      - \a \b \e \f \n \r \t \v は解釈される。
        \a はマクロ実行を途中で停止する効果がある。
      - \xhh は解釈される。2文字まで。1文字でも良い。
        直後に１６進数がなくて \x 単体の場合には単に x となる。
      - \ の直後にそれ以外の文字が来る時は無視される。

      - \C-\M- の両方が指定された場合には \e\C- という解釈になる。
      - \M-\C- とするとちゃんと Control-Meta 修飾になる。
      - \M-\C-\C- 等の様に3つ以上指定しようとしてもできない。
        \M-\C-\ までで一まとまりと解釈される。
      - \C-\M- の次に来るのは一文字だけである。
        其処に \a や \x43 等があっても先頭の \ だけ取られる。

      恐らく前半も同様に解釈されるのだろう。
      此処で難しいのは前半をキーの列に解釈し直すべきなのか、
      或いは、ble-decode-char の処理で一つの長いキーと思って解釈するのかという事である。
      できれば前半をキーの列に解釈し直したい。
      ble-bind を使って普通に bind した物と競合すると良くないので。

    * 2018-08-19 一つの bind '...' の中で複数の束縛を改行区切りで書けるか?
      試してみた所、書けない。
      どうも "([^\"]|\\.)*":".*" の形式で読み取っている様な気がする。
      と思ったが、そうでも無いようだ。謎の動作をする。

    2019-02-10 これについて実装する必要がある。
    特にユーザの指定した -x には対応していきたい物である。

    | うーん。取り敢えず前半部分と後半部分をどうやって分離するのか。
    | 試しに bind -x 'TAB: echo hello' とやるとエラーになる。
    | 最初の非空白文字が " ではありませんと言っている。
    | 一方で bind 'TAB:"echo helllo"' はちゃんと動く。
    | どうも bind と bind -x で解析器が異なる?
    | マニュアルによると他に Control-* とか Meta-* とか Rubout とかが存在している。
    | keyname の一覧は何処にあるのだろうか…。
    | うーん。結局 readline のソースコードに埋め込まれていた。
    | lib/readline/bind.c:2230: name_key_alist にある。
    |
    |   { "DEL", 0x7f },
    |   { "ESC", '\033' },
    |   { "Escape", '\033' },
    |   { "LFD", '\n' },
    |   { "Newline", '\n' },
    |   { "RET", '\r' },
    |   { "Return", '\r' },
    |   { "Rubout", 0x7f },
    |   { "SPC", ' ' },
    |   { "Space", ' ' },
    |   { "Tab", 0x09 },
    |
    | 大文字小文字は多分区別しないのだという気がする。
    | →bind 'rUBouT:"echo hello"' でも動いたので大文字小文字は関係ない。
    | 他に以下の物が埋め込まれている。
    |
    |   const char * const _rl_possible_control_prefixes[] = {
    |     "Control-", "C-", "CTRL-", (const char *)NULL
    |   };
    |   const char * const _rl_possible_meta_prefixes[] = {
    |     "Meta", "M-", (const char *)NULL
    |   };
    |
    | うーん。Meta の後に hyphen がないのは何故だろう…。
    |
    | bind '"\C-t""C-t":"echo world"' は前半の引用符の内容しか理解しない。
    | bind '"\C-t\"\"\C-t":"echo world"' はちゃんと全体の中身を理解している。
    | bind '"\C-t:\C-t":"echo world2"' はちゃんと二番目の : までを前半としている。
    | bind '"\C-t:\C-t"' とすると実は binding が削除される。

    まとめると以下の様になる。
    - /^("([^\"]|\.)*"|[^:])*/ で前半を読み取る
      - 最初の非空白文字が " の時、keyseq と見做して "..." の中身を解釈する
        二個目以降の "..." は解釈されない。
      - それ以外の時、keyname に従って解釈する。
        複数の単語から成る時無視される。
        不明な keyname の場合には一文字目が使われる。
    - 続きに : が存在していれば key bindings を作る。
      もし続きに : がなければ key binding を削除する。
      と思いきやよく分からない状態になる。何もしないという動作に binding されている気がする。

    bind '"\C-t" "\C-t": "echo hello"' としたら "\C-t": "\C-t\":" という事になった…。
    更に bind 'a "bull"' としたら "a": "bull" という事になった。
    つまり空白区切りという事なのである。

    * bind のオプション解析に関して

      何故か bind '"a": "bull1"' -m vi を実行すると m も v も動かなくなる。
      別のキーバインディングとして解釈されているのだろうか。
      bind '"a": "bull1"' m:self-insert v:self-insert とするとちゃんと動く様になる。
      bind '"a": "bull1"' -m:self-insert でも動く様になる。

      つまり、一度 -m 以外のオプションが現れると、それ以降は binding と見なされるという事?
      -x spec を与えた後に spec2 を与えた場合には spec2 は -x なしで解釈される様だ。

      bind -x '"a": echo hello' '"b": echo world' → -x a および b
      bind -x '"a": echo hello' -x '"b": echo world' → -x a および -x b
      bind '"a": echo hello' -x '"b": echo world' → a および -x および b

      つまり、一度オプション以外の引数を読み込んだ場合は、それ以降は通常の引数と見なされるという事。
      この振る舞いは bash-5.0 以降でも同様なのだろうか…。
      何と bash-5.0 で確認してみた所、最後に指定した物しか有効になっていない…。
      bash-5.0$ bind -x '"a": echo hello' '"b": echo world' → -x a および b
      bash-5.0$ bind -x '"a": echo hello' -x '"b": echo world' → -x b のみ
      bash-5.0$ bind '"a": echo hello' -x '"b": echo world' → (a: 成功) および (-x: エラー) および (b: 成功)

      うーん。どのバージョンの bind を基準にするべきだろうか。
      できるだけユーザの意図を汲む様な実装にする事にする。
      その様に考えれば、一度通常引数が現れたら引数は解釈しないという振る舞いは変だし、
      振る舞いが引数を指定する順序に欲しくない (上書きする場合を除いて) というのもある。

      まとめる。

      - bind の引数解析は最初に -* のオプションを解析して、
        - で始まらない引数が現れた時点でそれ以降を全て readline コマンドと見なす。
      - bash-5.0 では -x に関しては最後に指定したものだけが有効である。
        普通の readline コマンドとしてのバインディングは全て有効である。
      - bash-5.0 では二番目の単語が存在しない keyname:command に対してエラーが出る。
      - -m keymap はそれ以降の引数に対してのみ影響を与える。
        (bind -m vi -x '"a": echo hello' -m emacs -x '"b": echo world' で試した)

    [実装]

    * done: オプション解析の流れは実装した (.readarg)
    * done: keyseq:command の分離も実装した (.readarg/decompose-pair)
    * done: keyname の解釈も実装した (.readarg/parse-keyname)
    * done: keyseq の解釈 (.readarg/parse-keyseq)
    * done: 文字列からキー列への変換 (.readarg/decode-chars)

      現在の ble-decode-char の状態を破壊せずに、
      ble-decode-char の機能を用いて実装したい。

      以下の変数を被覆すればよいだろうか。
      _ble_decode_csi_mode=0
      _ble_decode_csi_args=
      _ble_decode_char2_seq=
      _ble_decode_char2_reach=
      _ble_decode_char2_modifier=
      _ble_decode_char2_modkcode=

      以下の変数も一時的にクリアしておく事にする
      _ble_decode_char__hook

      ble-decode-key 側の処理抑制も必要である。
      #%if debug_keylogger
      _ble_keylogger_enabled
      #%end
      _ble_decode_keylog_enabled

      これを用いて設定を行う。
      _ble_decode_key__hook

    * done: bind の実行

    ? bind -x の右辺を "" で囲んだ時、\C-* 等の特殊なシーケンスは解釈されるのか。

        $ bind -x '"\C-t": "od -t d1 <<< \C-t"'
        0000000   67   45  116   10

      これは C-t という文字列である

        $ bind -x '"\C-t": "echo \"hello\""'
        "hello"

      echo "hello" ではなく echo \"hello\" が実行されている
      つまりただ単に周りの "" を削除しているだけに過ぎない。
      また、'"echo hello' の様に片方だけ quote されている場合にはエラーになった。
      更に '"echo hello\"' としえもエラーになる。
      '"echo ""hello"' とすると 'echo ' が実行される事になる。

    ? ok: vi-move とは何かと思ってソースコードを見に行ったら vi, vi-command と等価だった。
      内部的な名前は vi_movement_keymap なのであった。

    取り敢えず実装は完了した。ちゃんと動くかどうかについては調べていない。

    [議論]

    * done: ble-bind -P での出力内容
      .ble-decode-key は ble-bind -s として表示する。

    * done: というか ble-bind -s に対応する。

    * done: ble-bind -s を説明書に追記する。

    * ok: 結局 keymap:*/define を autoload で定義する事にしたのである。
      今までの色々の処理を整理する事は可能だろうか。
      ただ、自分で新しい基底 keymap を定義する人が居た場合に備えて
      残しておいても良いのかもしれない。

      うーん。考えるのが面倒なので今後問題になった時に処理するという事で良い。

    * done: bind -r に対応していない
      対応した。

    * reject: \a でマクロを止める機能?

      \a というよりは bell である。
      しかし、その他の様々な機能との兼ね合いもあるので。
      decode.sh 側で一律に停止する様な仕組みにはし辛いのではないか。
      うーん。考えるのが面倒なのでこの機能は取り敢えず実装しない事にする。

    * done: ble/builtin/*

      モジュールの名前の下に直接組み込みコマンドの名前を置くと分かりにくい。
      例えば ble-edit/read というのは ble/edit における何らかの read とも見える。
      もっと分かりやすいように組込コマンドを上書きする意図のコマンドは、
      ble/builtin/* 以下に定義する事にした。

      既に存在していた上書きする関数は read と exit のみであった。修正した。

    * 対応表を実装する必要がある
      これは keymap 毎に解決する必要があるのではないだろうか。
      疑問点は vi モードの readline 関数をどの様に emacs に翻訳するのかという事。
      うーん。そのまま束縛すると何か変な事が起こらないだろうか…。
      また、vi.sh に定義されている widget を参照できるのかという問題もある。

      その様に考えると適切でない readline 関数は reject するというので良い気がする。

      うーん。テキストファイルに対応表を書く?
      取り敢えず emacs モードで対応した。
      vi_imap 及び vi_nmap に関しては後で対応する事にする。

    [動作テスト]

    * ok: ble-bind -s 及び対応する ble-bind -P は確認した。
    * ok: bind '"A": "echo hello"' は確認した。
    * fixed: bind -x '"A": "echo hello"' を実行したら変なエラーが出た。
      何故か readline function を探している…。
      引数の解析部分に誤りがあった。直した。
    * fixed: bind -x でプロンプトを消してそれからまた再表示するべきなのでは。
      bash の振る舞いに準じた動きをするべきである。
      現在はプロンプトを消す事もしないし、再表示もしない。
      確認してみる事にする。

      bind -c の方は .insert-newline を用いて消している。
      真似して .hide-current-line を作って見た。
      それを使って一時的に消してみる。

2019-02-09

  * bash-it でまた誰かが書き込んでいる [#D0914]
    https://github.com/Bash-it/bash-it/issues/894

    やはり需要があるという事なのだろう。

    - ble-0.3 を出す事にする。
      これまでの変更を Release 時にまとめる事にする?
      然し、長大になるし時間が掛かるし誰が読むわけでもなさそうなので、
      今回は見送る事にする。何れにしてもこの memo.txt には残っている訳だから。
      或いは、そのまま日本語で出してしまっても良いのではないだろうか。

      ble-0.2 changes
      - vi (xmap `aw`/`iw`): Extend backward to include the current entire word
      - util (`ble/util/openat`): Add workaround a Bash 3.2 bug that causes problems with <kbd>C-d</kbd> in nested shells
      - edit (`ble/textarea#render`): Fix a bug of wrong scroll/cursor position after entire redraw
      - main: Fix a `"$_ble_base"` determination bug on `source ble.sh` for local ble.sh
      - global: Fix a leak variable

      ble-0.1 changes
      - util (`ble/util/openat`): Add workaround a Bash 3.2 bug that causes problems with <kbd>C-d</kbd> in nested shells
      - main: Fix a `"$_ble_base"` determination bug on `source ble.sh` for local ble.sh

      取り敢えず bump して archive を作る。ダウンロードする。
      というか ble-0.3 についても作成してダウンロードする。
      ble-0.1 release を更新する。タグを push しなければならない。

    - bash-it をダウンロードしてどうなっているか確認する。

      ダウンロードしてみたら 40MB もある。重い。
      そんなに沢山のデータがあるという事があるのだろうか…。
      うーん。working tree は軽い。履歴に変な物が入っている?

      install.sh の中を覗いたが複雑なので読む気がしない。
      試しに実行してみる事にしようか…。実行してみた。
      現在の bashrc の末尾に追加するというのにしてみた。
      本当に末尾に追加するだけの様である。
      ちゃんとシンボリックリンクになっている事を認識して、
      中身を .bashrc.bak として保存して、
      更にシンボリックリンクの示す先を書き換えてくれた。

      末尾に追加された内容は基本的に以下に等価である。
      というか、これらは本当に "export" する必要があるのだろうか…。

      if [[ $- == *i* ]]; then
        export BASH_IT="/home/murase/prog/ext/github/bash-it"
        export BASH_IT_THEME='bobby'
        export GIT_HOSTING='git@github.com:akinomyoga/bash-it.git'
        unset MAILCHECK # Don't check mail when opening terminal.
        export IRC_CLIENT='irssi'
        export TODO="t" # todo.txt-cli
        export SCM_CHECK=true
        #export SHORT_HOSTNAME=$(hostname -s)
        #export SHORT_USER=${USER:0:8}
        #export SHORT_TERM_LINE=true
        #export VCPROMPT_EXECUTABLE=~/.vcprompt/bin/vcprompt
        # export BASH_IT_AUTOMATIC_RELOAD_AFTER_CONFIG_CHANGE=1
        # export BASH_IT_RELOAD_LEGACY=1
        source "$BASH_IT"/bash_it.sh
      fi

      見てみると勝手にプロンプトを書き換えて screen に何か表示する等、
      色々と勝手な設定を行ってくる様である。
      自分で色々設定している人に取ってみれば結構厄介であろう。

      取り敢えず試しに実行してみることにする。遅い。滅茶苦茶遅い…。
      ble.sh の機能とかちあって居るのかもしれないと思って、
      ble.sh を attach せずに使ってみたがやはり遅い。
      また ble.sh を使っていてもちゃんとプロンプトは表示されている様子だ。
      うーん。やはり信じられない遅さだ…。

      更に、green だとか purple だとか reset_color だとか、
      普通の変数名を思い切り汚染している…。調べてみると
      それでも PS1 で使うものだけしか汚染していない様だ。
      無節操に汚染しているという訳でもない。

      まあ、取り敢えず動くのだという事は分かったのでOK。

      * ble.sh を bash-it に組み込むとしたらどの様になるだろうか。
        或いは bash-it は alias しか許さないのだろうか…。

        うーん。bash_it.sh の中を覗くと enabled aliases 等は
        割と最初の方で source されている。
        theme 等の初期化はそれよりも後にある。
        PS1 が設定されるのは恐らく theme の中なのでこれでは駄目だ。
        もし ble.sh と組み合わせるのだとしたらば、
        bash_it.sh の中を弄らなければならない。

        或いは、ble.sh の側でプラグインマネージャ的機能を実装して、
        bash_it.sh の中で実行している内容を非同期に実行する様にもできるかもしれない。
        何れにしても bash-it に普通に Pull request として
        ble.sh の機能を提供するのは難しそうである。書き換えが必要である。

      * 因みに bash-it のロード時間は 0.744s である。
        ble.sh のロード時間は 0.218s で、attach には 0.437s かかる。
        bash-it よりは軽いが、そんなに軽いとも言い難い。
        環境によっては結構時間が掛かるのではないかという気がする。
        まあ初期化時間に関してはどうしようもない。

    - 説明書の英語版を作るべきだろうか。それは後回しで良い。
      別項目として立てる事にした。

  * manual: 以下の関数についても説明書に記述して --help に対応しても良いかもしれない [#D0913]
    - done: [public] ble-import, ble-assert, ble-autoload, ble-stackdump 1209ac6
    - renamed: [private] ble-color-ansi2g
    - renamed: [private] ble-color-face2{g,sgr}
    - renamed: [private] ble-color-g2sgr
    - renamed: [private] ble-color-gspec2{g,sgr}
    - renamed: [private] ble-color-iface2{g,sgr}
    - renamed: [private] ble-color-sgrspec2g
    - reject: [private] ble-decode-{byte,char,key}
    - reject: [private] ble-decode-{kbd,unkbd}

    オプション --help の対応は果てしなく面倒くさい。
    というか引数の解析が必要なかった物全てに引数の解析を実装しなければならないのが駄目。
    というより、その為に archive/getopt.sh があったのではなかったか。
    そして archive/getopt.sh は大変に重かったという事と
    使い方が分かりにくかったという事で archive されたのだった。

    うーん。引数の解析を実施すると速度が低下するので、
    特に ble-assert や ble-stackdump 等では実行したくない。
    結局、引数の解析を行わない内部用の ble/util/{import,assert,autoload,stackdump} と、
    ユーザに公開する --help 付きの ble-{import,assert,autoload,stackdump} を提供する事にした。

    ble-color-*2* に関しては、そもそも公開する理由がない。改名する事にする。
    以下の様なスクリプトを書いて一括で変換した。

    | #!/bin/bash
    |
    | function refactor-color-functions {
    |   local funcs slash fun
    |   funcs=(
    |     ble-color-ansi2g
    |     ble-color-face2{g,sgr}
    |     ble-color-g2sgr
    |     ble-color-gspec2{g,sgr}
    |     ble-color-iface2{g,sgr}
    |     ble-color-sgrspec2g)
    |   slash=/
    |   for fun in "${funcs[@]}"; do
    |     refact -b "$fun" "${fun//-/$slash}"
    |   done
    | }
    |
    | refactor-color-functions

    序にその他の ble-color/* 関数も改名する。

    | #!/bin/bash
    |
    | function refactor-color-functions {
    |   local funcs slash fun
    |   funcs=(
    |     ble-color/.name2color
    |     ble-color/.color2sgr-impl
    |     ble-color/.color2sgrfg
    |     ble-color/.color2sgrbg)
    |   slash=/
    |   for fun in "${funcs[@]}"; do
    |     refact -b "$fun" "ble/color/${fun#ble-color/}"
    |   done
    | }
    |
    | refactor-color-functions

    ble-decode-byte に関しては誰も参照していない。
    ble-decode-key に関しては様々な所から内部使用が見られる。
    ble-decode-char に関しても微妙に内部使用が見られる。
    これらの関数名をどうするかは微妙である。
    元々 "decode byte,key,char" という意味なので、
    もし真面目に変えるとしたら ble/decode/decode-{byte,key,char} になる。
    然し長いので気になる。一方で ble/decode/char というのも何か変な気がする。
    或いは、現状のままで --help に対応しないという方向性も考えられる。
    というか何故 --help に対応しなければならないのか…。

    ble-decode-kbd や ble-decode-unkbd も似たような物である。
    面倒になったのでこれらの関数については、
    これまで通り内部の関数として、但し関数名は今の儘で変えないという事にする。

  * ble-sabbrev: 定義の表示において key に含まれる特殊文字がそのまま出力される [#D0912]
    これは ble-complete/sabbrev/list の定義を見直した。

2019-02-08

  * global: ユーザ関数に --help を実装する (suggested by cmplstofB) [#D0911]

    正直面倒くさい。沢山ある割に大した複雑な使用方法も存在しない。
    ble-bind がほぼ唯一の指定が面倒な関数である。
    他に ble-color-setface 辺りは説明を実装しても良さそう。
    取り敢えず適当に説明を追加した。

    - ble-bind 対応済み
    - ble-update
    - ble-sabbrev
    - ble-attach, ble-detach
    - ble-color-show, ble-color-defface, ble-color-setface

  * BUG main: /bin/sh が dash/ash の環境で ble-update が動作しない (reported by cmplstofB) [#D0910]
    _ble_base_repository='...' を生成するコマンドが bash の機能に依存していたのが原因であった。
    パラメータ展開の ${var//before/after} は POSIX には規定されていない。
    結局 bash を明示的に呼び出す事にした。

  * main: support BLE_VERSION and BLE_VERSINFO (suggested by cmplstofB) [#D0909]
    変数名は最近は全て _ble_* に統一してきたが素直に BLE_* を使う事にした。
    今後は BLE_* はユーザに公開する変数に使う事にする。
    core-syntax.sh で使っている BLE_ATTR_* 及び BLE_CTX_* は後で改名する → 改名した 1fbcd8b

2019-02-07

  * BUG complete: チルダ展開における補完で大量のエラーメッセージが出る (reported by cmplstofB) [#D0908]

    以下のエラーメッセージが出る。単に action:tilde の実装がないだけだった。直した。
    -bash: ble-complete/action:tilde/initialize: そのようなファイルやディレクトリはありません

  * 2018-08-28 complete: bash-completion の幾つかの関数を上書きもしくは乗っ取り? [#D0907]
    [棄却: ただし、ble.sh 側で bash-completion に習って tilde 展開の補完に対応]

    bash-completion の _minimal などは ble 側で乗っ取っても良い様に思う。
    より良いサポートをする事ができるはずなので。
    例えば --prefix=... などに於いて。
    実は単にキャンセルすれば ble の既定の filedir 及び =... :... が動く。

    →と思ったが --prefix=... に関しては COMP_WORDBREAKS に対応した今、
    実は余り気にしなくても自動的に対応される…。
    その他に乗っ取って利点などはあるだろうか…。
    もし利点があるようだったら実装するというので良い気がする。

    * 調べると bash-completion _filedir はチルダ展開にも対応している。
      bash-completion の方が実は上なのではないか…。
      →ble.sh の source:file, source:dir でも対応した

      _tilde: COMPV =~ ^~[^/]+$ ならばユーザ名を生成
        compgen -P '~' -u -- "${COMPV#\~}"

      _filedir
        先ず _tilde を試みる or
        第一引数が -d ならディレクトリ名を生成 or
        第一引数がそれ以外なら、それを拡張子と解釈してファイル名を生成 or
        ファイル名を生成

      →取り敢えず tilde には対応した。

      [=:] に関しては完全には対応していないが、
      /C:foo --opt=foo opt=foo 等の形式には対応している。
      一方で opt=foo:bar の形式には対応していない。
      まあ、面倒だし、本当にそういう機会があるのかも分からないので取り敢えず放置する。
      もし対応するのだとしたら完全に [=:] で単語を分割して対応する方が良い。

      よく考えたら。クォートされている場合には発動してはならないのでは。。
      と思ったが COMPS でパターンマッチングしているのでクォートされている事はない筈。OK

    うーん色々考えたが。現状で _minimal に問題点があるという訳でもないので、
    取り敢えず乗っ取るのはわざわざする程の事でもないという事で棄却する。

2019-02-05

  * 改めて leak variables のチェックを行う [#D0906]
    ref #M0002
    何処かで len, ret, flags という変数が漏れている。

    - fixed: ble-syntax:bash/ctx-heredoc-word/remove-quotes rex
    - fixed: ble-bind flags
    - fixed: ble-complete/auto-complete/.search-history-light len
    - fixed: ble-complete/menu/show info_data menu_items

    | ret は手強い。調べてみると ble-attach で既に出ている。
    | 更に遡ると ble-edit/bind/.tail で出ている。
    | →ble-edit/info/reveal
    | →ble-edit/info/.render-content
    | →ble/canvas/panel#reallocate-height.draw
    | →ble/canvas/panel/layout/.determine-heights

    - fixed: ble/canvas/panel/layout/.determine-heights ret

  * 2018-04-12 [棄却] ble-bind -xf で cd を実行することについて [#D0905]

    プロンプトに現在のディレクトリを表示している場合、
    cd で移動した後にプロンプトを再計算したい。
    その時は ble-bind -xf 'C-@' 'cd ..; _ble_edit_prompt=; ble/textarea#invalidate' 等のようにすれば良い。
    しかし面倒なので ble-edit/prompt#invalidate の様なものを用意しても良いのではないかという気がする。
    同時に ble-edit/prompt/* 系統の関数名についても考え直したい。
    - というより単に ble/edit/prompt/* で良いのかもしれないが。
    - 或いは ble/textarea/prompt/* の方が良いかもしれない。
      →と思ったが確認してみると疎結合なのでやはり textarea の下には置かない。
    - 或いは ble/prompt/* という可能性もある。
      然し、そうすると ble-edit.sh の中に沢山の名前空間が出来て始末が悪い。

    現状では ble-edit.sh の中にあるのは以下の通り。
    他に ble-decode 及び ble-bind に対する設定関数がある。

    - ble-edit
    - ble/textarea
    - ble/util/c2w 系統
    - ble/widget

    この現状を考えると ble/edit/prompt が妥当であろうという気がする。
    或いは prompt 計算自体を ble-form.sh に移動して、
    ble/form/prompt にしても良いかもしれない。
    しかし、prompt は form/control というよりは
    寧ろ graphics 的な実装方法なのでやはり ble-form.sh に入れるのも微妙か。
    少なくとも現状では textarea に付属して ble-edit にあった方が良い。

    よく考えたら ble-bind -cf で実行すれば良いだけなのでは…。

  * bash-5.0 の localvar_unset [#D0904]
    localvar_unset が on の時には upvar などで使っている unlocal 機能が使えない。
    対策をしなければならない。

  * 2018-09-13 progcomp: scp の補完の動作が変である [#D0903]

    scp ... chat:... の入力時にタイミングによって文字入力ができなかったりする。
    これは一体どういう事なのだろう…。プログラム補完が入力を奪っている?

    % 今試すと再現しない。特定のホストだけで発生するという事なのだろうか。
    % うーん。一応標準入力を /dev/null に繋いで勝手に標準入力を食わない様に変更する。
    % もしユーザから入力を受け取るのであればその補完関数・コマンドが明示的に /dev/tty に繋ぐべきである。

    と思ったが、ユーザから入力を求めて補完候補を絞る機能があっても良い様な気がしてきた。
    そのような発想で補完関数を設計する人は沢山いるだろうと考えられる。
    やはり、標準入力を勝手に封じるのは問題の様に思われてきた。取り敢えず保留という事にする。

    →これが再現しなくなっていたのは実は別のバグで scp の補完関数 _scp に
    *:* の形式の引数が渡っていなかったからではないかと思われてきた。
    今修正が入っているので、再度確認してみて良い気がしてきた。

    今実行してみたら scp による補完が動く様になった…が、
    何故か既存のホスト名の部分まで置き換えてしまう様に補完された…。
    更に、文字入力が吸収されてしまうという現象が再現した。

    2つの問題がある。

    * 先ず、ble.sh 上で補完するとホスト名が消失するが、
      bash 上で補完するとホスト名はちゃんと残っているという事。
      これは ble.sh の側での結果の解釈が誤っているという事である。
      或いは何かの機能を忘れている。prefix をつけるなどの。

      うーん。取り敢えず観察する。

      ble.sh 上で動かした時。
      | declare -- COMP_CWORD="1"
      | declare -- COMP_KEY="67108969"
      | declare -- COMP_LINE="scp chat:mirr"
      | declare -- COMP_POINT="13"
      | declare -- COMP_PREFIX=""
      | declare -- COMP_TYPE="9"
      | declare -- COMP_WORDBREAKS="
      | \"'><=;|&(:"
      | declare -a COMP_WORDS=([0]="scp" [1]="chat:mirr")
      | declare -a COMPREPLY=([0]="mirror/")
      特に _scp 呼び出し前後で COMP_@ の変数の中身が書き換えられているという事もない。

      bash 上で動かした時。
      | declare -- COMP_CWORD="3"
      | declare -- COMP_KEY="9"
      | declare -- COMP_LINE="scp chat:mirr"
      | declare -- COMP_POINT="13"
      | declare -- COMP_TYPE="9"
      | declare -- COMP_WORDBREAKS="
      | \"'><=;|&(:"
      | declare -a COMP_WORDS=([0]="scp" [1]="chat" [2]=":" [3]="mirr")
      | declare -a COMPREPLY=([0]="mirror/")
      うーん。分かってしまった。ble.sh が COMP_WORDBREAKS に対応していないのが原因だった。

      うーん。COMP_WORDBREAKS の中でもシェルの特殊文字でない物に関しては、
      ble.sh の側で分割を実行しても良い気がする。

      - ok: ただし、これは ble.sh の補完の枠組みでは適用したくない。
        ble.sh の補完の枠組みの側では COMP_* は利用していただろうか…。
        →確認してみた所 COMP_* を初期化しているのは ble-complete/source:argument/.progcomp-helper-vars
        であり、この関数を使っているのは complete -F または -C に指定した関数・コマンドを呼び出す時だけだった。
        従って、ble.sh 独自の補完の枠組みでは使用されていない。

      .progcomp-helper-vars の実装を変更する事にする。

      - done: 先ず COMP_WORDBREAKS からシェルの特殊文字を除去する。
        特殊文字は util.sh から拾ってくる。
      - done: 次に単語を分割するという事。これも動いている
      - done: 分割した単語を用いて COMP_@ を構築する

      * done: wordbreaks するのは simple-word/eval してからであるべきでは。
        そうしないと ${hello:=world} 的な物に対して途中で分断されてしまう。
        これは文法的にも変である。

        うーん。先に eval してそれから wordbreaks する事にする。
        →大きく書き換えてしまったが対応した。

      * done: 更にまた整理を行った。

      * done: さて、これで補完関数は正しく動く様になった気がするが、
        生成された補完候補は単語の一部に対する候補なので、
        その事を ble.sh 側に正しく伝えないと、
        単語全体がその候補に置き換えられてしまって問題になる。

        これはどの様に調整すれば良いだろうか。
        point が単語片の中にある場合には、
        その単語の eval した結果を保持しておいて、
        それを COMPREPLY に付加するなどの工夫が必要である。

        或いは COMPREPLY を読み取る時に付加するというのでも良い。
        progcomp_prefix 的な変数に prefix を保存しておけば良いだろうか。
        或いは COMP_CWORD0 的な変数に最初の単語片の位置を記録しておけば良い。

        と思ったら compgen 関数を通して実行されるのであった。
        この時、中で設定したシェル変数を外から参照できるのだったか。
        試しにやってみたらできた。なのでこれで良いだろう。
        結局 progcomp_prefix という変数に、
        現在の単語の現在位置よりも前の単語片を追記していく方法にした。
        後で progcomp_prefix を候補生成時に付加する。

      動かしてみるとまだ問題が残っている。

      x ok: ディレクトリ名を保管した後にスペースが挿入されてしまう。
        補完関数はディレクトリ名の補完で / を挿入している。
        一方で ble.sh が候補を単語と解釈して、更にスペースを挿入してしまう。

        % nospace 的な compopt は設定されていないのだろうか。
        % うーん。確認してみたが _scp からはその様な物は指定されていない様子…。
        %
        % →不思議な事に普通の Bash で _scp を実行するとちゃんとスペースが挿入されずに補完されるが、
        % _scp_hook を通して実行するとスペースが挿入されてしまう。この振る舞いの違いは何か。
        %
        % うーん。調べてみると _ssh_options の中で compopt -o nospace が呼び出されているはず…。
        % 或いは compgen の中からだと unset -f compopt されてしまうのだろうか。
        % と思ってよく見てみると _scp は _ssh_options は呼び出していなかった。
        % 然し、何れにしても _scp の中で compopt +o nospace を呼び出しているのよりも
        % 前の何処かで compopt -o nospace を呼び出していると考えるのが自然である。
        %
        % 何と complete -F _scp_hook scp としてから complete -F _scp scp としても
        % 余分なスペースが入る様になってしまう…。

        と思ったら実は単に complete -o nospace -F _scp scp という事だった…。
        つまり、ble.sh の側では complete -p の結果に含まれる -o ... を正しく読み取れていない?

        と思って改めて実行してみたらちゃんと動く…。
        実はテストのために実行していた complete -F _scp_hook scp
        が設定を破壊していたというだけの話だった。

      x fixed: compopt 内部で呼び出している builtin compopt は必ず失敗している。
        "補完機能は現在実行されていません" というエラーメッセージが出ている。
        Bash 4.1--5.0 の何れでも同様の動作の様なので呼び出さない事にした。

    * resolved: 次に、scp の引数に対して入力をすると
      入力した文字列が消滅してしまうという問題について。
      これは ble.sh 上で Linux 上でも Cygwin 上でも再現する事を確認した。

      特に自動補完が有効になっている時に再現する様な気がする。
      うーん。自動補完が有効になっていてもなっていなくても、
      勝手に標準入出力が壊れるのは問題である。
      従って、勝手に補完関数の標準入力は塞ぐ事にする。
      →標準入力を /dev/null に繋いで実行する様にしたら問題は起こらなくなった。

      実際に補完関数が標準入力を必要とする事があるのかどうか分からないが、
      特に自動補完の事を考えたりすると標準入力を必要とする補完関数は変だ。
      という訳なので、補完関数は標準入力を使えないという事にする。
      敢えて標準入力を使いたければ自動補完でない事を確認して /dev/tty に繋いでもらう。

2019-02-03

  * 2019-01-27 complete: 前の単語に対してパス名展開を実行する編集関数? [#D0902]
    M-g (glob-complete-word)
    C-x * (glob-expand-word)
    C-x g (glob-list-expansion)

    どの様に現在の枠組みを修正するか。
    COMPV を配列にするか、展開前の値にするか。
    展開前の値にするのが良い気がする。
    comp_type に R を指定した時には展開前の値にする。

  * [ok] complete: insert_all で comps_flags をクリアしなければならないのでは [#D0901]
    と思ったがそうでもないような気もする…。後で実際に試してみる。
    そもそも候補の生成時点でその状態を前提としてクォートしている筈である。

    →試してみるとちゃんと動いている。${a} 等の補完もちゃんと動いている。

  * util: それよりも何処かで leak variable が存在している… [#D0900]
    勝手にシェル変数 a の中身が ! に書き換わる
    これは util.sh の中のエスケープ関連の関数だった→修正した

  * 2019-01-27 M-* (コマンドライン上でパス名展開を実施) などに対応する [#D0899]
    →改めて確認してみた所 M-* はパス名展開ではなくて
    補完候補を全て挿入という機能であった。

    うーん。確かに全て挿入される。また、クォートを閉じるだとか、
    ファイル名・ディレクトリ名に対してスペース・スラッシュを挿入するだとか、
    そういう機能はなくて、単にスペース区切りで全て連結している様に見える。

    試しに 'a/b の状態で展開を試みたらクォートは除去されて a/b* a/b* a/b* という
    内容が挿入される事となった。うーん。ここはやはりちゃんと全て complete を
    呼び出す様にしようか…。

    実装した。動いているので気にしない事にする。

  * progcomp: -o nosort noquote plusdirs などに対応する [#D0898]
    filenames の対応も不完全に見える。
    dirnames の対応についても再度確認したほうが良さそう。

    * nosort の時には uniq は実行するべきかどうか。
      問題は一意確定なのに確定しない場合があるという事なので、
      uniq で十分なのではないかとの説。
      でも結局 uniq で外部コマンドを読み込むのだとしたら awk で処理した方が良いかも。
      →awk で実装する事にした。
    * plusdirs ... 対応した
    * bashdefault, default に関しては、
      何も候補が生成されなかった時の振る舞いだが、
      bash ではこれらが指定されなかったとしてもファイル名候補を生成する。
    * filenames ... これは確認したが quote はデフォルトで実行される。
      また末尾の空白やスラッシュも現状の実装でちゃんとなる筈。
      バグがなければ。
    * dirnames ... これは対応している。
    * noquote については。action:progcomp/initialize を見る必要がある。
      quote は initialize で実行されている筈だから。
      調べた。plain/initialize は結局 quote しかしていない様なので、
      ble-complete/action/util/quote-insert という関数に分離する事にした。
      その上で noquote が指定されている場合には quote を実行しない様にした。

  * progcomp: 現在入力済みの文字列に合致しない物を生成しても全部棄却される [#D0897]
    ref #D0895

    以下での議論に関連して。
    https://lists.gnu.org/archive/html/help-bash/2019-01/msg00006.html

    元の Bash の実装ではOK。ただし、変な事が起こるので
    bind 'set show-all-if-ambiguous on' にしないと使い物にならない。
    更にそうしたとしても実際に補完されるのは一意確定の時のみである。

    現在の実装では、通常時 (ambiguous でない時) は
    ble-complete/source:argument/.progcomp の中の
    ble/util/assign-array arr 'ble/bin/sed ...' の部分で $COMPV を接頭辞とするフィルタをしている。
    曖昧補完時は上と同じ箇所で compv の最初の文字によるフィルタをした上で、更に、
    ble-complete/source:{command,argument} の ble-complete/candidates/.filter-by-regex によって
    曖昧補完に合致する様にフィルタリングを実施している。

    もしもっと自由な補完候補を生成したいのであれば、
    これらのフィルタリングを実施しない様なオプションを追加するなどする必要がある?
    その時には曖昧補完時には影響が出ないようにして、
    曖昧補完時に影響が出る様にする必要がある。

    ? というかそもそも何故 sed でフィルタする必要があったのだったか。
      どの様な状況でフィルタする必要があったのかについて改めて調べる必要がある。
      何処かに記録は残っていないだろうか。

      補完についての初めの議論は #D0181 である。
      うーん。ここではフィルタリングについては述べられていない。
      しかし、一番最初の実装からその様な実装になっていた気もする。
      覚えていないので寧ろ blame で遡った方が良いのかもしれない。

      blame で遡ると以下が見つかった。

      | $ git blame -C -M 4df15e1e~ -- complete.sh
      | 1929132b (Koichi Murase 2015-11-24 04:05:14 +0900 387,397)
      |   # * 一旦 compgen だけで ble/util/assign するのは、compgen をサブシェルではなく元のシェルで評価する為である。
      |   #   補完関数が遅延読込になっている場合などに、読み込まれた補完関数が次回から使える様にする為に必要である。
      |   # * "$COMPV" で始まる単語だけを候補として列挙する為に sed /^$rex_compv/ でフィルタする。
      |   #   compgen に -- "$COMPV" を渡しても何故か思うようにフィルタしてくれない為である。
      |   #   (compgen -W "$(compgen ...)" -- "$COMPV" の様にしないと駄目なのか?)
      |   # * sed で末端の [[:space:]]+ を除去する。
      |   #   git の補完関数など勝手に末尾に space をつける物が存在する為である。
      |   #   単語の後にスペースを挿入する事を意図していると思われるが、
      |   #   通常 compgen (例: compgen -f) で生成される候補に含まれるスペースは、挿入時のエスケープ対象である。
      |   #   →これだとスペースで終わるファイル名を挿入できない…。
      |   # * arr=($(...)) としないのは IFS=$'\n' の影響を $(...) の中に持ち込まないためである。

      というかこの sed に関する説明は今も残っている…。
      何れにしても 1929132b (2015-11-24) が怪しい。
      調べてみると 1929132b~ で既に sed の呼び出しは存在していない。
      2015-11-24 付近のログを調べてみる事にする。

      うーん。取り敢えず #D0245 の気がするが、特に sed によるフィルタリングについては書かれていない。
      ただ、#D0245 は progcomp の対応であるので、変な補完設定が勝手に変な候補を生成した際に、
      それをフィルタする必要があったという事なのだろうと思われる。

      というかもしかして補完関数を呼び出す時の呼び出し方が間違っていた (or 間違っている)?
      と思って調べてみる。1929132b の時点ではちゃんと "$comp_func" "$cmd" "$cur" "$prev" と呼び出している。
      一方で、その前の段階 cdd38598 (2015-11-23 23:58:01 これが #D0245 のメインのコミットと思われる) では、
      以下の様な実装になっていて -F で指定した関数の引数に単語などを渡していない。

      | function ble-complete/source/argument/.compgen-helper-func {
      |   local -a COMP_WORDS
      |   local COMP_LINE COMP_POINT COMP_CWORD COMP_TYPE COMP_KEY
      |   ble-complete/source/argument/.compgen-helper-vars
      |   [[ $comp_func ]] && eval "$comp_func"
      | }

      何だか単にこれが問題だったというだけの気がする。

    * done: 取り敢えず試しに既定では "$COMPV" によるフィルタリングを実行し、
      もしそれで候補が一つもなくなる様だったら生成された候補を全て使用するという様に変える。

      →取り敢えずその様にしてみたら動いた。
        クォートされてしまってパス名展開にならない的な事も起こっていない。
        よく考えてみれば ble.sh の progcomp は展開後の生の文字列を渡す事にしているので問題ないのである。

        % 逆に言えば b\*sh としても b*sh に変換されてパス名展開の処理を補完関数が実行すると
        % それが有効になるという事でもあるのだが。
        % →と思って試してみた所、有効にはならなかった。
        %   うーん。そういう物だったか。調べてみると ${comp_words[comp_cword]} から直接取り出していて、
        %   更に comp_words は extract-command を用いて生成している。
        %   extract-command は無駄な展開などしないので、
        %   補完関数に渡されるのは実際にコマンドライン上にある文字列である)

    x fixed: さて、動くには良いが既に存在している文字列が削れてなくなってしまう。
      更に、その状態で再度補完をやり直すと候補がまた沢山になってしまう。
      この辺りは対策をしていた様な気がするが何故動かないのか。
      曖昧補完の時にだけ対策が実行されるのだったか。調べる必要がある。

      調べると一致しない場合には insert_flags=r というフラグを立てている。
      しかし、実際にはこのフラグを使用している箇所はない。
      挿入・置換を実施するところで insert_flags == *r* の時で、
      かつ一意確定でない時には置換を実施しない様に書き換えた。

    * ok: 速度は気になる。今回の変更では assign の呼び出し回数が増えた。
      しかし fork の数は減っている様にも思う。
      これが実際の処理にどの様に影響を与えるであろうか。

      実際に以前のコード (1回の assign) と較べてみると、
      以前は 0.020 だったのが今回は 0.028 になっている。
      と思ったが、よく考えたら以前のコードは候補が絞れなかった時に候補が生成されないので比較対象として適切でない。
      同等の機能を持って、しかし1回の assign で実行する場合と比較しなければならない。
      というか、それには b*sh ではなくて g などで調べた方が良いのではないか。

      何かちゃんと動作しない。と思ったら .bashrc に書いている補完関数の方の問題だった。
      計ってみると以前のコードが 0.019 で今回のコードが 0.018 と言った様な具合で、
      新しいコードの方が若干高速である。とは言いつつ、何度か呼び出すと微妙に時間が反転することもある。
      →これで良いという事になった

    * ok: 実はデフォルトでフィルタしない動作で良い気がしてきた。
      compopt でなにか指定した時にだけフィルタリングを実行するなど。
      →compopt に独自の filter_by_prefix を追加する事にした

      この独自設定については何処か説明書に書く必要はあるだろうか。
      というかそもそも補完において、bash のプログラム補完が使えるという事を
      説明書に書いていない。うーん。面倒である。
      これは memo.txt の先頭に書いておく事にした。
      序に古い設定変数一覧は消す事にした。

    x fixed: 実際にフィルタリングなしで動かしてみると動作が変である。
      やはり filtering しないと駄目である。
      と思ったが変だ。うーん。実際にやってみると大量のファイル名を出力している。
      何故だろう…。そして、普通に ble.sh 以外から touch の補完を実行すると正しい候補だけを出力している。
      うーん。ble.sh による補完関数の呼び出し方が未だ間違っているという事なのか。

      詳しく呼び出しの状態を調べてみる事にする。
      先ず疑ったのは関数を呼び出す時の引数だったが、
      これについては具体的に出力してみた所、問題なかった。
      次に調べるのは declare -p ${!COMP*} である。
      →COMP_POINT が間違っている…。
        COMP_POINT は補完開始点ではなくて現在のカーソルの位置の様である。
        しかしこれだけで変わる物だろうか…。
        何れにしてもこれは問題なので修正する事にする。
      うーん。comp_point はちゃんと正しい値である。

      分かった。バグだった。修正した。

2019-01-27

  * [棄却] 2019-01-21 complete: 曖昧補完時にパス名展開を考慮に入れると良いのではないか? [#D0896]

    https://lists.gnu.org/archive/html/help-bash/2019-01/msg00003.html
    https://lists.gnu.org/archive/html/help-bash/2019-01/msg00006.html

    | 現在の実装ではパス名展開で一致した物の内で一番最初の物を選択し、
    | 更にその続きに来るかも知れない文字を探すという動作になっている。
    | 改めて考えるとその動作の方が自然な気がする。
    |
    | またコマンド名をパス名展開で検索するという考え方は変だ。
    | そもそもの話としてコマンド名にパス名展開を含んでそのまま実行しても実行されない。
    | 然し、よく考えてみればそもそも補完はそういうものである。
    | そのままでは実行できないけれども文字列を補完する事によって実行できる様にする。
    | その様に考えてみれば候補が他に存在しないという時に限って、
    | コマンド一覧をパス名展開で表示するというのは一つの手である様な気がする。
    |
    | というよりそういう細かい動作はユーザに complete -I で実装してもらう事にして、
    | ble.sh の側では何も関知しないという手もある。しかし、ble.sh の補完の仕組みは
    | 丁寧に作りすぎている所為で、グロブパターンが存在するとそれをクォートしてしまう。
    | そうすると期待通りに展開が為されないのではないかとも思われる。
    | 何れにしてもこれについて考えるのは complete -I を実装してからという気がする。

    先ず、引数の補完の場合には:
      パス名展開は複数のファイルに一致する事を意図しているはずなので、
      勝手にその内のどれかに展開してしまうのは変である。
    コマンド名の補完の場合には:
      どれか一つに一致するのが自然なので対応しても良いが、
      実のところ、本来は b*sh などではコマンドを実行できないので、変な気もする。
      これはユーザ側のプログラム補完 complete -I で個別に対応してもらえれば十分である。

  * 2018-07-28 complete: bash-5.0 の complete -I に対応する [#D0895]

    これは要するにコマンド名の候補の生成に使うと考えたら良いだろうか。
    他の入力画面でも同じ補完を使うのはやはり変なので、
    コマンド名の補完候補の生成に限って使うというのが良さそう。

    取り敢えず ble-complete/source:argument/.progcomp を改造して、
    -I の時に対応できるようにしたい。→取り敢えず
    .progcomp initial として呼び出せば -I で complete -p する様に修正した。

    ble-complete/source:argument/.generate-user-defined-completion も改造するか。
    実は最初の単語にカーソルがある場合には動作を切り替えるという様にもできるし、
    或いはオプションとして initial が設定されていたら動作を切り替えるという様にもできる。
    ここではオプションとして initial が設定されていたらという方法にする。
    というのも sudo command 等の場合には文法的には command が引数であっても、
    ユーザの手動の設定でコマンド名としての補完を要求することがあるかもしれないからである。

    ble-complete/source:command に ble-complete/source:argument
    に書かれている物と同じ物を書いてみる。実はこれで対応は完了なのではあるまいか。

    実際に動かしてみると動かない。候補が生成されていない。
    と思ったが、実は当然である。何しろ complete -I を指定していないのだから。
    試しに何か適当な物を指定してみる事にする。
    →opts "initial" を渡すのに失敗していた。動く様になった。
      しかし、今度は source:command で生成された候補が全部棄却されている。
    →調べてみると source:command の外側で棄却されているのではなくて中で棄却されている。
      更に観察してみると ambiguous の時には ble-complete/candidates/.filter-by-regex の時点で棄却されている。
      また、ambiguous でない場合にはもっと上流で棄却されている気がする。
      調べるとどうも ble-complete/source:argument/.progcomp の中の
      ble/util/assign-array arr 'ble/bin/sed ...' でフィルタしているのだった。

    うーん。これはそういう仕様である。何故その様になっているのかと言うと、
    compgen が時々 prefix に関係ない物まで全て列挙してしまうからであった気がする。
    しかし、その様な場合にはどの様に対処すれば良いのだろうか…。
    うーん。こういう場合については取り敢えず対応しないことにする。

    別の項目として立てておく事にする。

2019-01-22

  * 実は declare -i した変数 var の var+= の右辺でも算術式展開が起こる様だ [#D0894]

    しかも算術式評価で解析する量が減るので var+= が一番早いという結果も出ている?
    https://lists.gnu.org/archive/html/help-bash/2018-12/msg00092.html

    これは算術式の記事を更新しておく必要がある→更新した。下書きに入れてある。
    https://qiita.com/akinomyoga/items/2dd3f341cf15dd9c330b
    https://qiita.com/akinomyoga/items/9c9d6cfeb02f186f9185
    そんなに際どい事は書かれていなかったので多少例を追加するだけで済んだ。

    これに関連して ble.sh を修正する必要はあるだろうか。
    現在の ble.sh の実装だと declare -i や local -i は基本的に使わない様にしている。
    メーリングリストの計測結果を見ると、もしかすると declare -i や local -i
    にした方が動作が高速になるかもしれないが。。
    うーん。然し、-i になっていると代入する度に算術式評価が入るので、
    単純な値の代入が起こる限りはやはり -i をつけない方が速い様な気もする。
    実のところ、一長一短である。面倒なので -i をつけない方針で統一する方が楽なのではないか。
    因みに、現在の実装では主に引数を受け取る時に -i を結構使用している。

    色々考えるのが面倒になったので出来るだけ local -i は使わない様に変更する事にした。
    declare -i 及び local -i を使わない理由を以下に挙げる事にする。

    1 local -i を使ったり使わなかったりすると呼び出し元で算術式展開をしたりしなかったりする。
      そうすると確認する時に算術式展開をするべきかしないべきか判断しなければならない。
    2 逆にできるだけ local -i を使う様にすると良いと考えるかも知れないが、そうすると
      今度は整数引数なのかそうでないのかの仕様がだんだんとよく分からなくなってくる。
      また、算術式展開をわざわざ呼び出すまでもない整数引数を受け取る関数についても
      local -i で引数を受け取る事になる逆に処理の効率が悪くなってしまう。
    3 そもそも算術式展開がその場で必要になる機会の方が少なくて、
      そしてその様なときには呼び出し元がそれを知っているはずなので、
      呼び出し元でちゃんと算術式展開を実行する様にするべきなのである。

2019-01-21

  * 実は unset 変数名 とした時にその変数がなくて関数があると関数が消える [#D0893]

    例えば:
    $ function hello() { echo world; }
    $ hello=1234321
    $ unset hello # 変数が消える
    $ unset hello # 関数が消える

    unset -v を使う様にすれば関数が消えてしまう事はない。
    ble.sh の中の unset (-f なし) を全て unset -v にする。

2019-01-20

  * 2018-09-23 manual: 説明書について書き始める [#D0892]

    書き始めると仕様で微妙なところが浮き上がってくるのでその都度修正する事にする。

    - done: vi でも M- 系列を bind するオプションがあっても良いのでは。
      しかしキャッシュしていると反映されなくなってしまう。
      また、keymap vi の初期化の前にそのオプションは指定しなければならない。
      或いは、キーマップの継承などがあれば簡単なのかもしれない。
      しかし、これ単体の為に継承を新しく実装する程でも無い。
      或いは M- 系列を元から bind してしまう…?

      | うーん。現在のデフォルトの Meta/ESC の設定は何だったろうか。
      | bleopt_decode_isolated_esc=auto になっていて、
      | この時 ble-decode/uses-isolated-esc は vi モードで return 0 である。
      | 一方で、uses-isolated-esc の呼び出し元を確認すると、
      | 孤立ESCを受け取った時にそれを ESC として処理するかどうかの判定に使っている。
      | 現在の設定では孤立ESCは ESC として扱う振る舞いになる。
      |
      | ここで問題になるのは timeout の長い処理系を使っている人について、
      | ESC を入力してから次のキーを入力するまでの時間が短いと Meta になってしまうという事である。
      | また、Meta を押しながらキーを入力する事で確実にノーマルモードで実行する様にする、
      | という癖にして使っている人も世の中にはいるかもしれない。
      | その様に考えると M- 系列を初めから bind しておくというのは憚られる。
      |
      | 現在の実装では M- 系列が bind されていないので、timeout して孤立ESCが次の文字とくっついたとしても
      | 最終的には分解されてちゃんと単体の ESC として処理される。従って問題が発生していないのである。

      単に M- 関連を bind する為の関数を提供すれば良いだけの気がしてきた。
      ble-decode/keymap:vi_imap/define-meta-bindings という関数を用意する事にした。
      blerc に記述する。

    - done: vi_[nox]map C-end vi-command/last-line は vim の説明に依ると inclusive である筈。
      実際に試してみようとすると C-end が認識できないので入力できない。
      しかし、vimindex によると G と C-end は同じと書かれているにも拘わらず、
      実際に vim motion の頁を見ると G と C-end は異なるように書かれている。
      G は linewise であり C-end は inclusive であると書かれている。

      実装し直す事にする。実装した。簡単に動かしてみた所、動いているので後は気にしないことにする。
      C-home に関しても現在の実装では jump になっているが vimindex によると、
      (H と殆ど動作として同じであっても) jump ではない用なので実装し直した。

    - done: M-m 及び S-M-m の実装が単なる beginning-of-line になっている f77f1aa

    - done: vi_nmap: z z, z b, z -, z . の実装は不完全である (ref #D0886)

    取り敢えず今までの所で浮き上がってきた仕様の微妙な所は修正した。
    この項目についてはどの様にしようか。長くなって来たので Done に送りたい。
    他に残っているのは Emacs 編集モードの説明のみである。これは独立した項目にする。

  * update: .tar.xz から落とした場合でも ble-update を使える様にする [#D0891]
    しかし、これは次の 0.3 のリリースまでは実際には有効にはならないが。

    後、.tar.xz の時にはコンパイルに使用したディレクトリを記録しない様にするべきでは。
    偶々同じ名前のディレクトリ (例えば ble.sh の異なるバージョンなど) が存在した時に変な事になる。

    % 或いは .tar.xz の時には、何か特別のファイルを添付してそれで判別するか。
    % 例えば $_ble_base/ble-release-version.txt などのファイル。
    % → $_ble_base/ble-release というファイルを置く事にした。

    と思ったがやはり微妙な気がする…。余分なファイルができてしまうという事が先ず気になる。
    別に余分なファイルを作らなくても原理的には可能な機能である。
    次に、コンパイルしたディレクトリの記録を残しておく理由がない。
    その様に考えると、コンパイルしたディレクトリの記録の部分に特別な値を設定しておく方が自然である。

    - done: reload した時に再度設定を適用する為には README は更新しておかなけけばならない。
    - done: _ble_base_repository=release:branch の形式で特別な値を埋め込む事にした。

    実際にテストしてみた所ちゃんと動く様子なのでこれで良しという事にする。
    因みにこれを実行すると clone のカウントが増える。
    2019-01-20 に一回テストを実行したので clone の回数が一回増えているはず。
    取り敢えずこれで完了しているはず。。

  * fixed: うーん。ble-update のテストをしていたら何故か _ble_base の決定がおかしい… [#D0890]
    と思ったら source ble.sh の様にディレクトリを指定せずに読み込むと駄目の様だ…。
    これについては修正した。

  * 2018-09-28 isearch: 空文字列で検索を開始すると前回の文字列で検索する様にする可能性? [#D0889]

    これは bash の既定が空文字列による検索なので微妙かもしれない。
    然し、よく考えてみると既に確定時の振る舞いが異なるのだし、
    やはり emacs の振る舞いの方が自然に思われるので、
    これは実装しても良いのではないかという気がする。
    →実装した。意外と簡単だった。本当にちゃんと動いているかは自信がないが。
      取り敢えず暫く使ってみてから考えれば良いだろう。

    記録するのは検索を実行したタイミングではなくて
    実際に一致したタイミングであるべきなのでは。

2019-01-19

  * complete: 複数行モードにおけるメニュー補完で描画位置がずれている気がする [#D0888]
    と思ったら複数行どころか常に描画位置がずれるようになってしまっている。
    一箇所直したら治った。これは #D0880 で埋め込んだバグであった。

2019-01-16

  * bleopt: 内部の設定変数に internal_ を冠する事にした [#D0887]

    - suppress_bash_output -> internal_suppress_bash_output
    - ignoreeof_message -> internal_ignoreeof_trap
    - exec_type -> internal_exec_type
    - stackdump_enabled -> internal_stackdump_enabled

2019-01-14

  * vi_nmap: スクロール [#D0886]

    * C-d C-u C-e C-y について対応し始めたら何だか分からなくなってきた。
      現在の実装だと論理行と表示行の取り扱いが混ざり合っている。

      ble.sh のスクロールは表示行についてのスクロールである。
      更に、プロンプトの高さの分だけ全体の高さは引き算して考える必要がある。
      では vim の C-d, C-u は表示行なのだろうか、それとも論理行なのだろうか。
      更に C-e や C-y は表示行なのか論理行なのか。

      どうも調べてみると C-d 及び C-u は論理行の移動の様である。
      そして移動した分だけスクロールするという仕組みになっている様子である。
      何と、C-e や C-y についても論理行のようである。
      つまり、画面に表示されている先頭行を追加・削除するという形。
      カーソルはできるだけ移動しないが、画面に入り切らない時には内側に入れる。

      x fixed: ble/textmap を使って実装してみたがどうも動作が変である。
        もしかすると scroll 値の意味を勘違いしている。
        例えば scroll=15 なのに何故か表示は 17 行目からになっている。
        ble/textarea#render/.show-scroll-at-first-line の実装を観察すると、
        確かに scroll+2 を現在の行番号として表示している。その心は何だろうか。

        また、.determine-scroll の説明を読むと scroll とはスクロール量である。
        つまり、最初に表示されている行の番号という訳ではない。
        例えば、scroll=1 の場合を考える。この時、1行目は行番号に置き換えられて、
        2行目が欠損する形で3行目(y=2)からの表示となる。

        max_scroll の値も再考する必要がある。
        nline あって枠が height なのだとすれば nline-height だけ欠損すれば全体を表示できる。
        従って、max_scroll = nline-height = _ble_textmap_endy + 1 - height である。
        それから ay by の値も修正した。y<ay の時の y=ay が誤って x=ay になっているのも修正した。
        まあ、何やら動く様になったので良しと言う事にする。

    * ページのスクロールについても実装することにする。
      基本的には現在見えている一番下の行に移動するという事。
      引数を指定するとそれを繰り返し実行したのと同じ位置に移動する。
      つまり、移動後は上から2行目に表示されるので、表示高さを vheight として
      (ARG-1)*(vheight-2) だけ下に移動した位置に移動する。

      C-b の場合には scroll が 1 以上の時にだけ動作し、
      現在表示されている画面の一番上から2行目の行が画面の一番下に来る様に移動する。
      カーソル位置は以前表示されていた内容の1行目の非空白行頭である。
      (ARG-1)*(vheight-2) だけ上に移動する。

      頁のスクロールについても実装した。動いている気がする。

    * zz 辺りを実装する。
      引数を指定すると移動先の行番号となる。
      行は論理行であり、更に相対位置関係で列の位置が決まる。
      実装した。動いている。

2019-01-13

  * [自然解消] 2015-03-06 整理 [#D0885]

    | - 着色の古いコード
    |   これに関しては現在の複雑な実装と昔の簡単な実装の間の着地点を見つけたい。

    これも古い実装についてなので忘れる事にする。

  * [自然解消] 2015-02-24 ble-syntax-highlight+* の代替機能の実装と廃止 [#D0884]
    これは既に消滅している気がする。

  * [自然解消] 2015-02-23 complete: TAB を打たなくても補完候補がある場合は薄く表示する? [#D0883]

    | 重くなるといけないので read -t 0 で確認しつつ処理を行うのが良い。
    |
    | 実際に未だ入力されていない物を上に重ねて表示する場合、また新しい枠組が必要になる気がする。
    |
    | a 一つの簡単な方法は「編集文字列を本当に書き換えてしまう」方法である。
    |   しかし編集文字列を書き換えている状態で別のコマンドが起動されるなどすると
    |   編集文字列内容に齟齬が生じて面倒な事になる。それを防ぐ為に新しいコマンドが来るたびに
    |   編集文字列の内容を復元するようにトラップをしかけるのも綺麗でない。
    |   その他の理由でトラップをしかけたくなった時などに結局齟齬が生じる可能性が残る。
    |
    |   この方法は現実的でない。
    |
    | b もう一つの方法は上に重ねる事のできる「レイヤー」の概念を導入する方法である。
    |
    |   レイヤーを導入する場合、描画ルーチンが面倒な事になる。
    |
    |   b.1 既存の描画ルーチンを活かす方向で行くと、
    |     一旦一番下のレイヤーを描画した後でその上にあるレイヤーの描画をつづけて行えばよい。
    |     しかしこれだとちらつきが気になる。
    |
    |   b.2 もう一つの方法は描画を完全に座標指定で行う事にして、
    |     あるレイヤーを描画する際にはマスクを考慮して描画できる様にする。
    |
    |     うーん。わざわざ座標指定で描画を行える様にしなくても、
    |     既存の描画関数の内部を適当に書き換えるだけで行けそうな気もしないでもない。
    |     要するにマスクされた領域の上にある文字については、文字を出力する代わりに
    |     位置だけを更新して、最初にマスクされていない領域の文字を書き込もうとした瞬間に、
    |     その位置へ移動するシーケンスを生成する様にしたらよい。
    |
    |     ただこの時に問題なのはどの様にしてマスクされた領域を表現するかである。
    |     領域の上に複雑にレイヤーが存在している場合、領域に沢山の矩形の穴が空いた状態になる。
    |     この様なマスクがある場合マスクの上にあるかどうかの判定は物凄く重い計算になる。
    |
    |     やはり描画可能領域は矩形に制限して、上に重なっている別のレイヤーに関しては
    |     上から重ねて描画してしまうという手を取った方法の方が良いのではないかという気がする。
    |
    |
    |   b.3 或いは内部に完全に画面のバッファを保存してしまうという手もある。
    |     そして最後に更新された部分だけ反映させるという方法である。
    |
    |     o この方法だとサブウィンドウを作成したりする事ができて汎用性が高い。
    |       何れはこの方法を採らなければならなくなるのではと言う気がする。
    |
    |     x 特に各座標位置について描画属性などを保存する事になるだろう。
    |       しかしメモリを食うのではないかなどの懸念も残る。
    |
    |     x また描画用のシーケンスの生成にも処理時間が掛かりそうな気がする。
    |       何しろ記録した配列の要素をスキャンしてシーケンスを構築していかなければならないからである。
    |       或いは現在の編集文字列の記録と同様に配列に描画シーケンスも含めて記録しておいて、
    |       其処から特定の範囲の要素だけ単純に join して出力できるようにするか。

    2019-01-13 これは auto-complete として既に実装されている。
    この考察にはウィンドウシステム的な物の実現の可能性など
    示唆に富むものもあるが似たようなことは既に他の項目でも述べられているので Done に移動する事にする。

  * 2017-09-25 複数行編集スクロール: info の高さとの兼ね合い [#D0882]

    | 先ず info の高さを制限するようにしなければならない。
    | 現状では高さを計測する仕組みはあったが制限する仕組みはなかった気がする。
    | つまり高さを計測しながらもし予め指定した高さを超えるようであれば
    | そこで切るようにしなければならない。
    |
    | その後で info の高さを全体の高さの半分になるように制限する。
    | 編集パネルの高さはその時点での info の高さを引き算した値で決定する。
    | もし編集パネルの高さが 2 行未満しか取れない場合には info を削る。
    |
    | (そもそも端末の高さ LINES が 2 未満しかないような環境は無視する。)
    |
    | →第2のプロンプトも出すようにしたので、それも意識して修正しなければならない。

    これは #D0878 で実装された。

  * 2018-02-12 スクロール位置を変更する仕組み? [#D0881]

    現在の仕組みではスクロールはカーソル位置が表示範囲外になった時に自動的に行われる。
    明示的にスクロール位置を変更する仕組みを追加したい。
    どれだけスクロールするかのデルタを記録する方法だと絶対位置に移動するのが辛い。
    やはり現在スクロール量を直接編集できるようにしたい。
    その為には現在の描画におけるスクロール量と、
    内部の論理的なスクロール量の二つの変数を用意する必要がある。

  * 2018-08-30 complete: bug, menu-complete 中にコマンドラインの高さが変わると座標計算がずれる [#D0880]

    これは改めて試してみた所、端末の高さが足りている場合には問題は起こらない様である。
    (しかし、本当だろうか…問題が起こっていた時も高さが足りていた様な気がするが…)

    | 問題が起こるのは端末の高さが足りない時である。
    | つまり、コマンドラインの高さが増えた時に、
    | 本来それに応じて info の高さを減少させなければならない。
    | この問題は実は全般に存在する。例えば、画面一杯に編集している時に
    | cmap (panel 1) で複数行の内容を入力したらどうなるのかなど。
    | 結局、本体 (panel 0) を削る事が自然な状況も存在するという事である。
    | そして、本体を削った時にどの様に再描画を行うのかという問題がある。
    | 個別に対応していると汚くなり管理できない。
    |
    | 一般的な仕組みとして整えるとしたら、どの様に対応すれば良いだろうか。
    |
    | a 一つの方法はアクティブ・非アクティブの panel という概念を作り、
    |   アクティブな物は非アクティブな物から高さを一時的に奪う事ができ、
    |   また、新しくアクティブになった時に改めて高さを回復する様にする。
    |
    |   これを実装するには改めてアクティブになった瞬間に、
    |   再描画を呼び出す事ができなければならない。
    |   もしくは内容を別の方法で記録しておく様にすれば良い。
    |
    |   x 問題点は、二つの物を同時に表示したい時に、
    |     必ずどちらか一方 (最終的にアクティブでない方) は画面に入り切らないことである。
    |     やはり一時的なサイズの変更ではなくて、本当にサイズを変更する仕組みが必要である。
    |
    | b 或いは、高さが変更された時に再描画する様なコールバックを呼び出す様にする。
    |   この場合、高さを何処から奪い取るかの仕組みをどのように整えるかは難しい。
    |
    |   例えば min-height をそれぞれの panel に設定できる様にする。
    |   余裕の多いところから均等に高さを確保する様にする、という事にするのはどうか。

    これらは #D0878 で枠組みを整えた。しかし、それでも未だ問題が起こる。

    menu-complete を初期化した時に各項目の位置などを記録して、
    選択肢を変更した時にその位置だけ再描画する様にしている。
    しかし info の高さが変化して短くなると、選択肢が画面外に消える。
    その時に無理やりその位置だけ再描画という処理をすると座標計算がずれると思われる。
    従って、その位置だけ再描画する際に、現在の info の高さを確認して
    中に収まっている時に限って再描画を実行する様に変更するした。

  * 2018-12-02 座標計算を修正したと思ったが依然として長い日本語名のファイルに対して治っていない? [#D0879]

    | これは画面に収まりきらないぐらい沢山の項目がある場合に起こる。
    | しかし、それでも起こる場合と起こらない場合があるのは何が違うのだろうか。
    |
    | ASCIIだけで構成されたファイル名の場合には長いファイル名があっても問題は発生しない様だ。
    |
    | うーん。どうも一部のファイルの座標計算がずれているという事の様な気もしてきた。
    | 変な文字が含まれていると次の行に行くが、その時、続きに収まるファイル名を表示するか。
    | 現在は表示されている気がする…と思ったが、元からそういう仕様だったような気もしてきた。
    |
    | と思って試してみると改行を含むようなファイル名の時に確実に失敗する様である。
    | やはり改行を含んでいてもASCIIだけで構成されているファイル名の場合には問題は発生しない。
    | 日本語のファイル名を自分で作って試してみても再現しない。不思議な事である。
    | 空白類をたくさん含むファイル名を作って意図的にファイル名が長くなるような物を作成しても
    | 問題なく表示される (というか、menu で表示されるファイル名はエスケープの対象ではなかった)。
    |
    | 今試してみた所再現しなくなっていた…。もしかすると Poderosa の方のバグだという可能性もあるのだろうか。。
    | 或いは、ウィンドウサイズを変更した直後にだけ起こっているのかもしれない。

    どうも再現しない様だ。ウィンドウサイズを変更した後などには再現するがそれは一時的な物である。
    また、確実に再現する状況を作り出してからこれについては考える事にする。

    後は、曖昧文字幅の文字を表示した後に一文字ずれる。
    これは持っている文字幅の辞書との不一致による物だろう。という事で気にしなくても良い。

    2019-01-13 #D0878 で info / textarea の高さの融通の仕組みを整えた。
    多分、似たような描画のずれの問題が合ったとしてもそれで治っている気がする。
    もし依然として解決していないとしても現状では症状がよく分からないので再発した時に考える事にする。

  * textarea: 描画の高さ関連の項目がたくさんあるので解決する事にする [#D0878]

    先ずは高さを指定して再描画する機能を実装するのが良さそうである。

    - 高さが低くなる時
      info に関しては単に高さを削るだけで良いのではないか。
      編集文字列に関しても実は高さを削るだけで良い様な気がして来た…。
      と思ったが高さが収まっている状態から高さに収まらない状態に移行した時は、
      最初の行に現在の行番号を表示するのではなかったか。
      試してみるとスクロール位置が変わらない限りは最初の行は最初の行である。
      つまり、収まっている状態から収まらない状態に移行する場合は、
      スクロール位置を変更しない限りはやはり末尾を削るだけで良い。

    - 高さが高くなる時
      info に関してはどういう理由で設定されたかが色々なので、
      高くしても内容の再描画はしなくて良い気がする。
      というより高くなる機会があるのかもよく分からない。
      編集文字列に関しては再描画の必要がある。

    後試していて気づいたが、既に色々と問題がある。

    x fixed: 複数行編集モードのときに C-l をするとカーソル位置が先頭行に移動してしまう。
      列の位置は正しい。これは何故だろう。
      →これは改めて ble.sh を立ち上げてみたら再現しなくなった。
        一度スクロール状態になってから戻ると駄目なのかとも思ったがそうでもない様だ。何だったのだろう。
      →再現した。スクロール状態で一度 C-l を実行するとなるという事?
        調べてみるとスクロールを解除したのにスクロール状態になっていて、

      スクロール状態の時のカーソル位置の計算を確認したら間違っていた。
      二重に高さの位置を更新していた。これは修正した。再現しなくなった。

    x resolved: 複数行スクロールの時に bell で文字列が表示されるとプロンプトが消されてしまう。
      プロンプトの位置と bell の位置が被っている時にはプロンプトを再描画するべきではないか。
      恐らくこれは高さの計算を正しく実行する様にすれば解消できるはず。

      →実装し終わってから試してみた所、問題は発生しなくなっていた。

    うーん。どの様なモデルにするのが正しいのか。
    各パネルにどの様な機能を要求するのかというのを考える事にする。

    - 先ず再描画・更新描画の機能。

    - 高さ変更の通知とそれに伴う再描画の機能。
      これは内部の構成要素の配置も含むはず。

      これが呼び出されるのは他のパネルに高さを奪われた時以外に、
      端末の高さが変更された場合なども含まれる。
      ただし、現時点では端末の高さの変更には対応しない。

    - スクロール及び配置の計算は実は内側の枠組みではなくて
      外側の枠組みで提供するべきことのような気がしてきた。
      うーん。スクロールはやはり内部で管理するべき。
      外部には min-height 及び desired-height 的な物を公開する。

      もしくは span-h にしてできるだけ伸ばす設定にして、
      しかしながら実際の表示の高さは自由に設定できるようにするか。
      しかしそうすると何が何だかよく分からないのでこれはやめる。
      やはり外部に公開された情報を用いて高さを調整するのが良い。

      更に info と textarea の高さのバランスも考えたい。
      両方が高さを過剰に持っている場合には等分配か、
      或いは一定の比率で分配する様にしたい。
      うーん。やはり min-height 及び desired-height
      だけから取り敢えず実装してみる事にしようか。

    取り敢えず min-height 及び desired-height を問い合わせる仕組みを作る事にする。
    色々実装してみた。未だ途中の積もりだったが取り敢えず何となく動いている様な気がする。

    x ok: info による reallocate-heights によって編集文字列側の再描画が必要になる事があるはず。

      所で端末のサイズが変わった時には TRAPWINCH で textarea#redraw が呼び出されている。
      そして textarea#redraw の中では textarea#invalidate が呼び出されている。
      うーん。info によって高さが変わるのだとしたら通知が高さ変更の通知があっても良いのではないか。

      まあ、何かわからないけれども動いている気がする。
      試してみたら info が縮んで再び編集文字列にスクロールが不要になった時、
      次の入力が来るまでは再描画が実施されない…という事が分かった。

      % 何故かと言うと info を消去しているのが ble/util/idle からなので、再描画がされていない…。
      % →調べてみると ble/util/idle.do && ble/textarea#render の様に実行されるので、
      %   idle の中で on-height-change が起こったとしてもちゃんと invalidate で再描画される。
      %   これは関係ないし、気にしなくて良い。

      →実際にやってみると全く動作していなかった。今まで動いていた様に見えたのはたまたま
      編集文字列の内容に変更などが合ったために再描画されていただけだった。

    x fixed: 描画が乱れる問題

      % ちゃんと invalidate が呼び出される様にしてみた所、カーソル位置の計算が乱れる様になってしまった。
      % 何故だろう。単に invalidated を変更するだけでこうも違いが出る理由がよく分からない…。
      %
      % うーん。発生したりしなかったりで謎である。というか一回を除いて毎回発生している。
      % やはり invalidated を設定しない場合には表示の乱れは起きない。
      % うーん。分からないけれども info pane が一行はみ出ている気がする…。
      % それを直しても表示の乱れは治らない。
      %
      % やっぱり何か変な事が起こっている。というか textarea#render の方の問題の気がしてきた…。

      →これは全体更新の時に scroll が変化した時に _ble_textarea_scroll
      に新しい値を設定し忘れているという textarea#render 側のバグであった。修正した。

2019-01-12

  * 2018-10-08 vim: u で戻った時のカーソル位置 [#D0877]

    現在の実装では check-dirty と同じ方法を使って切り出しているが、
    これだと同じ内容が繰り返されているのを削除した場合にどの部分が削除されたのかを特定できない。
    結果として u で戻った時に元の場所ではなくて繰り返し部分の一番最後に移動してしまう。

    カーソル位置も一緒に記録して (或いは既に記録していただろうか)
    その付近で変更があったと解釈して範囲を特定する事は可能だろうか。

    これは vim というよりは edit.sh の ble-edit/undo/.load の実装に関係している。
    実際の所、記録を行った時のカーソル位置は一緒に記録されている。
    問題は、戻る時に記録を行った時のカーソル位置ではなくて
    変更範囲の先頭または末尾にカーソルを移動する時に誤った位置になってしまう事にある。

    具体的な例を考える事にする。

    例えば "echo abcabc@abcabc world" において 3x とした時にどの位置に戻るのかという事である。
    実際に ble.sh で試してみると "echo abcabcabcabc@ world" という状態になる。
    ここで元々の index の位置は記録していたはずである。
    削除した時に、"echo abcabc@abc world" になっている筈である。

    うーん。問題は簡単ではない気がしてきた。
    記録されているのは飽くまでその状態に初めてなった時にどの位置にカーソルが居たかである。
    従って、変更直前にどの位置にカーソルがいたかは記録されていない。
    寧ろ、変更直後のカーソル位置が記録されている。

    a なので次に記録されている entry の index から変更位置を探る必要がある。

    b しかし、もっとよく分からないのは一気に複数の変更だけ戻した時にどのように振る舞うべきかである。
      各ステップの diff を追跡するべきなのだろうか。
      もし厳密にやろうとするとそういう事になるはずである。うーん。

    c 或いは、戻す直前のカーソル位置に一番近い位置になるように common-prefix/suffix を切るという手。

    試しに現在位置と記録位置を境界として、それらより前の部分の先頭一致と、
    それらより後の部分の末尾一致を分離してから、改めて先頭一致と末尾一致を取り出す様にしてみた。
    しかし、記録位置は最初にその状態になってからの一致だったので、変な位置になってしまう。

      ble/string#common-prefix "${_ble_edit_str::_ble_edit_ind}" "${str::ind}"; local p1=${#ret}
      ble/string#common-suffix "${_ble_edit_str:_ble_edit_ind}" "${str:ind}"; local s1=${#ret}
      local substr1=${_ble_edit_str:p1:${#_ble_edit_str}-p1-s1}
      local substr2=${str:p1:${#str}-p1-s1}
      ble/string#common-prefix "$substr1" "$substr2"; local p2=${#ret}
      ble/string#common-suffix "${substr1:p2}" "${substr2:p2}"; local s2=${#ret}
      local beg=$((p1+p2)) end0=$((${#_ble_edit_str}-s1-s2)) end=$((${#str}-s1-s2))
      ble-edit/content/replace "$beg" "$end0" "${str:beg:end-beg}"

    記録位置を使わない様に実装し直してみる事にする。
    これは結構いい感じに動いている様な気がする。
    追記された時のカーソル位置は末端の方が嬉しいのでその様に修正した。

      ble/string#common-suffix "${_ble_edit_str:_ble_edit_ind}" "$str"; local s1=${#ret}
      ble/string#common-prefix "${_ble_edit_str::_ble_edit_ind}" "${str::${#str}-s1}"; local p1=${#ret}
      local substr1=${_ble_edit_str:p1:${#_ble_edit_str}-p1-s1}
      local substr2=${str:p1:${#str}-p1-s1}
      ble/string#common-suffix "$substr1" "$substr2"; local s2=${#ret}
      ble/string#common-prefix "${substr1::${#substr1}-s2}" "${substr2::${#substr2}-s2}"; local p2=${#ret}
      local beg=$((p1+p2)) end0=$((${#_ble_edit_str}-s1-s2)) end=$((${#str}-s1-s2))
      ble-edit/content/replace "$beg" "$end0" "${str:beg:end-beg}"

    更にコードを整理する。

2019-01-11

  * 2019-01-09 確認: set -o posix で ble-detach, ble-attach しても動くのだろうか [#D0876]
    →確認した所 ble-attach の冒頭で adjust を実行しているので問題ないはずである。
    これについては後で確認することにする。

  * reload: ユーザ設定の保持 [#D0875]

    * ok: bleopt 変数に関しては問題ない。

    * done: 構文着色の設定
      ble-color-defface は既に定義されている face の設定は上書きしない。
      つまり defface の引数は既定値として解釈する。

    * done: ble-sabbrev の設定

    * reject: ble-bind に関してはどうしようもない。
      そもそも編集関数も更新の対象なので全く更新しないという訳にも行かない。

    * done: blerc を再度読み込む等の方法を取らなければならない気がする。
      →特に rcfile が指定されない場合は前回使った rcfile を使う様にする。
      また rcfile の規定値として ~/.blerc を読み込む事にした。

    結局 blerc を自動で読み込む様にしたので、
    ユーザ設定の保持についてはそれほど気にしなくても良いような気がする。

  * 2019-01-01 アップデート機能? [#D0874]

    現在アップデートは git pull して make して make install する、
    という様に実行する必要がある。git の事などよく分かっていない人にはこれは難しい。
    ビルドしたディレクトリ及び使った INSDIR を覚えておく
    (INSDIR は単に _ble_base から算出すれば良い様な気がする)。
    - もしビルドしたディレクトリが存在していなければ新しく git clone する。
    - git や make や gawk が入っていない場合にはアップデートできない。

    或いは自動アップデート機能すらあっても良いのかもしれない。
    idle に登録しておいて勝手に background で実行するという事。

    取り敢えず ble-update というコマンドを作成してみた。
    動いてはいる。しかし、ble-update としても現在のセッションがアップデートされる訳ではなくて、
    次に実行した時に反映されるだけである。これは分かりにくい。
    やはり複数回 source する事ができるようにするべきだろうか。

    [ble.sh の reload に関する議論]

    | * 自動リロード: アップデート前のバージョンに対する依存性
    |
    |   | その時、関数内からソースする時はグローバルな連想配列を新しく宣言する事ができない。
    |   | 元々グローバルな連想配列が存在していれば良いが、
    |   | 連想配列のそれぞれについて元から存在しているかどうかは、
    |   | update 前の ble.sh のバージョンにも依存するので臨機応変に対応するのは難しい。
    |   | 結局 ble.sh を完全に unload してそれから reload するという様な方法を取るようにしないと、
    |   | バージョン間の差異や相性などに対応することができなくなる。
    |
    |   完全に unload してそれから reload するという様にする。
    |
    | * 自動リロード: ユーザ設定の継承
    |
    |   | 一方で、ble-bind や ble-sabbrev や ble-color-setface などの設定はどうなるのか。
    |   | ble.sh を reload すると完全にクリアされてしまうのだろうか。
    |   | 内部形式が変更される可能性なども考えると完全にクリアされる仕様にするしかないのか。
    |   | しかし ble-update しただけで設定が消滅してしまうというのも悲しいことである。
    |
    |   その様に考えれば幾つかの設定項目に関しては、内部形式のバージョンを定義し、
    |   内部形式の更新があればそれに応じて設定を書き換えるという仕組みが必要になる。
    |
    | 因みにリロードに関する議論は以前にもあったが棄却されている (#D0685)
    | 其処での考察では Bash 3.0 の C-d 受信用の子プロセスの削除、
    | 及び、stdout/on stdout/off などの状態についての考察があった。
    | 更に、ble.sh が特別の用途で使っている fd についても閉じる様にした方が良いのではないか。
    |
    | * openat を用いて開いた fd は抜ける時に全て閉じるようにする。
    |   openat の内部で実際に開いた fd の番号を記録しておくことにする。
    |   また exec による新しい fd は全て openat 経由で開く事にした。
    |   これにより fd が重複したりするのを防ぐ。
    |
    |   x openat でユーザが開いた物を勝手に閉じたら都合が悪いのではないか。
    |     ユーザが開いた物ではなくても、update 時に保持しておきたい fd はないのか。
    |     これは openat の呼び出し元を一つ一つ確認する必要がある。
    |     初期化時に開くような種類の物であれば問題はない。
    |
    | * Bash 3 の C-d 受信のためのプロセスは openat で開かれた fd 経由で通信している。
    |   試しに該当する fd を exec 32>&- として閉じてみたら受信のためのプロセスは終了した。
    |   つまり、上記の openat に対する処置で自動的にこちらもちゃんと unload される事になる。
    |
    | * stdout/{on,off} の状態や端末の状態に関しては
    |
    |   | ble-detach した上でリロードすれば良い。
    |   | 但し、ble-detach は detach の予約をするだけなので…
    |   | 具体的にはどの関数であろうか。
    |   | .check-detach まで呼び出してしまわなければならないのか。
    |   | うーん。或いは…ble-detach を実行して、更にその後で…。
    |   | たぶん、.check-detach でリロードを実行する機能を追加すれば良い。
    |   |
    |   | リロードが起こる状況には二種類ある。
    |   | 手で source ble.sh を実行した時。
    |   | それから ble-update を実行した時。
    |   | 更にそれぞれ ble attach 中かそうでないかという状態が存在する。
    |   |
    |   | attach 中は、その場で ble.sh を source するのは難しいのではないか。
    |   | source するべき ble.sh の位置を覚えておいて、
    |   | それを .check-detach の中で source するようにするか。
    |   |
    |   | detach している時は、その場で ble.sh を source してしまった良いものだろうか。
    |   | ble.sh のロード時に既に ble.sh がロードされて detach 状態である事を検出して、
    |   | その時に、色々の後始末をする処理を実行する様にすれば良い。
    |
    |   整理すると。
    |
    |   source ble.sh をした時点で  ble.sh の冒頭で、
    |   既に ble.sh がロードされている事を検出して、
    |
    |   a attach している場合には .check-detach でリロードする予約をして取り敢えず抜ける。
    |     .check-detach の中では ble.sh のアンロード処理を実行して、
    |     その上で改めて ble.sh を呼び出す事にする。
    |   b detach している場合には、中でアンロード処理を実行して
    |     ble.sh の続きを実行すれば良い。
    |
    |   何れの場合でも「アンロード処理」を実装すれば使い回せる。
    |
    | * trap '...' EXIT で実行されるべき操作はしなくてよいのか?
    |   ble/term/TRAPEXIT の中では stty の調整、一時ファイルの削除など、色々やっている。
    |   これは呼び出しておいた方が良い様な気がする。
    |
    |   更に言うと ble/term/TRAPEXIT の中を見ると _ble_base_run の処理もここでやっている。
    |   これは unload という関数でも用意してそれを EXIT に登録するべきなのではあるまいか。

    [まとめ]

    - 完全に unload してから ble.sh を再度読み込むことにする。
    - ユーザ設定の継承は改めて行う必要がある
      (特に ble-bind に関しては議論が必要である)。
    - unload で必要なのは特に detach することと openat で開いた物を閉じること。
      既存の ble/term/TRAPEXIT の関数を実行すること。
    - %%detach は .check-detach 経由で実行する必要がある。%%→これは棄却

    [実装]

    * done: ble/term/TRAPEXIT の処理を ble/base/unload 関数に移行する。
    * done: ble/base/unload にその他のアンロード処理を実装する。
      特にopenat で開いた fd を閉じる

    * reject: .check-detach に reload 機能を追加する

      試しに強制的に呼び出してみた所、遅延ロード関数が全部駄目になっている…。
      うーん。何が起こっているかと言うと…遅延ロード様に関数が上書きされて、
      遅延ロード用関数はファイルを読み込もうとするが、
      遅延ファイルは既に実行されたと思ってスキップするという事だろうか…。

      % 取り敢えず autoload において既に関数が存在している場合には何もしないようにした。
      % しかし、それでも色々の物が動いていない。
      % →autoload はやはり関数を上書きするべきである。
      %   問題は autoload ではなくて ble-import の読み込み済みの
      %   ファイルのキャッシュが残っていた事にあった。

      先ず構文着色が動いていない。予測補完も動いていない。うーん。
      取り敢えずこれらについては後で対処する事にすれば良さそうである。

    x done: .check-detach 経由の reload は実行順序が保たれず問題が起こる

      うーん。.check-detach 経由で unload する様にすると
      source ble.sh 前後の処理との順番が入れ替わってしまう為に変な事になる。
      やはりその場で detach/unload/source して何事もなかったかの様に継続できないだろうか。
      その様にしてみたら ble.sh attach 直後に epilogue が実行されて
      PS1 やその他の端末の状態がおかしくなってしまった。

      というか ble-detach; ble-attach した時にも同様の問題が起こるのではないか?
      →試してみたら再現した。従って、それも考えてちゃんと実装する必要がある。
      (しかし何故再現するのか今ひとつよく分からない。ble-detach を実行しても
      その場では detach されなかったはずである…。)
      うーん。実装を確認したら _ble_attached の値でガードしているが、
      ble-detach がその場で処理を実行しないために色々変な事になっている。
      _ble_attached の値は ble-detach の中ではなくて .check-detach の方で設定するべきである。

      a 一つの方法は eval-epilogue を抑制する機能をつけること。
        しかしどの様な条件で抑制するのだろうか。
        source ble.sh して ble-attach した時? 何だかよく分からない。
      b 或いは PS1 の設定のinternal/externalの状態を記録して退避を行うという事。
        というのも eval-epilogue を観察すると、その他の物については
        既に internal/external の記録をしているか二重に実行しても問題ないものばかりの気がするからである。

      * done: PS1 の二重退避は解決した。
      * done: ble-detach/ble-attach の _ble_attached= の管理はどうするか。

        やはり ble-detach; ble-attach の実行は自然になって欲しい。
        すると ble-detach で flag は設定したけれど未だ実際には detach していない、
        という様な状態の時には ble-attach は単に flag を削除するだけにするという手がある。
        →その様に実装したら実際に良さそうである。動いている。

    * done: 直接 source ble.sh できる様にする。
    * done: ble-update で最後に source する様にする。

    [現状の問題点]

    | * 構文着色が無効になっている
    |
    |   調べてみると ble-color/faces/initialize が呼び出されていない。
    |   というかそもそも構文着色の処理が呼び出されていない様な。
    |   試しに source $_ble_base/lib/core-syntax.sh を実行してみたら着色が有効になった。
    |   これはつまり単に core-syntax が呼び出されていないのが原因だった。
    |
    |   しかし、補完や help を実行しても core-syntax.sh が呼び出されないのは何故だろう…。
    |   と思ったが、よく考えたらこれは autoload で上書きを防ぐようにしたのが問題である。
    |   そもそも reload したのだから上書きするべきなのではないだろうか。。
    |
    | * ble_debug=1 として見たが何も表示されない…何事だろう。

    * done: ble-import を修正したら呆気なく動く様になった。

    * done: ble-edit/bind/load-keymap-definition:$defmap も unload 時に clear する事にした。

    未だユーザ設定の保持については実装していないが、また複雑になりそうなので、
    取り敢えずは commit して確定する事にする。

2019-01-08

  * 2019-01-04 "bash -i -c command" などとして起動した時に、コマンドの実行結果が出力されない [#D0873]

    そもそもコマンドを実行するのに -i を指定する必要があるのかという問題もあるが、
    その様な事が可能である (例えば interactive session の起動時間を測る目的などで)
    という事なので考察しておく必要はあるように思う。

    実行結果が出力されないのは bashrc を呼び出して以降プロンプトが表示されるまで
    の間にコマンドが実行されるからである。ble.sh の場合にはその間は出力を抑制する
    為にコマンドの出力結果は表示されない。

    [実装方法]

    もし bash -i -c command とした時にそのまま終了せずに対話状態になるのであれば、
    始めのコマンドの実行時またはユーザ入力時に抑制された内容を調べて
    それを標準出力へ流すことも可能だが、実際にはそのまま終了してしまうのでその機会はない。

    代わりに bash -i -c command の形式で起動されたことを検出して、
    その場合には ble.sh をロードしない様にすることは可能なのだろうか。
    例えば bash の環境変数またはシェル変数に引数が入っていればそれを解析できるだろうか。
    試しに実行してみた所、以下のように BASH_EXECUTION_STRING なる変数が設定されている事が判明した。

    $ bash -i -c 'set | grep fasdf >/dev/tty'
    BASH_EXECUTION_STRING='set | grep fasdf >/dev/tty'

    この変数は通常の起動の仕方をした時にはそもそも存在していないようだ。
    この変数 BASH_EXECUTION_STRING が導入されたのは Bash 3.0 の様なので問題ない。

    [実装]

    BASH_EXECUTION_STRING が設定されている時は ble.sh をそのまま抜ける事にした。

  * 2018-09-26 実は set -o posix に対する制限は外せる気がする [#D0872]
    但し、posix に対しても ble を実行するべきなのかという問題はある。
    起動時にはチェックするけれども、
    実行中に変更された場合には対応するという方針でも良い気がする。

    % _ble_edit_bind_force_draw=1 も考慮に入れる必要がある。
    % →これは廃止したので気にしなくて良い。
    % 追記: 一応 #D0324 に導入の経緯の議論があった

    2019-01-08 調べてみると set -o posix を実行すると
    POSIXLY_CORRECT に y が入るし、
    POSIXLY_CORRECT が設定されていると [[ -o posix ]] が有効になるようだ。
    つまり変数 POSIXLY_CORRECT だけ観察していれば対応できた事になるのではないか。
    つまり現在の実装で殆ど対応できているような気がする。

    問題は adjust-POSIXLY_CORRECT のタイミング?
    最後に restore して ble.sh を抜けて、
    いざ attach する時に adjust-POSIXLY_CORRECT を実行するべきではなかろうか。

    {adjust,restore}-POSIXLY_CORRECT を連続して実行したりしても大丈夫な設計になっていただろうか。
    見た感じだとなっていない気がする…。呼び出し元を観察すると必ずペアになっているので、
    単にそのような状況を想定していなかったのだろう。しかし、何かトラブルなどがあったりすると、
    ペアにならなかったりするので本当はちゃんと現在の状態 (adjusted/restored) を記録する必要がある。

  * POSIXLY_CORRECT=y でコマンドを実行すると unset : でエラーメッセージが出る [#D0871]
    このエラーメッセージは殺しても良いのではないか。
    というよりエラーメッセージが出ないようにしたのではなかったか。

    ref #D0722

2019-01-01

  * 2018-10-03 complete: "type" の補完指定が効いていない [#D0870]
    ref #D0714 #M0009

    調べると complete -c type になっている。
    調べたら compv_quoted で '' の中に名前を指定すると駄目の様だ。
    これについては一度確認したような気がするが、その時はどのような結論になったのだったか。

    #M0009 に記録が残っている。-A command,directory,file は駄目だそうだ。
    これは command,directory,file が補完に含まれる時にはクォートしないという方法を取る事にした。
    他の種類の補完候補が含まれている場合やチルダが含まれている時に問題になるかもしれないが仕方がない。

  * [自然解消] vi: operator d の特殊ルールは v で適用されるのか? [#D0869]

    % 少し動かしたら適用されている様な…。後で確認する必要がある。

    2018-12-26 operator d の特殊ルールとは何だったか。。
    うーん。これは ble/keymap:vi/operator:d の charwise の箇所で
    実行されている処理のことのはずである。

    * o_v で適用されるか

      % 試しに動かしてみる。
      % | AAAAAAAA$
      % |     echo$
      % | world   $
      % | BBBBBBBB$
      %
      % vim, blesh: e の位置で d2e とすると2行消える。
      % vim: e の位置で dv2e とすると echo\nworl が削除される。
      % blesh: e の位置で dv2e とすると echo\nworld が削除される。
      % つまり、operator d の特殊ルールは適用されなくなるが、
      % そもそも v の時の適用範囲が誤っている…。
      %
      % % これは実は xmap のルーチンを流用して来た方が正しいのかもしれない…。
      % % と思って xmap の時の処理を確認したら
      % % 処理は ble/widget/vi-command/operator で行われていて、
      % % 寧ろ処理の範囲は縮小されるのではなくて拡張されていた…。逆である。
      % % なので xmap は恐らく o_v の動作には関係ない。
      %
      % 寧ろ :help o_v の方に説明が書かれているかもしれない。
      % o_v の説明を読むと exclusive/inclusive を切り替えると書かれている…。

      o_v に関しては別に実装する事にした。
      inclusive/exclusive の切り替えもちゃんと実装したら動作は一致する様になった。

    * v (xmap/smap) で適用されるか

      | AAAAAAAA$
      |     echo$
      | world   $
      | BBBBBBBB$

      以上の e の位置で vjd とすると、vim でも ble.sh でも空白4つを残して他は消えた。
      どのような振る舞いになっているか考えるのは面倒だがちゃんと動いている。
      恐らく規則によって先頭の space 類は残したまま行指向になるのだろう。
      何れにしても既に一致した振る舞いになっているので気にしない事にする。

  * vi (omap `v`): dd や yy 等の場合にも omap v/V/C-v を適用する [#D0868]

    dd や yy などの時にも間に v や V 等挟んでも良いのだろうか。

    vim で試してみると dvd は行頭までの削除になって、
    dC-vd は現在位置から行頭までの削除 (inclusive) になる。
    dVd は同じ振る舞いである。
    しかし ble.sh では dvd 等と別の物が間に挟まっているとエラーになる。

    実装した。テストした。動いている。OK

  * vi (omap `v`): charwise の inclusive/exclusive を toggle する [#D0867]

    :help o_v によると元から charwise の時には
    inclusive/exclusive を切り替えるとの事。

    | さて問題は ble.sh の実装では全て exclusive と想定して
    | 実装しているという事である。
    | 従って、現在 inclusive なのか exclusive なのか、
    | 呼び出された側からは判定する事ができない。
    | 或いは、常に exclusive だと思って置けば良いのだろうか。
    | 改行が絡んでいる時にはどうしたら良いのだろうか…。
    |
    | 更に、inclusive/exclusive というのも opfunc 内に
    | 記録しなければならないという事になる。
    |
    | うーん。ble.sh における inclusive/exclusive に関する考察が
    | 何処かにあったような気がするがすぐには見つからない。
    | 取り敢えず #D0437 に多少の議論があるが、
    | もっと後に何か考察したような気がする。
    |
    | 改めて inclusive/exclusive について考える事にする。
    | exclusive-range.impl が charwise で呼び出される時の問題である。
    | というか exclusive-range.impl は元々 charwise で呼び出されるのであった。
    |
    | inclusive の物は数が限られているので inclusive である物を列挙する事にする。
    | $ (行末) g$ (表示上の行末) g_ (最後の非空白文字) fx tx (検索)
    | e E ge gE (単語末尾) % (括弧やコメント等の検索)
    | 取り敢えず https://vim-jp.org/vimdoc-ja/motion.html に載っているのはこれだけである。
    |
    | 一方で exclusive-linewise の判定ではどのようにしているのか。
    | exclusive-linewise は exclusive の時にだけ有効になる筈なのではないか。
    | どのように判定しているのか。exclusive-linewise で検索すると、
    | #D0565 で exclusive-linewise が実装されていて、
    | その記述によると exclusive は exclusive-goto.impl -> exclusive-range.impl と呼び出され、
    | inclusive は inclusive-goto.impl -> exclusive-range.impl と呼びされるので、
    | exclusive-linewise は exclusive-goto.impl で実装すれば良いとのこと。
    | 実際に確認してみるとその様になっている。
    |
    | とすれば…inclusive-goto.impl で書き換えれば良いという事になる。
    | 本当だろうか。一応上記の inclusive なコマンドがどの様に実装されているかを確認していく。
    | - $ 及び g$ と g_ ... 確かに inclusive-goto.impl を呼び出している。
    | - fx 及び tx に関しても確かに inclusive-goto.impl を呼び出している。
    | - e E ge gE についても inclusive-goto.impl を呼び出している。
    | - % (search-matchpair-or) も inclusive-goto.impl を呼び出している。

    結論: ble.sh の実装では exclusive な motion は、
      exclusive-goto.impl -> exclusive-range.impl で呼び出される。
      inclusive な motion は
      inclusive-goto.impl -> exclusive-range.impl で呼び出される。
      従って exclusive/inclusive 毎の操作は
      exclusive/inclusive-goto.impl で実装する事になる。
      現に exclusive-linewise の機能は exclusive-goto.impl の中で実装されている。

      これについては #M0011 に記録を残して置く事にする。

    | v に対して opfunc 内で偶奇性を保持する様に修正すれば toggle はできる。
    | さて、問題は修正をどの場所で行うのかという事になる。
    | inclusive の時にも exclusive の時にも修正を行う必要がある。
    | そして exclusive-range.impl の呼び出し元は実は
    | exclusive/inclusive-goto.impl だけではなくて沢山ある。
    | うーん。実は exclusive-range.impl 側で処理した方が良いのではないか。
    | inclusive の時だけは元々 inclusive な motion であるという情報を
    | exclusive-range.impl に何らかの方法で伝達する必要がある。
    |
    | うーん。第5引数に nobell を受け取っているがこれを opts に変更できないだろうか。
    | 使用箇所を確認してみると2箇所でしか nobell は指定していない。
    | そしてそれは exclusive-goto.impl 及び inclusive-goto.impl である。
    | これらを検索するとこれは呼び出し時に確定している様子である。
    | 従って、nobell を指定する様に変更してしまって良いだろう。
    | →opts に変更する事にした。

    結論: exclusive-range.impl の第5引数を nobell から opts に拡張する事にする。
      これを通して exclusive-range.impl に inclusive を伝達する事にする。

    * vim における exclusive/inclusive の動作について確認する。
      Fh で後退した場合に起点 (終端点) は inclusive に変換されるのか。
      実際に vim で試してみた所 g~Fh では起点は作用対象にならない (exclusive) だが、
      g~vFh とすると起点も作用対象になった (inclusive)。
      つまり、exclusive/inclusive の別は行き先に対して実行されるのではなくて、
      飽くまで範囲の終端点に対して実行されるのである。

    [実装]

    - done: v に対して偶奇を保持する様に修正
    - done: exclusive-range.impl の第5引数に opts を受け取る様に修正
    - done: exclusive-range.impl に於いて vi_char1 の時は exclusive/inclusive を反転する

    [動作確認]

    x fixed: vim の動作を調べてみた所…toggle すると書いてあったが、
      v を押す度に反転するという訳ではなくて、
      v を一回でも押したら反転したものになって、それ以降は変わらない様だ。
      つまり vi_char の偶奇性を判定する必要は全くなかった。
      偶奇のコードは削除する事にした。

    o linewise の時の動作は正しいか。例えば g~vj でどう振る舞うべきか。
      vim でどう動くか試してみる。→ exclusive である。g~vvj としても同じ。
      ble.sh の現在の実装での振る舞いもちゃんと一致している。OK

  * vi (omap `v`): linewise-range.impl の時も charwise/blockwise に変換する [#D0866]

    g?j などは linewise-range で呼び出されるが、
    その時でも exclusive charwise に変換するとの事。

    こちらの方が対処が簡単そうなので先に処理する事にする。

    実装を調べてみるとよく分からない事が出てくる。
    linewise-range で charwise/blockwise とする時、
    終点と始点はどの様にしたら良いのだろうか。
    例えば現在の処理の通りに行頭と行末にしてしまうと、
    結局 linewise と同じになってしまう。
    しかし実際に vim でやってみると j の時には、
    その移動先までという事になっている。
    また vim + でやってみると行頭までという事の様だ。
    もっとちゃんと調べると非空白行頭になっている。

    * ok: もう一つ気付いたのは C-v の時、
      開始位置を inclusive に含むという事である。
      しかし、これは実のところ普通の xmap の振る舞いと同じではある。
      調べてみると extract-block がちゃんと inclusive に右端を拡張する様になっている
      様子なのでこれについては気にしなくても良い。
      最後に実装が終わってから期待した動作になっているかを確認すれば良い。

    現在の実装ではオペレータがある時には、
    どの行移動についても同じ様に処理してしまっているが、
    実際の所は移動のそれぞれについてオペレータの動作も異なるという事。

    どの様に実装するのが正しいのだろうか。
    行き先を決定してから call-operator-linewise に渡すのが良いのか。
    これは linewise-range.impl を利用している複数の機能について調べて
    最も都合の良い方法を選択する必要がある。

    a 一つの方法は relative-line.impl の側で flag を見て、
      もし char/block だった場合にはそちら側で処理してしまうという方法である。
    b もう一つの方法は何れにしても relative-line.impl の側で
      位置を決定してから linewise-range.impl を呼び出すという物である。
    c 或いは、linewise-range.impl の中から
      relative-line.impl を呼び出して位置を決めるという手もある。
    d というか relative-line.impl の位置を決定するコードだけ分離すれば良い。

    取り敢えず d の方法が良い様な気がする。
    実際にこの方法を取らないとしてもコードの整理として、
    relative-line.impl の行き先を決定する関数はあって良い気がする。

    [実装]

    1 done: relative-line.impl の行き先を決定する関数の抽出
      と思ったが微妙である。relative-line の場合には、
      移動先の行がない場合 (最終行または第1行を超えて移動しようとする時) には、
      はみ出た行数の分だけ履歴行を移動する。はみ出た行数の計算を
      行き先を決定する関数の内部で実行している。
      初めに行数を数えてから行き先の計算を実行する様に変更したい。
      →取り敢えず実装した
    2 done: linewise-range.impl の実装
      relative-line.impl ではなくて先の項目で作成した
      get-index-of-relative-line という関数を使う様に修正した。
      更に charwise/blockwise の時の範囲の計算も適切に実装した。

    [動作確認]

    x fixed: jk などの relative-line.impl の動作がおかしくなっていないか。
      →見事に動かなくなっている。確認する必要がある。
      一箇所直した。j は動く様になった。しかし k が動かない。
      →もう一箇所直した。取り敢えずちゃんと動いている。

    x fixed: guvj 等が動作するか。
      動かない…次の行頭までになっている。
      →これも簡単なミスだった。修正した。

    o C-v の時右端が inclusive になっているか。
      これはちゃんと動いた。


2018-12-31

  * 2018-10-08 vi (omap v): o_v o_V に対応する? [#D0865]
    オペレータの振る舞いに影響を与える。
    詳しくは help o_v と help o_V を参照すれば良い。
    オペレータ d の charwise の時の特別な振る舞いも無効化する。

    実際に試してみて分かった振る舞いについて以下にまとめる。
    - omap C-v も効いている。
    - omap v, V, C-v を実行しても表示は変わらない。

    [実装方針に対する考察]

    現在の状態をどのように保持するのが良いのかという考察。

    | どの様に実装するのか。
    | ble/keymap:vi/operator を見る。omap の時にはそもそも operator は呼び出されない。
    | nmap で operator が呼び出されると opfunc が設定されて、
    | それを元にして移動などが起こった時に実際の動作に入るのである。
    | そして、コメントを見ると恐らく opfunc と同等の変数として新しく opmark をつける予定だった。
    |
    | 他の実装方法はないのだろうか。というのも opfunc や oparg と同様に実装すると、
    | また新しく変数を追加する事になってしまい、管理がまた大変になりそうだからである。
    |
    | a opfunc に付加する形にするのは難しい。というのも opfunc は二文字以上も可能にしているから。
    |   一応 opfunc に使える文字の種類を限定して : で区切って付加情報も記録できる様にする事も可能かもしれないが、
    |   それはそれで大変である。
    | b では oparg に記録する事は可能だろうか。
    |   oparg はそのまま _ble_edit_arg をコピーする事によって値が設定されている。
    |   また、記録していた物を再生する時には ARG がそのまま _ble_keymap_vi_optarg に設定されている。
    |   やはり面倒そうな気がする。もし oparg に記録するとしても ARG に情報を伝達すると、
    |   ARG を整数として扱っている数々の関数で問題が起こる事になる。
    |   何れにしても ARG FLAG REG に新しい変数を追加するか、
    |   或いは ARG FLAG REG とは別に local _ble_keymap_vi_opmark なる変数を用意して、
    |   それを経由して値を伝達するという事になる気がする。
    | c 新しく変数を作成するとしたら oparg と並列になる様に変数を作成すれば良い様な気がする。
    |   しかし、その時に ARG FLAG REG の3変数に更に新しい変数を追加する事になるのだろうか。。
    |   或いはグローバルの変数を経由して operator を呼び出せば良いのだろうか。
    |   グローバルの変数を経由して呼び出す場合には入れ子で operator を呼び出した時にどうなるのか。
    |   (というかそもそも入れ子で operator を呼び出すという事があるのかどうかも分からないが…)
    |
    | うーん。色々考えてみると実は opfunc/FLAG の中に情報を格納する方針の方が良い様な気がしてきた。
    | opfunc 及び FLAG はどの様に使われているだろうか。
    | 使用方法を調べてみると FLAG は上に伝達する時にしか使われていない気がする。

    結論: 取り敢えず opfunc 及び FLAG を拡張する方向で考えてみる事にする。

    opfunc/FLAG を拡張するという方針で問題がないかの考察。

    | done: FLAG を渡されている関数は以下の通りである。
    |
    |   - ble/keymap:vi/text-object.impl "$ARG" "$FLAG" "$REG" "$type"
    |     これは辿っていくと (flag が使用される場合には) 何れも以下の何れかに帰着する。
    |     -> ble/widget/vi-command/exclusive-range.impl "$beg" "$end" "$flag" "$reg"
    |     -> ble/widget/vi-command/linewise-range.impl "$beg" "$end" "$flag" "$reg" goto_bol
    |   - ble/widget/vi-command/backward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
    |     -> ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg"
    |   - ble/widget/vi-command/backward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
    |     -> ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
    |   - ble/widget/vi-command/forward-word-end.impl "$ARG" "$FLAG" "$REG" "$_ble_keymap_vi_REX_WORD"
    |     -> ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg"
    |   - ble/widget/vi-command/forward-word.impl "$ARG" "$FLAG" "$REG" $'[^ \t\n]+'
    |     -> ble/widget/vi-command/inclusive-goto.impl "$index" "$flag" "$reg"
    |     -> ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
    |   - ble/widget/vi-command/goto-mark.impl "$index" "$FLAG" "$REG" "$opts"
    |     -> ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg"
    |     -> ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg" 1
    |   - ble/widget/vi-command/graphical-relative-line.impl "$ARG" "$FLAG" "$REG"
    |     -> ble/widget/vi-command/exclusive-goto.impl "$index" "$flag" "$reg"
    |   - ble/widget/vi-command/relative-first-non-space.impl 0 "$FLAG" "$REG" charwise
    |     -> ble/widget/vi-command/exclusive-goto.impl "$nolx" "$flag" "$reg" 1
    |     -> ble/widget/vi-command/linewise-goto.impl "$nolx" "$flag" "$reg" require_multiline:bolx="$bolx":nolx="$nolx"
    |   - ble/widget/vi-command/relative-line.impl $((-ARG)) "$FLAG" "$REG" history
    |     -> ble/widget/vi-command/linewise-goto.impl "$_ble_edit_ind:$offset" "$flag" "$reg" preserve_column:require_multiline
    |
    |   結局諸々の関数の呼び出しは以下の関数に帰着するようにである。
    |
    |   - ble/widget/vi-command/exclusive-goto.impl "$beg" "$FLAG" "$REG" 1
    |     -> ble/widget/vi-command/linewise-goto.impl "$index" "$flag" "$reg"
    |     -> ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$nobell"
    |   - ble/widget/vi-command/inclusive-goto.impl "$index" "$FLAG" "$REG" 1
    |     -> ble/widget/vi-command/exclusive-range.impl "$_ble_edit_ind" "$index" "$flag" "$reg" "$nobell"
    |   - ble/widget/vi-command/linewise-goto.impl 0:$((iline-1)) "$FLAG" "$REG"
    |     -> ble/widget/vi-command/linewise-range.impl "$_ble_edit_ind" "$@"
    |
    |   更に以下の関数に委譲されている。
    |
    |   - ble/widget/vi-command/linewise-range.impl
    |
    |     | ((end<${#_ble_edit_str}&&end++))
    |     | if ! ble/is-function ble/keymap:vi/operator:"$flag"; then
    |     |   ble/widget/vi-command/bell
    |     |   return 1
    |     | fi
    |     |
    |     | # オペレータ呼び出し
    |     | ble/keymap:vi/call-operator "$flag" "$beg" "$end" line '' "$reg"; local ext=$?
    |     | if ((ext)); then
    |     |   ((ext==148)) && return 148
    |     |   ble/widget/vi-command/bell
    |     |   return "$ext"
    |     | fi
    |
    |     主に以上の箇所 $flag で使用されている。
    |     先ず初めに operator:$flag に関しては修正が必要である。
    |     後ろの方で $flag == [cd] という判定があるこれも修正が必要である。
    |     更に良く考えてみるとこの関数は linewise の関数なので、
    |     flag に charwise や blockwise が設定されていたとしても
    |     linewise として処理を実行しなければならないのではないか。
    |
    |     call-operator の実装について確認しておく事にする。
    |     call-operator の実装では第一引数をそのまま vi/operator:$1 の様に呼び出すのに使っている。
    |     つまり、何れにしても operator 名で呼び出さなければならないのである。
    |     また、linewise-range から call-operator-linewise を呼び出すのではなくて、
    |     直接に call-operator を呼び出しているのは、呼び出し元で行指向にする処理をしているからである。
    |
    |     従ってこの部分は単に演算子名にすれば良いのである。
    |
    |   - ble/widget/vi-command/exclusive-range.impl
    |     これは以下の箇所で使われているのみである。
    |
    |     | ble/keymap:vi/call-operator-charwise "$flag" "$src" "$dst" '' "$reg"; local ext=$?
    |
    |     さて今から実行しようとしている事は何かというと、
    |     この call-operator-charwise を現在記録されている矩形の種類に置き換えるという事である。
    |
    | ok: その他の FLAG の気になる使い方をしている箇所は以下の通りである。
    |
    | - ./keymap/vi.sh:2381:    if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:2576:    if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
    | - ./keymap/vi.sh:2601:    if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
    | - ./keymap/vi.sh:3380:  [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
    | - ./keymap/vi.sh:3386:  [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
    | - ./keymap/vi.sh:3393:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:3418:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:3444:  [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
    | - ./keymap/vi.sh:3765:  [[ $FLAG ]] || ble/keymap:vi/mark/set-jump # ``
    | - ./keymap/vi.sh:4764:  if [[ $FLAG || $_ble_decode_keymap == vi_[xs]map ]]; then
    | - ./keymap/vi.sh:4777:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:5833:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:5893:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:6013:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:6096:  if [[ $FLAG ]]; then
    | - ./keymap/vi.sh:6518:  if [[ $FLAG ]]; then
    |   これらは基本的に FLAG に opname が指定されているかどうかだけを確認している。
    |   opfunc を拡張するとしても既に何か設定されている時にのみ ~wise を付加するのだから関係ない。
    |   問題は具体的に値を使って何かを実行する時だけのはずである。なのでこれらは気にしなくて良い。
    |
    | - ./lib/vim-surround.sh:690:  local WIDGET=ble/widget/vim-surround.sh/nmap/csurround.repeat ARG=$arg FLAG= REG=$reg
    |   これは FLAG を空にするという動作であって、
    |   ~wise は FLAG が非空の時にのみ意味があるのでこれで良いのである。
    |
    | - ./keymap/vi.sh:649:   FLAG=$_ble_keymap_vi_opfunc
    | - ./keymap/vi.sh:3399:    _ble_keymap_vi_opfunc=$FLAG
    | - ./keymap/vi.sh:3419:    _ble_keymap_vi_opfunc=$FLAG
    | - ./keymap/vi.sh:3724:    _ble_keymap_vi_opfunc=$FLAG
    |   opfunc と FLAG は一致する扱いとすればこれで良い。
    |
    | - ./keymap/vi.sh:2469:  local -a repeat; repeat=("$KEYMAP" "${KEYS[*]-}" "$WIDGET" "$ARG" "$FLAG" "$REG" '')
    |   つまり 4 番目の要素に FLAG が格納される。調べてみるとこれが実際に使われるのは
    |   ./keymap/vi.sh:2531:  _ble_keymap_vi_opfunc=${_ble_keymap_vi_repeat[4]}
    |   という箇所のみであり、これも opfunc と FLAG が一致しているという前提の下で気にしなくて良い。
    |
    | 2018-12-31 少し時間を置いたら分からなくなった。今の状況を整理する事にする。結局、
    | 1. FLAG が空文字列かどうかを判定している箇所は、FLAG の内容の形式が変更されても問題はない
    | 2. FLAG の内容を記録している部分についても、FLAG の内容の形式には関係ないので問題ない
    |   記録時に FLAG の内容によって動作が変わるなどのことはしていないので問題ない。
    |   　また、記録される内容も v だったか V だったか C-v だったかまで一緒に記録するのが自然に思われる。
    |   実際の vim の振る舞いがどちらなのかは確認していないけれども。
    |   しかし v/V/C-v を忘れて再生されるというのは不自然なので当然 vim でもその状態を記録しているはずである。
    | 3. その様に考えると実際に問題になるのは FLAG の中身を覗いているコードのみである。
    |   それについては未だ確認していない関数のリストがあるので一つずつ確認していく事にする。

    結論: 使用箇所で修正が必要なのは以下の二つの関数である。

      - ble/widget/vi-command/linewise-range.impl
      - ble/widget/vi-command/exclusive-range.impl

      $flag を operator 名とそれに付属するオプションに分離する。
      linewise-range ではオプション部分を無視して operator 名だけ使用するようにすれば良い。
      exclusive-range においてはオプションによって呼び出す charwise/linewise/blockwise を変更すれば良い。

    opfunc/FLAG の形式を決定する必要がある。

    | どの様な物が良いだろうか。既存の opfunc 名と被らない様にしたい。
    | そもそも opfunc は operator:opfunc の形式で呼び出すのだから、
    | ":" 区切りにするのが自然な気がする。
    | wiki の operator 設計の箇所ではどの様に書いただろうか。
    | 特に MyOperator を構成する文字列に対する制限は書かれていない。
    | 一応 MyOperator.record という関数を使っているので、
    | "." を含む事を可能にするのは不味いだろうというぐらいである。
    | 恐らく識別子として使える名前に制限しているつもりの気がする。
    | と思ったら既に surround-extract-region というのがある…。
    | まあ、然しそんなところだろう。
    | ":" を使うという事はない気がする。

    結論: /Operator(:options)?/ の形式という事にする。
      また Operator には ":" や "." を含んではいけない事にする。

    [実装]

    1 done: o_v o_V o_C-v の実装
    2 done: 使用箇所の修正

    取り敢えず動いている気がする。
    後は面倒なので不具合報告が出てきた時に対応する事にする。

2018-12-30

  * color (ble-color-setface): "face:..." による設定が正しく設定されない (reported by cmplstofB) [#D0864]
    https://github.com/akinomyoga/ble.sh/issues/20

    これは調べてみたところ ble-color-face2g 及び ble-color-iface2g の使い方を間違えていた。
    これは直した。

    * fixed: しかし、face2g/iface2g の呼び出しに失敗するだけで、
      後に沢山のエラーメッセージが出てくるのはこれはこれで別のバグである。
      調べてみると、単語着色に於いて g 値が空文字列になった時に、
      _ble_syntax_tree に記録されている項目がずれてしまう問題があった。
      そもそも _ble_syntax_tree に記録される項目は空白区切りの単語列なので、
      空の単語が記録されない様に注意する必要があった。これも直した。

    * ok: では何故 "echo" 等の時は問題にならないのに "[" の時は問題になるのか。
      更に bash のエラーメッセージに於いて "-" というのがコマンド名の如くに表示されているのは何か。
      cmplstofB さんのログによると tree-enumerate の中で起こっている様に見えるが解せない。
      % と思ったら分かった。tchild= だとか tprev= の右辺は算術式で計算されていて、
      % 算術式の中身に "[" が単体で存在していると問題になるのだ。
      % "echo" 等が単体で存在している場合にはそれは変数名と解釈されるので問題が起こらない。
      % と思ったがそれも不思議な話である。コマンド名は _ble_syntax_tree の内部に記録しない。
      更に表示されているエラーメッセージを見る限りは問題になっている要素の内容は "-" である。
      ずれてダミーで設定している "-" の値が算術式に渡されているのが原因である。

      もしかして echo と [ で着色の仕組みが異なる? と思ったが、
      最終的に echo も [ もちゃんと同じ色で着色されているので、
      やはり着色の過程は同じになっているような気がする。
      何が echo と [ の違いを生んでいるのだろう。　

      →ble_debug=1 で dump して -/wattr を表示する様にした所、
      実は echo の時には一つの単語であるが、
      "[" の時には普通のコマンドとしての単語の中に
      word="none":0-1 という単語が設定されているという事が分かった。
      そしてこれは glob の [...] の検知の為に設置されている物の筈である。

      つまり、特に何か問題があって "[" の時にだけ問題が発現したというよりは、
      同じ位置でネストされた word がある時にだけ発現するという、
      元々発現しにくい問題がたまたま "[" の時にようやく発現したという事である。
      なので、この動作の違いについては気にしなくても良いのである。

2018-12-17

  * syntax (filename_ls_colors): 実は coreutils ls は二重拡張子にも対応している [#D0863]

    * done: 二重拡張子には対応した。

    * ok: 拡張子以外のパターンには対応していない様である。

    * done: できるだけ長い拡張子から順番に試すという様に実装する必要がある?
      % →coreutils ls で試してみると長い拡張子から順番に試すのではなくて、
      %   LS_COLORS に登録されている物の内、一番始めにあるものが優先される。
      % と思ったら勘違いだった。coreutils ls でも最初にあるものではなくて、
      % 長いものの方が優先される様に見える。
      →これには対応した。

    * done: もう一つ確認しておきたいのは . から始まるファイルである。
      → . から始まるファイルも拡張子として取り扱われている。
      →対応した。

  * 2016-07-20 ファイル名の色付けに LS_COLORS を参照する? [#D0862]
    https://github.com/trapd00r/zsh-syntax-highlighting-filetypes

    ble.sh の枠組で使用する為には ble-color.sh/gflags に変換しなければならない。
    しかし、実際に使っている terminal と sequence が異なる場合に齟齬が生じる。
    従って直接 LS_COLORS を用いるよりは、bleopt_filename_ls_colors 的な変数に指定して貰う事にする。
    そのまま LS_COLORS を使用したい場合は bleopt_filename_ls_colors=$LS_COLORS などとする。
    展開を実行するようにする。

    2018-12-16 https://github.com/akinomyoga/ble.sh/issues/19 に関連して。
    意味は例えば http://www.bigsoft.co.uk/blog/2008/04/11/configuring-ls_colors に書かれている。

    | no  NORMAL, NORM  Global default, although everything should be something
    | fi  FILE  Normal file
    | di  DIR Directory
    | ln  SYMLINK, LINK, LNK  Symbolic link. If you set this to ‘target’ instead of a numerical value, the color is as for the file pointed to.
    | pi  FIFO, PIPE  Named pipe
    | do  DOOR  Door
    | bd  BLOCK, BLK  Block device
    | cd  CHAR, CHR Character device
    | or  ORPHAN  Symbolic link pointing to a non-existent file
    | so  SOCK  Socket
    | su  SETUID  File that is setuid (u+s)
    | sg  SETGID  File that is setgid (g+s)
    | tw  STICKY_OTHER_WRITABLE Directory that is sticky and other-writable (+t,o+w)
    | ow  OTHER_WRITABLE  Directory that is other-writable (o+w) and not sticky
    | st  STICKY  Directory with the sticky bit set (+t) and not other-writable
    | ex  EXEC  Executable file (i.e. has ‘x’ set in permissions)
    | mi  MISSING Non-existent file pointed to by a symbolic link (visible when you type ls -l)
    | lc  LEFTCODE, LEFT  Opening terminal code
    | rc  RIGHTCODE, RIGHT  Closing terminal code
    | ec  ENDCODE, END  Non-filename text
    | *.extension   Every file using this extension e.g. *.jpg
    |
    | mh  MULTIHARDLINK for "Regular file[s] with more than one link"
    | ca  CAPABILITY for "File with capability."
    | rs  ???? "Reset to ordinary colors"

    取り敢えず *.extension に関しては対応した。

    * ok: うーん。LS_COLORS の具体的な振る舞いが分からない。

      | ? 複数の項目が当てはまる場合には属性は合成されるのか、
      |   それともどれか一つだけが選択されるのか。
      |
      | 面倒なので coreutils を覗いてみる事にする。
      | 丁度 ~/local/build/coreutils-8.28 があったのでそれを見る。
      | 恐らく src/ls.c:4677: get_color_indicator (const struct fileinfo *f, bool symlink_target) である。
      | これを見る限りは、通常ファイルについて setuid, setgid, exec, multihardlink を順に試している。
      | またディレクトリについて other-writable/sticky を試している。

      順番に試して先に一致した着色を採用する様である。
      拡張子については通常ファイルの時
      (setuid, setgid, exec, multihardlink の何れも適用されない時) に適用される。

    * done: 更にファイルの種類について増やす?

      | - do       これはSolaris限定らしい
      | - or mi    or については対応可能である。
      | - su sg st Bash から setuid 及び setgid を判定する方法はあったか → -u -g -k だった。
      | - tw ow    Bash から other writable を判定する方法は無い気がする。
      | - lc rc ec これらは ble.sh では登場しないのではないか。

      これに関しては or su sg st について対応した。
      tw ow do については対応できない。
      lc rc ec は ble.sh では使わない。
      mi については着色はしない。

    * done: menu-complete で使う着色も core-syntax.sh の関数を呼び出して決める事にする。
      これは ble-syntax/highlight/getg-from-filename という関数で対応することにした。

    新しい機能名は以下の通り
    - bleopt:filename_ls_colors
    - face:filename_ls_colors
    - face:filename_orphan
    - face:filename_setuid
    - face:filename_setgid
    - face:filename_directory_sticky

    取り敢えず動作テストした。
    o 拡張子の着色
    o setuid setgid sticky orphan の着色の確認
      これは色を調整した。
    o menu-complete における着色

2018-12-16

  * color (ble/color/read-sgrspec): 色番号の対応が不完全なのでは [#D0861]
    #D0860 を取り敢えず実装したが色番号について考慮していなかった。

    端末の設定に基づいて読み取るのだから
    (1) 最初の 8 色もしくは 16 色に関しては
      _ble_term_sgr_{af,ab} を参照するようにする。
    (2) 88 色の場合には index color の翻訳を実行する

    | (1) に関してはどのように実装するのが良いだろうか。
    | _ble_term_sgr_af が単一の番号であれば、
    | その逆写像を作成すれば良いのではないだろうか。
    | →どうもちゃんと単一の番号になっている気がする。
    | と思ったが init-term.sh の実装を見る限りはそうとも限らない。
    | 単一の番号の時のみに限り解釈する事にした。
    |
    | 世の中には 1; や 5; との組み合わせで highlight color を表現する場合もあるが、
    | それらについては面倒なので対応しない事にする。

    →(1) については _ble_term_sgr_term2ansi という配列を使って、
    SGR値を読み取り時に ANSI の値に置き換えて解釈する事にした。

    | (2) に関しては数式を確認する必要がある。#D0824 の記録を見ると、
    |
    |   16-79 4x4x4 0,58*v+81
    |   80-87 gray 46+25*v
    |
    | となっている。6x6x6 に関してはどうだったろうか。
    | 0-255 は 5 等分にする事ができるので、等間隔なのだろう。
    |
    | 0.58*v+81 とはどういう事か。0, 81, 139, 197, 255 と考えると 5 段階になってしまう。
    | 或いは一番暗かったとしても 81 という事になるのだろうか。
    | うーん。6level->4level の変換は R=(R*3+2)/5 という数式で行っている。
    | もっと単純に考えて R=(R*5+o)/3 とすれば良いのだろうか。
    | というか4値を6値に割り当てるだけなので実際の明るさなどはどうでも良くて、
    | できるだけ区別が残る様にするのが正しいのであろう。
    | その様に考えると元の値は関係なく変換するのが良い。
    | 適当に試して対称的になる o=1 を採用する事にした。
    |
    | 232-255 = 23段階 であるが実際には一番明るい色と暗い色が含まれていないので 25 段階である。
    | 同様に 80-87 は 7 段階の様に思われるが、実際には一番明るい色と暗い色が含まれていないので 9 段階である。
    | 結局、以下の関数のセットとして作成する事にした。
    | - ble/color/convert-color88-to-color256
    | - ble/color/convert-color256-to-color88

    →(2) 88色時の index color の翻訳にも対応した。

  * ble-color-setface で様々な形式に対応する (requested by cmplstofB) [#D0860]
    https://github.com/akinomyoga/ble.sh/issues/19
    当初は SGR の引数による指定の要望だった。様々な形式に対応する形で実装した。

2018-12-14

  * サブシェル (...) 内で command-help が効かない (reported by cmplstofB) [#D0859]
    https://github.com/akinomyoga/ble.sh/issues/18

    どうやら調べてみると extract-command に失敗している様である。
    extract-command の中を覗いてみるとちゃんと抽出できている様である。
    と思ったら、抽出できているのにも関わらず return 1 になる様になっていた。直した。
    これは前に extract-command を修正した時 #D0799 の修正忘れであろう。

2018-12-02

  * 最近思っていたが menu-complete において日本語の文字が含まれていると座標がずれる [#D0858]

    実際に試してみるとやはりずれている。どうも日本語の文字が半角の幅で計算されている様である。
    幅の計算を実行している部分を確認する必要がある。

    うーん。関係するのは ble-complete/menu/construct-single-entry の中の、
    ble-edit/info/.construct-text を呼び出している部分である。
    もしかすると Cygwin 上だと変な事になるという事なのかもしれない。
    locale 関係が理由で。padparadscha の上で再現するかどうかを確かめてみる事にする。
    →試してみた所 padparadscha の上でも再現する。つまり locale の問題ではないはず。

    construct-text の呼び出し前後での様子を出力させてみる事にする。
    結果、見事に単に文字数が計上されているという事が判明した。
    おかしい。construct-text が壊れているのだとすれば
    今までの info も壊れていたのではないか。
    或いは LC_COLLATE が効いていない?
    LC_ALL が設定されているとそういう事もあるかもしれない。

    * fixed: construct-text の方を観察してバグを見つけてしまった。
      存在しない変数 tail を参照している。
      tail は基本的に空文字列である事を考えれば
      必ず「特殊文字が存在しない」と判定されて文字数だけのカウントになってしまう。
      これで起こっている現象を説明する事ができる。
    * done: 序に LC_ALL 対策も実施する事にする。LC_ALL= と内部で設定する。
      意図的に ble.sh の動作を変更する為に LC_ALL を変更するという事は考えにくいのでこれで問題ない。

    動作確認もした。ちゃんと動作する様になった。OK

2018-10-18

  * 2018-10-06 edit (reported by Kikurage): Bash-3.2 で C-d で exit できない [#D0857]
    https://github.com/akinomyoga/ble.sh/issues/15

    更に、試行して以降全てのキー操作に対して "ジョブがあるので exit できない" の旨が表示される。
    これは C-d の受信に関係していると思われる。
    また、これより後に stty 等のジョブが途中状態で停止した状態になって残るのも確認された。
    しかも、入れ子のシェルでのみ発生するという現象である。謎。

    更に言うと PS1 の中身が消失してしまうというのまである。
    これが起こるのは無理矢理抜けた後のシェルでの様である。

    % 調べてみると何故か C-d は TRAPUSR1 経由で受信している訳ではない様だ。
    % 勘違いだった。デバグ用に弄っているのは devel だったのに
    % 0.2-master でテストを実行していた。

    調べてみると実は毎回 "Use "exit" to leave the shell."
    というメッセージを受け取っている。
    つまり、Bash 3.2 が毎回そのメッセージを送信しているという事?
    うーん。不思議だ。

    * checked: 再現する状況について再度詳しく調べてみる。
      Bash 3.0 では再現しない。Bash 3.1 では再現する。
      Bash 4.0 では再現しない。つまり、Bash 3.1 と 3.2 だけで再現する様子だ。

    * checked: どのタイミングでこの問題が発生する様になったか

      % また、今までは動いていたのだろうか。ble-0.1 では問題なく動いている。
      % という事は何処かのタイミングで問題が発生する様になった様だ。

      - 32037b9 (support-vi-mode merge) 再現する
      - f15f8c5 再現する
      - 97923a9 再現する

      と思ったら ble-0.1 でも再現する様だ…。
      つまり、これは何らかのミスで対応が壊れたのではなくて、
      特別に対策を考えなければならないケースの気がする。

    * もっと単純化した状況で再現できないだろうか。

      C-d で 'Use "exit" to leave the shell' が表示される。
      これは IGNOREEOF を設定している時には出るのである。
      この次に USR1 というシグナルを受け取る。
      そこで C-d に対応した処理が実行される。
      ジョブが存在しているので exit 等の処理は行われない。

      結局何が特別なのかが分からない。
      USR1 というトラップを実行するという事が鍵なのだろうか。
      うーん。適当に単純化した bashrc でやっても再現しない。

      というよりそもそも単純化すれば治るという物とも限らない。
      単純化すれば発生の条件が分かって対策方法が分かるかもしれないという事。

    * suspend 状態になっている stty を殺すと
      キーを押す度にジョブが表示される問題は止まる様である。

    * 後の気になる点は、何故 Done となったジョブが毎回表示され続けるのかという事である。

    改めて。どうして Bash が毎回メッセージを発するのか。
    うーん。少しずつ機能を少なくして行って試すという事をしなければならないのか。
    ble-attach を分解して行って機能を少なくして試すという作戦。
    終了できなくなるかもしれないがそれは kill で…。
    或いは ble-decode/.hook を乗っ取る。
    うーん。とりあえずは ble-decode/.hook を乗っ取った状態で C-d を押して再現するのかという事。
    D0728.bashrc で似たような事をしているから参考になるかもしれない。

    * というか入れ子で起動した時にのみ変な事になるというのはどういう仕組なのか。

      | 状態が継承されるとしたら環境変数または stty による設定である。
      | しかし、入れ子元が Bash 4.0-4.4, 5.0 だと発生しないというのも妙である。
      | 環境変数や stty は Bash の version に関係あるとは思われないのだが。
      | 何れにしても、もしも原因の設定を特定できれば修正できる可能性もある。
      |
      | ? reject: 取り敢えず起動した瞬間の環境変数と stty を出力する事にする。
      |   うーん。違いは MODULEPATH と NLSPATH と SHLVL のみである。
      |   stty については diff で引っかからなかったので違いはないのだろう。
      |   そして、macOS でも再現している事を考えるとこれらは関係ない。
      |
      |   {
      |     stty -a
      |     export
      |   } > debug-C-d.$SHLVL.txt
      |
      | ? reject: 標準出力・標準入力が何処に繋がっているかも関係あるかもしれない。
      |
      |   {
      |     ls -la /proc/self/fd/{0,3,2}
      |   } 3>&1 > debug-C-d.$SHLVL.txt
      |
      |   これで確かめてみたが変化はない。
      |
      | ? 或いは fork の時に特別な処理をしている可能性?
      |   バイナリが同じだったら exec を省略するなど。
      |   然し、3.1 から 3.2 に入った時でも再現する事からそれはない。
      |
      | 後、bash-3.2 bash-4.4 bash-3.2 と起動した時にはどうなるのだろうか。
      | →うーん。今度は C-d を全く受信できなくなってしまった。
      | stty を調べてみると -echoe という状態になっている。
      | stty echoe としたら戻った、それでも関係なく受信できない。
      | C-d を押すとまた stty -echoe に戻ってしまう。
      | この辺りに何らかの鍵があるのかもしれない。
      |
      | ? reject: うーん。一回コマンドを実行すると直るという事を思うと、
      |   やはり stty の状態がおかしくなっている事による問題とも捉えられる。
      |   試しに stty を実行しないとどうなるのか確かめてみるのも一つの手である。
      |   →試しに ble/bin/stty() { :; } を実行して stty が呼び出されない様にしたが、
      |   再現されるし、またコマンドを実行すると直る。うーん。何故だろう。
      |
      |   これは不思議である。何をきっかけとして直るのだろうか。
      |   絶対に何か直るきっかけが存在しなければならない。
      |   stty 以外で何があるのだろうか…。
      |
      |   ble/term/enter, ble/term/leave を丸ごと消したがそれでもコマンド実行で直る。
      |   だとすると ble-edit/bind/stdout.on, ble-edit/bind/stdout.off が鍵なのだろうか。
      |   然し、不思議な事に M-z を押しても直らない…と思ったが、
      |   vi mode では M-z は束縛していないのだった。C-z で直った。
      |   という事はやはり確実にコマンド実行が関係している。
      |
      |   試しにいい加減な widget を使って実験してみるのも良いかもしれない。
      |   試してみたところ stdout.on, stdout.off では直らない様である。
      |   続けて色々 widget を試す。少なくとも .begin/.end を実行すれば直る。
      |   そのどれが効いているのだろうか。絞り込んでいくと term/enter, leave で直る。
      |
      | - 色々試していて気づいた。これは親 bash が TRAPUSR1 を捕まえている。
      |   つまり、コマンド実行中は TRAPUSR1 を解除する様にしなければならない。
      |   →うーん。TRAPUSR1 を解除して実行したら USR1 を受け取って
      |   セッションごと全て落ちてしまった。うーん。
      |   更に残された subshell が無限に Use "exit" to leave the shell のメッセージを受け取っている。
      |   これも謎である。何故 pipe を通じて無限にデータが送られて来るのか…。
      |
      |   代わりに '' で無視する様にして見た所、反応しなくなってしまった。
      |   うーん。実は親の subshell が受信しているという事か…。
      |   そして親に TRAPUSR1 を送っているという事…。

      仕組みは分かった。C-d を受信すると親 Bash 3.2 の側で
      Use "exit" to leave the shell のメッセージが表示され、
      子 Bash 3.2 の側には何も通知が行かない。
      本当は Bash 3.2 に C-d を送信したい所であるが、どうしようもない。
      stty の設定を確認してみるが矢張りどうしたら良いか分からない。

    問題は2つある。

    1 メッセージが大量に出るという事。
      % stty を実行して直るのはこちらだけである。

      →これに関しては単に $_ble_term_state == internal の時にだけ
        反応する様にすれば良い。取り敢えず抑制できる事は確認した。

    2 % 子Bash (というより子プロセス全て) に C-d を伝達する事ができない。
      % エラーメッセージを抑制したとしてもこれに対処する事はできない気がする。
      %
      % と思って試しに子プロセスに全然 C-d が行かない事を立証しようとしたが、
      % cat に対して C-d を実行したらちゃんと受信できるという事が分かった…。
      % stty の状態によって Bash が C-d を奪うかそうでないかが決まるという事だろうか。
      % そして親 Bash 3.2 が子を起動する時には stty をちゃんと設定するが、
      % 子 Bash の側で ble.sh をロードして stty を調整すると、
      % その所為で親 Bash 側での処理が再度有効になってしまうという仕組みである。
      %
      % というか Bash 3.2 から Bash 4.0 を呼び出した時に C-d が動いていた様に見えたのは何だったのか。
      % →うーん。動いている。という事は何らかの条件を満たせばちゃんと子に伝達される。うーん?
      % うーん。やはり 4.0 ではちゃんと C-d を受信する事ができている。
      % C-d を入力した後でも同様である。両方共 eof は ^D になっている。

      これに関しては Bash 3.2 以外の子孫に対しては
      途中に Bash 3.2 が含まれていたとしてもちゃんと C-d を伝達できている。
      ただただ子 Bash 3.2 で ble.sh をロードした時にのみ親 Bash 3.2 が引っ掛かる。

    * うーん。現在の標準入力に対して好きな文字を流し込むという事はできないのか…。
      擬似端末のマスター側が必要である。そしてそれは普通見えない…。
      或いは子Bash側から C-d が欲しいという事を上に伝達する。

    * internal の状態における stty について Bash 3.2 と 4.0 で確認したい。
      →stty -a を両者で実行してみたが違いはない様に見える。

    ? reject: 何故 stty の設定で eof が ^D のままになっているのだろう。

      | これを undef にしたら解決したりしないのだろうか。
      | というか何故元々 C-d を IGNOREEOF で受信せざるを得なかったのかの議論を遡る必要がある。
      | 議論を遡ってみると #D0141 という物があるが、
      | ここでは stty で設定を変更する事に関しては議論されていない。
      | 試しに stty で eof を undef に設定してみることにした。しかし変化はない。
      | 更に bash-3.2 用の特別の処置を解除してみたが、
      | そうすると単純に入れ子かどうかに関わらず C-d が全く効かなくなった。
      | 従って stty で eof を解除するかどうかは全く効かない。
      | ソースコードを元の状態に戻す。

      結論 stty で eof ^D を変更しても何も効果はない。従って動かさない方向で行く。

    ? 目下の謎は、何故 Bash 4.0 がぶら下がっている時には親 Bash 3.2 が反応しないのに、
      Bash 3.2 がぶら下がっている時には親 Bash 3.2 が反応するのかという事である。
      というか、本当にその様な構造になっているのだろうか。

      - Bash 3.2 -> 4.0 は C-d が使える。
      - Bash 3.2 -> 4.0 -> 3.2 だと C-d が使えない。
      - Bash 3.2 -> 4.0 -> 3.2 -> 4.0 では C-d が使える。
      - Bash 3.2 -> 3.2 だと親 Bash 3.2 で Use "exit" を検知している。
      - Bash 3.2 -> 4.0 -> 3.2 だと親 Bash 3.2 では検知できていない。
        子 Bash 3.2 でも検知できていない。うーん。間の 4.0 に吸い込まれているのだろうか…。
      - Bash 3.2 -> 3.2 -> 3.2 の時には最初の Bash 3.2 が検知している。

      うーん。norc だと読み取る事はできるのだろうか。
      - 3.2(ble) ** 3 -> 3.2(norc) でちゃんと C-d を読み取れている。
      - 3.2(ble) -> 3.2(ble/nostty)
        もしかすると stty を何も実行しなければ受信できるのかもしれない、
        と思ったがやはり受信はできない様だ。
        この時もやはり親 Bash が代わりに受信をしている。
      - 3.2(norc) -> bindx 内から 3.2(norc)
        stty sane を実行しないと何も表示されないが、
        stty sane さえ実行してしまえば特に問題なくコマンド実行できる。
        C-d もちゃんと動作している。

      やはり標準エラー出力をリダイレクトしているか
      していないかにも関わってくるのだろうか。

      結局何がどうなっているのかはよく分からない。
      Bash 3.2 だけのチェインになっている時には最初の 3.2 が検知する。
      途中に Bash 3.2 以外が含まれていると誰も検知していない様に思われる。
      どの様なチェインになっていたとしても Bash 4.0 など他のプログラムは
      C-d を読み取れる。Bash 3.2 も ble.sh をロードしていない限りは読み取れる。
      Use "exit" 云々のメッセージも子 Bash 3.2 から発している気がする。

    現在分かる範囲での対策方法として何があるだろうか

    a reject: 一つの解決方法は子 Bash 3.2 を起動した時に親 Bash 3.2 に通知をして、
      親 Bash 3.2 が検知した時に今一番下にいる Bash 3.2 に対して通知を転送する方法である。
      しかし、この方法だと複数の Bash 3.2 の子供がいる場合 (というのが可能化は知らないが)
      にどう対応するのかは非自明だし、子 Bash のリストをどの様に管理するのか、
      管理に不整合が起こった場合にどの様に処理するのかなどを考察しなければならない。

      また、Bash 3.2 -> Bash 4.0 -> Bash 3.2 の場合にはそもそも誰も検出できないので、
      この方法は完全な解決になっているとは言い難い。
      例えば Bash 3.2 -> screen -> Bash 3.2 としたら何が起こるのだろうか。
      或いは、screen の場合には擬似端末とセッションを作るので実は問題にならないのかもしれない。

      何れにしてもこの方法は不完全であるし微妙。

    b もう一つの解決方法は具体的に何が C-d の受信を妨げているのかを特定するという事。
      これは実際に調べてみないとどの様な事になるか分からない。

      取り敢えず bind -x '"\C-d": hello' は Bash 3.2 で動くのだったろうか。
      Bash 3.2 with ble.sh の中から Bash 3.2 with test2.bashrc で起動して試す。
      試してみると実は有限の文字列が設定されている時には C-d は効くのだった。
      更に、文字列が空の時には問答無用で Use "exit" の様だ。
      但し、ちゃんと子 Bash の側で Use "exit" が表示されている様に思われる。
      つまり、子 Bash から検出可能なのではないか。

      どの様な設定を行う事によって Use "exit" が使えなくなって
      親 Bash 3.2 によって処理されるという事態になるのか確認が必要である。
      取り敢えず ble.sh を単に load するだけでは問題は起こっていない。
      attach すると問題が起こる。

      * attach した場合でも以前の実験により、
        stty を封じていても受信できなくなるという事は分かっているので、
        特に stty の設定の変化が悪いという訳でもないと考えられる。
      * 取り敢えず bind だけ実行してみるというのも手である。

      % ble-attach から始めてどんどん絞り込んで行って
      %
      % | function ble-decode/.hook {
      % |   ble-decode/PROLOGUE
      % |   local byte
      % |   for byte; do
      % |     case $byte in
      % |     (20) echo C-t; exit ;;
      % |     (4) echo C-d ;;
      % |     (*) echo $byte;;
      % |     esac
      % |   done
      % |   ble-decode/EPILOGUE
      % | }
      % | source $_ble_base_cache/ble-decode-bind.$_ble_bash.UTF-8.bind
      %
      % という所まで絞り込めた。
      % この PROLOGUE または EPILOGUE が悪さをしている様である。
      % どうも ble-edit/bind/stdout.off を実行した状態だと駄目の様だ。
      % この時親 Bash 3.2 で検知される様になる。
      % ble-edit/bind/stdout.on の後には大丈夫になる。
      %
      % % - reject: うーん。もしかして openat で変なファイルを開いている可能性?
      % %   確かめてみたがちゃんと自プロセスのファイルを開いている気がする。
      % % - reject: 或いは同じ fd で開いているから何か変な干渉が起こっているのだろうか。
      % %   % →_ble_util_openat_nextfd=33 としてみて起動して、
      % %   % fd を親 Bash 3.2 とずらす様にして試してみた。それでも駄目
      % %   bleopt_openat_base=33 としなければちゃんと fd がずれていなかった。
      % %   しかしそれをして fd がずれている事を確かめても C-d は受信できなかった。
      % % - 試しにぜんぜん違うファイルにリダイレクトするのを試してみる。
      % %   exec 1>>$_ble_edit_io_fname1 2>test.stderr
      % %   これだとちゃんと受信する事ができている。
      % % - 次に別の名前付きパイプを使って見る事にする。
      % %   何と自分で新しく作成した名前付きパイプを使うと受信できている…。
      % %   違いは何だろうか。
      % %
      % %   % しかし中を覗くと受信している内容は滅茶苦茶になっている。
      % %   % 文字が色々抜け落ちたりしている。これはどのタイミングで起こるのだろうか。
      % %   % →滅茶苦茶になっているのは一つのパイプに複数のプログラムがぶらさがっていたからだった。
      % %
      % %   うーん。よく分からない…。
      % %   pipe に繋がっている先のプログラムで行っている処理が関係しているのだろうか。
      % %   と思ったが、そもそも処理を一度も実行しない内から問題は始まっている。
      % %   diwown しているのが問題の元なのかと思いきや、正しく動いている方でも disown はしている。
      % %
      % %   うーん。取り敢えず bashrc の方で C-d を捕まえられる様になるかどうかを確かめる為に、
      % %   →幾らか修正した所 C-d を捕まえられる様になってしまった。
      % %   パイプを tmpfs の上に置いていると問題になるのだろうか。
      % %   と思ったが、ble-0.1 でも問題が同様に発生している事からそれは関係ない。
      % %   では openat を実行する場所が問題なのだろうか。
      % %   例えば source したファイルの中でやると駄目など。
      % %   或いは、ファイルディスクリプタがやはり問題になっているのだろうか。
      % %   今回は 35 番でやっているが、ble.sh によって設置されるのは 32 か 33 である。

      どうも動かなくなったのは単に _ble_term_state=internal が足りていなかったのが行けなかったようだ。
      遡ると PROLOGUE/EPILOGUE でも動作する様になった。
      更に ble-attach の中を分解してコメントアウトするなどしたがどうも動く様である。
      処理を関数の中に入れても動く。というか、ble-attach を直接呼び出しても動いた。

      結局 bleopt_openat_base=33 があるかないかで動くか動かないかが変わる様だ。
      使われていない番号でないと動かない。しかし openat でちゃんと上書きされる筈であるし、
      親プロセスの fd には影響はないはずである。試しに明示的に fd を閉じて見ることにする。
      動くようになった。うーん。

      調べてみると以下の様なバグ修正がある。恐らくこれであろう。

      > ------------------------------------------------------------------------------
      > This document details the changes between this version, bash-4.0-alpha,
      > and the previous version, bash-3.2-release.
      >
      > 1.  Changes to Bash
      >
      > (中略)
      >
      > ee. Fixed a bug that caused bash to close file descriptors greater than 10
      >     when they were used in redirections.

  * 2018-10-06 [棄却] edit: ble-0.1 系列でコマンド実行の度に "一致しません: ?" のメッセージが表示される [#D0856]
    これは failglob が原因だった。これには改めて対応はしない。

2018-10-09

  * 2018-10-06 vi (reported by cmplstofB): ビジュアルモードにおけるテキストオブジェクトの単語の振る舞い [#D0855]
    https://github.com/akinomyoga/ble.sh/issues/16

    % 調べてみると色々の異なる振る舞いをしている。
    % そもそもどういう振る舞いだと考えたのかがまず分からない。
    % 過去の議論を遡ることにする。
    % 余り情報は残っていない #D0443 に多少残っている。
    % やはり他に残ってはいない様だ。
    %
    % 改めて。以下は aw の振る舞いである。
    %
    % > - カーソル位置が空白の場合にはそれに続く単語の末端までを範囲とし、
    % >   この時単語に皇族の空白は含まれない。引数が複数ある場合についても同様である。
    % >   一番最後の単語に後続の空白は含まれない。先頭の空白には改行が含まれていても良い。
    %
    % これに関しては特に問題は無いように見える。現にテストケースでも問題は起こっていない。
    % - done: 但し、改行が含まれている場合というのをテストケースに加える事にする。
    %
    % > - 一方で、カーソルの位置が単語の内部にある場合には、
    % >   一番最後の単語に後続の空白は含まれる。
    % >   また後続の単語に改行は含まれない。
    %
    % - done: これは明らかに不完全である。後続の空白がない場合は前の空白を取り込む。
    %   これは対応した。一つのテスト項目しか減少しなかった。
    %
    % - また複数の単語を取る時、必ずしも空白で分かたれていなければならない訳ではない。
    %   異なる種類の単語であれば問題ない。
    %   しかしながらこれを正規表現で判定するにはどうしたら良いだろう。
    %   空白を入れなくて良い事にすると本来単語区切りでない所で単語が区切れて一致するという事が起こりうる。
    %
    % うーん。作り直す事にした。改めて個別の動作について確認する。
    %
    %
    % うーん。改行が絡んでいる時の振る舞いが全く分からない。
    % 因みに exclusive-range.impl では勝手に位置をずらすなどの事はしていない様である。
    %
    % - $'@:echo\n@\nhello\n\nworld\n' iw  $'@:echo\n@<>\nhello\n\nworld\n'
    % - $'@:echo\n@\nhello\n\nworld\n' aw  $'@:echo\n@<\nhello\n>\nworld\n'
    % - $'@:echo\n@\nhello\n\nworld\n' 2iw $'@:echo\n@<\nhello\n>\nworld\n'
    % - $'@:echo\n@\nhello\n\nworld\n' 2aw $'@:echo\n@<\nhello\n\nworld>\n'
    %
    % 現状ではこの様になっている。
    % ここで疑問なのは「範囲の末端の改行」は範囲から除かれるという動作。
    % この動作は元の text-object/word.impl の時から存在していた。
    %
    % 先ず初めに iw から考える事にする。iw の時点でよく分からない動作をする。
    % そう考えると iw は <\n> を最初囲んでから <> に縮まった物と思われる。
    % 一方で 2iw はどうだろうか。<\nhello\n> を囲んだのだとすれば
    % <\nhello> に縮まるべきであるが vim では縮まっていない。
    %
    % 再度試してみる事にする。やはり <\nhello\n> が削除される。
    % もしかすると <\nhello\n\n> まで囲んでから <\nhello\n> に縮んでいるのかもしれない。
    % と思って \n\n\n に対して試して見たがそうでも無い様だ。
    % うーん。しかも引数を増やす毎に一つずつ取り込む改行が増える。
    % 実は末尾に改行を除くという操作は元からしていなくて、
    % 最初の iw で <> が初めから選択されているという事なのだろうか。
    % しかし、空の選択範囲という物が選択されるというのも設計として変である。
    % 或いは、末尾の \n が除去される状況と除去されない状況というのが存在するのか。
    % もう一つ試しておくべき事は、末尾の改行が存在しない時である。
    % 後更に一つ引数を増やしたらどうなるか…あれ次の単語まで取ってしまう。
    %
    % - $'@:echo\n@\nhello\nworld\n'          1iw $'@:echo\n@<>\nhello\nworld\n'
    % - $'@:echo\n@\nhello\nworld\n'          2iw $'@:echo\n@<\nhello\n>world\n'
    % - $'@:echo\n@\nhello\nworld\n'          3iw $'@:echo\n@<\nhello\nworld\n>'
    % - $'@:echo\n@\nhello\n\nworld\n'        1iw $'@:echo\n@<>\nhello\n\nworld\n'
    % - $'@:echo\n@\nhello\n\nworld\n'        2iw $'@:echo\n@<\nhello\n>\nworld\n'
    % - $'@:echo\n@\nhello\n\nworld\n'        3iw $'@:echo\n@<\nhello\n\n>world\n'
    % - $'@:echo\n@\nhello\n\nworld\n'        4iw $'@:echo\n@<\nhello\n\nworld\n>'
    % - $'@:echo\n@\nhello\n\n\nworld\n'      1iw $'@:echo\n@<>\nhello\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\nworld\n'      2iw $'@:echo\n@<\nhello\n>\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\nworld\n'      3iw $'@:echo\n@<\nhello\n\n>\nworld\n'
    % - $'@:echo\n@\nhello\n\n\nworld\n'      4iw $'@:echo\n@<\nhello\n\n\nworld\n>'
    % - $'@:echo\n@\nhello\n\n\n\nworld\n'    1iw $'@:echo\n@<>\nhello\n\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\nworld\n'    2iw $'@:echo\n@<\nhello\n>\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\nworld\n'    3iw $'@:echo\n@<\nhello\n\n>\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\nworld\n'    4iw $'@:echo\n@<\nhello\n\n\n\n>world\n'
    % - $'@:echo\n@\nhello\n\n\n\nworld\n'    5iw $'@:echo\n@<\nhello\n\n\n\nworld\n>'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  1iw $'@:echo\n@<>\nhello\n\n\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  2iw $'@:echo\n@<\nhello\n>\n\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  3iw $'@:echo\n@<\nhello\n\n>\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  4iw $'@:echo\n@<\nhello\n\n\n\n>\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  5iw $'@:echo\n@<\nhello\n\n\n\nworld\n>'
    %
    % \n x 1: echo\n@(1)\nhello\n(2)world\n(3)
    % \n x 2: echo\n@(1)\nhello\n(2)\n(3)world\n(4)
    % \n x 3: echo\n@(1)\nhello\n(2)\n(3)\nworld\n(4)
    % \n x 4: echo\n@(1)\nhello\n(2)\n(3)\n\n(4)world\n(5)
    % \n x 5: echo\n@(1)\nhello\n(2)\n(3)\n\n(4)\nworld\n(5)
    %
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  1aw $'@:echo\n@<\nhello\n>\n\n\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  2aw $'@:echo\n@<\nhello\n\n\n>\n\nworld\n'
    % - $'@:echo\n@\nhello\n\n\n\n\nworld\n'  3aw $'@:echo\n@<\nhello\n\n\n\n\n>world\n'

    * done: vim のソースコードを読んで知ったが
      後続空白がなかったとしても行頭空白は含めないらしい。

    * done: 結局 vim のソースコードを読むことにした。
      読んでいても良く分からなくなるので分かった事をここに書きながら読むことにした。

      先ず初めに、omap もしくは xmap で一文字しか選択されていない場合には、

      inc は次の文字に移動する。行の最後の文字にいる時には行末の NUL に移動する。
      行末の NUL で再度 inc を実行すると次の行の行頭に行く。
      incl は行末の文字から次の行に跳ぶ。
      行末の NUL は ble.sh での \n と考えて良いだろう。
      inc は \n に止まるが incl は \n に止まらずに次の行の行頭に行く。

      back_in_line は同じ文字カテゴリの文字が続く限り行内で後ろに戻る。
      これは現在の ble.sh でやっているのと同じ動作になっているので大丈夫。

      if ((cls() == 0) == include)
        if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
          return FAIL;
      else {
        fwd_word(1L, bigword, TRUE);
        以下略
      }
      ここでやっているのは、
      iw で最初空白だったらその空白を拡張する。
      iw で最初空白以外だったらその単語の末尾まで拡張する。
      aw で最初空白だったら次の単語の末尾まで拡張する。
      aw で最初空白以外だったら次の単語の末尾まで拡張する。
      という事。丁度反転しているから xor で振る舞いを切り替えている…。
      更に include_white は aw でかつ最初非空白だった時に設定される。

      2個目以降の単語は取り扱いが異なる。と思ったが、
      if (include != (cls() == 0)) {
          if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
              return FAIL;
          if (oneleft() == FAIL)
              inclusive = FALSE;
      } else {
          if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
              return FAIL;
      }
      これは最初と条件判断の真偽が逆になっているだけでやっている事は同じに見える。
      比べてみると最初の単語の切り出しでは
      if (curwin->w_cursor.col == 0)
        decl(&curwin->w_cursor);
      としているが、while の中ではこれを実行していない。
      つまり count が 2 以上だった時、
      もしくは xmap でかつ ind != mark だった時は、
      末尾の改行の削除は行われないということの様だ。

      if (include_white && (cls() != 0
                   || (curwin->w_cursor.col == 0 && !inclusive)))
      これは「aw で最初非空白で、(現在地が非空白 または (行頭かつ !inclusive))」
      という条件である。!inclusive という事は行頭の文字は含まれない、
      つまり行末までの範囲という事である。

      | うーん。現在地が非空白、という事については ble.sh で対応しているので大丈夫。
      | しかし、行頭かつ !inclusive というのはどういう事か。
      | これだと行末に空白が並んでいる場合でも exclusive ならば、
      | 前方に空白を取り込みに行くという事の様に思われる。
      | うーん。inclusive = FALSE は最後の単語の探索で行頭に居た時に起こる様である。
      | しかし、試してみたがこれによってどういう振る舞いの違いが出ているのか分からない。
      | というか、単に vim の範囲表現の処理のような気がしてきた。
      | 実際に試してみてもこれによってどういう振る舞いの変化が起こっているのか分からない。
      | →よく分からないのでこれは無視する事にする。

      というか先に fwd_word を見ておくべき気がする。
      fwd_word を見ると空行 (col 0 に NUL がある) で止まると書いてある。
      また一番始めに空白があると空白を一つの単語として数えそうな気がする…。
      初めに空行にカーソルがあった場合に fwd_word を実行するとどうなるか。
      \n@\n\n ここで cls == 0 となる。そして次に進むと
      \n\n@\n という状態になる。ここで空白の読み飛ばしに入るが、
      実はその瞬間に終了するはずである。つまり1文字しか進まないはず。
      また、初めに単語にカーソルがあった場合に fwd_word を実行するとどうなるか。
      \n@hello\n\n となっている。ここで \nhello@\n\n まで進む。
      空白を読み飛ばすと \nhello\n@\n という事になる。

      これによって先の偶奇を説明する事ができるだろうか。
      恐らく、末尾の改行の除去を行う前は以下の様な動きになっている。

      | \n x 1: echo\n@\n(1)hello\n(2)world\n(3)
      | \n x 2: echo\n@\n(1)hello\n(2)\n(3)world\n(4)
      | \n x 3: echo\n@\n(1)hello\n(2)\n(3)\nworld\n(4★)
      | \n x 4: echo\n@\n(1)hello\n(2)\n(3)\n\n(4★)world\n(5)
      | \n x 5: echo\n@\n(1)hello\n(2)\n(3)\n\n(4★)\nworld\n(5★)

      | \n x 5: echo\n◎①\nhello\n②\n③\n\n④\nworld\n⑤ZZZZZ
      | \n x 10: echo\n◎①\nhello\n②\n③\n\n④\n\n⑤\n\n⑥\n\n⑦world\n⑧ZZZZZ

      ★を付した箇所が理解できない振る舞いをしている部分である。

      調べてみると diw を使っている時は fwd_word ではなくて end_word の気がする。
      end_word の中を覗くと、取り敢えず一文字は必ず進む。
      非空白文字の時は文字の種類が変わるまで進む。
      空白文字の時は空白が続くまで進むけれど空行に入ったらその位置で止まる。
      空行で止まった時以外は一文字戻る (これは inclusive 範囲なので)。

      この動作に従うと (3) は正しい気がする。(4) 以降はやはり理解できない。
      と思ったが、よく見ると end_word を呼び出す前に取り敢えず一文字移動している。
      しかも incl である。この時何が起こるのだろうか。

      hello\n@\n\n\n の時には incl で
      hello\n\n@\n\n という状態になる。ここで更に end_word を呼び出すと、
      hello\n\n\n@\n という状態になる。そう考えると (3) は二行進むはずである。
      しかし、何故か一行しか進まない。うーん。
      あー。何か分かった気がする。恐らく text object の中では以下の様になっている。

      | \n x 10: echo\n◎\n①hello②\n\n③\n\n④\n\n⑤\n\n⑥\n\n⑦world\n⑧ZZZZZ

      これがその後の補正に依って範囲が変更されている。

    * done: 取り敢えず vim の真似をして多少修正する。

      色々バグが出て動かない。

      test(xmap text object (word)/A7/iw): keys = (d i w)
        initial  = "echo^J@^Jhello^J^Jworld^J"
        expected = "echo^J@^Jhello^J^Jworld^J"
        result   = "ech@o^Jhello^J^Jworld^J"

      色々試してみると、二行ずつ進むという動作が再現しない。
      vim の側では daw も diw も十分大きな引数に対して
      2行ずつ進む様であるが、vim のソースコードを読んでも1行ずつしか進まない気がするし、
      それを参考にして実装した ble.sh も当然1行ずつしか進まない。

      如何なる仕組みによって二行ずつ進んでいるのだろうか。
      改めて vim のソースコードを見てみる必要がある。
      取り敢えず十分大きな count に対して思っているのと違う動作をしているので、
      その部分について観察してみる事にする。

      | while (count > 0) {
      |   inclusive = TRUE;
      |   if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) {
      |     今は xmap では試していないので此処には入ってこない筈である。
      |   } else {
      |     ここで一文字進む。つまり、\n の直前にいたとすると次の行頭に移動する事になる。
      |     或いは空行以外の場合にはカーソルが行末にいたとすると一番最後の文字の直前にいる筈だが、
      |     この場合でも incl を使うと二文字進んで次の行頭に移動する事になる。
      |     これは、常に exclusive end で管理している ble.sh 的には、
      |     行末にいる時には行頭に移動するという事と考えて良い。
      |     行末以外にいる時には特に何もしなくて良い。
      |     if (incl(&curwin->w_cursor) == -1)
      |         return FAIL;
      |
      |     include は aw か iw の違いである。
      |     cls() は現在位置の文字の種類で 0 はスペースである事を表す。
      |     改行ばかりが並んでいる時にはこれは常に TRUE になる。
      |     つまり aw の時にはこの if 文の true-clause に入り、
      |     iw の時にはこの if 文の false-clause に入る。
      |     if (include != (cls() == 0))
      |     {
      |         次に fwd_word について考える。
      |         ここに入るのは aw で非空白文字の上に載っていた時と、
      |         iw で空白文字の上に載っていた場合である。
      |
      |         if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
      |             return FAIL;
      |         | fwd_word = {
      |         |   sclass = cls();
      |         |   last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
      |         |   i = inc_cursor();
      |         |   if (i == -1 || (i >= 1 && last_line)) return FAIL; 編集文字列の末端 (NUL) だったら失敗
      |         |   if (i >= 1) return OK; 次の行に進んだら成功。
      |         |   取り敢えず一文字進んで見る。
      |         |
      |         |   if (sclass != 0) {
      |         |       while (cls() == sclass)
      |         |       {
      |         |           i = inc_cursor();
      |         |           if (i == -1 || (i >= 1))
      |         |               return OK;
      |         |       }
      |         |   }
      |         |   もし w だったら w+ だけ読み取る。途中で次の行に進んだら成功。
      |         |   もしくは文字列終端に進んだら成功。これは /w+($|\n)/ という事。
      |         |   それ以外の w+ は次に進む。
      |         |
      |         |   while (cls() == 0) {
      |         |       if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
      |         |           break;
      |         |           この条件が満たされる事はない気がする。
      |         |           fwd_word を呼び出す前に incl しているのでファイルが空でない限りは
      |         |           必ず文字の上にカーソルがいる状態で fwd_word が呼び出される。
      |         |           その状態で inc すると必ず col は 1 以上になる。
      |         |           col が 0 になるのは最終行以外で NUL を指している時に次の行に移動した時である。
      |         |           或いは最初から 0 でしかも最終行にいてそれが空行である時である。
      |         |
      |         |       i = inc_cursor();
      |         |       if (i == -1 || i >= 1)
      |         |           return OK;
      |         |   }
      |         |   ここは [bn]* を読んでいるが途中で $|\n を読んだら終了。
      |         |   うーん。初めが空白だったとしたら、/b(b*n|b*$)/ = /b+(n|$)/
      |         |   初めが改行だったとしたら /n(b+n|b*$)/ = /nb*(bn|$)/
      |         |   初めが w だったとしたら /w+b*(n|$)/ という事になる。
      |         |
      |         |   修正: i>=1 は i==2 も含む。i==1 は改行を通った場合だが、
      |         |   i==2 は改行の直前に達した時である。改行を通った場合は行頭で戻り exclusive になる。
      |         |   改行の直前に達した場合には行末で戻り、更に oneleft() して inclusive になる。
      |         | }
      |
      |         % aw で非空白文字の上に載っていた場合には、
      |         %   /w+($|n)|w+b*(n|$)/ を読み取る。つまり /w+b*(n|$)/ である。
      |         % iw で空白文字の上に載っていた場合には、
      |         %   /b+(n|$)|nb*(bn|$)/ である。
      |         %   = /b+n|b+$|nb+n|nb*$/ = /n?b+n|[bn]b*$/ うーん。微妙。元のままの方が良い。
      |         修正: n を読み取ったら即座に終了である。もしくは改行直前に達したら終わる。
      |         つまり iw は /b+|n/ である。実際に vim で動作を確認してみる事にする。
      |         aw に関してはどうだろうか。w+を読み取った後に改行に達したらやはり即終了である。
      |         改行は読み取りの範囲内に含まれない。つまり /w+b*/ である。
      |         check $'@:@    \necho' 'c i w' $'@:@\necho'
      |         check $'@:@\n    echo' 'c i w' $'@:@\n    echo'
      |
      |         if (oneleft() == FAIL)
      |             inclusive = FALSE;
      |         この部分は単に exclusive の解釈から inclusive の解釈になる様に修正しているだけ。
      |         ble.sh では常に exclusive で処理しているから関係ない。
      |     }
      |     else
      |     {
      |         先に iw の時を考える。特に end_word を引数 count = 1 で呼び出している。
      |         stop = TRUE で empty = TRUE である。
      |         if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
      |             return FAIL;
      |         この時 end_word の中は以下の様な処理になる。
      |         | []() {
      |         |   sclass = cls();
      |         |   if (inc_cursor() == -1) return FAIL;
      |         |   ここで取り敢えず一文字進んで見る。
      |         |   @\n\n の状態から \n@\n という状態になっていたはずなので、
      |         |   更に一文字進んで \n\n@ という状態になると考えて良い。
      |         |
      |         |   if (cls() == sclass && sclass != 0) {
      |         |       if (skip_chars(sclass, FORWARD))
      |         |           return FAIL;
      |         |   } else if (sclass == 0) {
      |         |     while (cls() == 0) {
      |         |       if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
      |         |         return OK;
      |         |       空行に入ったら一つ単語を見つけたと考えて end_word を抜ける。
      |         |
      |         |       if (inc_cursor() == -1)     /* hit end of file, stop here */
      |         |           return FAIL;
      |         |     }
      |         |
      |         |     if (skip_chars(cls(), FORWARD))
      |         |         return FAIL;
      |         |   }
      |         |   dec_cursor();                   /* overshot - one char backward */
      |         |
      |         | }
      |         | うーん。end_word(1, bigword, t, t) を正規表現で表すとどの様になるだろうか。
      |         | /ww+|[bn]+?(空行|w+)|w/ こんな感じである。要するに /w+|(b+n?)+w+|n/。
      |         | 否、何か違う気がする。/w+|(n|b(b*n))(b+n)*((?=n)|b*w+)/
      |         | /w+|(b*n)(b+n)*((?=n)|b*w+)/ ←これで考えるのが良い気がする。
      |
      |         aw に対しては空白に対して end_word が呼び出されるので、
      |           /(b*n)(b+n)*((?=n)|b*w+)/ である。
      |           実のところ (?=n) の位置で n が現れる場合には、
      |           必ず其処で正規表現の一致が止まる (他の一致の仕方はできない) し、
      |           それ以外の文字の時には必ず b*w+ か b+n かに当たるので、
      |           (?=n) の要請は結局ここに文字列末端が来ないという事の要請である。
      |           /(b*n)(b+n)*(b*w+)?/ で一致させてもし末端まで達していたら、
      |           最後が非空白文字である事を確認すれば良い。
      |
      |           訂正を入れる。b+w+ の場合が抜けている。
      |           /(b*n)(b+n)*((?=n)|b*w+)|b+w+/
      |           = /(b*n)(b+n)*(?=n)|(b*n)(b+n)*(b*w+)|b+w+/
      |           = /(b*n)(b+n)*(?!$)|(b*n(b+n)*b*|b+)w+/
      |
      |           更に訂正。b+$ の場合も抜けているのではないか。
      |           と思ったが、これは常に失敗なので考えなくて良い?
      |           しかし、これも考えた方が正規表現が単純になって見通しが良い。
      |           結局、後の確認ではねられる所ではあるが。
      |           /(b*n(b+n)*b*|b+)(w+|(?!$))/
      |
      |         iw に対しては非空白に対して end_word が呼び出されるので、
      |           /w+/ が使われる物と考えて良い。
      |     }
      |   }
      |   --count;
      | }
      |
      | 整理すると以下の様な事になる。
      | 先ず初めに \n が次にあればそれを取り込む。
      | 次に以下の場合分けで読み取る。つまり、
      |
      | - iw に対しては非空白に対して /w+/ を読み取る。
      | - iw で空白文字の上に載っていた場合には
      |   % /b+(n|$)|nb*(bn|$)/ を読み取る。
      |   /b+|n/ を読み取る。
      | - aw で非空白文字の上に載っていた場合には、
      |   % /w+b*n?/ を読み取る
      |   /w+b*/ を読み取る。
      | - aw に対しては空白に対して
      |   % /(b*n)(b+n)*(b*w+)?/ で一致させて、
      |   % /(b*n(b+n)*b*|b+)w+|(b*n(b+n)*b*|b+)(?!$)/ で一致させて
      |   /(b*n(b+n)*b*|b+)(w+|(?!$))/ で一致させて
      |   もし末端まで達して最後が空白文字だったら失敗

      まとめると
      先ず初めに \n が次にあればそれを読み飛ばす。
      % iw に対しては /w+|b+n?|nb*(bn)?/ で一致させる。
      iw に対しては /w+|b+|n/ で一致させる。
      % aw に対しては /w+b*n?|((b*n)(b+n)*b*|b+)(w+)?/ で一致させて、
      aw に対しては /w+b*|((b*n)(b+n)*b*|b+)(w+)?/ で一致させて、
      末端まで達して最初と最後が空白文字だったら失敗。

      * reject: aw の条件に関してはもっとましな判定方法は無いだろうか。
        うーん。難しい。(?=n) さえ正規表現にあれば簡単だったという事。
        これは諦める事にした。

    * ok: 一方で一番最初の単語の読み取りは全く同じでも良いのだろうか。
      fwd_word 及び end_word の中身は同じである。
      然し、その前に改行を取り込む等の事はしない。
      また、fwd_word の後で小細工をする。

    x fixed: end_words は改行を取り込む事について

      うーん。動かしてみるが思う様に行かない。
      exclusive/inclusive による振る舞いの変化だろうか。
      先に書いたコードによると、行末の非空白文字で終わった時に
      exclusive になるとか書いてあるけれど、これはちょっと意味が分からない。
      実際に読んでもその様になっている様には思われない。
      それよりは寧ろ、特定の条件で行頭に来た時に exclusive になっていて、
      その時には改行は含まないのであるという実装になっている。

      実は end_word 等で二重改行の中で終わっていたが、
      実は end_word の時は inclusive に二重改行も範囲に取り込むべきなのではないか。
      →調べてみたところ二重改行に対しては inclusive である事を考慮した dec が行われていない。
      つまり、end_word で二重改行に会った時には二重改行の末尾まで取り込むという動作である。

      これはどの様に正規表現を修正するだろうか。
      (?=n) だと思っていたのが n になると考えれば良い。
      aw で空白にいる時に
        /(b*n)(b+n)*(n|b*w+)|b+w+/ に一致する。
        % = /(b*n)(b+n)n|((b*n)(b+n)*b*|b+)w+/
        % = /(b*n)(b+n)n|((b|n|b+n)(b+n)*b*)w+/
        % = /(b*n)(b+n)n|(n(b+n)*b*|b(b*n(b+n)*)?b*)w+/
        = /b+w+|b*n(b+n)*(n|b*w+)/
      iw で非空白にいる時に /w+/
        特に iw を考えている分には二重改行の類は考えなくて良さそう。
      そうすると aw の正規表現を修正する。
      % aw で非空白文字にいる時には /w+b*n?/ であったので、
      %   /w+b*n?|b+w+|b*n(b+n)*(n|b*w+)/ という事になる。
      aw で非空白文字にいる時には /w+b*/ であったので、
        /w+b*|b+w+|b*n(b+n)*(n|b*w+)/ という事になる。

    x fixed: operator:d の特殊ルールに対応

      まだうまく行かない。

      initial  = echo^J@^Jhello^J^Jworld^J" -> daw
      expected = echo^J<^Jhello^J>^Jworld^J"
      result   = echo^J<^Jhello>^J^Jworld^J"

      どの様に動作するのかについて考える事にする。
      一番始めに前方に拡張が試みられるがこれは成功しない。
      改行は拡張に含まれない為である。
      次に一致が試みられる。改行から一致が始まる。
      正規表現的には hello の末端まで一致する。
      end_words の振る舞い的にもその様になっている筈である。
      dec されて o の直前にカーソルが行くので、
      結局囲まれる領域は hello までになるべきである。

      何故範囲が拡張されているのだろうか。
      これは exclusive linewise などなのだろうか。
      調べてみると exclusive linewise が実行されているのは、
      exclusive-goto.impl の様である。
      txtobj では exclusive-range.impl を直接呼び出しているので補正は効かない。
      しかし、exclusive-goto.impl の実装を確認してみると、
      補正が発生するのは行頭に exclusive で移動した時の話で、
      行末に inclusive で移動した時には発動しないので今回の事には関係ないのでは。

      改めて vim の実装と動作について考えてみる事にする。
      daw なので include == true である。
      cls() == 0 である。従って、end_word が呼び出される。
      辿ると結局実行されるのは以下の3行の様な気がする。
        inc_cursor();
        skip_chars(cls(), FORWARD)
        dec_cursor();
      skip_chars は異なるクラスになるまで移動する。
      つまり、hello の後の \n の位置で止まる。
      その後で dec_cursor を実行するので、
      hello の o の直前にカーソルが移動する。
      では end_word を抜けた後はどうなるだろうか。
      うーん。そのまま inclusive = TRUE を設定して抜けてしまう気がする。

      うーん。行が変わって行末に行く時には inclusive から
      linewise になるとかあるんだろうか。
      うーん。やはり vim の help を見ても inclusive の時に範囲を拡張する等の話は載っていない。

      vim のソースコードをいじって途中状態を出力させて見る事にした。
      すると current_word を抜ける時点ではやはり次の行の行末になっている。
      これはもしかすると d の方の働きによって行が削除されているという事なのだろうか。
      うーわ。これは d だった。https://vim-jp.org/vimdoc-ja/change.html#d

      > コマンド "d{motion}" に関する例外: 移動が行単位でなく、移動の開始点と終了点が
      > 同じ行になく、移動の開始点の前に空白しかなく終了点の後に空行以外がない場合に
      > は、削除は行単位となる。このときユーザーは空白のみの行が残ると期待するかもしれ
      > ないが、共に削除される。削除を文字単位に強制したい場合は o_v を使うこと。

      例によってよく分からない日本語であるが…。試してみる。
      終了点の後に空行以外がない場合、というのはどういう状況か。
      取り敢えず、終了点の次の行が空行以外であっても行毎削除される様である。
      また、終了点以降に空白しか無い場合も全部削除される様である。

      更に判明してしまった事は o_v なる機能が存在するという事である。
      これは新しい項目で処理する事にする。

    x fixed: inclusive = FALSE の時、前の \n は範囲に含まれない様だ

      未だうまくいかない。今度は \n が沢山ある時の勘定が変だ
      うーん。もしかすると d の特殊ルールは空行に対しては効果がない?
      と思ったが確かめてみると d3j とやるとやはり空行であっても
      ちゃんと行単位に変換されて一行余分に削除されるという事が分かった。

      ではやはり txtobj の段階で一つ少ない位置に一致するべきなのだろうか。
      vim に内部の状態を出力させてみると、ちゃんと同じ位置に止まっている様である。
      しかし、よく見てみると hello 直後の時と空行の時とで inclusive の状態が異なる。

      うーん。exclusive の時には一つ前の行末に移動する事にすれば良いのか。
      しかし、そうすると別の operator での動作が変わってしまう。
      少し ciw で試してみる事にする。ciw の方では変な範囲の拡張縮小は起こらないはず。

      ciw echo\n@①\nhello②\n③\n\n④\n\n⑤\n\n⑥\n\n⑦\nworld⑧\nZ
      diw echo\n@①\nhello\n②\n③\n\n④\n\n⑤\n\n⑥\n\n⑦world\n⑧Z

      と思って調べてみたところ、ciw の場合には ③ は一つ手前に置かれる様である。
      というか2行しか下に移動していない。どうしてだろう。
      更に diw と比べてみるとちゃんと全て一行ずつ下に移動しているのが分かる。
      ciw 基準で実装した方が良いという事か。

      しかし、この ciw の振る舞いが正しいとすると vim で調べた結果は何だったのか。
      ③ に対しては確かに3行下に移動していた様に思われた。
      先ず初めに 3ciw と 3diw で current_word は同じ結果を返している事を確かめる。
      OK これは大丈夫。しかし、実際の動作の次の行の行頭に exclusive で位置している。
      うーん。次に 1ciw から 8ciw まで試してみる事にする。
        1ciw 3:0 ->  3:0(inclusive) 結果 3:0
        2ciw 3:0 ->  4:4(inclusive) 結果 4:5
        3ciw 3:0 ->  6:0(exclusive) 結果 5:0
        4ciw 3:0 ->  8:0(exclusive) 結果 7:0
        5ciw 3:0 -> 10:0(exclusive) 結果 9:0
        6ciw 3:0 -> 12:0(exclusive) 結果 11:0
        7ciw 3:0 -> 14:0(exclusive) 結果 13:0
        8ciw 3:0 -> 14:4(inclusive) 結果 14:5

      つまり、行頭 exclusive は実際には前の行の末尾として取り扱われるのだと解釈するべき。
      その様に修正する事にする。しかし、どの様に行頭 exclusive を判定するのか?
      と思ったが、実は行頭にいる時は常に行頭 exclusive と思って良いのだろうか。
      しかし、二重改行などを考えると inclusive という事も考えられる。
      うーん。改めて inclusive exclusive の条件を確認する必要がある。

      exclusive になるのは、fwd_word で行頭に移動した時である。

    x fixed: 今度は {N}aw がちゃんと動いていない。
      うーん。1caw で試すと問題ないが、
      2caw で試すと余分に一行削除してしまっている。

      これは一体どの様な動作に依る物だろうか。
      特に3行ずつ範囲が拡大してしまっている。
      実装を調べてみる事にする。先ず \n を読み取る。
      その後で正規表現の b*n(b+n)*(n|w+) に一致している気がする。
      これは end_word 由来の一致である。
      end_word では二重改行に一致した時にその末端に一致するとした。
      しかし、改めて振る舞いを見てみると怪しい。
      改めて end_word を確認する必要があるのではないか。

      vim の振る舞いを確認する。先ず初めに incl が呼び出される。
      この時 cursor は行頭にあって、incl によって次の行の行頭に移動する。
      aw の時 include == TRUE であり、cls() == 0 も TRUE である。
      従って、end_word の方に入っていく事になる。end_word の中では以下の様に処理が進む。
      sclass = cls(); // [ @\n@\n\n, sclass =  0 ]
      inc_cursor();   // [ @\n\n@\n, sclass = 0 ]
      if (cls() == sclass && sclass != 0) この条件は満たされない。
      if (!stop || sclass == 0) この条件は満たされる。
        while (cls() == 0) { // [@\n\n@\n] OK
          if (empty && curwin->w_cursor.col == 0
            && LINEEMPTY(curwin->w_cursor.lnum)) この条件はいきなり満たされる。
            goto finished; これが実行される
          if (inc_cursor() == -1) return FAIL;
        }
      finished:
        stop = FALSE;
      }
      return OK;
      つまり最初カーソルがあった状態から2行進んだ状態で end_word を出ていく。
      この時呼び出し元では行頭にカーソルがあるけれども inclusive という取り扱いである。

      うーん。問題点は何かというと。この状態で次の単語を探しに行くと
      一文字進んでそれからまた一文字進む。2文字しか進まないという事である。
      一方で、この状態で最後の一致だとすると、inclusive として
      次の文字が含まれた状態になる。

      つまり $'\n' が次に居たら取り込むという動作をしているが、
      実はこれは inclusive か exclusive かで切り替えるべきなのではないか。
      此処で改めて考え直す事にする。
      ble.sh の実装では常に end は exclusive で保持する様にしたい。

      現在の実装ではどの時に exclusive でどの時に inclusive だったろうか。
      Vim では基本的には大体 inclusive なのである。
      特に現在の実装で inclusive なのか exclusive なのか気にしているのは改行で終わっている時である。
      iw に於いて空白に一致してその最後が改行であった時、exclusive になる。
      aw に於いて単語+空白に一致した時にも exclusive になる。
      これらの時、特に最初の一致と最後の一致だった時には最後の改行の前に移動する。
      これらの場合には既に exclusive としての処理を想定しているので、
      特に新しい処置は必要ない。

      問題になるのは aw に於いて空白から始まる場合に最後に改行だったという状況。
      これが現在の end_word による一致の状況である。
      この時には二重改行に出会うと1つ目の改行の直後で inclusive で抜ける。
      つまり、exclusive で表すならば end は2つ目の改行の直後である。

      さて、何が解釈に違いを与えるかというと、
      incl(&curwin->w_cursor); が結局何をした事になるのか、という事である。
      これは inclusive だった現在位置を exclusive の現在位置にする物と解釈していた。
      通常文字の上にいる時には常に inclusive であり、
      また incl によって exclusive な末端を得られた。
      また、exclusive に改行の直前にいる時には incl はその改行を範囲内に取り込むという事を意味する。
      一方で inclusive な改行の直前にいる時には incl は単に exclusive に変換しただけという事になる。

      ble.sh の実装では exclusive に改行の直前にいる時には現在の実装で問題はない。
      一方で、inclusive な改行 (つまり end_word の二重改行) の直後にいる時には
      「次の行に行く」という動作はしないという様にしなければならない。
      元の Vim では依然として二重改行の直前にカーソルがあって、
      incl を経て始めてカーソルが exclusive な状態になるからである。
      この時対象の範囲は変化しない (元から含まれているべき改行が含まれただけ)。
      さて、では inclusive な改行はどの様に判定したら良いだろうか。
      iw の時には 空白は空白だけで読み取るので、最初が空白の時にしか最後に改行が来る事はない。
      しかし最初が空白の時には fwd_word が使用されるので end_word は使われない。
      必ず exclusive な改行が来る事になる。
      aw の時には最初が非空白の時には fwd_word が用いられて exclusive な改行が来る。
      最初が空白で最後が改行の時に end_word になって二重改行の後に現在位置が移動する。
      しかし vim 的にはこの時カーソルは二重改行の間に置かれて inclusive な改行の状態になる。
      さて、判定は rematch == ["$ifs"]*$'\n' で問題ないだろうか。
      特に rematch == $'\n' になる事はないだろうか。
      今回の状況は、必ず二重改行に一致した時なので rematch は二文字以上ある筈である。

      % 然し、そもそも初めから二重改行を取り込まないという様にする可能性はあるだろうか。
      % その様な実装の時にはどの様に動作するべきだろうか。
      % 先ず直前の inclusive/exclusive の状態を記録する様にする。
      % 最後に inclusive か exclusive の状態かを見て範囲の調整を行う。
      % 途中の処理では実は inclusive か exclusive かは使わない。
      % →面倒になったのでこの可能性に関しては検討しない事にする。

      うーん。修正したが殆ど変わらない。最後の 6caw と 6daw だけ一致する様になった。
      途中は常に1個余分に削除されてしまっている。
      改めて動作について考える必要がある。2caw について例えば考える。
        initial  echo\n@\nhello\n\n\n\n\n\n\n\n\n\nworld\nZ
        expected echo\n[\nhello\n\n]\n\n\n\n\n\n\n\nworld\nZ
        result   echo\n[\nhello\n\n\n]\n\n\n\n\n\n\nworld\nZ
      @ が最初のカーソル位置で [] が caw による削除範囲である。
      カーソルの動きについて考える。一番最初に \nhello が読み取られる。
      次に \n が取り込まれる。そして正規表現によって \n\n が取り込まれる。
      (この時の vim の動作は \n\n の1つ目の改行だけ取り込んで、inclusive の状態になる)

      うーん。operator d の特殊ルールが適用される条件に
      inclusive がどうのというのもあるのだろうか。
      調べてみる必要がある。と思ったが、現在の対象は c である。関係ない。
      うーん。改めて vim でどの様になっているか確認する必要がある。
      vim では current_word は
        1caw echo\n[\nhell]o\n\n\n\n\n\n\n\n\n\nworld\nZ (inclusive)
        2caw echo\n[\nhello\n\n]\n\n\n\n\n\n\n\nworld\nZ (inclusive)
      を返している。ここで不思議なのは inclusive により
      hello の o は作用範囲になっているのに、
      inclusive により次の改行は inclusive になっていないという事である。

      つまり inclusive の時には2つ目の改行は作用対象には入っていないという事?
      然し、そうするとやはり二重改行は取り込まないという様にするべきだったのだろうか。
      →その様に直したら呆気なくテストを通る様になってしまった。

    * done: ble-0.2 に対しては簡単な修正を行うだけに留める事にする。
      →これについては取り敢えず修正はした。未だ commit は作っていない。
      未だ時間がかかりそうなので先にこれについて commit してしまう事にする。

    * ok: 前方の空白を取り込む処理については inclusive/exclusive
      は考えなくて良いのだろうか。

      % 改めて vim の処理について読んで見る事にする。
      % 前方の空白を取り込む条件は以下の通りである。
      %   if (include_white && (cls() != 0
      %                || (curwin->w_cursor.col == 0 && !inclusive)))
      % include_white は include かつ fwd_word が使われた時に設定される。
      % つまり、aw で最初の最初にカーソルが非空白位置にあった時に設定される。
      % 次に cls() は現在位置が非空白の時。この時常に inclusive なので、
      % 範囲の一番最後の文字が非空白の時を意味する。
      % 次に col == 0 && !inclusive は、改行直後でかつ exclusive の時。
      % 実は ble.sh では最後が exclusive の改行の時には、
      % 後で修正される事を見越して既に範囲を前の行末にまで狭めてしまう。
      % しかし、此処での問題は前の行末に非空白文字が存在するとは限らないという事である。
      % やはり flags に X を追加する等するべきだろうか。
      %
      % その前に vim の動作について確認する事にする。
      % 果たしてどの様な時に前方の空白取り込みが起こるのか。
      % % 特に、exclusive 改行直後に一致した時に、
      % % 直前に空行がある可能性はあるのだろうか。
      % % 例えば iw では決して二重改行に一致する事はない。
      % % aw では exclusive な改行になるのは非空白文字に始まって改行に終わる時であるが、
      % % その時二重改行に一致する事は決してない。
      % 然し、よく考えてみたら col == 0 && exclusive の時には、
      % 直前にどの様な文字があったとしても前方の空白取り込みが発生する。
      % つまり、直前が改行以外であったとしても、空白であれば前方の空白取り込みが発生する。
      % 再度振る舞いについて考える必要がある。
      % iw の時はそもそも前方の空白取り込みは発生しないので気にしなくて良い。
      % aw の時に exclusive になるのは非空白に始まって改行に一致する場合である。
      % つまり /w+b*n/ に一致する時である。vim の実装を見る限りでは
      % この場合にも前方の空白取り込みが発生する気がする。確かめる必要がある。
      %
      % うーん。試してみたが空白取り込みは発生していない様に思われる。
      % 実際に vim の current_word の中の様子を見るが取り込みは発生していない。
      % というかそもそも /w+b*/ には一致しているけれども /w+b*n?/ には一致していない。
      % この /w+b*n/ の出処は何処だったろうか。fwd_word の実装の観察である。
      % 再度確認してみる事にする。うーん。処理を大きく読み間違えていた様だ。
      % 正規表現はかなり簡単化する。修正した。
      % 既存のテストはこれに対して変化しなかった。新しいチェックも通る。
      % 安心ではあるが一方で既存のテストは穴だらけという事の証拠でもある…。
      %
      % 改めて考察してみる事にする。col == 0 && exclusive の時の
      % 改行の直前の文字として何が考えられるか。
      % iw で exclusive になるのは単一の改行を読み取った時である。
      % この時直前の文字が空白であるかどうかは分からない。
      % 例えば \n@\n という状態で iw を実行すると次の行に移動する。
      % この時、前方に空白を取りに行く。しかし、前方に空白は存在しない。
      % 或いは、xmap で \nhello@\n という状態で iw を実行するとどうなるのか。
      % (この初期状態を作るには $vlol とすれば良い。)
      % 試してみた所、hell[o] という選択状態になった。微妙…。
      % 現在位置が NUL である為、前方への拡張は行われず
      % 単に改行が一個読み取られるが一つ戻って結局幅 0 になる、
      % かと思いきや eol fix によって一つ戻る。
      % これは実は現在の ble.sh の実装もちゃんとそうなりそうな実装になっている。
      % 然し、実際に試してみた所違う振る舞いをする。テスト項目に加える。
      %
      % 色々考え合わせるとやはり col == 0 && exclusive の時の直前の文字は
      % 非空白文字であると仮定するのは難しい様に思われる。
      % ちゃんとチェックする様にする。
      %
      % 修正した。今までのテストで失敗する様になった物はない。
      % 新しいテストを追加するべきだろうか。
      % 特にこの振る舞いに依存する様な状況は何が考えられるだろうか。
      % つまり aw で exclusive になっているがその改行の直前が空白文字という状況である。
      % aw で exclusive になるのは非空白で始まって改行で終わる状況で、
      % しかしその様な事は起こりえない?
      % おかしい。何か変だ。fwd_word で exclusive が起こる。
      % fwd_word は include != (cls()==0) の時に呼び出されるので、
      % aw の時には非空白の時に使われる。うーん。
      % 実は aw の時には改行は読み取られないので exclusive になる事は有り得ない?

      前方の空白を取り込む条件は、
      1. include_white ... aw でありかつ最初の位置が空白文字だった時、かつ
      2a. 範囲の最後の文字が非空白文字だった時
      2b. 最後の位置が行頭でありかつ exclusive だった時

      ここで 2b の条件は絶対に満たされない様に思われる。
      先ず、include_white を判定している時点で aw である。
      aw の時 exclusive になるのは fwd_word を呼び出した後 (しかも成功) である。
      fwd_word を呼び出す前は必ず非空白文字になっている筈。
      fwd_word で行頭になるのはどういう状況かというと、fwd_word の中を見ていくと、

      | 先ず count = 1, eol = TRUE である。最初のループで count == 0 になる。2回目以降のループはない。
      | sclass = cls(); // sclass には非空白文字のクラスが設定される
      | last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) 最終行の時1
      | i = inc_cursor(); // 非空白文字なので必ず成功する。改行の直前であれば 2 それ以外なら 0
      | if (i == -1 || (i >= 1 && last_line)) // これが満たされる時は FAIL が返されて、そもそも exclusive にならない。
      |     return FAIL;
      | if (i >= 1 && eol && count == 0)  // ここに入る可能性はある。
      |                                   // つまり改行の直前にいた時 @a\n → a@\n という形になる。
      |                                   // しかし fwd_word 呼び出しの後の oneleft が成功するので exclusive にはならない。
      |     return OK;
      |
      | if (sclass != 0) // 非空白なのでこの中には入っていく
      |   while (cls() == sclass) // w+ を読み取る。
      |   {
      |     i = inc_cursor(); // 改行に接したら 2 が返される。それ以外ならば 0 である。
      |     if (i == -1 || (i >= 1 && eol && count == 0))
      |         return OK;  // ここに来るのはファイル末端か www@\n という状況である。
      |                     // 必ず w があるので oneleft が成功して exclusive にはならない。
      |   }
      |
      | while (cls() == 0) // 改行以外の空白に当たった時にここに入る。
      | {
      |     if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
      |         break; // 空行の時、という事だが w+b+の後なので此処には入らない。
      |
      |     i = inc_cursor();
      |     if (i == -1 || (i >= 1 && eol && count == 0))
      |         return OK;  // ファイル末端化 w+b+@\n に当たった時には必ずここに入る。
      |                     // この時も必ず oneleft() が成功するはず。
      | }
      | ここまで来るのは cls() != 0 になった時である。
      | つまり、また別の単語が始まった時である。
      | ここで抜けるとやはり必ず oneleft() が成功するはずである。

      やはり fwd_word で行頭で抜けて oneleft() が失敗して exclusive になるという事は有り得ない気がする。

      或いは oneleft はまた別の実装になっているのだろうか。
      何と、確認してみた所 virtual_active() の時には oneleft は getviscol() つまり、
      見た目の列で左に行くか行かないかが決まる様である。つまり、
      行の途中であっても exclusive になったりならなかったりする。
      これだと色々動作的に困る気がするのだが大丈夫なのだろうか…
      と思ったが実はそんなに問題にはならないのかもしれない。
      oneleft() する事と exclusive にする事は大体同じ動作だからである。
      何れにしても virtual_active() が成立していない時には oneleft は単に col を見ているだけである。

      結論: virtual_active() における oneleft() の動作を考えなければ、
        aw に於いて exclusive の状態になる事は有り得ない。
        従って、exclusive の判定は aw ではしなくて良いし、
        前方拡張についても exclusive の判定は省略可能である。

    x fixed: xmap について漸くテストを開始する。
      と思ったら早速振る舞いが変だ。
      viw が ciw と異なる範囲を選択している。
      vim の方では同じ範囲になる。

      うーん。調べてみると行末でなければ index++ するという振る舞いになっている。
      この振る舞いの根拠は一体何だったのだろうか。
      一応 vim の実装の方でも特殊な事をしていないかを確認する事にする。

      if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor))
          dec_cursor();

      うーん。寧ろ条件に依ってカーソルの位置を後退している。
      しかしこれは exclusive の位置から inclusive の位置に変換する為に行っている事。
      他には、事前の操作で visual モードの時に特別なことをするという処理は見当たらない。
      それよりも事後で何かしている。

      if (VIsual_active) {
          if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor))
              inc_cursor();
          if (VIsual_mode == 'V')
          {
              VIsual_mode = 'v';
              redraw_cmdline = TRUE;              /* show mode later */
          }
      }

      選択が exclusive の場合には inc_cursor している。
      しかしビジュアルモードの選択が exclusive というのはどういう状況だろうか。
      少なくとも現在の ble.sh では対応していない機能である。
      他に行ビジュアルモードだったら文字ビジュアルモードに変更して再描画する。

      実はビジュアルモードに対して特別な事をする必要はないのではないかという気がする。
      余分な処理を除去したら全て動く様になった。

    x fixed: 次に vhiw と vhaw のテストを試してみたら全滅だった。全然駄目。
      これはまた vim の振る舞いについて研究が必要になる。

      後退時は幾分簡単で以下のコードが繰り返し適用されるだけである。
      ここより前の部分にも幾らかコードがあったが、何れも条件を満たさないので実行されない。

      | if (VIsual_active && LT_POS(curwin->w_cursor, VIsual))
      | {
      |   if (decl(&curwin->w_cursor) == -1)
      |       return FAIL;
      |   先ずは現在位置を後退する。行頭にある場合には前の行の最後の文字に移動する。
      |   前の行が空行だったらそのまま前の行の行末。
      |   それ以外の場合には一文字左に移動する。
      |
      |   if (include != (cls() != 0))
      |   {
      |     iw (include == false) で非空白文字 (cls()!=0) にいる時。
      |     もしくは aw で空白文字にいる時。
      |
      |     if (bck_word(1L, bigword, TRUE) == FAIL)
      |         return FAIL;
      |
      |     | bck_word = [] {
      |     |   sclass = cls();
      |     |   if (dec_cursor() == -1) return FAIL; // 一文字戻る。戻れなければ失敗(※1)
      |     |   if (sclass == cls() || sclass == 0) {
      |     |       最初の文字が w の場合と b と n (空行の時のみ) の場合がある。
      |     |       この時点で /@.[wbn]$/ という状態である。
      |     |       while (cls() == 0) {
      |     |           最初が b または n ならば空白類は読み飛ばしたい。
      |     |           現在位置が空行ならば直ぐに止まる。
      |     |           n@n[bn]$ という状況だと即停止してしまう。
      |     |           n@nb*$ という状況や nnb*n$ という状況など。
      |     |           正規表現で表せば b*n(b+n)*b*n?$ という事になるだろうか。
      |     |           if (curwin->w_cursor.col == 0
      |     |                                 && LINEEMPTY(curwin->w_cursor.lnum))
      |     |               goto finished;
      |     |           if (dec_cursor() == -1) /* hit start of file, stop here */
      |     |               return OK;
      |     |               もしファイルの先頭に達したらOK
      |     |               つまりこれは /^b*n(b+n)*b*n?$/ というのに一致する状況。
      |     |       }
      |     |
      |     |       if (skip_chars(cls(), BACKWARD))
      |     |           return OK;
      |     |       最初が w の時には ww$ ならば skip_chars がそのまま実行されて
      |     |       うーん。何か変な位置で停止する気がする。と思ったけれども、
      |     |       if (skip_chars()) が 0 以外を返すのは失敗した時だから良い。
      |     |       要するに /w+$/ を読み取った場合という事になる。
      |     |       最初が b または n の時には /w*b*n(b+n)*b*n?$/ に一致する。
      |     |       但し、/^b*n(b+n)*b*$/ の時は既に一致しているし、
      |     |       /n@n(b+n)*b*$/ の時は既に終了している筈なので、
      |     |       此処に入ってくるのは /w+b*n(b+n)*b*n?$/ である筈。
      |     |   }
      |     |   上の条件文の中から来た場合は /@.w{2,}|@.w+b*n(b+n)*b*n?$/ である。
      |     |   条件文に入らないのは @Ww$ や @bw$ や @nw$ の時である。
      |     |   つまり、/@.w+(b*n(b+n)*b*n?)?$/ という事の様に思う。
      |     |
      |     |   inc_cursor();                   /* overshot - forward one */
      |     |   ここで /w+(b*n(b+n)*b*n?)?$/ に一致する様になる。
      |     | finished:
      |     |   return OK;
      |     | }
      |
      |     合わせると /^b*n(b+n)*b*n?$|w+(b*n(b+n)*b*n?)?$|(?<n)b*n(b+n)*b*n?$/ である。
      |     二重改行の条件は潰せないだろうか。/b*n(b+n)*b*n?/ の直前に来るのは、
      |     可能性としては ^nw の何れかである。b があれば一致するので。
      |     また先に w+* を判定しておけば w が来る事もない。
      |     二重改行以外の n の場合もちゃんと b*n 側に含まれる筈である。
      |     従って ^ または二重改行にちゃんとなる。
      |     /w+$|w*b*n(b+n)*b*n?$/ これで判定すれば良い。
      |
      |     特に iw で非空白文字にいる時は /w+$/ であり、
      |     aw で空白文字にいる時は /w*b*n(b+n)*b*n?$/ である。
      |
      |     所で※1の部分を見ると vim は 'he@llo' に対して vhiw とするとエラーになる。
      |     'hel@lo' に対して vhiw はエラーにならないのに。
      |     これは本当に意図した振る舞いなのだろうか。
      |
      |   } else {
      |     if (bckend_word(1L, bigword, TRUE) == FAIL)
      |       return FAIL;
      |     | bckend_word = [] {
      |     |   sclass = cls(); // /.$/
      |     |   if ((i = dec_cursor()) == -1)
      |     |     return FAIL; // /^.$/ だったら失敗
      |     |   if (i == 1) // /\n.$/ だったら成功
      |     |     return OK;
      |     |
      |     |   if (sclass != 0) { // /.w$/ の時
      |     |     while (cls() == sclass)
      |     |       if ((i = dec_cursor()) == -1 || (eol && i == 1))
      |     |         return OK; /(^|\n)w+$/ だったら成功
      |     |     /.w+$/ という状態
      |     |   }
      |     |   この時点で /.w+$|.[bn]$/ という状態である。/.(w+|[bn])$/ とまとめる。
      |     |
      |     |   while (cls() == 0) {
      |     |     if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum))
      |     |       break; 現在位置が二重改行ならば終了
      |     |     if ((i = dec_cursor()) == -1 || (eol && i == 1))
      |     |       return OK; 一つ前に ^ または n があればそれを読んで終了
      |     |   }
      |     |   % この部分は、最初に n があったならば二重改行の判定をして、
      |     |   % それ以降にはそもそも n を呼んだ時点で終了するので、
      |     |   % 二重改行が現れる事はないはずである。
      |     |   % つまり、/n@n(w+|[bn])$/ ならばそこで抜ける。
      |     |   % それ以外ならば /(^|n)b+[bn](w+|[bn])$/ で終了。という具合。
      |     |   % 途中で空白以外になったらやはり終了。
      |     |   % つまり /wb+[bn](w+|[bn])$/ の様な物。
      |     |   実はこの部分で最初に n がある事はない。
      |     |   改行 n が途中で現れたとしてもそれを読んで抜ける。
      |     |   従って、この部分を抜けた後は /wb*(w+|[bn])$/ である。
      |     |
      |     |   % まとめると、/w(w+|[bn])$/ だったらそのまま。
      |     |   % /nn(w+|[bn])$/ だったら1文字進める。
      |     |   % /b+[bn](w+|[bn])$/ で読めるだけ読んでおけば良い。
      |     |   % 直前が wn だった場合には余分に1文字後退する。
      |     |   % 直前が ^ だったらそのまま。直前が b である事はない。
      |     |
      |     |   うーん。結局 break しても return OK しても直後に
      |     |   return OK があるから違いはないのである。
      |     |   その様に考えればこのループが終わるのは
      |     |   改行を飛び越えた後か、飛び越えた文字が空白以外か、
      |     |   編集文字列の先頭に達したかという事であるか、
      |     |   という事であるから /(^|[wn])b*(w+|[bn])$/ である。
      |     |
      |     |   return OK;
      |     | }
      |
      |     (void)incl(&curwin->w_cursor);
      |
      |     これによりどうなるか。
      |
      |     1. /(^|n).$/ の時には /.$/ になる。 (vim 実装では ^.$ は失敗なのだがこれは多分ミス)
      |       →と思ったが /^.$/ の場合には /$/ になってしまうのでは。つまり、動かない。
      |       従って /.$/ の時には失敗で /\n.$/ の時には /.$/ に一致する。
      |       しかしながら結局後で失敗した時には先頭位置に移動するのでやはり /.$/ になると言って良い。
      |
      |     2. /(^|n)w+$/ の時には /w+$/ になる。
      |
      |     % 3. /n@n(w+|[bn])$/ の時には /(w+|[bn])$/ になる。
      |     %   →と思ったが /w+$/ の時には n が来た時点で抜ける筈なので、
      |     %   実際に実現するのは /n@n[bn]$/ のパターンのみである。
      |     %   更に /n.$/ のパターンは既に /.$/ という取り扱いになるという事を考えると、
      |     %   /n@n[bn]$/ の場合もここまで進む前に抜けてしまうはずである。
      |     %   従って、このパターンは実際にはテキストオブジェクトでは起こらない。
      |     % 4. /^bb*[bn](w+|[bn])$/ の時には最初の b が削られて /b*[bn](w+|[bn])$/ になる。
      |     %   更に incl なので bn という状況になっている場合には二文字進むなどもある。
      |     %   →これは上記と同様の議論によって、実際には /bb*b(w+|[bn])$/ しか実現しない。
      |     % /[wn]b+[bn](w+|[bn])$/ に対しては /b+[bn](w+|[bn])$/ となる。
      |
      |     3. /(^|[wn])b*(w+|[bn])$/ で抜けた時には、
      |       incl によってどうなるか。場合分けが必要である。
      |
      |       | a /^(w+|[bn])$/
      |       |   % 実は /^[bn]$/ だったら既に失敗している筈なので、
      |       |   % /^w{2,}$/ しか実現されない。この時には incl　によって /w@w+$/ になる。
      |       |   % 然し、本当にその様な動作になるだろうか…。うーん。
      |       |   % 実は dec_cursor() == -1 になった時というのは ^ を読み飛ばして、
      |       |   % 負のインデックスになっているという事なのかもしれない。
      |       |   % →うーん。確認してみたが (0,0) の位置にいる場合には、
      |       |   % 其処から動かずに dec_cursor() == -1 になっている。
      |       |   % つまり、次の decl によって一文字進んでしまう気がする。
      |       |   %
      |       |   % 然し、その様な実装になっているという事が今一理解できない。
      |       |   % 実際に実行して試してみる事にする。何と再現した…。
      |       |   % check 'echo@ hello' 'v h a w S a' 'e@<cho >hello' → これは vi_test.sh に追記した。
      |       |
      |       |   結局 /^w{2,}$/ ならば /w@w+$/ の位置になる。
      |       |
      |       | b /^b+(w+|[bn])$/
      |       |
      |       |   % 特に /^bn$/ の場合には2文字進む気がする。
      |       |   % そして最初と同じ位置になる。
      |       |   % これは本当にそうだろうか。試してみる事にする。
      |       |   % うーん。bn@ で aw を実行するとエラーに為る。
      |       |   % と思ったが、ここで試すべきは iw ではないだろうか。
      |       |   % うーん。bn@ で iw に対してもエラーになる。
      |       |   % /^bbn$/ の時には iw で /b@bn$/ になる。
      |       |   %
      |       |   % →うーん。改行の直前の場合には少し異なる動作をする。
      |       |   % /^bn$/ の時には最初の decl で /^@bn$/ という状態になる。
      |       |   %
      |       |   % もう少し真面目に考える必要がある。
      |       |   % 二重改行の場合には /^n@n$/ という形になって、
      |       |   % iw を実行した時に bckend_word に入るが、
      |       |   % /^n@n$/ から /^@nn$/ になってしかし改行を越えたという事で
      |       |   % 其処で終了して直後の incl で /^@n$/ という形になる。
      |       |   % /^@n$/ の場合には戻ろうとした時に失敗して、結局失敗する。
      |       |   % それ以外の場合には必ず n 以外の位置にカーソルがあるはず。
      |       |   % つまり /[wb]$/ という事になる。
      |       |
      |       |   その様に考えると $ の直前の構造として考えられるのは、
      |       |   /(^|n)n$/ か /[wb]$/ かのどちらかしかない。
      |       |   従って、/^bn$/ や /^bbn$/ の状態が達成される事はない。
      |       |
      |       |   更に言うと /(^|n)n$/ の構造になっている場合には、
      |       |   その前の段階で失敗か成功をするので、ここまで来る事はありえない。
      |       |   /n$/ つまり、n が $ の直前に来る場合については想定しなくて良い。
      |       |
      |       |   この場合には /^b{2,}$/ または /^b+w+$/ が実現される。
      |       |   何れの場合でも最初の b は incl によって除外される。
      |       |
      |       | % c /[wn](w+|[bn])$/
      |       | %   これは先の議論によって /[wn](w+|b)$/ という状態しか実現しない。
      |       | %   w+ の場合には w+ で w は読み切る筈なので /^w{2,}$/ だが、
      |       | %   これは別の場合に含まれる。或いは /nw+$/ である。
      |       | %   その場合には /w+$/ にまで縮小して終わる。
      |       | %   /wb$/ の場合には
      |       | %
      |       | % d /[wn]b+(w+|[bn])$/
      |       | %   これも先の議論によって /[wn]b+(w+|b)$/ という状態しか実現しない。
      |       | %
      |       | % これは別の場合分けをした方が良い気がしてきた。
      |       |
      |       | e /[wn]w+/
      |       |   % /w{2,}$/ これは /w@w+$/ となるが、そもそも此処に来るのはどの様な場合か。
      |       |   % /bw{2,}$/ という場合には b を読んで次の場合に入る筈だ。
      |       |   % /nw{2,}$/ という場合には /nw+/ という場合になる。
      |       |   % 途中で ^ に当たる場合は既に処理している。
      |       |
      |       |   従って、此処に入るのは /nw+$/ というパターンしか存在しない。
      |       |   その場合には /n@w+$/ になる。
      |       |
      |       | f /[wn]b+w+/
      |       |   此処に入るのは、うーん。これは普通に実現しそうである。
      |       |   この場合には最終的に /[wn]@b+w+$/ という事になる。
      |       |
      |       | g /[wn]b+/
      |       |   これも普通に実現しそうである。/[wn]@b+$/ という事になる。
      |
      |       以上をまとめると /^w{2,}$/ ならば /w@w+$/ の位置になる。
      |       /^b{2,}$/ または /^b+w+$/ の時には /^b@(b+|w+)$/ となる。
      |       /nw+$/ の時は /n@w+$/ になる。
      |       /[wn]b+w+/ 及び /[wn]b+/ の場合にはやはり一文字飛ばす。
      |
      |       最後が w の時とそれ以外の時で分けて考える事にする。
      |
      |       a aw非空白の場合: /^w{2,}$/ または /^b+w+$/ または /nw+$/ または /[wn]b+w+$/ で、
      |         何れの場合でも 1 文字進める。
      |         まとめると、/(^w|n|(^|[wn])b+)w+$/ で、何れの場合でも1文字進める。
      |         1.2. の時も考え合わせると /^w$/ の時には一回失敗となって先頭に置かれる。
      |         /nw$/ の場合には /n@w$/ になる。/(^|n)w+$/ の場合には一文字進む。
      |
      |         従って、/(^|n|(^|[wn])b+)w+$/ で、一致長さが2文字以上の時に1文字進む。
      |         もう少し変形できないだろうか。
      |         /(^|n)w+$|(^|[wn])b+w+$/
      |         うーん。微妙 (^|[wn]) を共通化するのは分かりにくくなる。
      |
      |       b iw空白の場合: 最後が n の場合は此処には入らない。最後が b の場合は、
      |         /^b{2,}$/ または /[wn]b+/ の場合で、これは1文字進む。
      |         1.2. も考えると /(^|n)b$/ の時には、/nb$/ なら1文字進んで、
      |         /^b$/ は一回失敗して先頭に行く。/(^|n)n$/ の時には、/n$/ に一致する。
      |
      |         従って、/(^|[wn])b+$/ の時、一致長さが2文字以上の時に1文字進む。
      |
      |       これらを "1文字進む" という特別動作を行わないで済むように変換できるだろうか。
      |
      |       a aw非空白: 先ず /w+$|b+w+$/ に一致させる。直前に ^ がなければ、
      |         直前には wbn の何れかが存在するはずである。w+ の場合には直前は b か n である。
      |         その場合は結局 1文字進めるという動作は /w+$/ に一致するのと同じ事である。
      |         b+w+ の場合には直前は wn の何れかである。これの場合も結局1文字進めるという動作は
      |         /b+w+$/ に一致させるのと同じ動作である。直前が ^ である時は、
      |         /^b*w+$/ に一致させる事になるが、この時は1文字進める必要が出てくる。
      |
      |         従って /b*w+$/ に一致させて、その後で「先頭まで一致してかつ2文字以上一致している時に1文字進める」
      |
      |       b iw空白: /b+$/ に一致させて、その後で「先頭まで一致してかつ2文字以上一致している時に1文字進める」
      |
      |     # さて、暫く時間が空いたので何を考えていたのか分からなくなってしまった。
      |     # 覚えているのは xmap で後退する時の読み取り規則を正規表現で表そうという事である。
      |     # 呼び出される関数が最初のカーソル位置の空白・非空白で切り替わる。
      |     # (1) 一方は iw で非空白文字にいる時または aw で空白文字にいる時である。
      |     # (2) 他方は aw で非空白文字にいる時または iw で空白文字にいる時である。
      |     # vim の振る舞いには怪しい点が幾つかあるのでそれを都合よく修正して解釈する事にする。
      |     # (2) に関しては取り敢えず前の単語の末端を見つけてから一つ文字を戻すという作戦である。
      |   }
      | }

      iw ならば /(w+|b+)?$/ に一致させる。一致部分が /^bb/ に一致するならば一文字進める。
      aw ならば /(b*w+|w*b*n(b+n)*b*n?)$/ に一致させる。一致部分が /.w$/ に一致するならば一文字進める。

      本当にこれで良いのだろうか…。直前の decl に対してどの様に動作するだろうか。
      特に直前に行頭にいた時には /.n$/ という状態になって一致が始まるのではないか。
      それは即ち改行(空行以外)があった時のみ1文字戻ると解釈される。うーん。
      取り敢えず実装してみる事にする。

      うーん。aw空白で始まった時の w+b+ が条件に含まれていない。
      現状の実装だと必ず改行が含まれなければならない事になっている。
      改めて bck_word を調べなければならない。

      | bck_word = [] {
      |   sclass = cls();
      |   if (dec_cursor() == -1) return FAIL; /^.n?$/ の時は失敗
      |   この時点で /..n?$/ という状態になっている。
      |   if (sclass == cls() || sclass == 0) {
      |     ここでは /(ww|.[bn])n?+$/ という状態になっている。
      |     while (cls() == 0) {
      |       % ここに入ってくるのは /[bn][bn]n?+$/ の時のみ。
      |       % 現在位置が空行ならばすぐに止まる。つまり /n@[bn][bn]n?+$/ で止まる。
      |       % これに従うと最大で nnn を読み取れる様になっている気がするが…。
      |       % うーん。n?+ が読み取られるのは n の直前に n 以外がある時のはずである。
      |       % つまり n?+ というよりは ((?<!n)n)? である。これは N と書く事にして後で考える。
      |
      |       ここに入ってくるのは /[bn][bn]N$/ の時のみである。
      |
      |       if (curwin->w_cursor.col == 0
      |                             && LINEEMPTY(curwin->w_cursor.lnum))
      |           goto finished;
      |       if (dec_cursor() == -1) /* hit start of file, stop here */
      |           return OK;
      |     }
      |
      |     現在位置が空行ならばすぐ止まる。/n@n[bn]N$/ だと止まる。
      |     それ以外ならば二重改行が現れる迄は [bn]* を読み取る。
      |     要するに /(ww|b*(n(b+n)*b*)?[bn])N$/ という事である。
      |
      |     途中で二重改行または編集文字列の先頭に達した場合は既に抜けている。
      |     つまり、ここまで到達するのは w に出会った時である。
      |     if (skip_chars(cls(), BACKWARD))
      |         return OK;
      |
      |     もし w+ を読み取っている途中で文字列の先頭に到達した場合には、
      |     その場で抜ける。w 以外の文字に到達した場合には下に流れる。
      |     最終的に w の先頭に移動してそれから抜ける事になる。
      |   }
      |   そもそも上の if 文に入らなかった場合も此処に来る。
      |   それは /[bn]wN$/ 等である。
      |   inc_cursor();                   /* overshot - forward one */
      | finished:
      |   return OK;
      | }

      まとめると、/(w+|w*b*(n(b+n)*b*)?[bn])N$/ ただし N = ((?<!n)n)? という事。
      ここに入るのは N を読み取った直後に iw非空白 または aw 空白にいる時である。

      a iw非空白: /w+N$/
      b aw空白: /w*b*(n(b+n)*b*)?[bn]N$/

      これに従って再度正規表現を修正する。iw の方は修正は不要である。
      aw の方は [bn]N は /bN|nN/ = /bn?|n/ と書き換えられる。

      因みに、vim の変な振る舞いについてまとめておく事にする。

      | 'hell@o' vhaw 'h[ello]'
      | '    @ ' vhiw ' [    ]'
      | 'ab@c'   vhiw '[abc]' + bell
      | 'ab@c'   vhaw '[abc]' + bell
      | '  @ '   vhiw '[abc]' + bell
      | '  @ '   vhaw '[abc]' + bell

    * ok: 所で xmap の時には末端に文字を移動する事ができるという事に注意しなければならないのでは…。
      これまで調べた vim の振る舞いも末端に文字が存在しないという事を仮定してはいなかったか。
      これに関してはテストを追加した。

      余り深追いしたくないが実際に試してみると違いがある。

      test(txtobj word xmap/Bn/viw): keys = (v $ o $ i w c)
        initial  = "0:echo hello^Jecho world"
        expected = "9:echo hell^Jecho world"
        result   = "9:echo hellecho world"

      行末までのはずが次の改行まで削除されてしまっている。
      operator:c により範囲が拡張されているのかと考えたが、
      実際に試してみるとそうでも無い様である。
      operator:c に範囲が渡された時点で次の行末までになっている。

      というより、iw で範囲選択している段階ではちゃんと行末までになっていた気がする。
      これは iw の問題ではない…と思ったが、そもそものテストケースは正しいのだろうか。
      と思って試してみたらテストケースの方が誤っていた。

2018-10-06

  * syntax (reported by cmplstofB): コメント上の単語が何故か除去されない [#D0854]
    https://github.com/akinomyoga/ble.sh/issues/17

    調べてみると悪いのは 854c3b4 のようである。
    少なくともここで発現する様になった。
    しかし、ここでは単語に関する着色は何もしていない。
    うーん。もっと前にやった変更がここで発現する様になっただけの可能性もある。

    うーん。ble-highlight-layer:syntax/update-word-table 冒頭には
    「単語の削除に関しては後で考える」と書かれている。

    うーん。改めて 854c3b4 を見てみる。
    .apply-attributes で着色を削除する d の判定が増えている。
    もしやと思って呼び出し元を調べてみた所、
    '' で呼び出して削除しようとしているところがあった。直した。

  * color: workaround Bash 3.0 算術式で <() がプロセス置換に勘違いされる [#D0853]
    検索してみたが他の箇所では <() という構造は現れていない様だ。

2018-10-01

  * 2018-09-23 manual: 説明書について書き始める (2) complete 等 [#D0852]

    - done: auto-complete: C-j が誤って insert になっていた 01476a7

    - done: dabbrev: RET, C-m は確定で、C-RET, C-j で実行にした方が良いのでは 01476a7

    - done: edit: M-S-f, M-S-b を束縛するべきところ M-C-f, M-C-b を束縛している箇所があった c68e7d7

    - done: complete: auto_complete の M- 事情はどうなっているのか? edd481c
      bleopt decode_isolated_esc=auto だと M- が吸収されてしまう。
      結局 decode_isolated_esc=auto で default_keymap もチェックする事にした。

    - done: isearch/exit-delete-forward-char は実態を反映していないのでは db28f74
      →これは元々 emacs の動作に合わせる為だった気がする。
      emacs では検索して C-d とするとその位置の文字が削除される。
      検索して一致した部分が削除される訳ではないのである。
      改めて試してみると確かにそうだった。

      Bash の振る舞いはどうであっただろうか。
      Bash はもっと原始的な振る舞いしかしない。
      常にカーソルは一致範囲の先頭であり、
      また、C-d とするとその位置の文字が削除される。

      一方で、現在の ble.sh の実装ではその他の様々の操作も全て
      一致した範囲に作用する様になっている。つまり、
      C-d だけ別の振る舞いをするというのも不自然である。
      従って、今の振る舞いのままで良いが、
      exit-delete-forward-char は Bash/Emacs 互換の動作として、
      既定では束縛しない様にする。

    - done: auto_complete 及び menu_filter の有効無効も切り替えられた方が良いのでは 4425d12

    - done: bleopt complete_stdin_frequency は改名したい
      これに対応する為にはうーん。
      complete_stdin_frequency に bind した時に警告を発生する様にしたい。
      後、どの様な変数名が適当であろうか。
      complete_stdin_check_interval
      complete_polling_cycle が良さそうだ。知っていれば何かすぐに分かる。
      古い変数名に対するチェックも行った。

  * refactor: 関数名を整理する [#D0851]

    特に / を含まない ble から始まる関数は
    ユーザに公開する関数のみに留める事にする。
    元々は他のファイルに公開する関数のみに留めようと考えていたが、
    そんなに疎結合ではなかったので限界がある。

    * 文字符号化方式関連では以下の関数が存在している。
      - ble-decode-byte+*
      - ble-text-b2c+*
      - ble-text-c2b+*
      - ble-text-c2bc+*

      以下の様に改名したい。
      - ble/encoding:*/decode
      - ble/encoding:*/b2c
      - ble/encoding:*/c2b
      - ble/encoding:*/c2bc

      改名した。

    * attach/detach 関連は特に初期の公開のポリシーに従っていた為に
      ble-edit-attach や ble-decode-attach 等が存在している。
      これらは ble-edit/attach や ble-decode/attach に変更する。
      然し、ble-edit/attach については既に存在している。使い分けは何だろうか。

      - ble-edit/attach -> ble-edit/attach/.attach # PS1 IFS IGNOREEOF LINENO 等の調整
      - ble-edit/detach -> ble-edit/attach/.detach # 同上
      - ble-edit-attach   -> ble-edit/attach # 上 + カーソル位置原点
      - ble-edit-finalize -> ble-edit/detach # 上 + ごみの削除
      - ble-edit-initialize -> ble-edit/initialize # プロンプト用定数の初期化

      ble-decode 関連は特に衝突も無い様だ。

      - ble-decode-attach   -> ble-decode/attach
      - ble-decode-finalize -> ble-decode/detach

      改名した。

    * ble-decode-key 及び ble-decode-char はあるのに
      ble-decode-byte は存在しない。一応ユーザに提供するという名目で公開する事にしても良い。

      # 然し、実は bind 'kseq: "string"' に対応する時に使う事になる様な気がしている。

2018-09-29

  * 2018-09-23 manual: 説明書について書き始める (1) decode [#D0850]

    - core: bleopt に設定名を指定子て設定内容を表示させる時、設定名の存在を確認する 725d09c
    - decode (ble-bind): オプション `-cf` 及び `-xf` をそれぞれ `-c` 及び `-x` に変更 f7f1ec8
    - decode (ble-bind): オプション `-d` に於いて `-c` 及び `-x` の引用符が二重になっている問題の修正 f7f1ec8
    - decode: 組み込みコマンド bind を上書きして引数をチェックする f7f1ec8
    - decode (ble-bind): オプション `--list-widgets` 64ad962
    - decode (ble-bind): オプション `[-m keymap]... -P|--print|-D|--dump` 64ad962
    - decode (cmap/default): rxvt の <kbd>(C-)?(S-)?(up|down|right|left)</kbd> 及び <kbd>S-(f11..f20|home|end|insert|delete|prior|next)</kbd> に対応 dc013ad
    - decode (cmap/default): <kbd>kpspace</kbd> は <kbd>SP</kbd> として受信する dc013ad
    - decode (csi/.decode): <kbd>kp5</kbd> を <kbd>CSI 1 ; <i>mod</i> u</kbd> で送る端末に対する対策 dc013ad
    - decode: `bleopt decode_isolated_esc=auto` 設定を追加 9b20b45

  * decode: バッチで挿入を実行するという事を考えたが、微妙な点が様々ある [#D0849]

    - 元々のアイディアは emacs もしくは vi_ins において、
      ble-bind -f __batch_chars__ ... 的な設定を追加して、
      __batch_chars__ が存在すればそれを呼び出して挿入を行うという物である。
    - overwrite_mode や選択領域がある場合などには 125 を返して、
      そうしたら通常通り1バイトずつ処理するモードに入る。

    % 微妙な点は以下の通り。
    %
    % x ASCII の GL 図形文字の範囲を特殊な文字に使用する文字コードで駄目。
    %   例えば iso-2022 は GL 図形文字を色々に変更することができる。
    %   またマルチバイト文字の二バイト目以降として
    %   GL 図形文字を使っている文字コードがあっても不思議ではない。
    %   →これに関しては先に文字コードの復号だけ行ってから実際の挿入処理を行うという手もある。
    %
    % x 文字に ble-bind して使う人がいると入力や通信の速度で振る舞いが変わる事になり駄目。
    %   例えば特定の文字に (文字挿入+何かの操作) を割り当てるなどの事が考えられる。
    %   magic-space の様に。
    %
    %   これに対して対応するにはどうすれば良いか。
    %   毎回 keymap の binding を検査するのも大変である。
    %
    % x 更に何らかのキーシーケンスやキー列の後半で通常文字を使う事もある。
    %   その通常文字と区別する事はできるのだろうか。
    %   →これはキーシーケンスが途中状態でないかどうかだけ見ればOK?

    実は __defchar__ を呼び出すところでキャッシュすれば良いだけなのかもしれない。

    x 但し、それだと通常文字ばかり大量に入力した時に progress が更新されなくなる。
      特に overwrite mode に入っているとき等は結局1文字ずつ処理する事になるので、
      とても遅い事になってしまう。

      →これは上限を 50 文字にするなどすれば良い。
        これで高速化が阻まれたとしても精々 2% 遅くなるだけなので問題ない。

    - キャッシュされた文字があるかどうかを key を受け取った時に
      最初に調べなければならない。

    x 次の入力がある時のみにキャッシュは行う。
      次の入力によってすぐにまた制御が戻ってくるはずだからである。
      しかし本当だろうか。入力バイトがあったからと言って、
      エンコーディングでマルチバイト文字が完成するとは限らないし、
      キーシーケンス復号でキーが完全になるとは限らない。

      →と思ったが、よく考えてみたら既に has-input では、
      不完全な文字符号化やキーシーケンスの時には
      続きがすぐに来るという事を期待している。

    x __defchar__ の処理中に keymap が変わったり、
      __batch_char__ の binding が変わったりする場合はどうなのか。
      また _ble_decode_key__hook が設定される場合も考えうる。

      →その様な変な動作をする場合にはそもそも __batch_char__
        を設定していないはずなので、大丈夫。
        一応説明書にその様に記述しておけば良い。

    - ok: bracketed paste mode はどうか。
      bracketed-paste-mode の時には _ble_decode_key__hook 経由でキャッシュされる。
      何れにしても _ble_decode_key__hook よりも後でキャッシュは実行するはずなので、
      bracketed paste mode に影響はないだろう。
      bracketed paste mode の間は _ble_decode_key__hook より後ろに来ることは無いので、
      bracketed paste mode に対して変な影響を与える事もない。
      また bracketed paste mode に突入するのは paste_begin を受信した時で、
      その時にはちゃんと後ろまで行ってキャッシュされた文字たちが実行されるので大丈夫。

    - 何処でキャッシュを実行するべきだろうか。
      最初はキーを受け取った直後でチェックを行って入力がなければ実行という事にしようと思ったが、
      それだと1文字ずつしかキャッシュされずに毎回実行される事になってしまう。
      しかし、だからと言って通常文字の場合にはキャッシュに追記する、
      という振る舞いにしてしまうと通常文字に対して bind がある場合に駄目。
      やはりキャッシュへの追記は __defchar__ で実行するべき気がする。

      或いは、キャッシュの実行は実際にコマンドが実行される直前、という事にする。
      それだと不完全なキーシーケンスで終わった時に、キャッシュが実行されない。
      という事を考えたが、ble-decode-key の一番最後で has-input を確認して、
      もし次の入力がなかったら実行するという事で良い気がする。

    これは少々実験的な実装になると思うので、
    bind レベルのキャッシュとは別で取り扱う事にして、一旦 commit する事にする。

    - vi_imap においては self-insert を記録している。
      これをどの様に取り扱うべきかはまた考える必要がある。
      例えば __batch_char__ についても記録して良いが、
      125 を返した場合にはどうするのか、など。

      と思ったが 125 を返さずに、内部でループで回して処理すれば良い気がしてきた。
      外で progress を表示するなどの事はできなくなるが、
      今は progress を batch に対して表示する事は諦めたので、
      そもそも 125 を返すことができる必要はない。

    実装した。動いている様な気がする。
    1000文字 8.5s ぐらいだったのが 3.5s ぐらいにまで高速化した。
    chatoyancy で試したら元から 1000 文字 1.5s ぐらいで、
    1s ぐらいにしか変化しなかった。chatoyancy は滅茶苦茶速い。

  * 2018-09-25 decode: 実は ble-decode/.hook で is-stdin-ready をチェックして [#D0848]
    バイト列を中でキャッシュする様にすれば高速化できるのではないだろうか。
    特に PROLOGUE と EPILOGUE の呼び出しを省略する事ができる。
    また、大量のバイト列を受け取った状態でプログレスバーを表示する事も可能である。

    この時 ble-decode/has-input はまた修正が必要になる事に注意する。
    特にキャッシュしたバイトを処理している途中状態でどう対応するか。
    一番最後のバイトを処理している時はもう入力がないと判定する必要がある。

    更に言うと今までの has-input も不完全だったのではないか。
    ble-decode/.hook で二つ以上の引数を受け取った時、
    一番最後以外のバイトを処理している時には、
    ちゃんと has-input が成功する様になっていただろうか。
    今確認した所そうはなっていない。

    2018-09-29 本当に実際に高速化するのかどうかは未知数である。
    試しにキャッシュしてみて実測してみることにする。
    時計を見ながら手動で計測した所、キャッシュしないと 10 秒程度だったのが、
    キャッシュすると 8 秒程度になった。微妙に速くはなったが、
    やはり実際に入ってきた文字を処理している時間の方が長いのであった。

    ところで PROLOGUE と EPILOGUE を各文字毎に呼び出さないと起こる不都合などはあっただろうか。
    改めてそれぞれ何をしているかを確認する事にする。問題なさそうである。

    処理が続行している間は進行状況を表示する事にする。
    - 但し、default の時にのみ。これの判定は [[ $_ble_edit_info_scene == default ]] で良い?
      他には show という状態しか無いようなので多分良いのだろう。
    - どの頻度で進行状況を表示するのが良いだろう。
      一秒に 2 回程度であろうか。だとすると 1000 件処理するのに約 10 秒として、
      100件処理するのに 1 秒で、50件毎に表示すれば良い気がする。
      (但し、これは遅いホストでの話しなので実際にはもう少し頻度が高くなるだろうがそんな物であろう。
      進行状況の表示によるオーバーヘッドであるがそんなには高くないと信じたい)
    - 実は vim-mode だから遅いというのはあるのかもしれない。
      と思って測ってみたが殆ど変わらなかった。

    bracketed paste を自動的に設定しようかとも思ったが、
    それだと本当に vim の操作としてアルファベットを入力しているのと区別がつかない。
    そのような事をする人がいるとは思い難いが、しかし勝手に振る舞いが変わるのは良くない。

2018-09-27

  * isearch: 空文字列で検索した時 stack による巻き戻しが無効になっている。何故? [#D0847]

    | % どうもこれは "空文字列の時に" 起こるのではなくて、
    | % C-r で当たった履歴項目の一つ前の項目に一致する時に起こることである。
    | % つまり、C-r で当たった時に "次の検索位置" が現在の履歴項目の一つ前に設定されている為に、
    | % そのまた次の検索で向きを変更した時に、
    | % 現在の履歴項目の一つ後から検索を始めなければならないのに
    | % 現在の履歴項目の一つ前から検索を始めてしまっているのが問題なのである。
    | % 改めて現在の実装がどの様な記録の仕方をしているのかについて確認する事にする。
    |
    | →否、全然違った。原因はそうではなかった。やはり空文字列の時に起こることである。
    | 有限の文字列の時には検索の向きを変更すると、カーソルの位置の都合から、
    | 一回同じ単語に一致するけれどもカーソルの位置だけ変化するという事が起こる。
    |
    | これをどの様に正しく実装したら良いだろうか。
    | 現在の実装ではとにかく移動する時には必ず記録する様にしている。
    | これは DEL を押した数と戻った回数の整合性という観点から望ましい。
    | そして、記録する時には追加するか或いは消去するという処理になっている。
    | 既に同じ一致がトップにあれば消去し、それ以外は追加する。
    | 然し、本来は「同じ一致がトップにあれば」というよりは、
    | 次にどちらの方向へ進むかを考慮に入れて実行したい。
    |
    | 或いは、空文字列の時でも一回は同じ位置で一致する
    | という様にした方が一貫性がある様にも思う。
    | うーん、前回の検索方向というのを覚えておいて、
    | 検索方向が前回と同じであればそのまま検索して、
    | 検索方向が前回と異なれば一回は転回処理を実行する、
    | というようにしたい。
    |
    | その様に実装した。
    |
    | x 動かしてみたら全く動かない。
    |   改めて考察してみるとこの修正では全然駄目である。
    |   しかし段々と何がどうなっているのか分からなくなってきた。整理する。
    |
    |   先ず、_ble_edit_isearch_arr の記録の仕方。
    |   これは新しい一致が見つかった時に、
    |   今までの一致の位置・検索文字列と、現在の検索方向を格納する。
    |   検索方向だけ新しい物を格納しているのが良いのかは分からないが
    |   取り敢えず其処は今回の問題ではない。
    |
    |   ABCD と一致した時、ABC は _ble_edit_isearch_arr の中にあり、
    |   D はグローバル変数 _ble_edit_isearch_* に記録されている。
    |   検索方向の転回をここで実行すると D に対する転回となる。
    |
    |   % % さて、この状態で再びその方向に検索を実行するとどうなるか。
    |   % % 新しく C に一致するだろう。そうすると配列の末尾にある C と対消滅する。
    |   % % これは現在の実装でちゃんと動く。
    |   % %
    |   % % しかしそうすると逆に今までの実装で何故ちゃんと動いていたのかが不思議である。
    |   % % 今までの実装で何が起こっていたかを考える ABC|D の状態で転回を実行する。
    |   % % そうすると再び D に一致する。この場合 ABCD|D という事になる。
    |   % % この後で再度検索すると C に一致する。この時元々の状態の D が
    |   % % 配列に push されて対消滅して ABC|C という状態になる。
    |   %
    |   % という事はやはり現在の実装で動くというのは勘違いだ。
    |   % ABC|D の状態で転回を実行すると ABC|D のままである。
    |   % この状態で元に戻ろうとすると C が一致する。
    |   % この時に現在の状態の D が push されて、ABCD|C という状態になる。
    |   % これだと永久に対消滅は起こらない。
    |   %
    |   % a 一つの方法は上から配列の二番目の状態を調べるという物である。
    |   %   でもそうすると A|B という状態で転回して元に戻ろうとすると、
    |   %   AB|A という状態になって…この場合はちゃんとうまく行く。
    |
    |   やはり何か違う。ABCD と入力する。この時点で ABC|D となっている。
    |   転回した時再び D になる。その時 _ble_edit_isearch_arr は弄らないので ABC|D のまま。
    |   この次に検索を実行すると C に一致する ABC|D の状態で C を push しようとするので、
    |   C は対消滅する。この時 D は記録されない。結果として AB|C という状態になる。
    |   (別に「対消滅」する訳ではなくて pop されるというのが正しい表現である)。
    |
    |   今までに動いていたのは何故だろうか。
    |   ABCD と入力すると ABC|D になる。ここで転回すると D が push されようとする。
    |   % C != D なので ABCD|D という状態になる。次に検索を実行すると C に一致する。
    |   と思ってよく見たら index と beg:end:needle が同じならば dir に依らずに
    |   push が省略される様だ。つまり、ABC|D という状態になる。従って、次に C が来ると、
    |   ちゃんと消滅が起こって AB|C という状態になる。
    |
    |   そうすると今度は何故今まで空文字列で動かなかったのか、という事になる。
    |   ABC|D と入力する。転回すると C に一致する。そうすると AB|C という状態になるはずである。
    |   これは確認しておく必要がある。どうも C に一致していない様だ。
    |   →分かった。$beg:$end が一致していない。何故か -1:-1 になっている。
    |   もしくは -1:-1 になる方が正しくて 3:3 や 4:4 になっているのが間違っているのだろうか。
    |   呼び出し元を観察すると beg==end の時には両方 -1 にする様に明示的に書いている。
    |   では何故 3:3 や 4:4 の様な物が可能なのであろうか。
    |   と思ったら push する時には obeg==oend のチェックをしていないのだった。
    |   →あっさり直ってしまった。と思ったが、実際にそうしてみると、
    |     今度はキャンセル時に状態を復元する時に _ble_edit_ind, _ble_edit_mark が復元できずに失敗する。
    |
    |     # 所で、この復元のコードは誤っている様な気がする。検索の方向によって
    |     # beg と end と _ble_edit_ind と _ble_edit_mark の対応は切り替わらなければならない。
    |     # これは別項目で後で修正する事にする。
    |
    |     やはり -1:-1 を記録するのではなくて実際の位置を記録するべきなのだろうか。
    |
    |   ? 逆に何故 beg==end の時に beg=end=-1 としたのかの方が謎である。
    |     blame したら分かるだろうか。探すとこれは最初からそうだった様だ。
    |     https://github.com/akinomyoga/ble.sh/commit/d10d5364e812d302f8c36d0b8a8729bb00761ec9
    |     しかも 3 年前のコードで git 上にある中ではかなり最初の方の実装である。
    |     この時の議論は残っているだろうか。2015-11-29 である。しかし memo.txt を見ると何も言及がない。
    |     昔はそのまま実装できると思ったものはそのまま実装していた様だ。
    |     commit message を見ると一致範囲も記録するとしか書いていない。
    |     % 特に考察した形跡もないので、試しに -1 に設定するのをやめて見る事にする。
    |     % 恐らく範囲がない == 一致していないという事と当時は解釈したのだろう。
    |
    |     →これは実際に beg=end=-1 にしないでやってみたところ、
    |       空文字列の場合には各履歴項目に一回しか一致しないという条件により、
    |       backward search では履歴行の末端に一致して、
    |       forward search では履歴行の先端に一致する。
    |       これにより forward search にしても同じ状態にならないので復元できないという事の様だ。
    |
    |   うーん。現在の振る舞いのままの方が良いのかもしれない…。
    |   もし戻りたければ DEL を入力すれば良いだけなのである。

    やはり従来の振る舞いで適切という結論である。
    空文字列で検索している時は一致の振る舞いが多少異なる。
    各行で一回ずつしか一致しない様に制限をしている。
    backward search の場合には編集文字列の末端に一致する。
    forward search の場合には編集文字列の先頭に一致する。
    通常の C-s と戻る C-s の振る舞いの一貫性を保つには、
    そして C-s が本質的にはカーソルの移動と考えるならば、
    行きと戻りは異なる経路として記録するべきである。

    * done: 所で、修正する途中で気づいた事だが、

        _ble_edit_bind_force_draw=1

      という物があった。これは例えユーザー入力があったとしても、
      行の再描画を強制するという要求である。
      実は、これは dabbrev 及び nsearch でも設定する必要がある。

      と思ったが、これは本当に効果があるのだろうか。
      これは実際に抜けた時に実行される物の筈である。
      という事は #resume を実行している間は実行されないのではないか。
      それよりはすぐに redraw を実行してしまった方が良いのではないか。

      その様に書き換えた。また、そうなるとそもそもこの
      _ble_edit_bind_force_draw=1 は必要なのか疑問である。
      何処で使われているか確認して不要そうだったら削除する。

      →今確認したところ誰も使っていない。削除する。

      追記: 一応 #D0324 に導入の経緯の議論があった。後で確認しても良い。

    * fixed: ble/widget/isearch/cancel: _ble_edit_ind と _ble_edit_mark の対応が違う
      これは別に記録しなければならないのではないか。
      というのも最初の _ble_edit_ind と _ble_edit_mark の状態は、
      検索前の状態なので検索の方向などから判定する事は不可能である。

      先ず ble-edit/isearch/prev の実装を確認すると、
      ble-edit/isearch/prev は…うーん。一番最初の状態には戻らない。
      実際にやってみると必ずカーソルが後ろになってしまう。
      .set-region で設定を行う為である。

      最初の状態だけは beg:end ではなくて ind:mark を
      記録する様にするという手もある。
      と思ったら既に _ble_edit_isearch_save という変数に記録してあった。
      _ble_edit_isearch_save は C-s で移動して確定した時に、
      ちゃんと領域を拡張できているようにする為に導入した物で、
      exit する時にそれに応じて調整する様にしていた。
      cancel も内部で exit を呼ぶようにしていたが、
      よく考えてみたら cancel の時は領域を拡張するのではなくて、
      本当に元の状態に戻すという事なので操作が異なる。

    * done: ここで一つの可能性が出てくる。
      forward search の場合にも編集文字列の末端に
      一致する様に変更しても良いのではないか。
      例えば history-prev/next については上に移動しても下に移動しても
      カーソルの位置は文字列の末端に移動する。

      確認して置かなければならないのは空文字列の時の
      行内一致はどうなっているのかという事。
      不思議だ。コードを確認してみたが、空文字列に対する対策は特に実行されていない気がする。

      実は isearch/search は一箇所でしか呼び出されていない。
      .next-history.fib からは呼び出されていない様だ。
      改めて確認したところ .next-history.fib の中では直接パラメータ展開を使って切り出している。
      従って、最初の一致と二回目以降の一致は元から処理の仕方が異なるのであった。
      forward search で一致するのを末尾に変更する為には、
      .next-history.fib の中で [[ ! $needle ]] の時だけ特別扱いすれば良い。

      実装の方法はともかくとして、何故行内で何度も一致しないのかの謎は解けていない。
      ここは少し出力してみる事にする。
      →なんと、isearch/search に対して空文字列で検索を実行すると何にも一致しない。
        何故かというと isearch/search は ${target#*"$needle"} と ${target%"$needle"*}
        を用いているので空文字列を使うと最小一致は幅0なので、何にも一致しなかった場合と区別が付かない。
        正規表現を用いている方は、逆側から最大一致を実行している筈なので微妙である。
        しかし正規表現の方はそもそもどのように一致の長さを事前に検知するのかは非自明である。

      うーん。isearch/search の設計としては空文字列を指定した場合にも一致する様にしたい。
      但し、現在地に一致するのではなくて、次の位置に一致する様にする。
      修正した。

    * reject: 因みに逆方向に検索を実行するときに常に配列の末尾を取り出して
      巻き戻しの検索になっていたら単にそれを復元するという実装にする事も可能である。
      しかし、その時には needle が一致している事などを確認する必要がある。
      逆に言えば needle が一致しているかどうかだけ見れば、
      そのまま取り出して再利用してよいかどうかが分かるのではないか。

      もう考えるのも面倒なのでこれはやらなくても良い。現状の動作で十分動いている。

    * fixed: 現状では検索方向の転回に必ず一操作を要しているが、
      C-s, C-r の本質がカーソル移動だと思うのであれば、
      やはり空文字列に対しては転回に対して一回使わない方が自然なのではないか。

      ここで bash の振る舞いを調べる事にする。
      先ず bash は空文字列で検索を開始する事はできない。
      更に有限の文字列で検索を実行するとしても転回に1回は使わない。
      今までの動作は Emacs の振る舞いを真似た物だったが Emacs では空文字列での検索はできない。
      空文字列で検索しようとすると前回の検索が使用される。
      その様に考えると、やはり転回に対して使わない方が自然である。

      以下の断片は転回に必ず (空文字列であっても) 1回要する時のコード断片で、
      元々 ble-edit/isearch/.next.fib にあったものであるが、
      削除する事にした。

      | local old_dir=$_ble_edit_isearch_dir
      |
      | 中略
      |
      | # 向きを転回する時はカーソルの位置を移動するだけ
      | if [[ $_ble_edit_isearch_dir != "$old_dir" ]]; then
      |   if [[ $_ble_edit_mark_active ]]; then
      |     local tmp
      |     ((tmp=_ble_edit_ind,
      |       _ble_edit_ind=_ble_edit_mark,
      |       _ble_edit_mark=tmp))
      |     ble/textarea#redraw
      |   fi
      |   ble-edit/isearch/.show-status.fib
      |   return
      | fi

  * complete: dabbrev も fiberchain で再実装する [#D0846]

    % と思ったが、そんなに面倒ではないかもしれない。
    % と思ったが、やはり色々面倒な事になってしまった。

    dabbrev でも無駄に start を記録していたがこれは実際使われていないので廃止する。
    代わりに最後に一致した位置 match を記録しようとしたが、
    実は常に最後の検索位置 index と一致している様な気がする。
    というのも履歴の一番最初に行ったらまた履歴の最後まで戻るためである。

    * done: うーん。何だかよく分からなくなった。
      dabbrev-expand の時は見つからなければまた最初に戻る。
      つまり、cyclic に検索するという事になる。
      外側から指定しようと思ったが、
      よく考えると元の検索器の方にその機能を追加した方が自然である。
      cyclic というオプションで指定できる様にした。

      % これで履歴内に検索対象が全くない場合に限り検索が失敗する様になる。
      % つまり、再一致を dabbrev 側で再試行する必要はなくなった。

    * done: と思ったら微妙なことが判明した。dabbrev は単に一致したらではなくて、
      現在一致している内容と異なる内容だったら、という追加条件がある。
      これを拡張正規表現で表現するのは困難である。
      一応できなくはないが、現状の様に外側で複数回一致させる方が自然の様に思われる。
      さて、それに当たっては start を固定したままで
      backward-search-history を複数回呼び出せば良い。
      折り返して再度元の場所に戻ってきたら必ず backward-search-history が失敗するので、
      無限ループになるという事はない。

      取り敢えずその様に実装し直した。微妙な間違いなども見つけた。
      動作確認はしていないが後でまた確認すれば良いだろう。

    取り敢えず細かい調整をして実装した。
    試しに動かしてみる事にする。

    * done: dabbrev で何故か cyclic にならずに終了してしまう。

      単に一個しか一致する物がないので、exclusive に検索している為に一致しないのか?
      という事を思ったが、二個一致する物に対しても cyclic にならずに終了してしまう。
      cyclic の条件判定のところを観察してみる事にする。
      →単に $1 を $opts に格納していなかっただけだった。
      これを直したら2個一致する時にはちゃんと cyclic になる様になった。

      | * しかし、自分以外に1個しか一致がない時にはやはり抜けてしまう。
      |
      |   変である。よく考えてみたら自分自身にも一致して良いのではないか?
      |   と思ったが、自分は履歴に登録されていないという事を考えれば一致しないのは当然である。
      |   因みに、現在の実装だともし現在地が過去の履歴であれば自分自身に一致する事になる。
      |   その辺りの一貫性をどのように確保するのかも課題の一つである。
      |
      |   仕様: 自分自身には一致しない
      |   仕様: 自分以外に1つしか一致がない場合は、巡回して戻ってきたらそれに一致する
      |
      |   →現在地が過去の履歴にある時には _ble_edit_history_edit には
      |     最新の未実行のコマンドが登録されるので、${#_ble_edit_history_edit[@]}-1 番目の要素
      |     (これは ble-edit/history/get-count (-1 しない) 番目の要素に同じ)
      |     も検索する様にすれば問題ない。実際にその様になっている。
      |
      |   →また自分自身に一致しない様にするために predicate 内部で
      |     index もチェックする事にした。
      |
      | * 自分自身に一致する様に start を 1 ずらして定義してみる事にした。
      |   するとずっとループして検索が停止しなくなってしまった。
      |   "現在の内容と厳密一致する時にはスキップする" という機能の所為である。
      |   これは次の項目の "遅い問題" と一緒に解決できる。
      |   つまり関数を使って一致判定を実行するということである。
      |
      | * hello の様な頻出の単語で検索すると速度が著しく低下する。
      |   厳密に一致する単語に何度も引っかかってしまって、
      |   その度に blockwise で 1000 件走るからである。
      |   本来は一回スキャンすれば良いはずなのにである。
      |   これは関数を外から指定して判定する事ができるようにするべきなのではないか。
      |
      |   →関数にしてみたが微妙に遅くなった。eval してくれる cond 的な物の方が良いのでは。
      |
      | * 一番初めのpos 初期化: 末端?

      取り敢えず関数を渡して検索するのを実装したので
      一つ一つについて動作を確認する事にする。
      その前に様々の問題が発生したのでそれを修正して行く。

      | x fixed: 先ず全く一致しなくなってしまった。これは直した。
      |   backward-search-history 側で predicate オプションを認識していなかった。
      |
      | x fixed: 一度一致しても blockwise search の途中で dabbrev_pos=0 に再設定されてしまうという問題がある。
      |
      |   % →これについては直した。外側で dabbrev_pos=0 に設定して、
      |   % 中では一致した場合を除いては勝手に弄らない様にする…
      |   % と思ったが駄目だ。そうすると一度 dabbrev_pos を設定すると、
      |   % それ以降の検索に影響を与えてしまう。
      |
      |   →search-in-history-entry では dabbrev_pos は設定しない事にして、
      |     dabbrev_match_pos に返すだけに留める事にした。
      |     外部で dabbrev_match_pos を dabbrev_pos に適用すれば良い。
      |
      | x fixed: 同じものに何度も一致している
      |
      |   % →これは blockwise search だからである。
      |   % 一番最後に一致した物についての結果しか得られない…
      |   % と思ったが、よく考えたら blockwise search の場合は
      |   % 一番最後に一致した物を採用するのだから問題ない気がする。
      |
      |   これは別の物に一致していたが、毎回 dabbrev_match を代入してから判定していたため、
      |   一致していない物の dabbrev_match で上書きされてしまっていたという事だった。
      |   一致した時にのみ dabbrev_match に書き込むように変更する事で解決した。
      |
      | x fixed: 何故かタスクがどんどん増えていく
      |   検索の最中に更に次の検索を要求すると発生する様だ。
      |   どんどんタスクが増えていく時は同じ履歴項目の間を振動している。
      |
      |   →これは fib_suspend をクリアし忘れていたのが原因だった。
      |   その為に折角一致しても fib_suspend したと判定されてすぐに停止するのだった。
      |   更に、検索を再開しても何度も同じ検索を実行していた事になる。
      |
      | x fixed: 同様の問題が isearch, nsearch でもないか確認する必要がある。
      |   →確認してみた所両方共大丈夫だったが、それぞれ別の書き方をしている。
      |   分かりにくいので fib_suspend を確認して読み取ったらすぐに空文字列を設定する様に変更した。
      |
      |   と思って nsearch で実験してみたら駄目だった。
      |   fib_suspend を確認する前に関数を抜けている箇所がある?
      |   →何処で抜けているか分かった。
      |   新しいコードの方が正しくて、今までのコードの方が間違っていた。
      |   今までのコードの方で再現して、新しいコードの方では再現しないという事が分かった。
      |
      |   isearch の方では問題は起こらない様である。
      |
      | x fixed: 実は nsearch で C-s で戻り切るとその後の検索が変である。
      |   これは C-x C-p して C-s するだけで再現する。
      |   fiberchain の側の問題ではないようだ。
      |
      |   試してみると途中で index=-1 になってしまっている様だ。
      |   backward-search から戻った時の index の値が怪しい。
      |   うーん。これは forward-search で失敗した時に index
      |   が一番最後にいると思っているのがいけない。
      |   実際には空文字列が設定されるのである。
      |
      |   ちゃんと backward-search の戻り値に応じて
      |   _ble_edit_nsearch_index を更新する様に修正した。直った。

      取り敢えず見つかった問題は解決したので
      改めて元々の問題が解決されているかについて確認していく。

      * fixed: 自分以外に1個しか一致がない場合に抜けてしまう問題について。
        これは単に既に一致している場合には bell を鳴らすだけで
        動かさないという様にすれば良い。

      * ok: 自分自身を飛ばす
        これは今まで試したところだとちゃんと動作している様に思われる。
        と思ったが、よく考えたら今までは最新の履歴項目で編集していたので分からないだけかもしれない。
        →古い履歴項目を書き換えて ring とやって ringo, 周回, ringing の順に一致して
        ちゃんと自分を飛ばしてまた ringo に一致するという事を確認した。

      * ok: 無限検索ループになることについて
        これは構造上今回の実装では起こりえないし、今までにも起こっていない。
        つまり backward-search-history-blockwise の cycle 判定がちゃんと動いているということ。

      * ok: 一番初めのpos 初期化: 末端?
        →これについては今までのところ問題は発生していない。

      * ok: 検索速度が遅いことについて

        頻出単語に対する検索の遅さは著しく改善したが、
        各行に対して関数を呼び出す為に全体に遅くなってしまった。
        試しに eval を用いる方法についても実装してみる事にする。

        うーん。何故か常に一致する感じになってしまっている。何故だろう。
        条件式を間違えていた。修正した。

        然し、predicate よりも余計に遅くなった。
        変数代入に続けて eval を書くのはもしかして遅いのかもしれない。
        時間を計測してみることにする。

        | a for ((j=i-block;++j<=i;)); do
        |     LINE=${_ble_edit_history_edit[j]} INDEX=$j eval "$needle" && index=$j
        |   done
        |
        |   これは 1000 件で 0.156 秒程度である。
        | b local LINE INDEX
        |   for ((j=i-block;++j<=i;)); do
        |     LINE=${_ble_edit_history_edit[j]} INDEX=$j eval "$needle" && index=$j
        |   done
        |   これは 0.154 秒程度である。
        |
        | c eval "function ble-edit/isearch/.search-block.proc {
        |    local LINE INDEX
        |    for ((j=i-block;++j<=i;)); do
        |      LINE=\${_ble_edit_history_edit[j]} INDEX=\$j
        |      { $needle; } && index=\$j
        |    done; }"
        |   ble-edit/isearch/.search-block.proc
        |   これは 0.086 秒程度である。多少速くなった。
        |   しかし、今までと較べるとやはり遅い様な気がする。

        うーん。取り敢えず c を選ぶという事にしても遅い。
        と思っていたら、どうも ring は string に引っかかるので、
        頻繁に関数呼び出しの方を実行しているという事の様に思われる。
        と思ったが本当だろうか。直前に区切り文字がない限りは反応しない筈だ。
        その様に思うとやはり不思議だ。単に正規表現が重いという事なのだろうか。

        | needle に以下の様に 1 行目を追加したところ 0.045s にまで短くなった。
        | 因みに1つ目の条件コマンドと2つ目の条件コマンドを結合すると 0.046s である。
        | 殆ど違いはない。つまり、ちゃんと遅延評価にはなっている様である。
        |
        |   [[ $LINE == *"$_ble_complete_dabbrev_original"* ]] &&
        |     [[ $LINE =~ $_ble_complete_dabbrev_regex1 ]] &&
        |     ble-complete/dabbrev/search-in-history-entry "$LINE" "$INDEX"
        |
        | 実は glob で全部実装した方がもっと速いのかもしれない。
        | 一時的に wordbreaks を復活させる事にする。
        | もしくは glob escape すれば良いのかもしれないが…。
        | 以下の様に glob だけで実装してみたところ一定しなくなった。
        | それでも 0.140 程度なので却って遅くなった。
        |
        |   [[ $LINE == "$_ble_complete_dabbrev_original"* ||
        |       $LINE == *["$_ble_complete_dabbrev_wordbreaks"]"$_ble_complete_dabbrev_original"* ]] &&
        |     ble-complete/dabbrev/search-in-history-entry "$LINE" "$INDEX"
        |
        | 変数名が長いのが気になると思って local dabbrev_{original,wordbreaks}
        | に入れてみたが速度としては変わらない様だ。

        結局、local dabbrev_original による枝刈りと
        local dabbrev_regex1 による判定で実装する事にした。0.044s
        まあ許せる速さではある。

    * done: cycle した時には bell を鳴らしたい

    * done: うーん。気づいたが show-status の中で ntask を参照している。
      然し、show-status を #resume の外で呼び出している様な気がする。
      これは isearch/nsearch を改めて調べて修正する必要がある。

      調べてみたところ nsearch は問題なかった。
      isearch ではそもそも #resume の中から呼び出され時にしか ntask を確認していない。
      #resume の外で .draw-line を呼び出した時にも fib_ntask を使って描画する事にした。
      それに伴って呼び出し元をたどって修正した。
      関数名の整理も行った。

2018-09-26

  * 2015-12-23 isearch: C-r C-s で mark が破壊されてしまう [#D0845]
    (現状の実装だと、範囲選択に C-r C-s を使う事ができない。)

    例えば mark が設定されている場合は現在の履歴項目の中で、
    mark を解除せずに検索を行うなどの様にすると良い。

    履歴項目を移動した場合には解除するというので良い。
    (また戻ってきた場合には復元する。)

    % 問題になるのは着色である。layer を追加するか、
    % 選択範囲の表示に使っている layer を拡張するかする必要がある。
    →抜けた時に復元すれば良いという事にした。
      選択範囲と一致範囲の両方を表示するのも見にくいし、
      また選択範囲だけしか表示しないというのも分かりにくい。
      なので、検索中は一致範囲だけ表示するというので問題ない気がする。

    実装した。動くことを確認した。OK

  * edit: ble/widget/accept-single-line-or/accepts は別の名前を割り当てる [#D0844]
    現在の名前だと ble-bind -L に表示されてしまう。直した。

  * edit: history-search [#D0843]

    dabbrev-expand でもそうだが、履歴の検索は遅い。
    連打したりすると応答がなくなる可能性がある。
    かと言って単に has-input で停止していると入力が消滅した様に見える。
    特定の回数連打した時に期待した位置に行かないなどの事が起こる。
    そうすると isearch の様に fiber を組み合わせて実装する事になる。

    思うに fiber を沢山重ねて実行する統一的な枠組みを作っても良いのではないか。

    * fixed: progress は _ble_edit_isearch_* に依存している。
      更に検索が完了したら毎回 clear する必要がある。

      これはどの様に実装するのが正しいだろうか。
      現状の実装では forward/backward-search-history が
      ble-edit/isearch/.draw-line-with-progress "$i" を呼び出す形になっている。

      % 取り敢えずこの関数の内容を確認してみた所、
      % 特に isearch 特有の表示はしていない。
      % なので、この関数自体を任意の場合に使える様に拡張するのが良い。
      %
      % _ble_edit_isearch_str は needle で置き換えられる筈である。
      % .draw-line-with-progress の呼び出し元を確認する。
      % - backward-search-history-blockwise 及び forward-search-history は大丈夫。
      % - .draw-line は様々な場所から呼び出されている。
      %   これは needle が定義されていない文脈からも呼び出される。
      %   .draw-line の中で needle を定義する事にすれば良い。

      と思ったが、やはり微妙に思われてきた。
      現在位置も表示しているが、nsearch の場合には現在位置は移動しない。
      やはり外部から表示内容を設定する事ができるようにするのが良さそうである。
      →外部から isearch_progress_callback を指定する事にした。
      今まで無意味に isearch_ntask に依存していたのを置き換える形である。

    * done: 実は記録されている現在位置と次に検索開始する位置は異なる。

      | 現在は _ble_edit_nsearch_start を最初に検索を開始した位置 (nsearch に入った時の位置) として、
      | また _ble_edit_nsreach_index を次に検索を開始する位置兼最後に一致した位置としている。
      | しかし、一番最後に一致に失敗した時は index の位置はどうしたら良いか分からない。
      | 一回一致に失敗したのだから次に検索を開始する位置は履歴の一番端であるべきだが、
      | 一方で最後に一致した位置は動いて欲しくない。
      |
      | isearch の場合には index は記録していなくて、全て history/get-index に依っていた。
      | つまり、最後に一致した位置となっている。
      | その為、一致しなかった時にはキーを連打した回数だけ、
      | 最後に一致した位置から履歴の橋までを繰り返し検索する事になる。
      | isearch の場合にはキーを入力する度に検索の条件が変わるため、
      | 繰り返し検索を実行する事に意味があった。
      |
      | しかし、nsearch の場合には前に行くか後ろに行くかの二種類しかないので、
      | 毎回検索の条件は同じである。従って繰り返し検索を実行するというのは不自然である。
      | やはり最後に一致した位置と次に検索するべき位置というのは別に管理するのが良いのではないか。
      |
      | また、現在の実装では start はどの様に使われているだろうか。
      | 新しい nsearch の実装では start は nsearch に入った時の位置としている。
      | しかし、どうも isearch の場合には start は現在処理しているキー入力に対する検索の開始位置の様である。
      | そういう意味で言えば、実は start を最後に一致していた位置として、
      | index を次に検索するべき位置と考えるのが良いのかもしれない。
      | 或いは、そもそも start を記録する意味はないのかもしれない。
      | 現に isearch の実装では start は記録していない。
      | suspend の時に suspend データに記録しているだけである。

      以下の様に実装する事にする。
      - _ble_edit_nsearch_start は廃止する。
        start は各入力に対して最初にどの位置に居たかを記録する事にする。
        各入力に対して使用するだけなので、これは fib_suspend に記録する。
      - _ble_edit_nsearch_index は最後に検索した位置を格納する事にする。
      - _ble_edit_nsearch_match に最後に一致した位置
        (現在表示している行内容がどの位置に対応しているか) を入れる事にする。

      変更した。動いている。

    * fixed: nsearch を抜けた後に検索状況の表示が残ってしまう。
      isearch は ble-edit/isearch/.erase-line を呼び出していた。
      これは中で ble-edit/info/default を呼び出している。
      同様に nsearch でも ble-edit/nsearch/erase-status という関数を作る事にする。

    * fixed: C-r して C-s して最初の状態にまで戻った時、
      囲まれていない。これは最初に nsearch を開始した時に
      _ble_edit_mark を調整していない為である。
      _ble_edit_mark を保持する理由もないので _ble_edit_mark を変更する事にする。

      と思ったが、よく考えたら non-incremental-history-search で
      ユーザに入力してもらった時には現在の行で一致があるとは限らない。
      C-s で戻る事ができるのは実際の一致に対応する ${_ble_edit_nsearch_stack[1]}
      以降というように制限するのが良さそうである。直した。

    * fixed: 実は C-r を連打すると fib_suspend した内容が消滅している?
      確認してみた所、別に C-r によって fiberchain の最後の項目が
      キャンセルされているという事ではないようだ。

      もしくは正しく検索状態を復元できていない?
      確認してみた所、何と、index= になっている。
      つまり、fib_suspend で start も記録する様に変更したのとは別に、
      元からちゃんと resume できていなかったという事になる。
      然し、何故 index= になっているのだろう…。
      →恐らく isearch/{for,back}ward-history-search の仕様であろう。
      と思ったが、改めて説明を呼んでも 148 を返した時にはちゃんと index を返す筈である。
      isearch/{for,back}ward-history-search の側のバグであろうか。

      試してみたら実は今までの isearch の振る舞いも変だった様だ。
      直した方で試すと C-r を連打した回数だけちゃんと記録されている様だ。
      C-g で溜まっていたものを全てキャンセルする様になっている。

    * done: 未処理の入力がある時、cancel でそれらをクリアする。

    * done: defface で region_search を追加

    * changed: `ble/widget/isearch/accept-line`

      今までは何故か exit-default を実行していたが、
      これだと accept-line に束縛しているキーによって振る舞いが変わってしまう。
      % 明示的に accept-single-line-or-newline を呼び出す事にした。
      % もしくは isearch/accept-{line,single-line-or-newline} を作るべきかもしれない。
      % autoload し忘れていたのを追加した。
      調べてみると vi_imap などでは特殊な関数を呼び出す必要がある。
      やはり `RET` を実行する様に変更する事にした。

    取り敢えずこの時点で commit を作成する事にする。

    * done: key binding として up down を使った物も用意する。

    * done: 後で mark の種類の名称を変更する事にする。
      mark:search -> mark:vi_search mark:nsearch -> mark:search
      これに併せて char block line についても変更したい。

      mark_active を辿れば良いと思う。
      - mark_type についても確認する必要がある。
        一応一通り見た。
      - _ble_keymap_vi_search_activate も辿る。
        これも一通り見た。
      - _ble_keymap_vi_xmap_prev_visual も調べる。
        これは単に mark_active を記録・復元しているだけの様だ。

      見逃しがないか不安である。改めて mark_active を見る。追加で以下も変更する。

      - _ble_keymap_vi_xmap_prev_edit
      - ble/widget/vi-command/visual-mode.impl
      - ble/widget/vi_xmap/switch-visual-mode.impl
      - ble/keymap:vi/xmap/switch-type も確認した。

      - ble/keymap:vi/call-operator 及び operator の context は変更しなくて良い。

      まあ、取り敢えず試しにやってみて動けばよいだろう。
      表示は OK C-v による操作も確認した。まあ、問題なかろう。

    * done: isearch も fiberchain で実装し直す
      直した。fiberchain で fiber に引数を指定できる様に拡張した。
      一応動いている。

      また isearch で region を復元するのもこれを機に実装するのが良い。
      →これは #D0845 で実装した。

    * done: non-incremental-* も実装する。
      これには emacs 側でも vi_cmap 的な枠組みが必要になる。
      read を直接使おうかとも思ったが、実は今の read の仕組みだと C-c に反応してしまう。
      同じプロセス内で実行できないだろうか。或いは、今の read の仕組みで実は問題ないだろうか。
      うーん。よく考えてみると問題ないのではないだろうか。
      今の read の仕組みでも C-c を受け付けて自分で処理している気がする。

      面倒になった。何も考えずに read で良い様な気がしてきた。
      わざわざ vi_cmap を使わなくても良いという気分である。

2018-09-24

  * complete: よく考えたら ble-sabbrev はエクスポートするべきなのでは [#D0842]
    https://github.com/akinomyoga/ble.sh/issues/5 で cmplstofB さんの質問で、
    ble-sabbrev は _ble_complete_load_hook で設定するのかという問いに対して。
    修正した。然し、何れにしても遅延ロードを有効にする為にはやはり load hook の中で実行する方が望ましい。

    後で core-syntax.sh `ble-syntax:bash/is-complete` も autoload されていない事に気づいた。
    これも autoload する様に変更しておく。

  * complete: "echo dist/ble1423@" に対して曖昧補完が効かない [#D0841]
    "cd dist; echo ble1423@" は効く。

    調べてみると generate の所ではちゃんと曖昧補完に入っている様である。
    但し、source:argument に入っている。source:argument が悪い気がして来た。
    動作を見てみると source:argument は "d" で始まる候補を列挙して成功している。
    つまり、d*/b* による候補が列挙されていない。
    曖昧補完の時にはこれで諦めてはならないはずなのである。
    しかし、だからと言って曖昧補完の時には常に source:file を実行するというのも変である。
    本来はフィルタした後に候補が全てなくなったら、source:file による曖昧補完を試みる、
    という形でなければならない。

    中でフィルタをかける事にした。
    フィルタをかけた上で候補の数が増えていなかったら
    source:file または source:dir を使う。

  * [自然解消] 2015-06-28 color: PATH=filename の filename の部分 (ref #D0839) [#D0840]

  * highlight: wtype==CTX_VALI (a=(1@)) 及び wtype==ATTR_VAR (v=1@) の着色? [#D0839]

    core-syntax.sh: ble-highlight-layer:syntax/word/.update-attributes/.proc では
    wtype が CTX_CMDI, CTX_ARGI, CTX_RDRF, CTX_RDRS の時にのみ単語着色している。
    CTX_VALI または ATTR_VAR の時は変数名や []= の部分を除いて着色する必要がある。
    その為には先ず範囲を切り出さなければならない。

    []= の形式の時に = の位置を特定するコードは、completion-context にあったはず。
    整理して ble-syntax:bash/find-{end-of-array-index,rhs} という関数にした。
    更にそれを利用して右辺の位置を特定して着色する様にした。
    単語の描画属性 (wattr) についても今までの単純な物から、
    単語内で色分けできる様に m(len:attr)+ の形式に対応した。

  * highlight (reported by cmplstofB): 単語着色で配列の指示初期化子が failglob 判定されている [#D0838]
    https://github.com/akinomyoga/ble.sh/issues/13
    ble-highlight-layer:syntax/word/.update-attributes/.proc を直した。
    対応していない wtype については無視する事にした。

2018-09-23 自然解消

  * [自然解消] 2016-06-22 timer の実現方法について [#D0837]

    一つの方法は read -t 0.1 < 何処か などという風にすることである。
    しかしこの方法は一定時間の sleep を行うだけで定期的な処理を実行する timer にはならない。
    処理自体に時間が掛かっていると遅延が生じてしまう。

    もう一つの方法は別のプロセスを起動してそのプロセスでひたすら時を刻みながら
    自プロセスに対して通知を行うという方法である。
    通知を行う方法は色々考えられる。シグナル、mkfifo、mkdir など。

    a シグナルには余り頼りたくない。思いがけずクラッシュしそうな気がするからである。
      シグナルハンドラの起動中にシグナルハンドラが呼び出されるとクラッシュするので、
      シグナルハンドラの内部ではカウンタをインクリメントをするだけにする。
      しかしその様にしたとしても何らかの遅延により
      シグナルハンドラが二重に呼び出される可能性は排除できない。
      また、別の問題点としてタイマーの開始・終了を制御する方法がないという事がある。
      →まあ、単純に生成したサブシェルを kill すれば良いだけとも言える。

      $ trap -- '((ble_timer_count++))' USR2
      $ (while xsleep 0.1; do kill -USR2 $$; done) & disown

      →実際にやってみたが思う様に動いていない様に見える。
      どうも親プロセスでキーボード入力をした回数だけしか発生していない様な…。
      というわけでそもそもこの方法は使えないという事なのかも知れない。

    b mkfifo による方法に関しては…。これは処理する側で遅延が発生すると、
      延々とパイプにデータが流し込まれメモリに悪そうだという問題がある。
      しかしバッファが一杯になったら都合良く停止するだろうか (バッファのサイズによる)。

      →或る程度呼び出したら停止した。と思ったらそんな事は無かった。
        というか 1 秒間に 10 文字程度ではすぐには buffer は一杯にならない。

      $ exec 3< <(trap -- '' INT QUIT; while echo -n t; do sleep 0.1; done)
      $ while read -t 0 <&3; do IFS= read -r -d '' -n 1 byte <&3; ((count++)); done; echo $count

      所で timer を停止したい場合にはどうしたら良いのか…。プロセス番号を取得するには?
      と思ったらプロセス置換の場合でもちゃんと $! にプロセス置換のプロセス番号が入っていた。
      なので $! さえ何処かに記録しておけば問題ない。

      更に実際に動かしてみると安定して動いている様に見える。

    c もし自プロセス内で閉じた方法があればそれが一番良い。
      例えばミリ秒単位で時刻を計測することができれば経過時間に応じて
      sleep 量を調整する事ができる。

      printf -v '%(%s)T' を用いる方法だと秒より下の単位は取得できない。
      GNU coreutils の date はその様な機能 (%N) も持っている様だが、拡張に過ぎない。

      あった。procfs をマウントしていれば (そして現在のシステムでは殆どそうだろう)
      cat /proc/uptime でシステムを起動してからの時間を見ることができる。
      と思ったが linux, cygwin には /proc/uptime があるが、mac os x ではそもそも /proc がない様だ。
      FreeBSD でも /proc はあるが、BSD にはなかったからの様だ。他に HP-UX もない。
      Solaris には /proc はあるが /proc/uptime は無い様な雰囲気である (確認できていない)。

      また /proc/uptime を呼び出す overhead が如何程の物かという問題もある。
      →0.05ms であった。本当に計測できているのだろうか??
        関数に入れて見たが計測できている様だ。という訳で overhead はない物として良い。

  * [自然解消] 2016-06-19 complete 補完候補一覧表示: [#D0836]
    やはり現在までに入力した部分と、
    未だ入力されていない補間文字列の部分を色分けして表示した方が良い。
    特に入力文字列が長い場合に見にくい。

  * [自然解消] 2016-06-19 complete 補完候補一覧表示: [#D0835]
    また、候補が長い場合や入力が面倒な場合 (例えば日本語の場合) があるので、
    矢印キーなどで選択できる様にした方が良い。

  * [自然解消] 2016-06-19 timer/非同期実行機能: [#D0834]
    history 検索やゲーム的機能 (demo 用) の実装のためには、
    やはり timer の様なイベントを発生させる仕組みを整えた方が良い様な気がする。

    →しかし無駄に複雑にしたり需要に合わない様な形に実装しても仕方がないので、
    取り敢えずは history の検索に於いて非同期に処理を行う方法を実装して、
    その後でその実装を参考にして仕組みを整える方が賢明である様に思われる。
    あるいは、history を非同期に検索できる様にしたとしても
    途中で面倒になって統一的な実装にしたくなるかも知れないが、
    そうだとしても history を目的として最小限の統一的実装にするという方向でよい。

    非同期の実行の仕組みとしては、

    1. 先ず処理を中断できる様な方法で実装するという事、
    2. それからユーザからの入力があった場合にそれを検知できるという事。

    これらだけあれば基本的に十分である。
    ユーザからの入力は bash-4.0 以降であれば read -t 0 で確認できる。
    なので、基本的には処理の方を細切れにできれば何も問題は生じない筈である。
    一応ユーザからの入力を受ける時に bash が勝手に色々操作をするので、
    それの対策として色々出力を繋ぎ変えたり表示を更新した理などの処理はあるが、
    それらは別に大したことはない。context switching か何かの一部だと思えば良い。

  * [自然解消] 2016-04-06 補完候補表示で既に入力が完了しているディレクトリ部分についてはそれを表示しない様にする [#D0833]
    表示されている候補がファイル名とは限らないが、補間されている候補の種類に依らず省略して良いと思う。
    そちらの方が自然である。もしファイル名でないとしても似たような入れ子構造に対応している可能性が高いので。

    →でも、前に何か対応したような気がするが…、と思って改めて確かめてみたら、
      ちゃんと ../../ の様な面倒な物は省略されて表示されている様な気がする。
      では何故先程は ../../ の様な文字列が大量に表示されていたのだろうか…。

    →いや、cd コマンドの候補 (プログラム補間候補) がそうはなっていない様である。
      前に同様の事を議論したような気がするのでログを漁ってみる事にする。

    2018-09-23 これは基本的にプログラム補完 (bash-completion) が悪い。
    余り黄にしても仕方がないので取り敢えず保留という事にする。

  * [自然解消] 2015-11-21 同じ場所で complete (TAB) を連続で呼び出した時にカウントを行うべき [#D0832]
    + peco や sentaku など (?) の外部コマンドを起動する時の基準に使用できる。

    2018-09-23 これは結局 core-complete.sh 自身で絞り込みを提供するので余り必要なくなった。
    また既に同じ場所で連続で呼び出したかどうかは LASTWIDGET 経由で判定できる様になっている。
    回数まではカウントしていないが、widget の側で数える様にする事は容易である。

  * [自然解消] 2015-11-21 vi bind (これは bind -p で調べれば大丈夫の筈?) [#D0831]

    →bind -p して見たがどうも vi には vi の完全に異なるコマンド体系がある様である。
      単純な移動コマンドぐらいならば対応できるが、それ以外の物についてはどの様な操作なのか
      よく理解していないので憶測で実装するのは難しい。

    2018-09-23 これは既に support-vi-mode で実装済みである。

  * [自然解消] 2015-11-18 PROMPT_COMMAND を一番外側の環境で実行する様に変更する [#D0830]

    現在は .ble-line-prompt/update の中で直接実行している。

    また、stty 等を正しく設定して呼び出すようにする?

      参考の為: 現在 ble-bind -cf による登録では、
      function .ble-edit.bind.command を通して .ble-edit.accept-line.add
      でコマンドを登録し一番最後に外側でコマンドを実行する。
      このコマンドによる出力はプロンプトの次の行に表示される。
      またコマンド終了後には改めてプロンプトが表示される。

      一方で ble-bind -xf proc に関してはそもそも未実装の状態になっていた。
      このコマンドではプロンプトの次の行に行ったり、プロンプトを消したり、
      或いはプロンプトを再描画したりなどと言った事は不要である。
      (勝手な出力をしないという前提・表示が乱れた場合 proc の方が悪いという事にする)

    2018-09-23 これは既にその様な実装になっている。
    stty の設定は行っていないが、上記の議論の通り、
    変な表示になったりしても前提を崩す様な処理を行う方が悪いのだという事にする。
    つまり、現状の通り stty などによる調整は行わないで良い。

  * [自然解消] 2015-02-27 complete: 文脈判定を強化する。他にも色々な箇所で補完を実行する [#D0829]

    2018-09-23 これは曖昧な項目であるが少なくとも当時よりは大幅に増強された。

  * [自然解消] 2013-06-01 以前 compgen, history コマンドを関数内から自由に利用する事が出来るか [#D0828]
    → できる (2018-09-23)

2018-09-23

  * auto-complete: 構文エラーが自動補完により解決される時 <kbd>RET</kbd> でコマンド実行が抑止されない [#D0827]

  * isearch: C-d で現在の選択範囲を削除する様に変更。また C-m (RET) で確定した時は選択範囲を解除 [#D0826]

  * complete (suggestion by cmplstofB): vi_imap に於いて C-] から sabbrev-expand に束縛 [#D0825]
    https://github.com/akinomyoga/ble.sh/issues/5

  * 2015-03-04 減色 (88colors の時の palette について) [#D0824]
    16-79 4x4x4 0,58*v+81
    80-87 gray 46+25*v

  * term: term.sh の local j=$((k-i1+j1)) の k は i の誤りである [#D0823]
    序でに端末が256色対応していない場合の減色処理についても追加する。

  * edit: 検索中や auto_complete にて C-RET ですぐに実行という意味にしたい [#D0822]

    序でに isearch/accept → isearch/accept-and-execute にしようと思ったが、
    検索を終了して実行しない物は既に isearch/exit という名前が与えられている様なので、
    isearch/accept のままにする事にした。そうすると、今度は auto_complete/accept-and-execute
    の方を auto_complete/accept にして、auto_complete/accept を別の単語にしたくなる。
    accept の代わりに "確定する" という様な意味の単語があれば良いが、
    検索してみると determine, decide などが出てくる。これらは意味が違う。
    他に settle や fix 等があるが前者は余りニュアンスが分からない。
    後者は色々意味がありすぎて auto_complete/fix などとしても伝わらない気がする。
    もっとよく使われる単語で良さそうな物はないだろうか。
    insert にしようか。insert が良さそうだ。編集関数名の変更の一覧を作成しておく。

    - menu_complete/accept              → menu_complete/exit
    - auto_complete/accept              → auto_complete/insert
    - auto_complete/accept-on-end       → auto_complete/insert-on-end
    - auto_complete/accept-word         → auto_complete/insert-word
    - auto_complete/accept-and-execute  → auto_complete/accept-line
    - isearch/accept                    → isearch/accept-line

2018-09-22

  * term (reported by cmplstofB): libvte 系列のターミナルで SGR(>4) が画面に表示されてしまう [#D0821]
    これは bleopt term_modifyOtherKeys_{in,ex}ternal=auto に対応し、
    端末の DA2 応答を見て libvte では SGR(>4) を既定では送らない様にする事にした。
    libvte をちゃんと区別する方法はない様であるが、DA2R の最初の数字が 1 の物は
    vt220 か libvte 及び Windows のマイナーな端末しかない様なので、
    これらが SGR(>4) に対応しているとは思われないので問題ないだろう。

  * 2018-09-10 complete: 略語展開 [#D0820]

    動的略語展開に対応するにしても zsh-abbbreviations に対応するにしても、
    補完文脈を外から指定できる様にする仕組みが必要になる。

    現在の仕組みは ble-syntax:bash/completion-context/generate に固定になっている。
    この部分を別の補完文脈生成に差し替える事ができる様にする仕組みが欲しい。

    ble-complete/candidates/get-contexts の中で呼び出している。
    これを ble-complete/context:$context/generate 的な物に置き換えられたら良い。
    というか補完文脈を生成する物にどのような名前をつけたら良いであろう。

    % 補完文脈を生成するものも context (文脈) と呼ぶのだと混乱の元である。
    %
    % 因みに現在は ble-complete/source:SOURCE と ble-complete/action:ACTION がある。
    % 今 context と読んでいるのは位置と source の組である。
    % 最近 context 配列を contexts に変更したがこれは失敗したかもしれない。
    % 実は context == sources だったのかもしれない。
    % pick-nearest-context なども pick-nearest-source であるべきだったかもしれない。
    %
    % うーん。今となっては面倒なので context を生成する機構は switch という事にする。

    2018-09-20 元気があったので今まで context ctx と呼んでいた物は全て source src に改名した。
    source を生成していた物が今後は context になる。

    改めて思うことは、実は静的略語展開にしても動的略語展開にしても、
    実は complete の枠組みとは処理の仕方が異なるので、
    また独立に実装する必要があるのではないかという事。
    もしそうだとするならば context:??? を用意して実装するというのは変な気がする。

    * 寧ろ context:??? を用意して実装するのは個別の補完の種類を指定した補完なのではないか。
      取り敢えず実装仕掛けてしまったので個別の補完の種類を指定した補完に対応する事にする。
      取り敢えず実装して emacs モードでテストした。動いている。

      | 問題は vim mode でどの様に実装するべきかである。
      | M-/ 等には bind したくない。すると C-x / 等だけに bind する事になり、
      | 最初から menu-complete を試みる事になる。本当にそれで良いのだろうか。
      |
      | * vim での振る舞いについて確認しておく事にする。
      |   vim の振る舞いは何だかよく分からない。取り敢えず C-x C-v とするとメニュー補完に入る様だ。
      |   その意味では menu-complete に入るという振る舞いは良い。
      |   しかし、その後で C-v を再び押すとどんどん次の候補に移動する様である。
      |   という事は、menu-complete でも例えば C-x / で始まった時には、
      |   / を連続で押す事によって次の候補に移動するという事をしても良いのではないか。
      | * と思って bash の振る舞いを再度確認したら、
      |   これはメニュー補完ではなくて、単にメニューを表示するだけだった。
      |   C-x $ に続けて連続して $ を入力しても、普通に $ が入力されるだけで、
      |   別にメニュー補完に突入する等の事はないようだ。
      |
      | まとめると
      | - vim では C-x C-v とするとメニュー補完に入り、続けて C-v を押すとメニュー内の選択をできる。
      | - bash では C-x / などとすると単にメニューを表示するだけでメニュー補完に入るという事はない。

      これを踏まえて以下の様に実装する事にする。

      - emacs モードでは bash と同様の動作とする。つまりメニューを表示する。
      - vim モードでは menu-complete に入る。但し、同じキーを続けて打つ事による選択には対応しない?

      まあ、取り敢えずこれで完了という事にする。

    * 次に静的略語展開について考える。
      静的略語展開は補完候補の生成などは実は行わない。
      単に文脈を見て完全一致したら置換を実行するだけである。
      magic-space を改造する必要がある。

      先に静的略語展開に対応する事にした。

    * 動的略語展開は command argument word など?
      或いは、extract-command で取得できる範囲?
      それを入力済みの文字列として履歴から合致する単語を探し出す。

      しかし、履歴に含まれる単語を厳密に切り出すと時間がかかる。
      事前にバックグラウンドで単語の分割を実行したとしてもメモリを食う。
      更に、入れ子になっている場合なども考えていくと処理は単純ではない。

      Bash の振る舞いはどうなっているのだろうか?

      | 調べてみると例えば 'f に対して dabbrev-expand すると、
      | 過去の f で始まる単語に一致する。過去の "'f" で始まる単語には一致しない。
      | * 更に実際に挿入される文字列はちゃんと閉じ ' も付加される。
      |   →これは core-complete の action:word/complete 辺りで行っているのと同様の事をすれば良い。
      | * また、過去の 'hello f*** world' 的な引用符の中の単語にも一致しない。
      |   →これは単純なシェル特殊文字による分割ではなくて入れ子構造も考慮した探索になっている事を表す。
      |
      | うーん。これをちゃんと対応するのは難しい。
      | しかし、引用符の中を考えなくて良いのであれば或いは簡単かもしれない。
      |
      | 引用符をスキップして一致した物を見つければ良いのでは。
      | あと空白とシェルの分割文字 ><;|&(。
      | * また = と : については特別扱いするべきか。
      |   調べてみた所 : も = も特別扱いはされていない様だ。
      |   : または = で区切られた補完候補も生成されないし、
      |   また : または = が含まれていても全体として一つの補完候補となっている。
      | * 単に '' の部分だけ除去するだけでは駄目の様だ。
      |   つまり、'bbbb'aaaa が履歴にある時 aaaa は候補にはならない。
      | * コマンド置換の中にある単語も候補にはならない。
      | * 引用符の中での dabbrev はできるが、クォートがある場合には dabbrev はできない。
      |   つまり 'f からは dabbrev できるが、\f からは dabrrev できない。
      |   もしかすると COMP_WORDBREAKS 以降の文字列に対して dabbrev しているだけなのかもしれない。
      |   →なんとそれだった。\ を COMP_WORDBREAKS に入れたら \f から dabbrev できるようになった。
      |
      | つまり、以下の様な実装になる。
      | 1 COMP_WORDBREAKS 以降の文字列を入力済み部分とする
      | 2 入力済み部分に一致する単語を履歴の中から探し出す。
      |   単語がどう切り出されているのかは不明

      ble でどの様な仕様にするかは色々考えられる。

      | a COMP_WORDBREAKS で区切って最後の単語に対して履歴から検索を行う。
      |
      | b 文法構造に従った単語で履歴から検索を行う。
      |   文法構造を解析しているので単語を抽出する事は容易である。
      |   しかし、履歴の方については文法構造に従った抽出は困難である。
      |
      |
      | ? 展開した結果の文字列を履歴から検索するのか
      |   展開前の文字列について履歴から検索するのか。
      |   これは、履歴を一つ一つ展開するのが困難であるし、
      |   展開語が一致する様に展開前に対する正規表現を構築するのも不可能であるから、
      |   整合性を考えるならば展開前の文字列について履歴から検索するのが妥当である。
      |
      | ? Bash では履歴の中の引用符に含まれる文字列などには一致しなかった。
      |   これを正しく実装するのは ble では難しい。
      |   正規表現で単語を切り出しながら一致させる事も可能であるが、
      |   そうすると少し複雑な単語が含まれているだけで、
      |   それ以降の単語について一致させる事ができなくなる。
      |
      |   改めて Bash で試してみると、例えば $ から dabbrev-expand すると、
      |   ちゃんとコマンド置換の単語も抜き出す事ができているという事から、
      |   やはりトップレベルの単語について全て記録している、
      |   もしくは一致させる時にちゃんと解析をしているという事になる。
      |
      |   これを ble で実現する為には、
      |   内部的に文法構造の解析を実行するか、
      |   或いは、簡易な方法で読み飛ばすか、
      |   という事をしながら履歴を検索していかなければならない。
      |   因みに Bash は簡易な方法で読み飛ばしているのではないかという気がする。
      |   元々の解析自体が簡易な方法で読み飛ばしてから、
      |   中の構造をまた解析し直すという解析方法を取っているように思うので。
      |   簡易な方法で読み飛ばすとしたらどの様にすれば良いのか。
      |   ${} と () をカウントすれば良いだろうか。
      |   それと " についてもちゃんと開く・閉じるを調べる必要がある。
      |   再帰下降で解析すればそんなには難しくないのだろうという気がする。
      |   但し Bash で実装するのには重い気がする。

      Bash の動作

        COMP_WORDBREAKS で区切った単語を現在位置から切り出し、
        文法構造に従ったトップレベルの単語を履歴から検索する。
        単語のクォート除去などは行わない状態で検索を行う。

      方針1

        文法構造に従った単語を現在位置から切り出し、
        文法構造に従った単語を履歴から検索する。
        これは事前に単語の一覧を作っておくか、
        その場で解析を実行しなければならない。

      方針2

        COMP_WORDBREAKS で区切った単語を現在位置から切り出し、
        COMP_WORDBREAKS 区切りで単語を履歴から検索する。

      実用性という観点から考えると、例えば $(...)
      という様な単語を切り出すという事があるのかという疑問がある。
      それよりは細かい単語を補完させる場合の方が多いのではないかと思う。
      その様に考えると COMP_WORDBREAKS で区切った物を履歴から検索する方が自然に思われる。

      取り敢えず方針2で実装する事にする。

  * complete: メニューが表示されている状態で C-x ~ 等を実行すると [#D0819]
    その時にメニューに表示されている内容でメニューに入ってしまう。
    context= が指定されている時にはメニューに入るべきではないのではないか。
    →取り敢えずその様に実装した。この仕様は微妙かもしれないが暫く試してみる事にする。

  * 2018-09-15 [保留] complete: 補完で stackdump が出た。恐らく補完のバグである [#D0818]

    TAB RET を連続で打った。しかし、本当にそれが原因かは分からない。
    寧ろ menu-filter や auto-complete の方が問題である可能性もある。
    備考: magnate で発生した。直前に cd で [ble: EOF] が表示される問題が再現している。

    | [murase@magnate2016 0 bin]$ cd
    | [murase@magnate2016 0 ~]$ c[ble: EOF]
    | [murase@magnate2016 0 ~]$ cd bin/l
    | [murase@magnate2016 0 bin]$ stackdump: X1 0 <= beg:0 <= end:1 <= iN:1, beg:0 <= end0:-1 (shift=2 text=l)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:6 (ble-syntax/parse)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4 (ble-edit/content/update-syntax)
    |   @ /home/murase/.mwg/src/ble.sh/out/lib/core-syntax.sh:14 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:5 (ble-highlight-layer/update)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:40 (ble/textarea#update-text-buffer)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:3 (ble/textarea#render)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:2 (ble/widget/.insert-newline)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:34 (ble/widget/.newline)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:0 (ble/widget/accept-line)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:21 (ble-decode/widget/.call-keyseq)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:42 (ble-decode-key)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:43 (ble-decode-char/.send-modified-key)
    |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:50 (ble-decode-char)

    padparadscha 上で試しても再現しない。
    上を観察すると beg, end は正しい値になっているが
    end0 が設定されていないという状況の様だ。謎である。
    また、これは今までによく発生していた mark と ind のエラーではなくて、
    ble-syntax/parse の中で起こっている更新範囲のエラーである。
    特に ble-syntax/parse から利用する end0 に触っている箇所は限られているはずである。

    * 辿って行くと、ble/dirty-range#update を信頼するならば、
      ble-edit/content/.update-dirty-range の呼び出し元が怪しい。
      これの呼び出し元は三箇所で以下の通り
      - ble-edit/content/replace
      - ble-edit/content/reset
      - ble-edit/content/reset-and-check-dirty
      reset の場合には内部で文字列長を取得しているので end0 が負になる事はありえない。
      reset-and-check-dirty に関しても ble/string#common-suffix が渡した文字列よりも長い
      誤った結果を返さない限りは end0 が負になる事はない。
      従って、ble-edit/content/replace の呼び出し元を調べれば良いはずである。
      core-complete.sh の中での ble-edit/content/replace の呼び出し元は以下の通り。
      - ble-complete/menu-complete/select
        ここは end として _ble_edit_ind を渡している。
        _ble_edit_ind が負になっていたらもっと色々なエラーが出ている筈であるし、
        また今回の操作には menu-complete は関係ないのでこれは大丈夫だろう。

      - ble-complete/auto-complete/.check-history
      - ble-complete/auto-complete/.check-context
        ここでも _ble_edit_ind を渡している。
      - ble/widget/auto_complete/cancel
      - ble/widget/auto_complete/accept
        これらは _ble_edit_mark の方を渡している。
      - ble/widget/auto_complete/self-insert
      - ble/widget/auto_complete/accept-word
        _ble_edit_ind を渡している。
      うーん。何れも問題がないように思われる。

    * ble/dirty-range#update の実装を確認する。
      どうもこれを読むと beg>=0 で end<0, end0<0 という状況も想定している様である。
      end<0, end0<0 は恐らく末端までという意味であろう。
      しかし、今回は beg>=0 ならば end>=0 かつ end0>=0 と仮定する。
      この時 end0 が元にない値になるのは、
      delta=endA-endB0 が負の時でこの時 end0=endA0-delta とされる。
      しかし、これは end0 を増加させるのであって、end0 が負になることの説明にはならない。
      因みに、例えば以下のような形の変更である。処理としても正しい。

        0---bA-----------eA0---e0---$
        |   |            /    :    /
        |   |           /    :    /
        0---bA---bB---eA---eB0---$
        |   :    |         /    /
        |   :    |        /    /
        0---bA---bB------eB---$

    * core-complete.sh 内部で _ble_edit_mark に値を設定している箇所を確認する。
      何れも _ble_edit_ind に正の値を渡しているか、或いは直接正の値を代入している様に見える。
      _ble_edit_ind に関しては insert_beg または _ble_complete_ac_comp1, _ble_complete_menu_beg が負の値だと
      もしかすると負の値になってしまうかもしれない。
      insert_beg は _ble_complete_menu_beg または _ble_complete_ac_comp1 から値を持ってきている。
      それ以外の場所は自明に正の値になっているはずである。
      _ble_complete_menu_beg は COMP1 から値を取ってきている。
      _ble_complete_menu_comp1 も COMP1 から値を取ってきている。
      COMP1 は補完文脈から直接値を取得している。

    補完文脈でバグにより負の値が生成される事があるのだろうか。
    取り敢えず ble-syntax/completion-context/.add に
    ble-assert を設置して様子を見る事にする。
    また、エラーが発生した時の修正で end0 も値を設定する様にした。
    後はまた様子見をする事にする。

  * [保留] 2018-09-11 complete: 止まってしまう問題。端末の問題なのか ble.sh の問題なのか切り分けが必要 [#D0817]
    と思ったが最新版では再現しない。何だったのだろうか。

    - これはやはり今でも起こる様である。
    - 先ず今までに screen の中で起こった事はない。
      rosaterm に関して起こった。
    - Cygwin だけでなく Linux (padparadscha) の上でも起こる。
    - 別の端末から bash を殺すと再度動く様になることから、
      端末の表示がおかしくなっているという事ではない。
    - コマンドの実行直後に起こる事もある
      実はかなりの頻度で起こっている。

    2018-09-19 今試すとやはり動かない。何らかの発生条件があるのだろうか。

2018-09-19

  * edit: コマンド実行が伴わないとき、ちらつき防止の為 insert-newline で info を消去しない [#D0816]
    空のコマンドに対しても毎回 info を隠したり表したりするのは
    非効率でありちらつきの原因である。

    序でに、コマンド実行時に現在のカーソル位置より下に表示されている
    端末の内容を上書きする様に変更した。

  * 2018-09-12 face が見つかりませんでしたのエラーメッセージは [#D0815]
    info か或いは新しい行に表示するべきではないか。

    試しに internal の時には .SHELL_COMMAND を呼び出すようにしてみたが、
    表示が乱れるし何だかよくわからない振る舞いをする。
    調べてみると実際に setface が呼び出されるのは最初の render の最中であり、
    その render は exec が設定されていない時に ble-decode/.hook 内部から呼び出される
    bind/.tail からなのであった。従って、ここで .SHELL_COMMAND を呼び出すと、
    以下の様にして問題が発生する様である。

    1 .SHELL_COMMAND 自体が今までの編集文字列を disabled にして
      明示的に textarea#render を呼び出すので、render の中で render を呼び出す形になる。
    2 exec が設定されているかどうかを確認した後なので、
      .SHELL_COMMAND を呼び出しても実際にそのコマンドが呼び出される事になるのは
      更に次のユーザ入力のあとになる。

    ここで望ましい振る舞いは何だろう。

    望ましいのは現在入力中の文字列は灰色に再描画して、
    その上で直後に表示を行うという事。
    .SHELL_COMMAND を呼び出すのは様々な端末の設定を復元してから実行したい場合である。
    また、関数の中ではなく一番外のスコープで実行したいという時である。
    今回は単に echo するだけなので .SHELL_COMMAND 経由で呼び出す必要はない。

    なのでその場で .insert-line してから実行してしまえば良い気がする。
    但し、着色の初期化が終わってからでないと描画に支障を来すかもしれないので、
    初期化中に発生したエラーは初期化が終わってから一括で表示する事にする。

    - C-x C-v で表示するバージョン表示も同様にして表示すれば良い。
      特に、何かを echo するだけの .SHOW_MESSAGE 的な物を作れば良い気がする。
      →ble/widget/print という編集関数を用意した。
    - 他の箇所も全て ble/widget/print を呼び出す様に変更する、と思ったら、
      echo して序でに jobs も実行するという物があった。
      つまりコマンドの実行もできた方が良い。
      結局 ble/widget/internal-command という関数を用意する事にした。
    - command-help に関しても序でに "外の環境でコマンドをその場で実行する" ものとして
      ble/widget/external-command を実装してそれを使って表示する様に変更した。
    - 分かりやすさの為、.SHELL_COMMAND は ble/widget/execute-command という編集関数を用意して、
      その編集関数をそのまま呼び出すことによって実装する様に変更した。

  * ble-edit/read は ble/util/strftime で timeout を計っているが [#D0814]
    EPOCHREALTIME 等、他にももっと良い計測方法が在るのではないだろうか。
    idle で使用している物を流用できれば流用したい。
    特に idle で使用している物を汎用的な物に書き換えるなどすると良さそう。
    初期化と取得に分けて時間間隔を計ることができるようにする。

  * decode: ユーザが勝手に先に keymap にキーを追加していると [#D0813]
    ble-decode/keymap/load が呼び出されずに、既定の設定が呼び出されない可能性がある。

    a 元々存在していない keymap は受け付けるべきではないのではないか。
      現在の実装はどうなっているだろうか。様々の keymap について明示的に定義していただろうか。

    b 或いは、既に keymap が存在している場合には bind 時に define を呼び出す様にするか。
      しかし、それだと keymap:$keymap/define も遅延ロードされる時にやはり駄目。

    やはり a の方針で行く事にする。
    取り敢えず ble-decode/keymap/load を bind 時に実行して、
    失敗したらエラーという事で良いのではないかと思ったが、
    よく考えたら ble-decode/keymap/load は内部で bind を呼び出すので無限ループになってしまう。

  * complete (request by cmplstofB): 補完関係の設定をする為に補完に load hook を追加した [#D0812]

  * complete (request by cmplstofB): ble/widget/auto_complete/accept-and-execute [#D0811]
    名称をどうするか悩んだが結局 accept-and-execute にした。
    accept-and-accept だとよく分からないし、
    accept-and-accept-line も似たような物である。
    単に accept-line とすると accept-word との対比から勘違いする。
    結局 accept-and-execute という事にした。後でまた変更するかもしれない。


2018-09-18

  * 2018-09-15 complete: "for a in @" と "do @" の補完で空の補完源が指定されている様だ [#D0810]
    エラーメッセージが出る。と思ったら
    ble-syntax/completion-context/.check-prefix/ctx:next-identifier 内部の変数名の typo だった。直した。

  * 2018-09-13 edit: TRAPWINCH による再描画条件 (TERM=rosaterm において cd した時の表示が変だ) [#D0809]
    何故か [ble: EOF] が表示されてから改行が実行されるという事が起こっている。
    今試すと再現しない。magnate からだけ再現するという可能性もある。
    →試してみた所 magnate では再現する。

    | うーん。もしかするとこれは Bash が cd の変更による
    | プロンプト再表示に対応しているという事なのだろうか。
    | つまり、余分に表示されているプロンプトは Bash によるものの可能性。
    | しかし、screen の中では発生しないというのは不思議な事である。
    |
    | また builtin cd の呼び出しでは再現しない。
    | cd を複数回中で呼び出してもプロンプトの余分な表示は一回だけ起こる。
    | 調べるに当たって複数の方向性が在る。
    | 一つは ble.sh のどのタイミングでプロンプトの余分な再描画が行われているのか。
    | そしてもう一つは mwg_cdhist の中のどの行が問題を引き起こしているのか。
    |
    | * どうも mwg_cdhist.push "$PWD" &>/dev/null が問題を引き起こしている。
    |   しかも、何故か &>/dev/null がある時に限って問題が起こる。
    |   段々と絞れてきた。
    |
    |     $ f1() { (echo 1); }; f1 &>/dev/null
    |
    |   だと再現するが、
    |
    |     $ f1() (echo 1); f1 &>/dev/null
    |
    |   だと再現しない。何が原因なのかは不明である。
    |
    | * うーん。過去の ble.sh の version に遡ってみる。
    |   どうも b232a88 からの様である。
    |   調べると bleopt_term_modifyOtherKeys_external= だとならなくて
    |   bleopt_term_modifyOtherKeys_external=1 だとなる。
    |   というより bleopt_term_modifyOtherKeys_external が非空白だとなる。
    |   この振る舞いは最新版でも再現した。

    * f1() { (echo 1); }; f1 &>/dev/null で発生するが
      f1() (echo 1); f1 &>/dev/null では発生しない。
    * bleopt_term_modifyOtherKeys_external に非空白の値が設定されているとなる。
      つまりコマンド実行直前に CSI > 4 m が送信されるかされないかの違いである。

    うーん。何故上記の組み合わせで起こるのかは謎であるがこれは Poderosa のバグ、だろうか?

    もう少し試してみた。先ずプロンプトに + を追加して様子を見てみる。
    そうすると余分に表示されるプロンプトに関しても + が付加されている。
    更にプロンプトの計算回数も + の前に付加してみると、
    余分に表示されているプロンプトは確かに一つの独立した描画によって為されている様である。

    分かった気がする。どうやら Poderosa が modifyOtherKeys を受け取った時に画面の下端に
    不明なシーケンスを受け取った旨を表示するがその瞬間だけ画面サイズが変化する。
    その通知を ble.sh が受け取って再描画を実施しているという事の気がする。
    調べてみると screen の中に居る時には CSI > 4 m は Poderosa に到達していない様だ。

    更に &>/dev/null の有無で変化するのは TRAPWINCH からの出力が何処へ行くかの問題の様に思われる。
    これは TRAPWINCH に於いて現在プロンプトを表示している状態かどうかを検査すれば良い。

    プロンプトの表示・非表示は何処で設定されているだろうか。
    コマンド実行は gexec/.begin 及び gexec/.end で囲まれて実行される。
    これは gexec/.setup で設定されたフックによって実行される。
    gexec/.setup は gexec/process から呼び出され、
    これは ble-decode/EPILOGUE で呼び出される。
    ble-decode/EPILOGUE は ble-decode/.hook の最後に呼び出される。
    うーん。この decode の枠組自体はより一般の物なので
    ここではプロンプトの処理はしていない。

    * internal/external の状態について確認
      だとすると寧ろコマンドを最初に登録している箇所での制御である。
      それは ble/widget/.SHELL_COMMAND などである。他にも沢山ある。
      ble/widget/.insert-newline を呼び出している箇所と考えれば良さそうである。

      - ble/widget/.newline
        - ble/widget/discard-line
      - ble/widget/accept-line
      - ble/widget/read/accept
        これはパネル 1 の上で実行されている。
        しかもサブシェルの中で実行されているので、
        ここでの状態は外には反映されない。
        この中で TRAPWINCH を捕まえると何が起こるだろうか。
        というか中で TRAPWINCH が実行されるという事があるのだろうか。
        恐らく中では TRAPWINCH は実行されない様に思うが、

        もし中で実行されるとすると .insert-newline が実行されると何が起こるか。

        というか、そもそも .insert-newline は何を実行するのだったか。
        先ず、現在の状態で (未だ描画していなかった部分を) 描画を実施する。
        ble-info は仕舞う。textarea の末端へ行き、次の行に移動する。
        ジョブがあれば出力する。
        ble/textarea#invalidate を実行する。
        (実は単に _ble_textarea_invalidated=1 を設定するだけ)

        その様に考えれば read の中で .insert-line が実行されて、
        プロンプトの類が表示されない状態になっている時、
        TRAPWINCH を呼び出されると何が起こるかというと、
        read の入力のプロンプトが再度表示されるという事になる。
        これは不都合である…。

    * 判別方法

      | a うーん。単に $_ble_term_state を見て external だったら再描画せず、
      |   internal だったら再描画するというので良い様な気もする。
      |
      |   この方法で確認して置かなければならないのは external になるのは、
      |   本当にコマンド実行のタイミングだけだったのかという事である。
      |   この状態は ble/term/enter, leave を呼び出した時に変更される。
      |   ble/term/enter の呼び出し元を調べる。
      |   というより ble/term/leave の方を調べた方が良い。
      |
      |   - ble/term/finalize
      |   - ble/term/TRAPEXIT これは bash を終了する時である
      |   - ble-edit/exec:exec
      |   - ble-edit/exec:gexec/.begin
      |   - ble-edit/read/.impl
      |     これは external で read を呼び出した時に
      |     読み取り処理の途中だけ一時的に internal
      |     になっていたのを元に戻すのに使っている。
      |     実は、これはサブシェルの中で実行するべきなのでは、
      |     と思ったが、微妙である。サブシェルの中でクラッシュすると
      |     変な端末状態のままになってしまう。
      |     余り面倒な事は考えたくないので現在のままにしておく。
      |
      |     うーん。そもそもこの read は internal の時にちゃんと動くのか謎だ…。
      |     ちゃんと落ち着いて考える必要がある。
      |
      |   - ble/widget/command-help.impl
      |     これはまあ外部コマンドと同様である。
      |     実際に invalidate を呼び出している。
      |
      | b 或いは、当初の案で行くとどうすれば良いかと言うと…
      |   _ble_textarea_invalidated=1 が設定されている場合には、
      |   何れ再描画される事が意図されているのでわざわざ再描画はその時点ではしないと判断できる。
      |   しかし、本当にそれで良いのだろうか。それだと次のキーが入力されるまで再描画されない事になる。
      |   それでも _ble_textarea_invalidated=1 で放置されて何も表示していないという事は、
      |   直後に未処理の入力があるか或いはコマンド実行中か、或いは関数の中にいて、
      |   ble-decode/.hook の最後で再描画が為されるのを待っている状態という事になるから、
      |   やはり再描画はその場ではしなくても良いという事になる気がする。
      |
      |   一方で、 _ble_textarea_invalidated= の状態で TRAPWINCH を受け取った場合にはどうだろうか。
      |   もしかすると行全体の invalidate が起こっていないだけで、実は処理の途中で
      |   ble-decode/.hook の最後で再描画されるのを待っている状態かもしれないし、
      |   或いは、アイドル状態でユーザの入力が為されるのを待っている状態かもしれない。
      |   ユーザの入力を待っている状態であれば即座に TRAPWINCH を処理しないと不都合である。
      |
      |   そう考えると実は _ble_textarea_invalidate だけを見るのではなくて、
      |   dirty の方も確認するというのは手かもしれないと思われる。
      |   dirty が残っていたら _ble_textarea_invalidated=1 を設定して終了する。
      |   そう思って確認したが ble/textarea#render に於いて部分描画の必要性を判定する部分は単純ではなかった。
      |   結局、色々 highlight layer や syntax 等を処理した上で umin:umax を求めてそれを元に判断している。
      |   なのでやはり _ble_textarea_invalidate を確認するだけで良い様に思われる。

      折衷案で行く。

      - _ble_textarea_invalidated に非空文字列が設定されている場合には、
        その直後の然るべきタイミングで再描画が行われるという事を期待して再描画はしない。
      - read 以外に関しては上記の方法で十分である。
        read に関しては、そもそも現在の実装に問題がないのかも含めて判断する必要がある。
        必要があれば _ble_term_state で external かどうかも判定の考慮に入れる。
        或いは、(read の実装がそれに合っていれば) それとは関係なく external で判定しても良いかもしれない。

    * read を internal で呼び出した時の動作について確認を行う。
      処理は result=$(ble-edit/read/.loop) というサブシェルの中で行っている。
      ble-edit/read/.setup-textarea でパネル 1 に表示を行う。
      パネル 1 に表示を行うのはパネル 0 の表示を保持したまま入力を行う為であったと思われる。
      もしパネル 0 の表示を read する度に消して良いのだとしたらパネル 0 にそのまま表示しても良かった様に思われる。
      その後設定を行って文字を1文字ずつ読み取る。_ble_edit_read_accept に非空文字列が設定されたら終了する。
      特にループが終わった時に表示を調整するなどはしていない。
      つまり、_ble_edit_read_accept を設定する側で表示の調整を行っている。
      実際にやっているのは ble/widget/read/accept と ble/widget/read/cancel である。

      ? ok: 特にキャンセルに関して言うと、実は何もしていない。
        うーん。external で使っている限りでは特に問題は起こっていない様に見える。何故だろうか。
        →と思ったが、よく見たら cancel の中で accept を呼んでいて、
        その accept が .insert-newline を実行しているのだった。

      さて、ここでの問題は、internal で read をした時にどうなるかという事である。

      $ function ble/widget/test1 { local REPLY; read -ep 'hello$ '; }; ble-bind -f C-t test1

      これで実際に実行してみた所、表示の計算がずれることになった。
      さて、では逆にどの様な表示が望ましいだろうか。

      a 一つの方法は一旦今まで表示していた textarea を disabled で再描画して、
        それから read で何かを読み取って、その後で再度新しい行に行を完全に描画し直す。
      b vi_cmap と同様に panel 1 に表示して、入力が完了したら入力に使ったパネルは消去する。
        これは何を入力したかを後で確認できなくなるという問題が残る。
        しかし、そもそも ble-bind で処理する時点で残る事を期待するのも変である。
      c 或いは一旦 textarea を消去してそこに read による入力を実行する。
        入力が完了したら新しい行に移動して、元々の編集文字列を再描画する。
        これは実質 a と殆ど同じで、元の内容を消去するか残すかの違いしかない。

      | ところで bash はそもそもどの様に振る舞うのか。
      | bash-4.3 で試したら変な事になった。
      | 先ず、read を起動した瞬間に元のプロンプト・編集文字列は一旦消去する。
      | 確定すると次の行に移動するが read の行がもう一つ重複して表示されてしまう。
      | その後で本来のプロンプトが改めて描画されたりされなかったりするが、
      | 元の編集文字列の内容は消えてなくなっている。
      |
      | 更に bash-5.0 ではもっと変な振る舞いになっている。
      | 先ず、元のプロンプト(a)・編集文字列(b)は一旦消去する。
      | 新しい read のプロンプト(c)を表示して入力を受け付ける。
      | 確定すると次の行に移動して、プロンプトは read に使った(c)のままで(b)が表示されるが、
      | 更にその場で(b)がコマンドとして実行されてしまう。
      | その後で新しいプロンプトと空の編集文字列が表示される。
      | もしかすると bash-4.3 の振る舞いもこれと同じことだったのかもしれないが再度確認するのは面倒だ。

      結局、bash 自体が変な振る舞いをするという事が分かったので、
      これに関しては ble.sh の側で自由に適切と思う動作を選択する事にする。
      特に上記の b の方向で実装する事にする。

      これは実装した。

    次に TRAPWINCH を修正する。
    read については独自に trap WINCH するのが良いのではないか。
    確認のためにサブシェルの中で trap がどうなっているのか確認する。
    サブシェル内部で "trap" とやると WINCH も出る。継承されている?
    実際に発動するのか分からないので確認してみる事にする。

    調べてみた所、やはり親の側で発動している様である。
    では内部で改めて trap を実行した場合にちゃんと内部で発動する様になるのだろうか。
    ちゃんと呼び出されている。しかし再描画させようとしたら式に誤りがあるというエラーが発生した。後で見る。
    これは IFS の問題だった。TRAPWINCH の中で IFS を設定するようにしたら直った。

    取り敢えず動いている様子なので一旦コミットする→直った事を確認した。

2018-09-15

  * mshex: mwg_cdhist が failglob で動かなくなる [#D0808]
    これは後で確認する。そんなに難しい事ではないだろう。
    何箇所か修正したが本当にこれで全部なのかは分からない。
    取り敢えず問題は起こらなくなったが、mwg.dict の実装を再度確認する。
    再確認した。また古いコードを大幅にレファクタリングした。

  * bash-3.0: 補完できない時に ble-complete/source/: No such file or directory  のメッセージが出る [#D0807]
    % これはまた bash-3.0 配列のバグ回避に失敗している気がする。
    これは単に ble/array#push の bash-3.0 向けの実装に問題があった。
    push する要素が一つもない場合にから文字列を追加する様になっていた。
    これを修正したら直った。

  * [棄却] base: --noattach を忘れた時に PS1 が元に戻る問題の対策 [#D0806]
    これは元々使い方を誤っているのが問題なのだが、
    多少変な使い方をしても変なことが起こらないようにはしたい。

    と思ったが最初のキーを受け付ける迄には PS1 は表示しなければならない。
    つまり最初のキーを受け付けるよりは前に PS1 を読み取って、
    しかし bashrc の末尾で PS1 を更新するという様にしなければならない。
    しかし、そもそも ble-attach した瞬間に既にプロンプトを表示するので、
    PS1 が設定されたのを検出できたとしても
    最初の一回は必ず設定前のプロンプトになってしまう。
    やはり遅延初期化をし忘れた場合に PS1 を正しく実行する様にするのは難しい。

2018-09-13

  * edit: read/exit の振る舞いが破壊されていた [#D0805]

    mshex: mwg_cdhist が何故かフリーズする。
    これは謎である。今までは起こっていなかった。
    ble.sh との相互作用で何か変な事が起こっているのだろうか。
    →ble.sh をロードせずに実行するとフリーズするという事はない。
      何が悪いのだろうか。例えば、fd がバッティングしている可能性など?

    これはあらゆる所で問題をおこしている。
    早く修正しなければならない。
    どうも C-@ しか受信できない状態になっている様だ。

    →分かった。read が全く働いていない。引数を渡し忘れている。

  * bash-3.0: ble-detach 後に stty sane を実行しろというメッセージが出る事に関して [#D0804]

    * ok: bash-3.0 では stty sane がコマンドラインに入らない。
      →そもそも READLINE_LINE は bash-4.0 からの機能なのでコマンドラインに入らないのは問題ない。

    一方で bash-4.3 では stty sane を実行しなくても特に問題は発生せず、
    しかし、前者に関しては謎である。見た感じ .check-detach で READLINE_LINE に
    stty sane を設定して、そのまま return 0 している。return 0 した時には、
    gexec/.end で bind/.tail を実行せずにそのまま終了する。
    従って、READLINE_LINE に stty sane が入っているはずである。

    と思って確かめてみた所実はちゃんと READLINE_LINE には stty sane が代入されているが、
    それが表示されていないということの様だ。何故表示されていないのだろう。。

    | | 何かこれに関して議論があったはずと思って調べた。
    | | #D0436 によると PS1 のずれを補正する為の茶番だそうだ。
    | | つまり、bash は以前の PS1 のまま表示しようとするので、
    | | 結果として空の PS1 になるのであるが、
    | | ble.sh が代わりにそれを表示して誤魔化している。
    | | しかし、それだと不都合が生じるので適当に何かコマンドを実行する必要があった。
    | | その為に stty sane を実行するのだという。
    | | いっぽうで、改めて試してみるとやはり stty sane を実行しないと問題になるようだ。
    |
    | ^L を入力して (別の理由によってそれが直接入力されて) 実行すると、
    | その後で stty の状態が変になっているという事が露呈する。
    |
    | しかし、現状では描画がずれて stty sane が表示されない。何故だろう。
    | READLINE_POINT=9 から 0 に変更しても同様だった。
    | 不思議なのは home を押すと内部的にはちゃんと home に行っている様なのに
    | 表示上はカーソルの位置が全く変わらない事である。
    |
    | 実は PS1 をクリアせずに保持するという手もあるのかもしれない。
    | 毎回何か変な内容が出力されるのを握りつぶす事になるが、…
    | と思ったが PS1 に含まれるコマンド実行などが余分に実行されるという問題がある。
    | 特にコマンド置換を用いていると余分に fork が発生して、
    | 特に Cygwin では遅延が二倍になって余り嬉しくない。
    |
    | やはり現状で何が起こっているのかについて調べる必要がある。
    | うーん。やはり不思議としかいいようがない。
    | そもそも再描画しないのだと仮定しても、カーソル位置が動かないのはおかしい。
    | うーん。普通に bind -x で echo hello 等とした場合には再描画が実行される。
    | ちゃんと全体が再描画されてカーソル位置の調整も行われる。
    |
    | うーん。どうやら bash は stty の状態に応じて
    | プロンプトの出力をする・しないが切り替わるのだという事を思い出した。

    結局何が起こっているのかというと以下の事が起こっている。

    - 恐らく Bash は前回の stty の状態に依存して、
      プロンプトなどの類を表示するかしないかを切り替えている。
      ble-detach の直後にはプロンプトも編集文字列も表示されない。
    - DEL でカーソル位置が動かなかったのは stty が中途半端な状態で、
      erase=^? の設定が欠けていたためにそもそも back の役割を持っていなかった為に、
      実際に文字の削除も行われていない状態だった。
    - 普通に文字を入力すると入力できている様に思われたのは、
      単に入力文字がエコーされているだけの様である。

    調べると bash-4.0 -- 4.4 で一貫してこの事が起こっている様だったので、
    READLINE_LINE に関してもそのまま ble.sh 側で描画する事にした。
    bash-5.0 でも同様の振る舞いである。更に過去の ble の version ではどうであったか。
    ble-0.1 でも ble-0.2 でも再現した。全てに適用する事にする。

  * bash-3.0: ble-detach した後で " が効かない [#D0803]
    Bash 4.3 ではこの問題は発生していない。
    代わりに bash 4.3 で試すと ^L が効かなくなっている。
    Bash 3.0 でも ^L は効かない。

    Bash 3.0 で bind -p してみると "\"" に対してはちゃんと bind できている気がする。
    他に C-? が色々 self-insert になってしまっている。
    ^A-^C ^E-^G ^K ^L ^N-^Q ^X ^Z ^\ ^] ^^ である。

      "\C-a": self-insert
        中略
      "\C-^": self-insert

    unbind が一体どうなっているか確認する必要がある。
    調べたら unbind ではなくて $$.bind.save だった。

    % * 中は完全に空である。何故か?
    %
    %   普通に起動して attach せずに
    %   bind -sp | ble-decode-bind/.generate-source-to-unbind-default/.process を実行してみた所、
    %   ちゃんと内容が出力されている。ということは bashrc の中で bind -sp すると何も出力されないという事か。
    %   と思って再度実行してみるとちゃんと bind.save は有限のサイズになっている。
    %   更に bind.save をソースしている途中でエラーになって、跡で確認すると bind.save が空になっている。
    %   と思ったら単に ble-decode-detach で読み取ったものをクリアしているだけだった。

    * bind.save を読み込んでいる時に出るエラーは何か。
      ble-attach している状態で bind.save の中を確認する必要がある。

    % * ok: 確認すると何と ^A-^^ の問題のキーは確かに bind '"\C-a": self-insert' 等となっている。
    %   取り敢えず '"\C-a": self-insert' の原因だけ探る。改めて bind -sp してみる。
    %   不思議な事に ble-decode-bind/.generate-source-to-unbind-default の中で実行した。
    %   bind -sp は self-insert になっている。
    %
    %   --attach=prompt が悪いのかと思って --noattach に直したが同じである。
    %
    %   何と bashrc の中で bind -sp を評価したら "C-a": self-insert になっている…。
    %   これは実は Bash 4.3 でも同じである。対策する必要がある。
    %
    %   更に調べてみると bashrc の中でも source ble.sh する前と後で
    %   bind -sp の内容が変化するのであった。どうも調べていくと rcfile の前後で変わっている。
    %   .blerc を見ると set -o vi をしていた。つまり ^A-^^ のキーは set -o vi
    %   の時には元から bind されていないという事だろうか。その様だ。
    %   従って、これは問題ない動作なのであった。

    再び元に戻って $$.bind.save について調べる。

    うーん。どうも bind -p で "\"": self-insert が有効になっている様に見えるのに実際は無効である。
    試しに改めて bind '"\"": self-insert' を実行しても駄目だった。
    また bind '"\x22": self-insert' や bind '"\042": self-insert' を実行しても駄目だった。
    double quotation が stty で何か特殊文字になっているという事もない。

    bash-3.0 --norc で起動して bind -r '"' して bind '"\"": self-insert' を実行した場合はちゃんと動く。
    途中で bind -x '"\"": ...' して bind -r '"' しても大丈夫。

    更に ble-detach してから ble-attach して " を入力して数秒すると SIGSEGV する。
    もしかしてこれは既知の問題だったりするだろうか…。

    やはりどの様にしたら再現するかについて調べる事にする。
    これは純粋に bind の問題であろうという気がする。
    なので取り敢えず bind と unbind について調べる。

      ble-decode-bind.30022.UTF-8.bind -> 30022.bind
      ble-decode-bind.30022.UTF-8.unbind -> 30022.unbind
      $_ble_base_run/$$.bind.save -> 30022.restore

    これを source して見たところ再現した。
      source 30022.bind; source 30022.unbind; source 30022.restore
    更に、unbind/restore だけでも再現する。
      source 30022.unbind; source 30022.restore
    restore だけでは再現しない。
      source 30022.restore

    unbind を少しずつ削ってみると怪しいものが見つかった。
    他に可能性として関係がありそうな物も含めると、以下の二つ。

      builtin bind -r '"\e"'
      builtin bind -r '\"'

    後者についてはエスケープがあっても問題ないのだろうか。
    →実際に確かめてみるとエスケープがあっても期待の通りに束縛が削除される様だ。
    前者についてはそもそも -r '\e' はあるのだろうか。
    →確認してみた所 \e? はあるが \e がない。
    bind.sh を確認した所、明らかなミスであった。直した。

    ble-detach した後でも " がちゃんと入力できる様になった。
    また ble-detach して ble-attach した後に "" を入力しても落ちなくなった。

2018-09-12

  * "bash: read: 0.0-9: 無効なタイムアウト指定です" @ Cygwin [#D0802]
    これは何処かにバグがある。しかし再現しない。
    read -t ? を呼び出しているのは ble/util/sleep しかない。
    ble/util/sleep を呼び出している所を探すと、実はそんなにない。

    - ble/util/sleep 遅延初期化後の改めての sleep
    - vbell の消去までの時間
    - ble/util/idle/.sleep しかしここでは引数は算術式を使って構築しているので
      0-9 の様な変な値が混入する事はありえない。

    そうすると消去法で vbell が怪しいという事になる。
    しかし vbell も改めて確認した所算術式経由なのでやはり変な値が紛れ込む余地はない。
    改めて考えると ble/util/idle/.sleep で 0 を前置している。
    だとすれば負の値を ble/util/idle/.sleep に渡すと 0-9 の様になっても不思議ではない。
    負の値を ble/util/idle/.sleep に渡した場合には sleep せずに抜けるのが良い。修正した。

  * edit: 履歴展開が前の置換指示子に依存した動きをするということ [#D0801]
    https://github.com/akinomyoga/ble.sh/issues/10

    調べてみると置換指示子さえ使わなければ問題はなさそうだ。
    ble.sh 内部で置換指示子を使用する時はサブシェルで実行する必要がある。
    しかし、現状では履歴展開は内部使用するが置換指示子は使用していないので大丈夫。
    一方で、Bash 3.0 で履歴展開をサブシェルの中で実行していることにより、
    置換指示子が記録されないという問題がある。これは実際に起こることを確認した。

    | 該当する部分のコメントに依ると #D0233 で議論されているそうだ。
    | #D0233 によると history -p を実行する度に 2 つずつ履歴項目が消滅するという事になっているが、
    | 調べて見た限りでは履歴項目が減少しているという事はない。
    | 逆に history -r で読み取る事により履歴項目の数が矢鱈増えている。
    | 具体的にどのような状況で履歴項目が減少してどのような状況で履歴項目が登録されるのか調べる必要がある。
    |
    | 今試してみると問題なく動いている様な気がする。不思議だ。
    | もしかすると history -s で履歴行を追加している時のみの問題だったのかもしれない。
    | と思ったがやはり不思議だ。history -p する度に履歴行が減少するというのは確かに観測していた筈。
    | bash --norc の上で試してみる。 history -p だと何も起こらない。history -p '' だと減少する。
    | history -p -- '!!' でも減少する。bind -x 経由でも再現するか調べる。
    |
    |   bind -x '"\C-t": history -p -- ""; history | tail -1'
    |
    | やはり減少する様だ。すると、何故 ble.sh の枠組みから呼び出した history -p で減少しないのかは不思議である。
    | 試してみるとやはり減少はしていない。標準入力(もしくは tty)に繋がっている時だけの問題という可能性はあるか?
    | 改めて bash-3.0 --norc の bind -x 内で振る舞いを調べる。
    |
    | - 関数内で呼び出しても履歴項目が減少する (bind -x '"\C-t": f001')
    |   function f001 { history -p -- '!!'; history | tail -1; }
    | - 仮想端末につなげても同様に減少する (bind -x '"\C-t": f001 >>/dev/pts/16')
    | - ファイルに出力してもやはり減少する (bind -x '"\C-t": f001 >>B.txt'; cat B.txt)
    | - 標準エラー出力を捨てても減少する (bind -x '"\C-t": f001 >>B.txt 2>/dev/null'; cat B.txt)
    |
    | - NOBLE で ble.sh だけ読み込まずに mshex だけ読み込んだ状態でも減少は再現する
    | - set -o vi しても再現する
    | - HISTFILE=A.txt bash-3.0 --rcfile ../ble-dev/out/ble.sh で試してみる。
    |   ble-detach してから実行してみる。やはり減少は再現する
    | - ble.sh の側で -o vi と -o emacs を観察すると両方共減少しない。
    | - 別に history コマンドを変な関数で上書きしているという事もない。
    |
    | - 問題の関数 ble/edit/hist_expanded/.core を bind -x から直接呼び出すと減少が再現する。
    | - ble-edit/hist_expanded.update を呼び出しても再現する。
    |   bind -x '"\C-t": eval "ble-edit/hist_expanded.update aiueo"' としても再現する。
    |   bind -x '"\C-t": ! ble-edit/hist_expanded.update aiueo' としても再現する。
    | - 再び attach してみたら再現する様になった。不思議だ。
    |
    | - 再度起動し直して、ble-detach して ble-attach する。再現する。
    |   ble-detach; ble-attach だと再現しない。
    |   ble-detach を実行してから (stty sane を実行せずに) ble-attach を時刻すると再現する。
    |   ble-detach; history -p -- ''; ble-attach しても再現しない。
    |   set -o vi によって切り替えを実行しても再現しない。
    |   bash --norc で起動してその後で source ble.sh すると減少が再現する。

    [現象]

    - bash-3.0 では history -p -- '' を実行すると履歴項目が一つ減少した上で展開が実行される
    - history -p だけでは減少は起こらない。
    - ble.sh を rcfile として読み込んでその中で attach した場合には減少は起こらない。
      途中で detach & attach を一つの bind -x 呼び出しの中で完結して実行しても減少は起こらない。
      逆に後で attach したり、1回 detach してから別のコマンドとして attach を実行すると、
      history -p -- '' で履歴項目が減少するようになる。

    [実装]

    更によく考えてみると、もし減少する状況だったとしても、
    どの様に元の情報を復元したら良いのかは非自明である。
    というのも history -p -- '!!' は、減少してから一番最後の項目を取り出すので、
    減少した項目は取得できないためである。正しく実行する為には、
    HISTTIMEFORMAT= として history | tail -1 を実行して、
    その先頭から番号を取り除くという事をしなければならない。

    更に、その時に減少するモードになっているのか減少しないモードになっているのかを判定しなければならない。
    実装できなくはないが大変に面倒である。検証も面倒である。と思ったが結局実装した。

2018-09-11

  * syntax (report by cmplstofB): 履歴展開の置換指示子の切り取りが正確でない [#D0800]
    https://github.com/akinomyoga/ble.sh/issues/10

    先ず gGa は指示子というよりは指示子に対する接頭辞として働くこと。
    また s?..?..? の形式に対応していないという事。
    これは実際に対応してみたらそれほど複雑ではなかった。
    指示子は元々別に読み取っていたということと、1つの関数の2箇所でしか使っていなかった。

  * edit (report by cmplstofB): command-help の切り出しが変ということ [#D0799]
    https://github.com/akinomyoga/ble.sh/issues/10

    これは確認したら extract-command の振る舞いがおかしい。
    実装の中で何が起こっているのか調べようとしたら、
    その前に unset の使い方がおかしいという事に気づいた。
    これは unset で現在のスコープで定義された変数も削除できると思っていた時期のコードである。
    修正した。現在のスコープの変数を削除する関数の名前は何が良いか悩んだが、
    他に良いものが思い浮かばなかったので unlocal という事にした。

2018-09-09

  * complete: auto_complete keymap で C-x C-x DEL すると stackdump が発生する [#D0798]

    カーソル位置の計算が誤っている。これは auto_complete から抜ける時の mark の更新の問題の気がする。
    確認したらこれは簡単だった。他にもないか確認したが、他の場所は大丈夫のようだ。
    動作確認する。もう起こらなくなった。大丈夫。

  * vi: [棄却: 意図的な振る舞い] C-x ? のシーケンスに対する処理が怪しい [#D0797]

    例えば C-x C-s を入力すると ^X が挿入されてから C-s による検索が始まる。
    初めは何らかの仕様に基づく動作だったかと思ったが調べてみるとよく分からない。
    例えば C-] は何にも束縛していないが、これを入力すると普通にエラーメッセージが出る。
    また C-x C-x C-x A としても ^X は一個しか挿入されない。
    これは内部で何が起こっているのかを詳しく調べる必要がある。

    因みに modifyOtherKeys を使っていても同様の現象が起こるので、
    C-x キーの readline からの受け取りの部分では問題は起こっていないと予想される。

    調べてみると ble/widget/vi_imap/__default__ において明示的にそのような実装になっている。
    そうすると疑問が二つある。

    * 何故 C-] はそのまま挿入されないのか。
      他に C-^ もある。C-[ C-\ C-_ C-? に関しては既に束縛しているのでそちらが呼び出される。
      調べてみると C-] と C-^ では __default__ に入ってこない様だ。
      改めて ble-bind -d を監査室してみた所 C-] と C-^ は実は既に bell に束縛していた。
      従って、これらによって何も挿入されないのは自然なのであった。

      一方で、元々の vim ではどうだろうか。^_ はそのまま挿入される。
      ^F もそのまま挿入される。また ^\ に関しては二文字めを待って挿入される。
      一方で C-^ や C-] に関しては何も反応しない。

      ^X は実は補完に割り当てられている様だ。
      更に言うと2文字目に (C-x ? の組み合わせの割当がない) 何を入力しても吸収される。
      あと C-s は vim-surround が入っているのであった。

    * 何故 C-x を複数入力しても一つしか挿入されないのか。
      →これは簡単だった。よく考えたら C-x C-x の組み合わせで exchange-point-and-mark なのだった。

  * 2018-09-02 [棄却: これは Bash のバグ] edit: history -p '!!hello' の実行結果が異なる [#D0796]

    | % 元々の Bash で (直前のコマンド)hello になるところが、(現在のコマンド)hello になる。
    | % というか試すと history -p '!!' の時点で自分自身に展開されてしまって使えない。
    | % これは余り気にしなくても良さそうだが、一応そういう問題があるという事を記録しておく。
    | % これに対応する為には、登録前のコマンドの配列に記録しておいて、
    | % コマンドが実行される度にその配列に記録してあったコマンドを登録し、
    | % 最後に未だ残っているコマンド (何らかの拍子に抜けてしまったもの) を最後まで登録する。
    | % という様にすれば今まで通りにちゃんと履歴に登録されることが保証される。
    |
    | しかしやはり変だ。history | tail を実行すると自分自身も既に登録されている。
    | これは Bash でも ble.sh でも同様である。しかし、それなのに、
    | history -p における !! は Bash では最後から二番目を指しているのに対して、
    | ble.sh では最後を指しているという事になっている。
    |
    | これは Bash のコマンドを実行している途中では
    | history は何か特別な状態になっているという事だろうか。
    |
    | bash --norc で色々試してみると変な挙動に出会う。うーん。
    | どうも history -p '!!' 等をコマンド実行に於いて呼び出すと、
    | 現在の項目が削除される様である。
    |
    |   | $ function f1 { history | tail -1; history -p '!! @'; }
    |   | $ f1;f1;f1;f1;f1;f1;f1;f1
    |   | 41119  f1;f1;f1;f1;f1;f1;f1;f1
    |   | history | tail -2 @
    |   | 41118  history | tail -2
    |   | : hello world @
    |   | 41117  : hello world
    |   | history | tail -1 @
    |   | 41116  history | tail -1
    |   | : hello world @
    |   | 41115  : hello world
    |   | history | tail -1 @
    |   | 41114  history | tail -1
    |   | : hello world @
    |   | 41113  : hello world
    |   | function f1 { history | tail -1; history -p '!! @'; } @
    |   | 41112  function f1 { history | tail -1; history -p '!! @'; }
    |   | : hello world @
    |
    | うーん。
    |
    |   | $ function f2 { history | tail -1; history -p '!-2 @'; }
    |   | $ for f2 in {1..10}; do f2; done
    |   | 41114  for f2 in {1..10}; do f2; done
    |   | bash --version @
    |   | 41113  function f2 { history | tail -1; history -p '!-2 @'; }
    |   | : hello world @
    |   | 41112  bash --version
    |   | echo hello @
    |   | 41111  : hello world
    |   | history | tail -1; history -p '!! @' @
    |   | 41110  echo hello
    |   | ble-bind -d | grep C-x @
    |   | 41109  history | tail -1; history -p '!! @'
    |   | ble-bind -d | less @
    |   | 41108  ble-bind -d | grep C-x
    |   | ble-bind -d | grep C-x @
    |   | 41107  ble-bind -d | less
    |   | set -o vi @
    |   | 41106  ble-bind -d | grep C-x
    |   | set -o emacs @
    |   | 41105  set -o vi
    |   | ble-bind -d | grep M-C-m @
    |
    | やはり履歴をどんどん削っている。
    |
    | この事から分かるのは bash-3.0 以下でのバグだと思われた
    | history -p によって履歴行が消えてなくなる仕様は (#D0233)、
    | 実は単にこの動作が (コマンド実行時だけでなく) bind -x
    | の関数実行時にも適用されていたという事の様だ。
    |
    | これは Bash の振る舞いが悪いという事にして深追いはしない事にする。

    [まとめ]

    Bash ではコマンド実行中に history -p を呼び出すと履歴項目を一つ削ってから展開を行う。
    さらに history -p を複数回呼び出すと呼び出した回数だけ履歴項目が減少する。

    これは bash-4.3, 4.4, 5.0 (devel) で再現する。3.0 でも再現した。
    途中の version は試していないが何れでも再現するのだろう。

  * decode: ble-bind -d が動かなくなっている [#D0795]
    割と最近の問題の様である。
    →調べてみたら割と最近の問題、という訳ではなくて failglob が原因だった。

  * 2018-09-02 isearch: 文字を入力せずに C-r を連打して遡った後に C-h で戻った時の選択範囲 [#D0794]
    何故か編集文字列全体が選択されている。
    何か文字を入力して処理している場合には何も起こっていない。
    ble-edit/isearch/search の空文字列に対する振る舞いが原因かもしれない。

    C-h で戻った時には ble-edit/isearch/prev にて、単に記録していた状態に戻っているだけである。
    記録されていた情報を確認してみると、記録していた時点で先頭から末尾までの範囲が設定されている。
    実際に配列に記録している箇所へ行く。ble-edit/isearch/.push-isearch-array である。
    ここで push する内容を観察すると先頭から末尾になっている。
    そしてその値は _ble_edit_ind と _ble_edit_mark から計算している。
    _ble_edit_ind と _ble_edit_mark は ble-edit/isearch/.set-region で設定されている。
    但し、長さが 0 の場合には何も設定されない。
    というか、長さが 0 の時にはそもそも beg:end は -1:-1 の様である。
    更に _ble_edit_mark_active は設定されない。

    ble-edit/isearch/.push-isearch-array で push する時に、
    _ble_edit_mark_active を確認して、範囲が有効になっていなければ
    oend は obeg と同じ位置にする事にした。

  * 2018-09-05 complete (progcomp): 一応補完開始点に単語の切れ目を入れる [#D0793]

    % よく考えてみたら --prefix=... の場合には単語が切れてしまうと不都合である。
    % 元々 check-here が起こった時に変な補完になるのが問題だったのだが、
    % check-here が起動する時点で不備があるということなので、
    % そこで変な事が起こっても気にしない事にする。
    %
    % と思ったが、本当に大丈夫だろうか。例えば --prefix= の途中で補完が起こった場合には…
    % 実は progcomp では必ず単語の先頭で補完が始まるはずなので --prefix= の途中で補完が起こる可能性はない。
    % 従って、そのような場合に単語が切れて困るという事はない。

    やはり補完開始点 (progcomp を呼び出した argument) で切るのが良さそうに思われる。

    問題は単語の切れ目を入れる時に ble-syntax:bash/extract-command 側で実行するか、
    それとも complete の側で実行するのかという事である。

    % ble-syntax:bash/extract-command の側でのデフォルトを変えるのはない。
    % 新しくオプションを受け付ける様にするという手もある。
    % しかし考えて見るに、本当にその様な事ができるだろうか。
    % 例えば simple-word ではない場合には中途半端な位置で切っても仕方がない。
    % なので complete の側で修正は行っても良いのではないかと思う。
    % また、complete の内部でそう何度も呼び出す処理ではないので多少遅くても問題ない。

    と思ったが、よく考えてみたら現在の complete の実装で既に
    .progcomp-helper-vars 関数の中で再度コマンドラインを構築し直している。
    従って、ここで単語の切れ目を導入するのが自然である。
    わざわざ extract-command 側を修正する可能性について考察する必要はなかった。

    ? 今実装を見て思ったのだが、本当に comp_point の実装は正しいのだろうか。
      元のコマンドラインの中での位置だったりはしないだろうか。
      と思ったが、元のコマンドラインの中での位置だった場合には、
      わざわざ comp_point に値を格納する必要はないから、
      やはり comp_line は再構築したコマンドラインであり、
      comp_point はその中での位置なのだろうという気がする。確認する。
      →確認した。大丈夫 comp_line は現在のコマンドから再構築した仮想的な文字列であり、
      また comp_point はその中での位置であり、単語は必ず ' ' で区切られる。
      →これは大丈夫。

    * しかし実は補完開始点は comp_point とは関係ないのであった。
      今、comp_point に入っているのは補完開始点の位置ではなくて、
      現在のカーソルの位置である。

      しかし、現在のカーソルの位置も重要な情報であるからこれの代わりに補完開始点を extract-command に渡す訳には行かない。
      或いは extract-command を二回呼び出すのも無駄だし、その二つの呼び出し結果の間に不整合があったらまた厄介である。
      考えてみれば extract-command が単語をそのまま切り出しているのだとすれば、補完開始点とカーソル位置の距離は保たれる筈である。
      その過程から comp_point-(COMP2-COMP1) が補完開始点と考えて良い。

    実装してみて思ったが、COMP_LINE COMP_POINT COMP_WORDS COMP_CWORD だけの問題ではないのでは。
    ble 自体の補完機能を使う場合には comp_line comp_point comp_words comp_cword を参照する筈である。
    そう考えると comp_line comp_point comp_words comp_cword の方も修正するべきなのでは。
    と思ったが、まあ、COMP2-COMP1 を使って自分で補完開始点をチェックすれば良いという事なのかもしれない。
    然しながら、それだと毎回ちゃんと単語の先頭に補完開始点があるかどうかを調べなければならず不便である。
    やはり適当に単語を分割するべき様な気がする。

    →やはり extract-command の直後で単語の分割は実施する事にする。
    特に、その様な変な事は基本的に起こらないはずなので、
    先に最初に単語の途中に補完開始点があるかどうか確認し、
    単語の途中に補完開始点がある時にだけ分割の処理を実行する事にした。

  * complete: やはり予測候補の色が分かりにくいので背景色を設定する事にする [#D0792]
    背景色を薄灰色にしている人は恐らくそんなにいないだろう。

    他の案として (昔の Windows のツールチップの様に) 薄黄色にしてみたが
    やはり何か陳腐な感じがするのでやはり敢えて無彩色で行くのが良いだろう。

  * 2018-09-05 highlight (layer:region): 改行直後の色が違う [#D0791]

    | ble-highlight-layer:region/getg で face2g region で決め打ちにしている。
    | ここは mark:MARK/getg を呼び出す様に変更する必要がある。
    |
    | うーん。実際に用意しているのは mark:MARK/get-sgr である。
    | sgr と g のどちらの方が primitive なのであろうか。
    | face → g → sgr という変換はできる。然し sgr → g はできない。
    | 従って、多少面倒ではあるが getg という関数を用意して、
    | 更に、其処から sgr に変換するという様にした方が良いのかもしれない。
    |
    | 因みに実装を確認してみた所、何れの get-sgr も face2sgr を呼び出していた。
    | また ble-color-face2g を呼び出してから ble-color-g2sgr を呼び出すよりも、
    | ble-color-face2sgr を直接呼び出した方が速い。
    | その様に考えると get-g と get-sgr の両方を貞経した方が高速である。
    | しかし、それだと実装が煩雑になる。
    | 或いは get-face という関数を呼び出すという手もある。
    |
    | しかし、今度は逆に動的に着色を生成する等の事が難しくなる。
    | 動的に着色を生成するという可能性はあるのだろうか。
    | 例えば、括弧を異なる色で着色する場合には動的に色を生成するのかもしれない。
    | 或いは複数の選択箇所を異なる色で着色する場合など。
    | しかし、改めて考えてみれば現在の実装では範囲は全て同一の色で着色する事を想定している。
    | その時に動的に色を生成する理由はない様に思われる。
    |
    | 将来的に色々な色に着色できるように拡張する可能性はあるが、
    | それはその時に対処すれば良い事である。
    | 更に言うならば、現在の実装は同一着色である事を前提とした最適化がされている気がする。
    | その事から、将来的にも異なる色で着色する様になる可能性は低い気がする。

    mark:MARK/get-face という関数で実装し直す事に決定した。

  * complete: 候補一覧にて入力済み範囲の着色がされない [#D0790]
    一時は動いていた筈なのに、今は効かない。
    少なくとも絞り込みを実行すると動かなくなる。

    絞り込みが実行されていない時にも一瞬だけ着色されて、
    その後で着色が外れる。絞り込みが発生しない筈なのに
    何故か絞り込みが発生している気もする。

    1 先ず、絞り込みが実行されている時に menu_common_part が空になっている。
      menu_common_part は menu/show 内で宣言されて、
      menu/initialize 内で初期化される。
      menu/initialize では COMPV の値をそのまま menu_common_part に設定している様だ。
      確認してみると menu-filter の呼び出し元では COMPV はちゃんと設定されている。
      menu/initialize の呼び出し直後にもちゃんと COMPV は設定されている。
      と思って確認してみた所、menu/initialize の中では insert 変数も参照していた。

      この insert という変数は何のための物だったろうか。少し観察したが見当が付かない。
      blame で確認すると 2018-08-27 04:52:33 29d8ef54 である。これは
      29d8ef5 - (13 days ago) complete: highlight candidates in menu である。
      つまり一番初めの実装からその様になっている。
      これは menu-filter の実装よりも前である。更に言うと menu-complete よりも前である。
      今調べると menu/show を呼び出しているのは元々の complete と、menu-filter の二つだけである。
      insert を使う事に意味に関しては ble/widget/complete だけ観察すれば良い。
      恐らく complete によって挿入が起こった後の着色範囲を指定する物である。

      complete の内部では3箇所から menu/show が呼び出されている。
      それぞれについてどの範囲を着色すれば良いかについて確認する。
      opts に enter_menu が含まれている場合には、そのまま menu-complete に突入する。
      この時には共通一致部分が仮にあったとしてもそれを挿入せずにメニューが開始するので
      本来は insert を使うべきではない。現状の実装では恐らく enter_menu になるのは
      共通一致部分がない場合に当たるので問題が起きていなかったという事なのだろう。
      show_menu が含まれている場合にはそのまま表示して終わりである。
      最後の所は menu_common_part を insert から再構築する必要がある。
      結局観察した所 menu_common_part を insert から再構築する必要があるのは一箇所だけの様だ。
      その部分を menu/show の呼び出し元に移動する事にした。
      つまり、menu/show の呼び出し元で予め menu_common_part を設定する様にする。

    2 次に filter-incrementally で候補表示が二回行われている様に思われることについて。
      complete の直後では filter-incrementally はスキップされる筈なのだが何故だろう。
      調べてみた所、なんと候補一覧を表示した時の _ble_complete_menu_filter は make_c であった。
      これを実際にメニューを構築した時の入力内容を使う様に修正した。

      しかし、そうすると今度は曖昧補完で確定が進んだ時に着色が起こらない様である。
      →これは単に曖昧補完であったとしても COMPV から insert 評価値に変更するだけで良かった。
        また改めて確認してみた所 construct-single-entry においては、
        曖昧補完かどうかに拘らず menu_common_part が接頭一致したら強調する様になっていたので、
        特にこれに対して修正する必要はなかった。

    実はこの修正により menu/initialize という関数の意味がなくなった。
    (更に言うとそもそも一箇所からしか呼び出されていないのであった。)
    削除する事にした。

2018-09-08

  * edit: コマンド exit を上書き。ジョブが残っている場合はユーザに尋ねる [#D0789]
    cf https://github.com/akinomyoga/ble.sh/issues/8

    →サブシェルで exit を実行しても確認が走ってしまう。これはチェックを入れる。

  * syntax (bug): Bash-4.1 以下で関数定義の構文解析ができない [#D0788]
    ble_debug で調べると途中で CTX_UNSPECIFIED になっている。
    nest を閉じることができなくて全体がエラーになっている。

    | bash-4.2$ f1() { echo hello; }
    | _ble_syntax_attr/tree/nest/stat?
    |  2 aw   000 'f' |  stat=(CTX_CMDX w=- n=- t=-:-)
    |  | aw   001 '1' +  word=ATTR_FUNCDEF:0-2
    | 12 a    002 '('
    |  | a    003 ')'
    | 26 a    004 ' '    stat=(CTX_CMDXC w=- n=- t=$2:-)
    | 18 a    005 '{' ++ word=CTX_CMDI:@1>5-6>@5 word="none":5-6 nest=(CTX_CMDI w=CTX_CMDXC:5- n=- t=-:$2) stat=(CTX_CMDXC w=- n=- t=$2:-)
    | 17*a    006 ' '    stat=(CTX_CMDX1 w=- n=- t=$6:-)
    |  2*aw   007 'e' |  stat=(CTX_CMDX1 w=- n=- t=$6:-)
    |  |*aw   008 'c' |
    |  |*aw   009 'h' |
    |  |*aw   010 'o' +  word=CTX_CMDI:@5>7-11
    |  3*a    011 ' '
    |  4*a    012 'h' |  stat=(CTX_ARGX w=- n=- t=$11:-)
    |  |*a    013 'e' |
    |  |*a    014 'l' |
    |  |*a    015 'l' |
    |  |*a    016 'o' +  word=CTX_ARGI:@10>12-17
    | 12*a    017 ';'    stat=(CTX_ARGX w=- n=- t=$17:-)
    |  1*a    018 ' '    stat=(CTX_CMDX w=- n=- t=$17:-)
    | 19*a    019 '}' +  word=CTX_CMDI:@16>19-20 stat=(CTX_CMDX w=- n=- t=$17:-)
    |  |    s 020 ^@    stat=(CTX_CMDXE w=- n=- t=$20:-)
    |
    |
    | bash-4.1$ f1() { echo hello; }
    | _ble_syntax_attr/tree/nest/stat?
    |  2 aw   000 'f' | stat=(CTX_CMDX w=- n=- t=-:-)
    |  | aw   001 '1' + word=ATTR_FUNCDEF:0-2
    | 12 a    002 '('
    |  | a    003 ')'
    | 26 a    004 ' '   stat=(CTX_CMDXC w=- n=- t=$2:-)
    |  6 a    005 '{' + word="none":5-6 nest=(CTX_UNSPECIFIED w=CTX_CMDXC:5- n=- t=-:$2) stat=(CTX_CMDXC w=- n=- t=$2:-)
    |  |*a    006 ' '   stat=(CTX_UNSPECIFIED w=CTX_CMDXC:5- n=- t=$6:$2)
    |  |*a    007 'e'
    |  |*a    008 'c'
    |  |*a    009 'h'
    |  |*a    010 'o'
    |  |*a    011 ' '
    |  |*a    012 'h'
    |  |*a    013 'e'
    |  |*a    014 'l'
    |  |*a    015 'l'
    |  |*a    016 'o'
    |  |*a    017 ';'
    |  |*a    018 ' '
    |  |*a    019 '}'
    |  |    s 020 ^@   stat=(CTX_UNSPECIFIED w=CTX_CMDXC:5- n=- t=$6:$2)

    core-syntax.sh を 40100 または 40200 で探してみても関係ありそうな分岐をしている箇所はない。
    一つずつ見ていく事にする。直前の文脈は CTX_CMDXC である。これの処理は
    ble-syntax:bash/ctx-command で行っている。.check-word-begin までは問題ないようだ。
    取り敢えず現在の ctx である CTX_CMDXC を wtype に設定して単語が始まる。
    次の check-variable-assingment は CTX_CMDXC ではスキップされる筈である。
    ${_ble_syntax_bash_chars[CTX_ARGI]} の内容にも違いは見られない。
    うーん。どうやらブレース展開に入りかけてすぐ出るというのが正しい動作だが、

    そのブレース展開に入る nest で失敗している様子である。
    ブレース展開に入る所を調べる。nest の前後を見ると、何と push 直前の ctx が 0 になっている。
    ctx を最後に書き換えているのは同じく check-brace-expansion の中の真ん中あたりにある。
    _ble_syntax_bash_command_IsAssign という配列を参照している箇所である。
    _ble_syntax_bash_command_IsAssign の中身を確認してみたが何も変化はない。
    ctx は 2 → 0 に変化してしまっているがそもそも _ble_syntax_bash_command_IsAssign には 2 は登録されていない。

    これは bash 算術式のバグだろうか。
    何とこれは既知のバグであった。このバグの存在を忘れていた。
    最近書いたコードにもこういう物が含まれている可能性はある。
    他にも似たような物がないか core-syntax.sh の内部は調べた。一箇所直した。
    vi.sh と ble-edit.sh の中も調べたが特に怪しいものはない。
    ble-canvas.sh と ble-color.sh の中も調べた。ble-decode.sh の中も調べた。

2018-09-07

  * 2015-12-12 IGNOREEOF に対応 (現在 bash-4.0 未満では勝手な値を設定しているので [#D0787]
    cf https://github.com/akinomyoga/ble.sh/issues/8
    これはコマンド実行の瞬間だけに復元する様にする必要がある。
    PS1 と同様の取り扱いで良いと思われる。)

  * edit (request from cmplstofB): ジョブがある時の終了コマンド (C-d) [#D0786]
    cf https://github.com/akinomyoga/ble.sh/issues/8
    bleopt allow_exit_with_jobs=1 として対応した。

  * complete: CentOS 7 で LC_ALL=C.UTF-8 に対してエラーが出る [#D0785]

  * complete: 起動時に暫くとまる [#D0784]

    調べると auto-complete.idle が止めている。
    更に入っていくと ble-edit/isearch/backward-search-history-blockwise が止めている。
    ちゃんと stop_check は設定されているのでユーザから入力されれば止まるはずだ。
    と思ったら、それ以前の段階で履歴がロードされるのを待っていたのだった…。

    履歴がロードされるまでは history heavy は呼び出さない様にする事にした。

  * complete (reported by cmplstofB): failglob の時、コマンドの補完候補に * が含まれてしまう [#D0783]
    https://github.com/akinomyoga/ble.sh/issues/7

  * ble/util/assign 入れ子対策? [#D0782]

2018-09-07

  * complete (reported by cmplstofB): workaround: プログラム補完関数が failglob を踏むとシェルが終了する [#D0781]
    https://github.com/akinomyoga/ble.sh/issues/6 修正した。

2018-09-05

  * auto-complete: 実は元から灰色の文字がデフォルトのターミナルが存在する [#D0780]

  * color (reported by cmplstofB): ble-color-setface がエラーを起こす [#D0779]
    https://github.com/akinomyoga/ble.sh/issues/6

    調べた所 ble-color-defface / ble-color-setface の順序が効いている。
    恐らく defface 自体を遅延させている為に、順序が入れ替わって、
    結局 ble-color-defface / ble-color-setface の評価順を逆転した意味がなくなっていた。

    確認の為に、defface 及び setface を出力してみることにする。
    やはり順序が反転している。_ble_color_complete_{defface,setface}_hook の2種類を作る事にした。
    これで大丈夫のはず。

  * mwg_pp.awk: PHONY targets for dependencies [#D0778]
    調べたら既にその機能はついていた。単に Makefile に書き忘れていただけである。

  * complete (progcomp): 実は simple-word/eval は eval "set_return $1" で行けるのでは [#D0777]
    しかし本当に複数単語に展開してしまうと大量の単語が現れた時に処理が遅くなる。
    やはり現状の様に最初の単語だけ取得するというので良い気がする。
    何れにしても、現状の実装でも結局配列に全要素を入れているので大差はないかもしれないが。

    現在の実装が =~... になっているのには理由があったのだろうか。
    ログを漁ってみたが特に記録はされていない。

  * complete: bug: 自動補完が起動しなくなっている [#D0776]
    これは宣言していない変数 ext を参照しているのが問題であった。

  * complete: bug: 曖昧補完で補完を実行しようとすると入力した物が削除されて空になる [#D0775]
    →これは determine-common-prefix で local ret を宣言していたのがいけなかった。直した。

  * complete: ブレース展開の中での補完 [#D0774]

    * done: 先ず初めにブレース展開を解析するコードが必要である。

      | 更にブレース展開以前を書き換えるといけないので、
      | "書き換えてはならない範囲" というのを complete 側に実装する必要もある。
      | 自動補完でもそれを考慮に入れなければならない。
      | 直前のパラメータ展開はブレース展開より後にあると保証できるので大丈夫。
      |
      | 後、ブレース展開の中では nest に入っているので、
      | 元の単語を抽出するにはブレース展開を抜ける必要がある。
      | 然し、どうせ nest に入っている構造を遡るのだから、
      |
      |   その際に一緒にブレース展開の最初の候補を抽出してはどうか
      |   …と考えたが問題が幾つかある。
      |   先ず初めに現在の枠組みでは初めに補完文脈を生成してから
      |   それを補完器に渡している。補完文脈には開始点と種類の情報しかない。
      |   オプションとして何か指定できるように拡張するとしても面倒である。
      |   更に、将来的にはユーザによる補完の起動なども実装したい。
      |   やはりその際には開始点と種類だけから起動できる様になっているのが望ましい。
      |   その様に考えると、やはり別々にブレース展開を解析する方が良いと判断する。
      |
      | * ブレース展開の解析は simple-word と似た様な形で、
      |   しかし、{,} を特別に処理してやれば良い。
      |   rex_letter を {,} とそれ以外に分割して、
      |   extract-parameter-expansion と同様に処理すれば良い。
      |   実装したが動作テストはしていない。
      |
      | * ブレース展開に符号を入れられるという事が分かったので対応した。

      ブレース展開と引用符を閉じる関数を作った。
      更に、ブレース展開を実行した時の最後の単語を取得し、
      ブレース展開の構造を壊さないで変更できる word の最初の位置として simple_ibrace を返す様にした。
      閉じた引用符の種類は今までの close_type の代わりに simple_flags という変数を用いて返す。

    * done: 次に、simple_ibrace を用いて、変更してはならない範囲を保持したまま置換が行われる様に変更する。
      その為には reconstruct-incomplete-word (旧 close-open-word) を呼び出している箇所で一つずつ問題がないか確認する。

      1 ble-complete/source:argument/.progcomp-helper-vars
        これはプログラム補完から見える単語を復元する為に使用する。
        一番最後の単語だけここで取得される事になるが、まあ、今までと大差ないだろう。
        (今まではブレース展開が処理されないままにプログラム補完に渡されていたと思う)

        もし気になるようであればプログラム補完に渡す時には複数単語にちゃんと展開するという可能性もある。

        …今気づいたのだが、実は eval は eval "myfunc $1" で行けるのではないか…。→ #D0777
        もしそうだとすれば simple_flags を見ればブレース展開による全ての単語を取得する事もできる。

        % と思ったが、うーん。単に eval を実行するとパス名展開まで実行されてしまう。noglob で評価するべきか。
        % 改めて考えてみると実は現段階で既にパス名展開は実行している (最初の単語を選択している)。
        % そう考えるとやはりパス名展開まで実行しても誤りではないのではないか。
        %
        % 所で、よく考えてみると文脈によって展開のされ方は違う筈である。
        % 例えば変数代入の場合にはパス名展開は実施されない。ブレース展開も実施されない。
        % と思ったが、特にこの関数で呼び出しているのは引数の場合だけだから、
        % やはりパス名展開は実行されてよいのである。

        パス名展開は寧ろされている方が自然である。

      2 ble-complete/candidates/.pick-nearest-context
        次は候補の生成部分である。ここでは取り敢えず simple_ibrace を comps_ibrace としてそのまま返す。
        呼び出し元は ble-complete/candidates/generate である。

        % 未だ此処では個々の候補は生成していないので comps_ibrace によるフィルタリングはできない。
        % と思ったが、よく見たらフィルタリングをしているのはこの箇所だった。

        しかし実は comps_rex_ambiguous はこの時点で設定できる…

        うーん。フィルタリングをしようと思ったが、実は ibrace だけだと不都合である。
        というのも ${word::ibrace} の評価結果を使わないと評価結果によるフィルタリングはできないが、
        ${word::ibrace} の評価結果を得る為には結局またブレース展開を閉じるなどの処置が必要になる。
        同じ処理を繰り返し実行する事になってしまって効率が悪いので、ibrace の他にも情報を返したい。
        実は、単に ibrace と一緒に reconstruct-incomplete-word の戻り値の中での index も返せば良いのでは。

        ? reject: 曖昧一致は ibrace>0 で禁止するという手もあるのだろうか。
          しかし、うーん。やはりブレース展開よりも後の場所で曖昧一致させられる方が自然である。

      3 ble-complete/candidates/determine-common-prefix
        ここは common part が曖昧一致するかどうかっを調べている。
        comps_ibrace が設定されている場合には、
        既にここに入る時点で候補は全て comps_fixed_part を保存する様になっている筈なので、
        曖昧一致だけ確かめれば、ちゃんと comps_fixed_part は保持したままになっている筈である。
        ここは気にしなくても良い。

      4 ble-complete/menu/initialize
        うーん。これは何だろう。
        これは ble-complete/menu/show の頭で呼び出されている関数である。
        他の場所からは呼び出されていない。menu_common_part を初期化するのに使っている。
        これはまあ、問題ないだろう。単に太字にするだけなのである。

        ambiguous の場合にはまた曖昧一致部分がちゃんと fixed_part になる様に調整が必要であるが、
        現状では ambiguous の場合に入力部分を太字にするのには未対応である。
        ambiguous で対応する場合に注意する様にすれば良い。

      5 ble-complete/menu/filter-incrementally
        うーん。まあ、これは絞り込みをかけているだけだから問題ない気がする、
        と思ったが {aaa,bb の状態で補完候補を出して、その後で {aaa,bbb,b と入力した時に、
        そのまま候補一覧を表示したままにしておくとメニュー補完において {aaa,bbb,
        の部分を置き換えて bbb, が失われてしまう。従って、
        ibrace が元々の ibrace から移動した場合には候補一覧をキャンセルするなどの対処が必要である。

        これは実は get-active-range の中で判定するべきことなのかもしれない。

      6 ble/widget/auto_complete/self-insert
        self-insert で {,} の何れかの文字を挿入する時、
        特に曖昧一致や前方に置換がある時については、
        ブレース展開の状況が変わるかもしれないので、auto_complete をクリアする。
        一方で、_ble_complete_ac_type が [ch] の時は、
        {,} が入力されてもブレース展開の状況は変わらないか、
        或いはそれも見越して一致する場合にしか auto_comoplete 内での self-insert は怒らないので、
        現状のままの実装で問題ない。

    * done: menu-complete の時にブレース展開の構造の部分まで反転して置換対象であるかの様に表示されるのは妙である。
      従って、_ble_edit_mark を移動したいところだが、他の場所に影響は出ないだろうか。
      特に _ble_edit_mark を参照して処理をしていたりしないだろうか。

      ble-complete/menu-complete/select と menu_complete/accept で参照している。
      menu-complete に於いて _ble_edit_mark を設定しているのは menu/enter のみである。
      ここでは _ble_complete_menu_beg の値がそのまま beg に入り、それから _ble_edit_mark に入っている。
      従って、上記で _ble_edit_mark を参照している所は実は _ble_complete_menu_beg に置き換えれば良い。

    * done: 実際に動かしてみるとどうも変な振る舞いをする。
      例えば echo {a,m} に対して m が挿入される。
      と思ったら、実は completion-context で変な物が生成されている気がする。

      調べてみると check-here による補完文脈が生成されていて、
      しかしその後の progcomp での単語切り出して m が既に入力されている者とされ、
      結果として m が候補として生成される。ところが check-here なので m が重複して挿入される。

      実は progcomp 側でも check-here などで生成された場合に対する対策として、
      補完開始点で無理矢理単語を分割するべきなのではないか、とも思う。→ #D0793

    * done: {,} もエスケープするべきなのではないか。今確認した所、{} はエスケープしている。
      , はエスケープしていない。ブレース展開がある場合には , もエスケープする。
      それ以外の場合には特に , はエスケープしない、という方針で良い気がする。

2018-09-03

  * 2017-11-26 complete: 変数代入の時は右辺でファイル名補完をするが、 [#D0773]
    実は arr[$(...)]= の様な複雑な場合に右辺を正しく切り出せていない。

    2018-08-26 この時直前の stat に記録される文脈は、
    arr[...@]= の位置にある CTX_EXPR である。
    これは CTX_EXPR 側で対処するべき事の気がする。
    例えば tail == ']=' かつ、nest type が a[ の時に、
    変数の右辺の補完を開始する。

    実際に実装してみたが微妙である。
    arr[@] (@: stat の位置) に対しては = を挿入させる事はできる。
    arr[@]= に対してはファイル名補完を開始させる事はできる。
    arr[1]=@hello に対しては正しくファイル名補完を起動する事ができない。
    この時 @ に設置されるのは VRHS であるが、一番最初の VRHS を検出する手段がないからである。
    更に、arr[1]+ に於いて arr[1]+= としたいが、
    実際には、arr[1]@+ で @ に stat が設置され文脈は CTX_VRHS となっている。

    要するに、問題は CTX_VRHS において右辺の開始位置を検出する事ができないという事である。
    ところで、CTX_ARGI などの場合には word の始まりが単語の始まりという事で判定できた。
    CTX_VRHS は単語の始まりは変数名の始まりという事が難しい。
    arr[]=... の形式の場合には [] の部分を読み飛ばして開始点を決定する事ができれば良い。

    * done: うーん。解析の構造を見ると、先ず初めに単語の先頭以降にある最初の nest (1) を探す。
      更に、それ以降の stat を調べて最初に nlen が (1) より前 (もしくは -1) を指す様になった所が、
      最初の CTX_VRHS である。もしくは、最後の nlen が (1) 以降を指す stat が閉じる ] の直前になる。

    * done: a[1]+ の状態ではどうなっているか。うーん。+ の直前に VRHS が設置される。
      やはり最後の "nlen が (1) 以降を指す stat" から "]" の後に何があるかで判定する方が良い。

    * done: a=([1]=a の場合には CTX_VRHS の代わりに CTX_VALR である。
      これについては rex='^(\[)'; [[ $word =~ $rex ]] の時だけ

  * 2017-03-01 complete: "function fun [" で補完を実行すると '[[' ではなくて '[\[' になってしまう [#D0772]
    これを解決するためには complete.sh の source の wordlist で、
    エスケープをオフにするオプションを用意する必要がある。

    ble-complete/action/plain/initialize で行われている escape-specialchars が原因だ。
    action として word を使用している為にそのままその機能を継承している様だ。
    新しい専用の action を定義するか或いは wordlist にオプションを指定できる様にするかすると良い。

  * complete: bug, 一意確定した直後に更に新しい補完を始めようとすると menu-complete が始まる [#D0771]

2018-09-02

  * 2018-07-28 complete 再考 [#D0770]

    元々の問題提起は以下から。

    | * 2016-07-15 complete: そもそも現在の実装は妥当なのだろうか。
    |   全ての候補に一つずつ候補の文字列・挿入文字列・説明 etc を計算して登録しているが、
    |   これらは最低限の情報に留めておき表示する必要が生じた時に改めて計算すればよいだけなのではないか。
    |   つまり、source 番号と一緒に登録しておけば全部計算できるような気がする。
    |
    |   一つ気になるのが INSERT を事前に計算しておく必要があるのかどうかと言う事である。
    |   現状の実装では共通一致部分を算出するのに INSERT を使用している。
    |   - source の種類によって一致対象の文字列が同じでもエスケープの仕方が異なる事が考えられ、
    |     その場合にはエスケープも含めて共通一致部分までしか確定できないはずだからである。
    |     例えば変数名 $variable 及びファイル名 variable の両方に一致して $var まで入力しかけた時、
    |     一致候補の文字列が同じ variable であっても前者による補完は $variable だし、
    |     後者による補完は $var\variable になる筈である。
    |   しかし、この措置によって処理が複雑化している気がする。
    |   その様な状況が本当に発生するのかどうかも含めて再度考え直しても良いのではないか。
    |   例えば上記の例で言えば、実際には $variable の補完の方が優先される。
    |   その点から始まる補完 (ファイル名 variable) は他に候補がない場合に限られるからである。

    完全に再実装するのは二度手間なので、現状の実装を改善する方向で行く。
    途中で必要があれば需要に応じて構造を変更する事にする。
    →結局 complete の構造は元々の構造を保持したまま発展させたので
    大きく再設計するという事はなかった。この項目はそのままログに送る。

    * その為には現在の実装がどの様な構造になっているかについて調べる必要がある。

      1. source 一覧生成
        先ず初めに ble-syntax/completion-context を呼び出して
        補完開始点と使用する補完生成器の一覧を生成する。

      2. 候補生成
        次に各 source に対して候補を生成する。
        各 source は ble-complete/source/NAME 関数として実装され、
        COMP1 COMP2 COMPS COMPV を受け取る。
        生成する候補は生成時点で既に escape などの処理を終わらせる。

      3. 候補の絞り込みを行う
        結局現在の実装では一番近い開始点からのものしか用いていない。
        また、その様にしないと候補表示が分かりにくいというのもある。
        ここは、一番近い開始点からの補完しか行わないと仮定して良いのではないか。
        その様にすれば処理も幾分楽になる。

        もし後々になって複数開始点からの補完をしたくなったら、
        その時になってから考える事にすれば良い。

      4. 確定の場合には続きを入力する為に、
        補完文字列に対応して、末尾に / または ' ' を追記する。

      5. 置換を実施する。

    * ok: 候補の表現は適切か。

      | 現在の所、生成した候補は以下の配列に格納される。
      | 複数の配列に格納するのは候補数が沢山ある場合に効率が悪くなるので統合したい。
      |
      | cand_cand[icand]="$CAND"                  # 候補名文字列 (直接)
      | cand_prop[icand]="$ACTION $COMP1 $COMP2"  # 置換操作と範囲
      | cand_word[icand]="$INSERT"                # 挿入文字列 (escaped)
      | cand_show[icand]="$SHOW"                  # 表示文字列
      | cand_data[icand]="$DATA"                  # 現在使用されていない
      |
      | - 先ず初めに COMP1-COMP2 は共通である。
      |   もしくは source 毎に確定である。
      |   なので、これは source 名などに置き換える事ができる筈である。
      | - DATA に関しては現在は使われていない様である。
      | - INSERT は共通部分の一致を試す為に結局使用するので、
      |   候補生成時点で出力して良い。
      |   また、source しか知りえない方法で escape したいという事もあるかもしれない。
      |   と思ったが、fignore などを考えるとやはり後で escape を実施しても良いのかもしれない。
      |
      | - SHOW は結局現状の実装では CAND に等価である。
      |   将来的に syntax highlight 等も非同期で行う様になると SHOW は使用する事になるかもしれない。
      |   何れにしてもこれは遅延で計算すれば良い事の様に思われる。source は遅延に対応する。
      |   特に source が返還を貞経しなければ CAND をそのまま表示すれば良い。
      | - または表示時の文字列に限らず、例えば候補の説明を表示するという事も考えられるが、
      |   それらについても遅延で計算すれば良い。
      |
      | 或いは別の案として以下の様な記録方法を取るという事も考えられるが…。
      |
      |   cand_cand[i]="$ACTION:${#CAND}:${#INSERT}:${#SHOW} $CAND$INSERT$SHOW$DATA"
      |
      | やはり処理が複雑になる為にそんなに速くなさそうである。
      | これは具体的に実測する等して比較するしかない。

      紆余曲折を経て現在では cand_cand, cand_word, cand_pack の三つの配列で取り扱っている。
      速度的には問題があるかもしれないが現在のところはこれが現実的である様に思われる。

    * ok: escape の処理を何処で行うか [→現状の儘で良い]

      これは枠組みとして考えれば候補生成とは別に行うという事も考えられる。
      しかし、落ち着いて考えれば文法要素も含めて補完を実施したい時もあるだろうから、
      外側で一律に escape をするという仕組みになっていると都合が悪い。
      候補生成側で直接 escape した物を生成することにして、
      適宜こちらで用意した escape 関数を呼び出してもらうか、
      或いは、候補生成時に escape の種類についての値も出力とするという手がある。
      これは現状通りにこちらで用意した escape 関数を呼び出してもらう事にするのが良さそうだ。

      特殊な escape をしたい場合などには各 source で個別に適切な関数を呼び出す様にする。

    以下については既に対応されていた。

    | * 2017-03-01 complete: 既に入力された部分を修正する様な形での補完があっても良いのではないだろうか。

  * auto-complete: 入力している時に時々固まる。history auto-complete が怪しい [#D0769]
    本当に history auto-complete が原因なのかは未だ確認していない。
    後で調べる事にする。
    →これは単に ble-edit/isearch/.read-search-options のミスだった。
    結果を返す為の変数を local にしていた所為で stop_check 等が無効になっていた。

  * 2018-08-29 complete: "$hello" などでも補完できる様にする [#D0768]

    これは simple-word の拡張が必要になる。
    また simple-word を使用している各箇所の動作についても確認する必要がある。

    - simple-word の拡張自体はそんなに難しくなさそうだ。
      然し、これを使っている場所で不都合が起こっては困る。
      使っている箇所について調べる事にする。

      | - ble-edit.sh command-help でコマンド名を抽出するのに使っている。
      |   直後に command=$literal を用いて展開を実行しているから、
      |   これは "$hello" の様な物があったとしても問題ない。
      |   一方で、直接 command=$literal の様な事をしても問題ないのだろうか…。
      |
      |   調べてみるとコマンド名であってもパス名展開は有効だし、
      |   また、パラメータ展開の変数名とローカル変数の変数名が被る可能性もある。
      |   従って、eval を用いて評価したほうが良い。
      |
      | - core-syntax.sh: ble-syntax/completion-context/.check-prefix/ctx:next-command
      |   ここで is-simple を使っている。これはコマンド名として補完の対象となりうるかを判定する為に使っている。
      |   所で、ここは is-simple で良いのか…確認してみると next-argument の方では
      |   is-simple-or-open-simple を使っている。ここは修正する事にした。
      | - core-syntax.sh: ble-syntax/completion-context/.check-prefix/ctx:redirection
      | - core-syntax.sh: ble-syntax/completion-context/.check-prefix/ctx:rhs
      |   ここでも is-simple を使っていたが、is-simple-or-open-simple に書き換えた。
      | - core-syntax.sh: ble-syntax/completion-context/.check-prefix/ctx:next-argument
      | - core-syntax.sh: ble-syntax/completion-context/.check-prefix/ctx:quote/.check-container-word
      |   これらは is-simple-or-open-simple を使っているが "$hello" に対応しても問題はないだろう。
      |
      | - core-syntax.sh: ble-highlight-layer:syntax/word/.update-attributes/.proc
      |   これは is-simple のままで問題ない。着色なので閉じていない単語については処理しなくて良いので。
      |   また、"$hello" に対応しても大丈夫。
      |
      | - core-complete.sh: これは "$hello" に対応しても問題ない。
      |   特に全て close-open-type & eval を介しての使用である。

      特に使用箇所での使用方法に対して不都合が起こるという事はなさそうである。

    - done: simple-word/eval で変数名を抽出する時にちゃんと "$hello" も抽出する必要がある。
      特に ble-syntax:bash/simple-word/extract-parameter-names である。
      →対応した。動作確認した。is-simple も確認した。

    - パラメータ展開で終わっている時には挿入時に ${param} または $param\
      の様に書き換える必要がある。つまり、引用符の中でもこれを実行するという事。
      一方で ' や $' の中に現れるパラメーて展開と同様の文字列は、
      実際にはパラメータ展開ではないので書き換える必要はない。

    x hello=mem; echo "$hello@ に対して o が挿入される筈なのに動かない。
      menu 補完に入れば期待通りに動くが、通常の補完で "${hello}o までは入力できる筈である。
      調べてみると cand_word までは "${hello}o になっているが、

      % determine-common-prefix で何故か "$hello になっている。
      % 実装を調べると、これは ambiguous の時に起こる様である。
      % と思って調べたが特に ambiguous に誤ってなっているという事もない。

      改めて確認してみると ambiguous でない場合でも、
      遡って書き換わる時でかつ一意確定でない時には書き換えが起こらない様だ。
      元々この様にしていた理由は、遡って書き換わる事によって変な書換になって、
      続きの補完ができなくなってしまう事を懸念しての事だった。
      そうであるならば、共通部分が変な書き換え (non simple-word) になっていなければ大丈夫という事である。
      新しく simple-word かどうか判定して、simple-word の時は書き換えを実行する事にした。

  * complete: auto_complete keymap における M-f C-f 等の対応 [#D0767]

  * auto-complete: 履歴からの検索 [#D0766]

    [実装方法]

    | a 試してみると下手に tac 等を使うよりは以下の様に awk を使うのが速い。
    |   time HISTTIMEFORMAT= history | awk '/aaa/ {a=$1} END{print a;}'
    |   しかしそれでも 0.226s 程度かかっていて遅い。
    |   更に incremental に遡っていく度に同じ位時間がかかるという事である。
    |
    |   また、これだと文字を入力する度に他のプロセスを起動する事になるので避けたい。
    |
    | b これは bash 自身を使って遡るのとどちらが良いであろうか。
    |   bash 自身を使う場合は検索の途中状態を表示する事も可能である。
    |   しかし自動補完によって background で実行している物の経過を表示するのは正直うるさい。
    |
    |   問題は bash 自身を使って遡る時に結局一致が見つからない場合である。
    |   その場合にはさっさと局所的な補完が起動して欲しいが、
    |   bash 自身を使って遡るとすると大分待ってからでないと通常の補完に入らない。
    |
    | c 実は履歴展開を使って何とかならないだろうか。
    |   と思ったが、スペースなどが入った時にちゃんと検索してくれるのだろうか。
    |
    |   試しに history -p で試してみると ' ' が含まれていると、
    |   その直前までしか展開してくれない。
    |   スペースをクォートしたとしても '\' の1文字が検索対象として追加されるだけである。
    |   COMP_WORDBREAKS 的な設定も見つからない。
    |   試しに COMP_WORDBREAKS= history -p として見たがやはり影響は受けない。
    |
    | d 或いは bash 自身を使って遡るが遡る件数を制限する。
    |   既定で 1000 件にして、ユーザの設定で変更できる様にする。
    |   因みに bash の既定は 500 である。随分と小さい。
    |   検索すると CentOS は独自に上書きしていて 1000 だそうだ。
    |   他に 2000 にしている人と 10000 にしている人がいる。
    |
    | e 実は先に通常の補完候補で一旦自動補完してから、
    |   裏でゆっくり検索して見つかった時にすり変えれば良いのではないか。
    |   更に一つの単語で構成されている時には history -p '!string' を用いれば良い。
    |   複数の単語で構成されている時にも初めに最初の単語を使って
    |   history -p '!string' として存在が確認できる時にのみ実行すれば良い。

    e の方法で実装する事にする。

    [実装1: history -p による検索]

    具体的な実装に入る。
    履歴展開の !string の形式で string の終わりになる文字は何だろうか。
    調べてみると <>;&|$IFS() の様である。これは COMP_WORDBREAKS の既定値から "'= を覗いた物である。
    また ! の直後に来るとイベント支持子として解釈されて駄目な文字列というのも存在する様だ。

    先ず '!' 単体だと自分自身に展開されてしまう。
    少なくとも一文字はないと行けない。
    しかし、これは逆に !string の string が空の場合の振る舞いとして自然な気がする。
    また、コマンドの最初の文字が 0-9 の場合にも駄目。! # ? の場合も駄目。
    更に試してみると最初の文字が - の場合にも駄目である。

    実は !?...? の形式の場合には途中に ? が含まれていなければそれ以外の文字も含む形で検索する事ができる様だ。
    取り敢えず、history -p を使った高速な実装は終わった。動いている。

    しかし、やはり一致したりしなかったりするので微妙である。

    [実装2: 配列の探索]

    ちゃんとした検索を実装するには history-edit/isearch/search を拡張する必要がある。
    或いは正規表現を構築して ^ を付加して既存の regex で検索するという手もある。
    しかし、やはり速度を考えると glob で一致させる方が速いだろう。

    * しかし改めて考えてみると途中でファイル名に補完されたのに、
      その後で暫くしてよく分からない別の場所で実行されたかもしれないコマンドに置き換わるのも妙である。

    * C-r による検索で色々試すと、実はそんなに検索に時間はかからない様である。

    何れにしても取り敢えず実装してみる事にする。
    途中で中断したとしても検索状態を記録しておいてまた後で続きから検索できる様にすると良いだろう。

    実際に試してみると十分速い様に思われるので既定で先に history を見てから通常の自動補完を行う事にした。

2018-09-01

  * menu-complete: やはり重い気がする。表示までに時間がかかる [#D0765]
    後でどの部分が遅いか確認する。

    やはり ble/function#try ble-complete/menu/style:"$menu_style"/construct
    に 0.660 程度かかっている。

    x resolved: しかも計測してみて分かったが何故か無駄に2回も呼び出されている。
      自動補完では呼び出されていない。スタックを出力させてみた所、
      一回目は ble/widget/complete でありこれは想定していた物であるが、
      二回目は filter-incrementally だった。これは想定していない。
      一文字も入力していなければ最初に呼び出した時と結果は変わらないはずで、
      再度わざわざ実行する必要はないはずだ。
      filter-incrementally は以下のコマンドによって重複した計算を省略しているはずだが、

        [[ $input == "$_ble_complete_menu_filter" ]] && return 0

      どうやらこれが正しく動作していない。_ble_complete_menu_filter の初期値はどうなっていたか。
      うーん。調べてみると input には e が入っていて、_ble_complete_menu_filter には '' が入っている。
      つまり input は補完開始店から切り出していて、filter の初期値は新しく入力した文字列だと思っている。
      改めて _ble_complete_menu_filter の使い方について確認してみる。
      →_ble_complete_menu_filter の使用箇所を確認したら実はここだけだった。
      これは _ble_complete_menu_filter の初期値を COMP1-COMP2 の文字列にしたら直った。

    [計測]

    | さて、getg がどれだけ遅くしているのかを確認する。
    | getg を呼び出さない様に変更してみた所 0.533 になっている。
    | getg は実はそんなに時間を食っている訳ではない。
    | 今は特に重い getg (内部で ble/util/type を呼び出し) を使っていて、それでも 0.100s である。
    | 別の場所が遅いという事である。
    |
    | ble-color-g2sgr の呼び出しを削除してみた所 0.338 にまで減少した。
    | 先ずここがかなり食っているという事になる。0.200s である。
    | というか、ble-color-g2sgr はキャッシュしているのではなかったのか。
    |
    | ble-edit/info/.construct-text の代わりに
    | ble-edit/info/.put-simple "$((${#show}-alen))" "${show:alen}"
    | ble-edit/info/.put-nl-if-eol を使ってみたところ、
    | 0.090s 程度は高速化した。更に何もしないように変更すると 0.040 程度短くなった。
    | うーん。実は正規表現で print+ を呼び出すのは微妙に遅いという事なのかもしれないが、
    | しかしそれでもそんなに重い処理ということではない様だ。
    |
    | 一つ上の階層で、construct-single-entry 自体を空の物に置き換えるとどうなるか。
    | 調べてみると、0.097 にまで短くなった。つまり、construct-single-entry が悪いのである。
    | 改めて少しずつ調べる。unpack は 0.070s 程度はある様である。
    | 改めて各部分について再計測する。

    construct 0.650 の内訳           計測2
    - construct-single-entry  0.550s 0.389s 488
      - unpack                0.070s 0.040s  99
      - getg                  0.110s 0.119s 139
      - g2sgr                 0.210s 0.063s 258
      - construct-text        0.140s 0.142s 321
        - 正規表現 print+?    0.090s
        - 内容の構築          0.040s
      - 結果の処理            0.020s 0.025s 463
        Note: construct-single-entry がちゃんとした結果を返した時に、
        それを外部で処理する時に増える時間である。
    - 外側の処理

    [高速化]

    取り敢えず unpack がそんなに時間がかかるというのは問題なので確認する。
    将来的には全てのデータをこの unpack の方式に変更したいので、
    これについてちゃんとした速さを確認しておく必要がある。
    ble/string#split (空要素やglobに対する対策あり) の代わりに単純な配列代入に置き換えてみた所、
    0.030s 程度短縮した。つまり 0.040s ぐらいになったはずである。

    次に g2sgr について確認する事にする。
    upvar によって結果を返すのをやめてみたが 0.040s 程度しか短縮しない。
    キャッシュが働いていない可能性があると思ったがそうでもない。
    何故こんなにも遅いのだろうか。空の関数に差し替えてみると 0.050s 程度更に縮まった。
    つまり配列アクセスだけで 0.050s 程度も損しているという事になる。
    更に、未だ 0.110 程度の時間が残っている。おかしい。
    と思って、呼び出しを削除してみたら 0.030s 程度しか変化しない。
    先程の計測は誤りだったのだろうか。
    再度計測し直す事にする (計測2)。どうも upvar をやめただけで 0.140s 縮んでいる?
    0.040s しか縮まなかったというのは勘違いだったのであろう。

    全般に upvar は使わない様に書き換える事にした。書き換えた。

    しかし、依然として全般に遅い事は変わらない。print+ の高速化を試みる。
    うーん。難しい。まずは試しに正規表現一致を外で行う様にしてみたが 0.028s 縮んだだけだ (0.460)。
    正規表現の代わりに glob を使う様にしてみたが対して速度に変化はない (0.449s)。
    最初に予期しない文字が含まれていなければ簡単に処理する様にしてみたが、
    するとそれだけで 0.032s も早くなる (0.417s)。これで construct-text は最初の半分の時間になった。

    所で g2sgr の配列アクセスに時間がかかるのは気になるので、
    試しに _ble_color_g2sgr__table を local で宣言してみるとどうなるか確認する。
    →これは殆ど変わらない。寧ろ毎回 g2sgr を一回計算し直すので 0.005 程度遅くなる。

    うーん。g2sgr のキャッシュを先にみて関数呼び出しを省略したらそれだけで
    0.417 → 0.384 に早くなった。0.033s の高速化である。
    しかも、試してみた所、実は関数呼び出しを省略しなくても、
    キャッシュする関数と実際に計算を実行する関数を分けたら、
    それだけでも 0.018s の高速化になるという事が分かった。
    つまり、実際に実行する処理が同じでも実行する関数の長さに依存して
    関数呼び出しの実行時間が変化するという事だろうか。

    更に g2sgr 周りの呼び出し方を変えたら早くなるかと思ったら遅くなった (0.382 → 0.386) ので戻す。
    何か計測方法に不備があった可能性もあるが、何れにしても殆ど変わらない。元のままで良い。

    次に getg について。特に変数名の列挙の時に時間がかかっている。
    ble-color-face2g syntax_varname を毎回呼び出すのをやめたらどうだろうか。
    0.709 → 0.694 に減少した。大した変化ではない。
    また、変数名を勝手にキャッシュするのではなくて、
    ble-color-face2g で使っている変数を参照する様に変更した所、0.696 になった。
    殆ど変わらないが、着色をユーザが変更した時に追跡できるようにする事を考えると、
    その配列を参照するのが良い。しかし、何れにしても微妙な違いしか無いという事が分かったので、
    これについては元の通り ble-color-face2g を呼び出す様にする方が良い。

    うーん。これ以上は微妙。改めて試してみると古い実装は高速だった。
    或いは、一定以上の項目数の場合には awk 等を使った高速な実装に切り替えるという事も必要なのかもしれない。
    それはまた問題になってから考える事にすれば良い。

  * complete: / を含む関数名の補完で途中でメニュー補完が起動してしまう [#D0764]
    新しく挿入文字列が合った場合にはメニュー補完は起動するべきではないのではないか?
    と思ったが、今回の問題はそうではないようだ。挿入できる時でも挿入する前にメニュー補完に入っている。

    何故メニュー補完が開始してしまうのかと言うと、
    連続で二回同じコマンドが呼び出されるという場合に該当するからである。
    関数名の補完の場合は / の区切り毎に補完を実施することにしているが、
    連続で二回同じ補完コマンドを呼び出した時にメニュー補完に入るのは、
    一回の補完で必ず挿入できるところまで全て挿入するという前提があるからである。

    その前提が必ずしも成立しないとすると、どの様にメニュー補完に入るのを判定したら良いだろう。
    或いは、既に表示した時点で新しく…うーん

  * ble/util/assign: 第2引数をコマンドとして第3引数以降を引数にしたら良いのではないか [#D0763]
    現在の実装では第2引数以降を全て eval に渡しているが、
    現状使用されている箇所を確認すると全て第2引数にしか指定していない。
    寧ろ、パラメータを渡す為にわざわざ一時変数を介するなど面倒な箇所 (ble/util/type) がある。
    パラメータを渡す事ができる様にする事は便利であるはずなのでその様に実装を変更すると良い。

    よく見たら term.sh の中で呼び出している ble/util/assign はおかしい。直した。
    また第2引数(コマンド)がクォートされていないものは全てクォートする事にした。
    ble/util/assign 及び ble/util/assign-array の両方を $2 のみ評価する様に修正した。
    ble/util/type の実装はこの新しい機能を使うものに切り替えた。問題なく動いている様だ。

  * 2018-08-26 complete: 候補一覧でコマンド・ディレクトリ名や変数名の着色 [#D0762]

    対応してみたが何故かキーワードが赤く着色されてしまう。何故か。
    確認してみた所、ble-syntax/highlight/cmdtype はキーワードに対しては呼び出さないので、
    もし仮に keyword が返された時には、ジョブ名かその他の特別な状況である。

    仕方がないので ble-syntax/highlight/cmdtype1 を直接呼び出してみる事にする。
    そもそもメニューの表示においては同じコマンド名が複数現れるとは考えにくいので、
    余りキャッシュの効果もないだろうと予想する。

    因みに type -t commands... で一括で結果を取得するという事も考えたが、
    どうやら type -t commands... だとエラーのあるコマンドについては何も出力しないので、
    結局どの行がどのコマンドに対応するのかが分からない。
    一番最初に生成される候補の時点でちゃんと全て存在する物であるならば問題はない。
    一方で type commands... だと関数定義まで出力してしまうし、
    type -p commands... だとファイルとしてのコマンドについてしか出力を行わない。

2018-08-31

  * complete: vi_cmap での自動補完・絞り込みなどはどうなっているのか [#D0761]

    そもそも補完は定義されていただろうか。
    確認してみると vi_cmap ではそもそも補完は bind されていなかった。
    しかしコマンドを入力する場合などを考えると補完があった方が便利である。

    コマンド以外の物を入力する場合でも、
    文脈値に対応していなければそもそも補完文脈が生成されないだけなので、
    特に問題は起こらない様に思われる。

    そもそも現状では TAB を入力すると何が起こるのか?
    →TAB が入力されるという事はなくて C-i になるので unbound keyseq になる。

    単に有効にしてみると何が起こるか。
    →(恐らく) check-here でファイル名による補完が起動する。
    →もう一つの問題は 入力欄を panel 2 に表示している為に、
      候補一覧が表示・非表示される度に表示位置が変更されて見にくいという事である。

    実際に補完文脈を生成している部分を観察してみたが、
    "認識できない文脈の時に file を文脈として生成する" 等の機能はない様に見える。
    うーん。調べると確かに argument が生成されている。更に variable 等も生成されている。
    % .check-here で生成される事があれば、.check-prefix で生成される事もある。
    % →確認したら .check-prefix で生成されていたのは普通の文脈に戻った時だけだった。
    .check-here で argument が文脈として生成されている。
    ctx を確認してみると 0 (CTX_UNSPECIFIED) である。
    文脈値が重複している物がないか確認したがない。
    という事はどれかの文脈値の名前を間違えているか?
    分かった CTX_FARGX3 と書くべき所が FARGX3 になっていた。直した。

  * vi: !! をキャンセルしても _ble_edit_mark_active が元に戻らない [#D0760]
    これは最初単に _ble_edit_mark_active= を設定する位置の問題かと思ったがそうではなかった。
    元々のコマンドラインの内容に対して着色を行っているのであるから、
    vi_cmap を抜けた時の自動的な復元の対象とはならない。
    vi_cmap に _ble_keymap_vi_cmap_cancel_hook 変数を追加する事にした。
    修正した。ちゃんと元に戻る事を確認した。

  * decode: xterm で modifyOtherKeys とすると C-back で DEL を送り back で BS を送る [#D0759]
    試してみると modifyOtherKeys に関係なくその動作の様である。
    これらの端末ごとの動作に関しては何処かにまとめて置くと良いだろう。
    #M0010 にまとめる事にした。

2018-08-30

  * decode: xterm で _ を入力しようとすると S-_ がありませんと言われる [#D0758]
    現在はアルファベットしか処理していないが、
    実はキーボートに表示される可能性のある全てのキーについて S- は処理するべきなのでは。
    更によく考えるとヨーロッパの国では変な文字がキーボードに表示されている事もある。
    その様な状況を考えれば S-通常文字 については常に S- は外すべきなのではないだろうか。

  * menu-complete: vi マクロ・繰り返しにおける対応 [#D0757]

    % これは対応し始めると大変な気がするので
    % menu-complete が実行された場合には imap-repeat は無効化する事にする。

    と思ったが選択過程は無視してどう置換されたかだけで記録すれば良い様な気もする。
    置換に失敗した時にそのまま処理を続行しても良いのかどうかは謎であるが、
    少なくとも現在の complete の実装はその様になっている。

    これは ble/widget/menu_complete/accept において、
    一旦内容を元の状態に戻して、それから ble-complete/insert
    を用いて展開すれば良い様な気がする。
    序に menu_complete/accept に於いて action/complete も調整する事にした。
    但し insert の書き換えには対応していない。

    テストする。imap-repeat も . も動いている様に思う。

    * ok: マクロに関してはどうしようもない。

      % tab 等による選択もマクロとして記録されてしまうが、
      % それをそのまま再生した時に本当にちゃんとできるのかは謎である。
      % だからと言って別の操作を勝手に実現する様にするのも変である。
      % というかマクロはキーシーケンスとして記録されるのだから、
      % 何れにしても変更の余地はない。
      %
      % そもそも auto-complete の時に特別な処置が必要だったのは、
      % auto-complete が実際のキー操作を伴わずに勝手に起動して、
      % その後のユーザ操作の結果に影響を与えるからであった。
      % menu-complete に関してはユーザの操作で閉じている。
      % menu-filter に関しては基本的には表示情報が更新されるだけで、
      % ユーザ操作の編集結果に対する影響はないので特に考えなくても良さそうである。

      マクロに関しては特別に対応する必要はない

    * done: 実は action:action/complete は以下の変数を提供する事になっている

        COMP1 COMP2 COMPS COMPV comp_type comps_flags

      これらは別の変数に記録しておく必要がある。
      更に insert 自体の書き換えが起こる可能性もあるし、
      insert_flags の書き換えも起こりうる。
      何れにも一応対応した。

    x fixed: bug そもそも complete 自体が正しく動いていない気がする
      どの様に記録されているかを確認する必要がある。

      - done: insert.hook を調べてみた所、そもそも実際に挿入が行われていないのに
        insert.hook が呼び出されている。スキップするべきなのではないか→修正した。

      分かった事は auto_complete で self-insert を取っているので、
      その間に入力された内容が記録されていないという事であった。

      a うーん。auto_complete self-insert から vi_imap に push するのは変だ。
      b __before_widget__ を呼び出すのも変な事が起こりそうだ。
      c 新しい hook を定義する程でもない様な気がする。
      d そうすると insert_hook を流用して通知する事になるだろうか。

      取り敢えず d の方針で実装する事にする。
      修正した。これで取り敢えず auto_complete が混ざった補完の繰り返しは動く様になった。

    o menu-complete も menu-filter も問題を起こさず繰り返しできている様に見える。

  * decode: modifyOtherKeys が全然駄目 [#D0756]

    mintty や xterm で試してみる。

    x fixed: 調べてみると ESC [ key ; mod u は送られてきているが、ちゃんとデコードできていない?
      と思ったら変数名を間違えていた。

    x fixed: 何故か S-A 等はちゃんと入力できる。
      CapsLock の状態で S-a を入力すると、今度は何故か M-a と認識されてしまう。
      →これもバグだった。mods で modify するべき所を kcode で modify していた。

    - done: S-a や S-A に対してはどの様に対処すれば良いだろうか。

      どうやら mintty の場合には S-(Shift済み文字) を送ってくる様だ。
      C-S-a 等の場合にも C-S-A を送ってくる。
      うーん。どうやって検出するのが良いだろうか。

      先ず Shift 以外の修飾がない場合には通常の文字入力と解釈したいので、
      単に S- を外す様にすれば良い。
      次に Shift 以外の修飾がある場合には実際に押されたキーを使いたいので、
      寧ろ文字の方を小文字に変換する様にしたい。

      後で xterm も試してみた所、同様の動作だった。

    x fixed: ログアウトした時に変な状態?
      やはり external の既定値は 0 にするべき。少なくとも 1 が望ましい。
      取り敢えず 1 にする事にする。1 にしておいたら抜けても大丈夫だった。

    o ok: 普通の入力はできる様になった。mintty で S-RET はできる。
      C-TAB は何も送信されて来ない(?)がこれは仕方がない。
      xterm で試してみた所、xterm では C-TAB が送られてくる。S-RET も効く。

    x resolved: うーん。mintty は Alt で普通に A- 修飾をしてくる。
      ここは M- 修飾という事に読み替えるか…。
      うーん。そもそも 2 を A- として
      0x20 を M- にするのは独自の仕様である。

      うーん? 他の端末だとどうか?
      xterm を試してみた所やはり Alt で修飾 2 である。
      ここは 0x20 を A- にして一般的な 2 は M- 修飾にする。

2018-08-29

  * complete: echo ~/m@ から補完を実行すると COMP_PREFIX が効いていない [#D0755]
    全ての候補に余分に /home/murase/ がついている。

    - 今までの ble.sh ではちゃんと動いていた様子である。
      これはまた bash-completion だろうか。
    - また echo ~/@ から補完を実行した時にはちゃんと COMP_PREFIX は効いていて、
      候補たちには余分なパス /home/murase/ は付加されない状態で表示てきている。
    - ble-syntax:bash/simple-word/eval '~/m' をしてみると、
      ちゃんと /home/murase/m に展開されている。
      従って COMPV の不整合ではないと思われる。

    また後で詳しく調べる事にする。

    - 調べるとどうも action:plain/initialize の直後ではちゃんと ~/m* の形の候補になっている様だ。
    - 確認してみると先頭を削っているのは action:action/initialize ではなかった。
      そもそも menu で表示しているのは INSERT ではない。
      menu/style:style/construct の中で PREFIX_LEN を参照してその分だけ削っている。
      つまり PREFIX_LEN または COMP_PREFIX の計算が間違っている。
      実際に COMP_PREFIX は全く設定されていない様だ。
    - yield の呼び出し元を調べると progcomp である。
      compopt で filenames が指定されていないという事だろうか。
      と思ったらちゃんと指定されている。
    - 分かった。単に自分の作ったバグである。
      "COMPV に / が含まれている時に COMP_PREFIX を設定する" ところが、
      "COMPV が / で終わる時" に誤ってなっていた。直した。

  * complete: [refactor] $ACTION は ble-complete/action/ は含まない様に変更する [#D0754]

    また ble-complete/action/ から ble-complete/action: に変更する。
    元々 ble-complete/action/ の形にしていたのは
    "外からカスタマイズする時に action というディレクトリにファイルを置けば使える"
    という様にできたらいいなと思っての事だったが、具体的な計画はないし
    そもそも結局 $path/complete/action/foo の形で検索しなければならないのだから、
    関数名を ble-complete/action/ の形式にしておいても余り利点はない。

    同様に ble-complete/source/foo も ble-complete/source:foo に変更する事にした。

  * decode: [refactor] _ble_decode_key__kmap -> _ble_decode_keymap [#D0753]

  * decode: modifyOtherKeys の振る舞いについて [#D0752]

    調べると xterm では $'\e[>4;1m' 等を送ると有効になると書いてある。この情報は本当か?
    https://unix.stackexchange.com/questions/165104/does-gnome-terminal-have-an-equivalent-for-xterms-modifyotherkeys

    更に C-tab を使う為には modifyOtherKeys を 2 にしなければならないが、
    これを設定すると Ctrl+space が C-@ ではなくて C-SP になるなど色々面倒な事になる。
    どの設定でも動く様にする為には C-@ と同時に C-SP 等にも束縛して置かなければならない。
    これらは実際の xterm で試す必要があるだろう。

    なんと xterm.el にもその様な設定が含まれている。
    https://emacsformacosx.com/emacs-bzr/trunk/lisp/term/xterm.el
    これを読む限りでは \e[>4m で解除で \e[>4;1m で有効化の様である。
    実は \e[>4;2m とすれば C-TAB もできるようになるという事ではあるまいか。

    検索してみると mlterm は "CSI > 4 ; 2 m" に対応している。
    https://sourceforge.net/p/mlterm/feature-requests/16/
    しかも "ESC[<unicode>;<mod>u" の形式を使っている…。

    うーん。'\e[>4;1m\e[>4;2m\e[m' でも送っておけば良いだろうか。
    現在の所、端末がこれらの設定に対応しているかどうか調べるのは難しい。
    解除に関しては、ユーザが敢えて設定している事もあるかもしれないので、
    \e[>4m は送らないで置く…と思ったが、\e[>4;2m で放置しておくと、
    C-SP が他のソフトウェアで効きませんという事になるかもしれないので難しい。
    bleopt で設定できる様にするべきである。

    以下のページによると mintty は C-TAB で \e[1;5I を S-C-TAB で \e[1;6I を送ってくるそうだ。
    https://tmsanrinsha.net/post/2012/07/%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%A7ctrltab%E3%81%A8%E3%81%8B%E3%82%92%E4%BD%BF%E3%81%86/
    cmap/default.sh を参照してみるとこれらは kptab に割り当てられている… (つまり C-kptab, S-C-kptab)。

    [修正]

    - done: 先ず初めに synonym となるキーに関して確認を行う。

      - done: C-@ と一緒に C-SP も登録する事にした。ただそもそも一箇所しかなかった。念の為 NUL も登録した
      - done: C-m と一緒に RET も登録する事にした。一箇所だけ欠けている所があった
      - done: C-i と一緒に TAB も登録する事にした。一箇所 S-TAB だけの所があったので C-S-i も登録した
      - done: C-?, C-h と一緒に DEL, BS も登録する。これは結構修正した。主に C-h と DEL しか登録されていなかった
      - done: C-_ と一緒に C-DEL, C-BS も登録する。これは一箇所 C-_ だけの所があった。他に C-BS は一つもなかった

    - done: 次に CSI u に対応する。

    - done: kp～ は区別しても役に立たないので
      ユーザが特に区別したいというのでなければ既存の物と同じにする。

    - done: '\e[>4;1m\e[>4;2m\e[m' を送ることにする。
      結局状態を管理する事にした。
      ble.sh の外でどの設定にするかは bleopt_term_modifyOtherKeys_external で設定する。

  * complete: 絞り込み [#D0751]

    初め fish の様に入力欄を候補一覧の上に表示する事を考えたが管理が面倒だ。
    更に言うとコマンドラインと別に表示する意味があるのかわからない。
    それよりはコマンドラインの中に入力して、
    入力しながら直ぐに候補一覧を更新するという様にした方が懸命である。

    % その時にどの様に処置をするのが良いだろうか。
    %
    % a 一つの方法は keymap:complete を定義するという事
    %   この keymap の中で self-insert や delete-backward-char があった場合には、
    %   候補一覧をその場で更新するという仕組みにする。
    %
    %   少々問題がある。auto-complete が更に起動している場合、
    %   self-insert は auto-complete が食ってしまう。
    %   これに対して正しく対処するためには、
    %   auto-complete 側が complete の情報を利用する様に書き換えると良い。
    %
    % b 或いは寧ろ auto-complete が候補一覧を出すというのでも良い。
    %
    %   取り敢えず auto-complete に候補一覧を出させてみる事にする…
    %   と思ったが、候補の更新は background で実行したい。
    %   もし background で候補を更新するのだとしたら、
    %   実は候補一覧が表示されている時に限り、
    %   すぐ様、候補の絞り込みの処理を実行すれば良いのではないか…
    %
    % c auto-complete.idle に処理させる。

    うーん改めて望ましい動作について整理する必要がある。

    * done: [準備] ところで候補一覧を計算している途中に次の入力が来たときには処理を中止する。
      中止したとしても候補一覧を無効にしたくはないので、
      処理を中止した場合には _ble_complete_menu_* に変化がない様にしたい。
      つまり、処理が完了したらその時に _ble_complete_menu_* を更新する様に変更する。

    * ok: 絞り込みによって候補がなくなった場合に曖昧一致に切り替える時

      | 先ず初めに補完候補一覧を出したとする。それに続けて文字を入力したとする。
      | すると段々と候補が少なくなってもし変な文字列を入れると最終的には候補は全てなくなる。
      | この時に改めて曖昧一致などを試みるべきだろうか。
      | しかし、そうだとすると一番最初の候補生成のところからやり直すべきなのではないか。
      | 更にいうと、候補生成は開始点を遡って候補生成を試して、
      | 一つも候補が見つからなかった時に限り曖昧一致の候補を生成する様になっている。
      | もし絞り込みで候補が尽きた時にも同様の動作をするとすれば、
      | 結局絞り込みの開始点が勝手にずれるという事になり混乱の元である。
      |
      | 更に delete-backward-char 等でカーソル位置を元に戻した時に、
      | a 元の候補一覧に戻すようにしない、というのは不便である。
      | b 一つの方法は元の候補集合をカーソル位置毎に覚えておく方法である。これは非現実的な気がする。
      | c そもそも候補集合を変更しない様にするというのが現実的な気がする。
      |   つまり、ユーザが明示的に TAB (complete) を呼び出さない限りは候補集合は変更しない。

      結論: 候補が絞られてなくなった時、候補集合を自動的に曖昧一致で再生成するか?
        →しない。既に持っている候補集合に対してのみ曖昧一致を試みる。
        もしちゃんとした曖昧一致を実行させたいのであれば、
        ユーザがもう一度明示的に complete を押すようにするべきである。

    * done: どの様な操作があった時に候補絞り込みを継続(中断)するのか。

      | 例えばスペースを挿入する事によって単語が切れた時。
      | これは例えば補完開始点と終了点を記録しておいて、
      | 補完開始点からカーソル位置の間までが simple-word (close 可能) であるかどうかの判定で良い。
      |
      | 或いは、一旦スペースを挿入して backward-delete-char
      | で戻った時にまた再開するかどうかも微妙な問題である。
      | 一回スペースを挿入したのにまた戻ってきたら再開するというのも妙な話である。
      | 然し一方で、誤って挿入してしまったとしてもまた元に戻る事ができるというのも便利である。
      |
      | また一回カーソルで移動してからまた元の位置に戻ってきた時の動作はどうか。
      | 一回離れてまた戻ってきた時にまた動き出すというのも変な話である。
      | しかしながら一方で、絞り込みの途中で前後に移動したいという需要はあるかもしれない。

      以上を総合すると次の様な実装にするのが良いのではないだろうか。

      1 最初の候補一覧表示の際に、以下を記録して置く。また "絞り込み" がアクティブの状態にする。
        補完開始点 beg, 補完点 end, 前の文字列 left=${str::end}, 後の文字列 right=${str:end}

        実装: 実はこれは現在の実装で既に記録している物に一致している?
        しかし _ble_complete_menu_state はもしかすると廃止するかもしれないし、
        直接文字列を格納している訳ではないので分かりにくい。
        取り敢えずの実装として _ble_complete_menu_str を記録する事にする。

      2 idle の処理に於いて絞り込みがアクティブである時、
        1 カーソル位置のチェックとして次を行う。
          [[ ${str::ind} == "$left"* && ${str:ind} == *"$right" ]]
          が満たされていなければ、絞り込みから外れたと見做し、
          絞り込みを非アクティブにして終了する。
        2 ${str:beg:${#str}-${#right}} が simple-word でなければ
          やはり絞り込みを非アクティブにして終了する。

        注意: この時、もし auto-complete が有効であるならば、
        一時的に挿入されている文字列に反応しても困るので、
        str1=${str::ind}${str:mark} を対象にして上記の判定を実行する事にする。

        更に、isearch など他のモードになった時に勝手に候補絞り込みが走られても困るので、
        keymap が emacs, vi_imap 及び、特別に対策した auto_complete の時のみ処理する。
        それ以外の場合には絞り込みを非アクティブにして終了する。

        実装: これはそのまま実装する。

      絞り込みの非アクティブ化は idle で実行するため、
      一瞬で絞り込みの条件を破壊し回復しても絞り込みの続きができる。
      これは仕方がないので気にしない事にする。

      取り敢えず実装してみた。動いている。

    * done: この絞り込みがアクティブかどうかの条件を menu-complete に入るかどうかの判定に使える。
      現在は $_ble_edit_ind:$_ble_edit_str しか見ていないので、
      編集してから同じ状態にして其処で complete を実行した場合でも、
      menu-complete に入ってしまう。やはり試してみると不自然な動作に思われるので、
      絞り込みがアクティブかどうかを考慮に入れるのが良い様に思われる。

    * done: 絞り込みが行われた状態でメニュー補完に移る条件は?

      現在の実装だと complete を連続で押すか、
      最後に候補一覧が更新された時と同じ状態で complete が呼び出されると、
      メニュー補完に突入する。

      連続で complete を呼び出した時にメニュー補完に入るのは良い。
      最後に候補一覧が更新された時と同じ状態という条件はそのままだと問題になるかもしれない。
      絞り込みが行われた時に一緒に _ble_complete_menu_state も記録していると、
      絞り込みの途中で共通部分の complete を実行しようと思っても必ず menu-complete に入ってしまう。

      - done: これは _ble_complete_menu_active を用いて判定する事にした。実装した。

      - done: menu-complete では _ble_complete_menu_active はそのまま保持する事にした。
        menu_complete を抜ける時に cancel ならば続きからに絞り込みできる様にする。
        accept ならばその時に _ble_complete_menu_active を無効にする。
        他に menu_complete から抜ける箇所はないので、
        _ble_complete_menu_active が残存して問題が起こる事はないだろう。

    * done: _ble_complete_menu_state はもし不要になっていたら削除する
      確認したらもう既に使われていないので削除する。

    * done: 絞り込まれた状態でメニュー補完に入っても問題は起こらないか。
      普通に動いている様だが、そもそもどの様な懸念があったろうか。

      | 試していたら駄目だった。beg と end が恐らくずれている為に問題が生じている。
      | メニュー補完で確定した後に挿入する位置が間違っている。
      | beg と end がどう使われているかを再度確認する必要がある。
      | 1 先ず、menu-complete の範囲の切り出しに使用されている。
      | 2 また、menu-filter の有効期限判定の為にも使われている。
      | 前者では最新の状態に対応する範囲を使う必要がある。
      | 後者では一番最初の状態に対応する範囲を使う必要がある。
      | つまりそれぞれ記録する必要がある。
      |
      | menu-complete の範囲の切り出しに使うのは、
      | menu-filter によって計算された範囲という事にしようと考えたが、
      | よく考えてみたらビジーだと menu-filter は実行されない。
      | 従って、menu-complete の側で独自に menu の有効期限を更新する必要がある。
      | 特に毎回更新を行うのだとしたら、わざわざ最新の beg と end を記録する必要はない。
      | 一方で、最新の beg と end を計算する仕組みを共通化するという観点から考えると、
      | 最新の beg と end をグローバル変数に記録する仕組みになっていてもおかしくはない。
      |
      | 取り敢えずは最新の beg と end を計算するコードを書いてみてから比較して判断する。
      | やはりその場で毎回範囲を計算しなければならない。
      | get-active-range という関数を作って編集範囲を取得する共通コードを括りだした。

      menu-complete にしろ menu-filter にしろ、
      取り敢えず最初の beg end str と現在の str ind を較べる事により、
      候補一覧がアクティブであるかどうかを確認し、
      その後で現在の範囲を用いて処理を行う。
      現在の範囲を取得する関数として共通の実装にする事にした。

    * done: _ble_complete_menu_beg をチェックしてメニュの有効無効を判定している箇所は
      _ble_complete_menu_active に変えても問題ないか確認した上で変更する。
      そのすぐ下で既に _ble_complete_menu_active のチェックを行っていたので、
      単に判定を削除するだけで対処した。

      ble-complete/menu/clear に関しては _ble_complete_menu_beg による判定が残っているが、
      そもそもこの ble-complete/menu/clear の処理は必要だったのだろうか。
      単に menu_active を無効にして ble-edit/info/clear するだけで良い様な気もする。

      * done: そもそも何故 ble-complete/menu/clear という関数を作ったのだったか。
        現状では実質、メニュー補完で確定をした時に画面を消去するのにしか使っていない。
        メニュー補完で確定した後にまたメニュー補完が始まると嫌なので
        _ble_complete_menu_beg をクリアしたが、
        _ble_complete_menu_beg だけクリアするのも変ということで全て消したのであろう。
        →_ble_complete_menu_active= だけ実行する様に変更する。

      * done: 一意確定の時に ACTION/complete を呼び出す前に menu/clear している
        元々は ACTION/complete の中で候補一覧を表示するために先に clear をしていたが、
        現在は新しく候補一覧を出す時には ACTION/complete の中で要求を出して
        外側で改めて候補一覧の生成を実行する様に変更した。
        今となっては ACTION/complete の中で menu/clear を実施する必要がない様に思われる。
        →この呼出は削除する事にする。

      x resolved: メニュー補完で確定した後も絞り込みが有効になっている。
        →メニュー補完ではなくて自動補完の方だった。
        - checked: 通常の補完確定でもメニューは無効化される。
        - checked: メニュー補完の確定でも無効化される。
        - checked: 自動補完の確定でも今回無効化されるようにした。
        何れの場合でも補完が確定すれば候補一覧を消すという方向で統一した。
        前よりも見通しが良くなった気がする。

    * done: よく考えたら現在の枠組みでどうやって候補再生成を実行するのか

      | 必ず menu-complete に突入してしまう。
      | 直ぐに menu-complete したいという時もあるのでどうするか。
      | うーん。やはりアクティブでかつ元と同じ状態という事にするか。
      |
      | 望むらくは有限の共通一致部分が新しく挿入すれば補完し、
      | それ以外の場合にはメニュー補完に移動する。
      | という事を考えたが、目で見て瞬時に判断するのは難しいので、
      | 結局は一回は共通一致部分の挿入を確かめる事にするのが良い。
      | 一方で、折角絞り込んでも候補の再生成を行うと異なる物が表示される可能性もある。
      | どちらの方が良いのか。或いは別のキーで直接メニュー補完に入れる様にする。
      |
      | - 直接メニュー補完に入った時には元の状態と同じでなくても良いが、
      |   依然としてアクティブである事を確かめる。失敗したらベル?
      | - complete からメニュー補完に入る時は元の状態と一致する事も追加要件とする。

      complete の先頭で menu-complete/enter する時に、
      _ble_edit_str の一致をチェックするだけで良さそうだったのでそうした。
      以前は _ble_edit_ind の一致も確かめていたが、
      それは _ble_complete_menu_active=1 の時には一致している筈なので省略できる。
      また、明示的に ble/widget/menu-complete を呼び出した時は、
      別の経路で ble-complete/menu-complete/enter が呼び出されるが、
      その時はチェックなどせずに強制的に実行されるので気にしなくて良かった。
      単にその位置で menu-complete に入らなかった時に bell を鳴らす様にだけ変更した。

    * done: 絞り込み処理の途中でユーザが入力した時に中断しても問題は起こらないか。
      これは実際にテストの途中にやっていて起こっている様だったが、特に問題になってはいない。
      と思ったら _ble_complete_menu_filter による判定を間違っていた。
      _ble_complete_menu_filter_str を参照していた。直した。
      構造を改めて見たが問題にはならなそうだ。
      最後に表示する時に _ble_complete_menu_filter= を更新しているので。

    * ok: 変数を整理する
      変数を配列にまとめるなどしたら綺麗にならないだろうか。
      観察してみたがまあ特に問題はないだろう。
      _ble_complete_menu_filter だけは表現を変更する事にした。

    * ok: 変数名 _ble_complete_menu_... の refactor

    * done: info が途中で別の操作によって上書きされる可能性が常にあるのでは。
      これは menu-complete に突入する時にも既に同じ問題がある。
      修正する必要がある。
      →menu-complete については修正した。
        menu-filter に関しては毎回完全に再描画するので
        info が上書きされていても大丈夫である。

    * done: 現在絞り込みの状態である事が分かる様なサインはないのか?
      未だ絞り込みが有効であると思って何か入力しても反応しないというのは悲しい。
      或いは絞り込みが無効になったら候補を消してしまう?

      取り敢えずその様に修正した。
      もしやはり候補一覧は表示したままが良いという場合には、
      get-active-range と ble-complete/menu-filter.idle で呼び出している
      ble-complete/menu/clear を別の物に置き換えると良い。
      例えば灰色一色の候補一覧を表示するなど…。

    x resolved: メニューが消えるタイミングが変である…
      echo b@ で候補を出してその後でスペースを挿入すると、
      その直後にメニューが無効化されて消えて欲しいのに、
      実際には更に次の操作を行った時に始めて消える。
      →これは調べたら単に buffer に溜まっていただけだった。
      immediate-clear を使う様にしたら直った。

2018-08-28

  * edit: refactor function names "_ble_edit_str.*" -> "ble-edit/content/*" [#D0750]

    * 他にも全般に関数名を見直す。
      - _ble_* で始まる関数名
      - ble-edit/prompt/update 周りの関数名で非公開の物に . をつける
      - ble-edit/prompt/update/backslash:* -> ble-edit/prompt/backslash:*
      - ble-edit/prompt/update/append -> ble-edit/prompt/print
      - _ble_util_array_prototype -> _ble_array_prototype
      - _ble_util_array_prototype.reserve -> ble/array#reserve-prototype
      - _ble_util_string_prototype -> _ble_string_prototype
      - _ble_util_string_prototype.reserve -> ble/string#reserve-prototype

    * declare -F で眺めて気になる物を直す。

      refact -F ble/adjust-bash-options        ble/base/adjust-bash-options
      refact -F ble/restore-bash-options       ble/base/restore-bash-options
      refact -F ble/workaround-POSIXLY_CORRECT ble/base/workaround-POSIXLY_CORRECT
      refact -F ble/unset-POSIXLY_CORRECT      ble/base/unset-POSIXLY_CORRECT
      refact -F ble/adjust-POSIXLY_CORRECT     ble/base/adjust-POSIXLY_CORRECT
      refact -F ble/restore-POSIXLY_CORRECT    ble/base/restore-POSIXLY_CORRECT

  * 2018-07-30 complete: menu-completion [#D0749]

    曖昧一致の時には自動的に開始しても良いかもしれない。
    或いは、その様にすると動作が予期できなくて却って邪魔かもしれない。

    その前に他のシェルでどの様なインターフェイスにしているのかを確認する必要がある。
    下手に実装して非直感的で使いにくい物にしてしまっても仕方がない。

    - done: menu-completion の前に候補の表示の仕組みを整える必要がある。
      各候補を表示している座標が必要である → #D0746
    - done: mark_active の実装
    - done: C-m, RET で確定
    - done: tab の場合は一番最後に行ったら最初に行く。
      S-TAB なら一番最初に行ったら最後に行く。
    - done: 次の行・前の行に行く機能
    - self-insert で絞り込み
      本当に self-insert で絞り込みというので分かりやすいか。
      続けて入力を開始したら確定して続きへの入力にしたい。

      それよりは、auto-complete の側で、
      候補一覧が既に表示されている時には、
      候補一覧の内容を更新するという形にしたほうが良いのではないか。

      o 入力領域を新しく用意しなくて済むので便利である。
      - 但し、その場合には、更新の途中で中止した時の為に、
        直接は _ble_complete_menu_list を書き換えずに、
        処理が完了した時に限り _ble_complete_menu_list を書き換えるのが良い。
      - また has-input の確認の間隔は短めに設定するのが良いだろう。

      →これは別項目を立てる事にする。

    - done: menu-complete on/off option
      bleopt_complete_menu_complete を追加した。

    x resolved: auto-complete が途中で起動するとキャンセルされてしまう。
      どの様にして直前が complete であったという事を判定すれば良いのかが問題である。
      __before_widget__ で毎回 complete をチェックするのは不毛である。
      或いは _ble_edit_arg に何かマーカを設定するか?
      と思ったが、それだと他の処理に支障を来す。

      LASTWIDGET として自動で起動された物が設定されているのが行けないのか?
      と思ったが、実際に exit-default を介して widget が実行されている。

      うーん。もう面倒なので menu を表示した瞬間の _ble_edit_ind と
      _ble_edit_str を記録しておいて、それらが一致したら
      メニュー補完に入るという事にしてしまう。

    x resolved: また、現在の気になる振る舞いとして高速に tab を二回押すと
      menu-completion が起動しないという事がある。
      これは一回目の tab による complete が中止されて、
      最後まで行かない為に menu が表示されず、
      結果として二回目の tab によって menu-complete が開始しないという事にある。

      現在は menu-complete の開始条件を menu が現在の ind:str の状態で記録されていたら、
      という事にしているが、LASTWIDGET もチェックして同じ物が連続で呼び出されていたら、
      問答無用で menu-complete に入る様にするべきだろうか。。

      →と思ってその様にして見た所、complete を二回叩いたら何も表示されず変な状態になる。
      どうやら menu-complete/enter は既に計算済みの _ble_complete_menu_list を使用するので、
      新しく起動する為にはこちらの手許で候補生成を実施しなければならない。。
      更に menu-show も実施しなければならない。

      →opts に enter_menu を追加して opts=show_menu と同様の処理の仕方をする事にした。

2018-08-27

  * mshex: <del>base (--attach=prompt):</del> screen の中からだと効くが外だと効かない [#D0748]
    ble-attach さえ実行すれば読み込まれるのでロードに失敗しているという事ではない。
    →これは mshex の側の問題であった。

2018-08-26

  * complete: compopt -o filenames に対応する [#D0747]
    echo dir/ から補完すると dir/ の部分が省略されない。
    これは何故かというと bash-comopletions の _minimal が呼び出される為。
    更に、action/file で定義されている候補着色などの機能も効かなくなっている。

    →これは action/progcomp の DATA として $comp_opts を記録して、
      action/progcomp で場合分けして処理する事にした。

      (今までは comp_opts に応じて action/argument{,-nospace} を切り替えていたが、
      その方針だと comp_opts の種類の累乗で action が必要になり始末が悪いので、
      一つの action で実装する事にした)

  * 2018-08-05: complete: 候補一覧の配置と着色 [#D0746]

    候補の表示についてはもう少し考える必要がある。
    元々は候補源の側で表示の仕方を制御できる様にしようと考えていたが、
    よく考えてみれば色々と微妙な問題が存在する。

    - 候補に ^M や [m 等の特殊文字が含まれる場合に、
      これを着色やレイアウトの為のエスケープシーケンスとどう区別するのか。
      特に、エスケープシーケンスを含む事を可能にするのだとしたら、
      呼び出し元でわざわざ候補に含まれるエスケープ文字に対して
      表示文字列に変換しなければならない。

    - 更に、上位の枠組みで着色を変更したい需要がある。
      例えば既に入力済みの部分と一致している部分を太字にするなど。

      候補源側で着色するという手もあるが、各候補源で着色を別々に実装するのは
      不毛だし面倒だし分かりにくいし、表示の統一性を保ちにくい。
      また、絞り込みなどのインクリメンタルな処理を行う際に、
      毎回候補源を呼び出すというのも効率が悪い。

      また、上位の枠組みによる着色が、
      候補源側による着色と被るとそれはそれで分かりにくい。

    一つの案は候補源は候補の色 (bg,fg) のみを指定し、
    上位の枠組みで入力済みの部分を太字にして、
    menu_completion で選択している物は反転して、
    等の様に直交するような着色を実行する。

    1 入力済みの部分を着色するという事

    2 各候補の表示位置を計算するという事

    3 候補が行を跨がない様にするという事

      特に幅が現在の幅より小さい場合には次の行に送る。
      現在の幅より大きい場合にはどうせ入らないので、
      続きに表示してしまう事にする。

      方針としてはまず最初に各候補の幅について計算するのが良い。
      タブなどは ^I で表示する事にするので、文字幅は固定である。
      但し、折返しが起こる時にはその行で一番最後の文字の
      文字幅が影響してくるので注意する。
      これは行数分だけ幅に余裕を持って考えれば良いだろうか。
      と思ったが、行数が文字幅を超える場合は、それでも問題になる。
      1行に収まりきらない候補については必ず末端に表示する事にするか。

      或いは行を跨ぐのは諦めるという手もなくはない。

    これを達成する為に、info text を改造した様な物を考える。

    * 行を跨ぐ場合には、そのまま文字列を出力するとずれる。
      再描画の時に再度計算し直すか、
      或いは最初に計算した時に esc を記録するか。
      再描画の際には esc が変化するので、
      記録しておいても仕方がないかもしれない。

      % 或いは、反転させるだけならば、反転の SGR で全体を囲むだけ?
      % と思ったが太字解除等のシーケンスに対応していない端末では、
      % 太字解除に SGR(0) を使ってしまうので単に全体を囲むだけでは駄目である。
      % 実際、現在の仕組みを調べてみた所、毎回 SGR(0) でクリアしている。

      やはり毎回全体を構築する事になるのだから、
      esc の状態で記録しておく事に意味があるかどうかは分からない。
      或いは、ble/textmap の様に文字の部分と SGR の部分を分離して記録する手もあるかもしれないが、
      それは面倒だし処理の量も増えるので好ましくない。

    * 複数の配置モードを実装するというのも手である。
      その様に考えれば、最初は一番簡単な実装方法で良い。

    [実装]

    * done: 取り敢えず着色などを考えずに実装する。
      また行に収まらない時の改行なども考えずに実装する。

      実装した。bleopt_complete_menu_style を用いて配置方法を選択できる様にした。
      今まで通りの何も気にせずに続けて表示する物は dense とした。
      行に収まらない時の改行の処理についても実装した dense-nowrap とした。
      更に、align, align-nowrap という名前で綺麗に整列するのも実装した。
      align{,-nowrap} では bleopt_complete_menu_align を用いて、
      整列する時の最大幅について設定できる様にした。既定値は 20

    * done: 着色を行う。
      COMP_PREFIX 等によって削られている場合に対して対策が必要である。

      というか寧ろ cand_show には COMP_PREFIX を入れておいて、
      cand_cand の中身と合わせて生成したほうが良いのではないか?
      と思ったが、cand_show と cand_cand の両方を参照するのは効率が悪くなる。

      cand_show の形式を変更する事にする。
      cand_show="${#COMP_PREFIX}:$CAND" に変更する。
      形式は変更した。

      取り敢えず入力済みの部分を太字にするのを実装したが問題が残る。

      1 done: 補完を実行する直前の入力部分が着色されているが、
        補完実行後の入力部分 (つまり候補の共通部分) に対して着色するべきではないか。
        これについては対応した。

      2 done: 制御文字が含まれていた場合 ble-edit/info/.construct-text
        は _ble_term_rev _ble_term_sgr0 を用いてそれを囲んでいる。
        それによって太字などの描画属性が消えてしまう。

        * done: 使用する sgr 及び特殊文字に使用する sgr を外から指定できる様にする。

          一つの手は .construct-text は弄らずに
          _ble_term_rev _ble_term_sgr0 を local で上書きする事だが汚い。
          代わりに ble-edit/info.construct-text の機能として、
          別の変数を使って特殊文字とそれ以外の描画属性を外から指定できる様にする。

        その上で何が必要になるだろうか。
        先ず、候補に SGR が設定されている場合について考える。

        * done: 候補ごとに適切な sgr を取得する方法を決める。
          (現在は未だ色を設定できる様にはしていないがその内に実装の予定である。
          但し実装の方法は複数考えられる。ACTION 経由で取得できる様にした方が良い気がする)

          →結局これは ACTION 経由で取得できるようにする事にした。

          cand_show の形式も拡張して ACTION や DATA 等の全ての情報を格納する事にした。
          結局 cand_show, cand_prop, cand_data の三つの配列を統合し、
          cand_pack という名前の配列とする事にした。
          その上で cand_pack の要素を展開する関数として ble-complete/cand/unpack を用意し、
          それを呼び出した上で "$ACTION/getg" を呼び出す事にした。

        * done: ファイル名に関してはディレクトリかそうでないかで色分けする事にする。
          結局 syntax 定義されているファイルの種類の全てに対応する事にした。

    以下はこの項目によって解消した

    | * 2013-06-06 complete: 候補一覧の整列

  * history: ロード中に up などで履歴を参照すると履歴の初期化に失敗する [#D0745]
    空の履歴になってしまう。

    これは async の処理の途中で sync を呼び出した時に、
    条件が満たされて初めて呼び出されると期待している場所に、
    条件が満たされていないのに突入してしまうのが原因であった。

2018-08-25

  * complete: ファイル a=b について a= で補完すると a=a=b になる [#D0744]

    #0742 で直したと思っていたが直っていない。
    →変更漏れがあったので直した。
    更に、argument 以外の時には、= に対する処置を core-complete.sh 側で実行していないので、
    argument 以外の時に限って core-syntax.sh 側で = または : 以降の補完文脈を生成する事にした。

  * complete: bug: 曖昧補完での置換で元々あった文字列が削除されていない [#D0743]
    ble-complete/insert の呼び出しまでは問題ない様だ。

    調べてみると insert_beg の値が滅茶苦茶になっている…
    と思ったら算術式として計算するべき所で、
    文字列としての追記が行われていた。

  * complete: bug: 変数 var にディレクトリ名が入っている時 echo ${var} で補完すると [#D0742]
    変数の中身が余分に挿入される。

    調べてみると何とそもそも補完文脈の時点で
    補完開始点が ${var} の直後になっている。

      hello=cmap
      echo ${hello}@

    に対して "argument 13" という補完文脈が生成されている。
    不思議なのはその後でちゃんと $hello に入っている cmap で確定している事である。

    調べてみると、どうも source/argument は内部で独自に ble-syntax:bash/extract-command
    を呼び出していて、${hello} を抽出している様である。
    つまり、argument 候補文脈を生成する時にはちゃんと正しく開始点を決定できなければ、
    誤った候補が生成されてしまうという事を意味する。

    然し…現在の completion-context の next-argument を観察すると…
    例えば引数が ...= の形式をしている時に ...= の部分を削除して
    引数として argument を生成する等している。
    実際に、

      touch a=b
      echo a=@

    で補完を実行した所 a=a=b という具合に重複して補完される事を確認した。
    うーん。実は ...= の右辺に関しては argument
    で処理するべきではないのかもしれない。
    もしくは文脈の生成側で勝手に ...= などを切り出すべきではないのか。うーん。

    * 取り敢えず少なくとも解決しなければならない事は、
      ${hello} に対して補完開始点が正しく検出できない事。
      $hello に対しては正しく検出できている。

      どうも ${hello} の時は ble-syntax/completion-context/.check-prefix/ctx:next-argument
      が呼び出されていない様である。check-here を介して候補が生成されているのではないか。
      調べてみると CTX_PARAM を介して check-prefix を起動しようとしている。
      直前の ${hello@} における文脈を拾っている。
      うーん。これは外側の文脈を用いて補完を起動するべきなのではないか?
      と思ったが、パラメータ展開を閉じていない場合には
      やはり CTX_PARAM によって補完するべきである。

      % うーん。現在位置と同じ nest か、より上の nest になるまで遡るべきなのではないか。
      % どの様に判定したら良いか。同じかどうかの判定は簡単である。
      % より上の nest であるかどうかはどう判定するか。
      %
      % extract-command におけるスキップを見れば良いのかもしれない…。
      % と思ったが extract-command は tree-enumerate を使っていた。

      うーん。そもそもの考えとしては、直前の文脈を参照すれば、
      現在の文脈が何であるかが分かるはず、という話だった。
      その時に直前の文脈から現在の位置に至るまでの間に含まれる文字列も検索するのであった。
      この考え方に従えば CTX_PARAM 文脈に対する処理として実装し、
      '}' があれば一つ上の文脈を用いて補完を実行し、
      それ以外の時にはパラメータ展開の中身としての補完を実行する、
      という具合に実装するべきなのである。

      実装した。動くようになった。

    * 序に数式中で変数名を補完する様に修正した。

    * 候補源 argument が中途半端な場所から始まった時に問題が起こる事に関しては、
      そもそも中途半端な場所から始まった時には argument は使うべきではないと判断する。
      プログラム補完が定義されている場合でも、--prefix=... の形式の ... の部分を
      通常の補完候補と同じ様に補完させてよいのかは非自明である。

      更に、補完文脈を生成する際に = や : の位置以降の物を生成するのは都合が悪いのでは。
      というのもプログラム補完の側で = 以降や : 以降の候補の生成に対応している可能性がある。
      従って、補完文脈の側では = や : 以降の補完文脈は生成せず、
      候補源の側で適当に = や : 以降を用いて生成する様にするのが良い。

      丁度関連する議論として #D0718 があって、
      = や : 以降の方を優先させる事について書いていたが、それについては撤回する事にする。

      実際に見てみた所、単に completion-context/.check-prefix/ctx:inside-argument
      の中で生成している : または = から始まる補完文脈を削除すれば良いだけの様に思われる。
      削除した。

  * 2016-07-15 complete: "" の中にある $variable で確定した時は空白は挿入しないようにしたい [#D0741]
    また ${... の中で variable で確定した場合は '}' を挿入するようにしたい。
    もしくは } が既に存在している場合にはその次の文字へカーソルを進めたい。

    % つまり、何を挿入するかは候補側が決めるというよりは実のところ
    % 候補生成箇所の文脈に依存するという事である。
    % variable:= などを導入して候補生成箇所の文脈を伝える様にはした。
    % しかしこの方法だと無駄に複雑になる気がする。
    % 補完の枠組自体を再考する必要がある。

    2018-08-25 "" の外にあったとしても $variable で確定した問は空白は挿入しない事にした。
    ${... の補完の場合には } を挿入する事にした。
    既に存在している物をスキップする機能は既に上の枠組みで実装している。
    結局現在の枠組みで実装する事にした。

2018-08-23

  * 2018-08-05 complete: パラメータ展開で厳密一致で一意確定の時にはそもそも候補の生成を行わない? [#D0740]
    曖昧一致も許さない様にする。
    そうすれば別のコマンドが生成できる。

    実際にやってみたら動かない、と思って調べたら候補生成を停止すると、
    今度は曖昧一致を試みるので、結局候補が生成されてしまうという事だった。
    曖昧一致の優先順位を変更する事にした。これまでの曖昧一致の順位に余り深い意味はなかった。
    今までは先頭一致または曖昧一致で一番近いものを使っていたが、
    先頭一致 (で一番近いもの) がなかった時に限り曖昧一致で一番近いものを使うように変更した。

  * complete: git の補完が効かない [#D0739]

    % 例えば git com まで入力した状態で補完を実行する場合で考える。
    % ちゃんと補完関数は呼ばれている。
    % 試してみると __get_cword_at_cursor_by_ref で cur=com になるべき所 cur=' com' になっている様だ。
    % 以下を実行してみると分かる。
    %
    %   COMP_LINE="git com" COMP_POINT=7 COMP_CWORD=1 COMP_TYPE=9 COMP_KEY=9
    %   __get_cword_at_cursor_by_ref ""  words cword cur; declare -p words cword cur
    %
    %   % これは git の bash completion のバグだろうか。
    %
    % COMP_* を何も弄らないと cur="'com'" になっている。
    % 中途半端に弄ったせいで cur=' com' になったのかもしれない。
    %
    %   COMP_WORDS=(git com) COMP_LINE="git com" COMP_POINT=7 COMP_CWORD=1 COMP_TYPE=9 COMP_KEY=9
    %
    % で実行してみた所、ちゃんと実行する事ができている。

    つまり git completion はクォートしていると動かないという事になる。
    これはクォートが要らない場合にはクォートしない様に修正すれば良い。

  * complete: 引用符の中にいる時 addtail で閉じる引用符を入れる [#D0738]
    参照: #D0717

  * ble.pp: bashrc の末尾で自動的に ble-attach するようにできるのではないか [#D0737]

    % 実は trap -- '' RETURN を使えば bashrc 末尾でわざわざ
    % attach を実行する必要がなくなるのでは。
    %
    % x しかし自動的に検出する為には、bashrc の中にいるという事を検出しなければならない。
    %   BASH_SOURCE を参照する方法だと --rcfile を使って bashrc を指定した時に使えない。
    % x history が初期化されているかどうか確認する方法だと、
    %   bashrc の内部で history -n したりしている場合に失敗する。
    % x BASH_ARGC 及び BASH_ARGV を使うとどうなるか。
    %   うーん。普通の source との区別が付かない。
    %
    % 実のところ --noattach の代わりのオプションを作るというのが現実的かもしれない。
    %
    %   source /path/to/ble.sh --auto-attach --rcfile ~/.blerc
    %
    % 等の様な感じにする。もしくは
    %
    %   if source /path/to/ble.sh --auto-attach; then
    %     # ble configuration
    %   fi
    %
    % 実際に bashrc の中に trap RETURN を記述して試してみたが、
    % bashrc の末端で trap RETURN は呼び出されない様だ。
    % trap DEBUG だと全ての行で実行されるので最後を判定できない。

    trap RETURN を使う方法では実現は不可能。

    或いは別の方法としてシェルの起動に使われた bashrc のファイル名が分かれば良いが、
    BASH_ENV には何も設定されていなかった。というかファイル名が分かったとしても、
    "最後に実行した行" を検知できなければ意味がない。。
    →と思ったが、別に bashrc かどうかとかは関係なくて、
      ble.sh がロードされた時の呼び出しスタックで一番浅い所を抜ける時に
      ble-attach を実行する様にすれば良い。

    % 実はそのファイルの行数をカウント wc でカウントしておいて、
    % 一番最後の行を実行した時を DEBUG で検出すれば良いのかもしれない。
    %
    % 試してみた所 RETURN はやはり全然呼ばれない。
    % DEBUG は各行を実行する時に (前か後かは後で確認) 呼び出される。
    % 一番最後に実行される行 (LINENO) は一番最後の行番号である。
    %
    % - 但し、空行やコメントは実行されない。
    % - 一番最後の行の最後のコマンドが \ で分断されている場合は、
    %   そのコマンドの先頭行が一番最後に実行される行である。
    %   (一番最後の行ではなくて一番最後のコマンド)
    % - 一行に複数のコマンドが含まれている場合は、
    %   それぞれのコマンドに対して実行される。
    % - どうも、やはりコマンドを実行する直前に実行される様であるので、
    %   一番最後のコマンドの最後に、というのは難しい。

    trap DEBUG は、コマンドを実行する前に呼び出されるので使えない。

    PROMPT_COMMAND を使えば良いのではないか…。
    しかしこれは多くの distro で変な物が設定される。
    マニュアルに記すとしても角の方に機能を乗せるに届けておくべき。
    少し試して見た限りでは実現できそうな気がする。
    実際に簡単に実装して動けば細かいところまで対応する事にする。

    試して見た限りでは良好に動作しているが、
    何故か知らないが起動直後にジョブが走っている…。
    以下の様なメッセージが表示される。
    [1]   終了                  '/usr/bin/stty' "$@"
    [2]   終了                  tty 2> /dev/null

    しかも初回のコマンド実行時だけである。
    手で local tmp; ble/util/assign tmp 'date' など実行しても現れない。
    取り敢えず ble/util/joblist.flush しておく事にした。

    ところで、そもそも何故 source ble.sh を bashrc の上の方に書くのだったか?
    一番下で source ble.sh をすれば良いのではないか?
    元々は bind を上書きするつもりだったが、実のところ今は未対応である。
    まあ、余り考えない事にする。

2018-08-22

  * 2018-08-05 complete: 補完後の文字列が実は index 以降に続いている時は、 [#D0736]
    それを吸収する形で補完を実行する。

    | ただし、意図しない吸収を防ぐために INSERT が index 以降に
    | 全て揃っている場合にのみ吸収する。つまり部分的に INSERT の
    | 前半部分が続きにあるだけの時には吸収は行わないようにする。
    |
    | うーん。emacs の auto-complete の振る舞いを見ると、
    | もう少し柔軟にしても良いかもしれない…と思ったが、
    | 本当に auto-complete が柔軟に動いているのかどうかは確かめる必要がある。

    これは結局 #D0735 の対応と同時に実装した。
    カーソルの右の文字列が、挿入文字列の先頭と一致する場合、
    また、挿入文字列の末端と一致する場合に吸収を行う。
    SUFFIX (addtail で追記した部分) と INSERT を別々に取り扱い、
    それぞれ吸収を行う様にした。

  * 2018-08-17 auto-complete: vim-mode の繰り返しやマクロとの相互作用 [#D0735]
    ref `#D0724`

    所で… vim-mode の繰り返しの設定だとかマクロだとかとの関係はどうなっているのか…。
    特に自動補完候補の表示だけで繰り返しが無効化されては困るし、
    また、実際に候補を確定した際に繰り返しが無効化されるのも余り良くない。
    マクロに関しては「候補を確定する」という操作が記録されると、
    自動再生の時には自動補完候補が生成されていないのでこれもまた変な事になる。
    この辺りは丁寧に考察する必要がある。

    * 先ず初めに vim-mode の insert の繰り返しについて調べる。

      | これは irepeat もしくは imap-repeat という枠組みで記録され再生される。
      | ble/widget/vi_imap/__before_widget__ を通じて記録が行われる。
      | つまり、実際に処理が実行される前に記録が実施される。
      | white list に登録されていないコマンドが実行された時、
      | 繰り返しは無効化される。
      |
      | さて、現状の auto-complete ではどの様な振る舞いになっているか。
      | 先ず初めに auto-complete はコマンド実行を介さずに勝手に導入される。
      | つまり、繰り返しはキャンセルされないが、補完した文字列が欠ける事になる。
      | 実際に試してみた所確かにそうなる事を確認した。
      |
      | 此処で改めて white list を調べる。
      | 補完によって実行される置換・挿入を
      | white list に登録されているコマンドの組み合わせで実行できるか。
      | 確認してみると delete-backward-char が存在しているので普通にできる。
      | 所で、記録されているのはキーと WIDGET のみなので、引数などは記録できない。
      | 或いは、引数の設定自体も登録してしまうという手もある…
      |
      | と思ったら引数を設定する widget は emacs.sh にしか含まれていなかった。
      | ble/widget/emacs/append-arg である。或いは complete 専用の widget を作るという手もある。
      | KEYS に削除する文字数を指定して、引数に挿入する文字列を指定するなど。
      | というか、KEYS に指定しなくても引数1と引数2に指定すれば良いのでは。。

      もし実装するとしたら

      1. auto-complete 側で挿入時に呼び出す hook を提供する
      2. vi_imap 側で hook を登録する。
        面倒なので hook を外したり入れたりは省略。
        取り敢えずの実装では vi.sh ロード時に入れてそのままにする。
        (或いは keymap initialize/finalize 的な所で実行しても良いが…)

      うーん。確定する時に文字列をどの様に置換したかという情報を使うか。
      「現在位置以前に置換前の文字列がある時に限り置換後の文字列に置換する」という widget にする。
      この widget は complete を vi_imap で実行した時の再生動作としても使う事ができる。

    * というかよく考えたら通常の complete でも vim-mode
      の繰り返しに支障を来すのではないか。
      現状の動作では、補完が途中で行われた場合には繰り返しがキャンセルされる。

      | これに関してはどの様に処理すれば良いか微妙である。
      | white list に登録すると結果として irepeat 配列に登録されてしまうので、
      | 後で削除・上書きするか或いは complete を無効にするか、うーん。
      | それとも complete 自体をそのまま繰り返してしまうという手も考えられる。
      |
      | 一番無難なのは "置換前と置換後を記録しておいて一致する時だけ置換する"
      | という前項の案で出てきた widget に上書きするという物である。
      | もし complete が実行できない場合には complete は削除する。

      1. widget "vi_imap/complete" を定義して、white list に登録する。
        この widget では内部で irepeat に対する操作の上書きを実行する。
      2. complete 側で実際の補完の実行に対して hook できる様にする。
      3. widget を呼び出す際に hook を一時的に設定してから呼び出す様にする。

      うーん。どの様な情報を記録してどう置換するのが良いかわからなくなった。
      特にカーソルの右側に挿入文字列に一致する内容が存在する時の取り扱い。
      元の文字列が action/complete においてどの様な修正を許容するかの問題でもある。
      単に末尾に文字列を追記するという事を仮定しても良いのだろうか。
      或いは、そのような仮定に依存せずに実装する事ができればそれが一番良い。

      問題は前方に hoge.txt があって、挿入文字列が "hoge.txt " だった時に、
      "hoge.txt" を吸収するかどうかという事にある。実際の所、吸収して欲しい。
      しかし addtail で末尾に文字列を追加する可能性を考えると、
      吸収の判定は "末尾一致" ではなくて "途中一致" になる。
      途中一致で給してしまっても問題ないだろうか…。

      吸収の処理を明確にしておく必要がある。

      | * 先ず空白類で区切られている物を吸収して欲しくはない。
      |   例えば挿入文字列が "a\ b\ c.txt" だった時に、
      |   "a@ c.txt" で補完を実行した時に、
      |   "a\ b\ c.txt@" という様に補完するのは不自然である。
      |   元々存在したクォートされていないスペースが、
      |   クォートされたスペースに変換されてしまっている。
      |
      |   一般化すればクォートされていない物をクォートするのは禁止したい。
      |   これを実現するためには挿入文字列に含まれる "正しい区切り目"
      |   の単位で一致するかどうかを判定しなければならない。
      |   しかし、これは実装が煩雑になるしユーザから見て分かりやすいか微妙である。
      |
      |   取り敢えず現状の実装では吸収可能範囲は最初の空白までと定める事にする。
      |
      | * 次に部分一致を吸収するかどうかという事である。
      |
      |   更に吸収すると仮定した時にどの様にそれを判定するかという事。
      |   例えば "hoge.txt " が挿入文字列で、前方に "@ogewaa" があったとして、
      |   これを補完する事によって "hoge.txt@waa" になるという事。
      |   やはりどうも不自然な様に思われる…。
      |
      |   やはり先頭一致か末尾一致に限定したい気がするし、
      |   そちらの方が一致範囲を決定するのが楽である。
      |   うーん。INSERT と SUFFIX を区別するのが自然な気がしてきた。
      |
      |   更に INSERT の吸収と SUFFIX の吸収を別々に実装する。

      結局吸収まで実装した。

    * . による繰り返しの場合には irepeat をコピーする事によって実現されているので、
      irepeat の方さえ正しく登録する様にすれば問題は起こらない。

    取り敢えず実装方針については固まった気がするので一つずつ実装していけば良い。
    実装したので動作確認を行う。

    - 取り敢えず complete と auto-complete のそれぞれについて
      3i<C-[> でちゃんと繰り返される事を確認した。
    - . での繰り返しはどうか→ちゃんと動いている。

  * 2018-08-17 auto-complete: キーボードマクロによる再生の対応 [#D0734]
    ref `#D0724`

    qによるマクロでの自動補完のサポート?
    q によるマクロの場合には、これはキー操作のマクロであると考えれば、
    特に特別な操作は必要ない様に思われる。

    | と思ったが、S-RET が間髪入れずに入力されると厄介な事になる。
    | 実際には delay があってから auto_complete keymap に入って、
    | その時点で S-RET をユーザが押した場合であっても
    | 再生時には delay や idle は実行されないので、
    | 元々の keymap において S-RET が再生されてしまう。
    |
    | vi_imap では既定では S-RET には何もないので単にエラーになる。
    | (#D0733 の修正後に) 実際にその様に振る舞う事を確認した。
    | ユーザが何か S-RET に割り当てている時には尚も変な事が起こる可能性がある。
    |
    | これに対してどの様な方針を考える事ができるか。
    |
    | a 特に対処は行わず単にキーボード操作を再生する。
    |   間髪を入れずに補完確定に使用した S-RET が再生される事により、
    |   補完が実施されなかったり別の操作が実行されたりする事については関知しない。
    |
    | b キーを入力した時の keymap の状態も一緒に記録する。
    |   しかしこれはキーボードマクロを文字列で記録している事と相性が悪い。
    |   これは駄目。
    |
    | c 推測補完 keymap に入る時にそれに対応するキーを仮想的に押す。
    |   特別なキーを用意しておいて ble-decode-key で特別なキーを押した事にする。
    |
    |   或いは、keymap に入るのに ble-decode-key を介して実行する事も考えたが微妙。
    |   推測補完は実際に補完候補が生成されるかどうか分からないので、
    |   最終的に keymap に入った時にのみ key を登録したい。
    |   すると必然的にどの様な補完候補によって keymap に入るのかの情報が確定した状態で keymap に入る事になる。
    |   既に確定した情報を元に keymap に入る様な widget で処理する事になる。
    |   しかしそれだと再生の時に困る。再生の時には自分で候補を見つける様な widget として振る舞いを変えなければならない。
    |
    |   その様に思うのであれば実際に ble-decode-key は実行せずに、
    |   keylogger に外部から手でキーを加えるという様にするしかない。
    |   これは次の d に比べると不自然な実装になるので駄目。
    |
    | d 実は auto_complete keymap にいる時には何もしない様な ble-decode-key を実行すれば良いのでは。
    |
    |   例えば auto_complete という名前のキーを定義して、
    |   keymap:vi_imap から auto_complete キーが押されたら、
    |   推測候補を生成して更に keymap に入る。
    |   keymap:auto_complete で key:auto_complete が押されたら何もしない。
    |   という動作にすれば良い。

    ここは d の方針で実装するというので良いだろう。

    * 特殊キーの名前は考慮の余地はある。

      | 無節操に機能毎にキーを定義するのは憚られるので、
      | 何か名前空間の様な命名規則を使いたい気がする。
      |
      | complete に所属するので寧ろ complete_autocomplete だとか、
      | complete_suggest だとか complete_autosuggest
      | complete_auto など。或いは、comp_auto comp_suggest など。
      |
      | 或いは ac という名前を認めてしまえば、
      | ac_enter だとか ac_suggest だとかでも良い。
      | →今の所 ac は complete_ac_delay だけに使っている。
      |   行く行くはもっと分かりやすい物に変更したい。
      |   従って避けたい。
      |
      | - complete_auto
      | - complete_suggest
      | - complete_auto_enter
      | - complete_ac_enter
      | - comp_auto
      | - comp_suggest
      | - comp_autosuggest
      |
      | うーん。メニュー補完なども考えると、以下の辺りだろうか。
      |
      | - complete_menu_enter
      |   complete_auto_enter
      | - complete_ac_enter
      |   complete_mc_enter
      | - comp_menu_enter
      |   comp_auto_enter
      | - comp_ac_enter
      |   comp_mc_enter
      |
      | 一方で、既に keymap の名称は auto_complete にしている。
      | menu 補完については menu_complete とするだろう。
      | そう考えると auto_complete_enter 等だろうか。

      auto_complete_enter にする事にする。

    - done: auto_complete_enter の定義
      実は明示的に定義しなくても自動的に ble-bind したら kcode が生成される気がする。
      何れにしても core-complete.sh 側で kcode を知っておく必要があるので、
      generate-keycode (.gen-keycode から改名した) は呼び出し置けば良い。

    - ok: _ble_decode_keylog_depth について
      自動補完から ble-decode-key を呼び出した時に
      _ble_decode_keylog_depth による判定はどうなっているか、と思ったが、
      よく考えたら自動補完は idle.do から起動されるので
      _ble_decode_keylog_depth=0 になっている筈で、
      普通に ble-decode-key を呼び出せば記録される様に思われる。

    - done: ble-decode-key による記録

    - done: sync モードの定義。
      ble-complete/auto-complete.impl sync

      複数の手段が考えられる。

      | a comp_type 等に新しい文字を入れる。
      |   [[ $comp_type != *s* ]] && ble-decode/has_input && return 148 等の様に書き換える。
      |   もしくは、頻繁にグロブを呼び出すコストを考えたらループの外側で判定を行って、
      |   何らかの文字列変数に入れて [[ $opt_async ]] && ... とする。
      |
      | b opt_async の様な感じの変数を定義する。
      |   実のところこちらの方が分かりやすいかもしれない。
      |   これまでの comp_type も実はこれにした方が良いのではないかとも思うぐらい。
      |
      |   何故、comp_type に含まれている物を opt_* にしなかったのかについて再度考える。
      |   先ず初めに comp_type に含まれる文字は、親の complete で決まるのではなくて、
      |   呼び出した先の関数で決まる物であるという事。
      |   従って、呼び出し元で local だけ沢山して、
      |   呼び出された先の関数で値を設定するというのは分かりにくい。
      |   更に comp_type は補完関数からも参照される事を意識していた。
      |   やはり同様に補完関数から参照される変数が多いのは分かりにくい。
      |   つまり、comp_type 等に含まれるフラグたちは外部の枠組みから参照される物であり、
      |   インターフェイスを小さくする為にフラグ変数で取り扱ったのであった。

      やはり a の方法で実装する事にした。実装した。

    - ok: よく考えると本当に中断しなくて良いのだろうか。
      例えばマクロ実行中に C-g を押して中断したくなったとする。
      その時に候補生成が中断しないと時間がかかってしまう。

      % また入力時にゆっくり入力した時などに、
      % 1文字入力する毎に auto_complete_enter が記録されるとすると、
      % 実際に入力したときには候補が生成される前に中断されていたとしても、
      % マクロ再生時には候補を最後まで生成してから実行する事になるのではないか。
      % と思ったが、よく考えると auto_complete_enter は候補が最後まで生成されてからしか記録されないし、
      % また続きのキー入力がマクロ上にあったとしても ble-decode/has-input では判定できない。

      特に気になったのは最終的に棄却された自動補完であっても、
      マクロ再生時に再現してしまうのは無意味ではないのかという事だったが、
      これは余り気にしても仕方がない事の様に思う。

      唯一残る問題はマクロ再生を中断できないという事だが、
      考えてみればマクロ再生は元から中断できない。
      この部分を気にするのであればマクロ再生の仕組み自体を考え直す必要がある。

      またマクロ再生を中断する仕組みさえ整えば候補生成は中断する程には遅くない気がする。
      中断しないという現在の実装で良いという事にする。

    実際に動作確認する。

    - 動いている。特に問題もない気がする。

2018-08-19

  * vi-mode: 今気づいたのだが @x による再生がうまく行っていない [#D0733]
    特殊キーがそのまま文字列として挿入されてしまっている…。

    調べてみると再生を行っているのは ble/keymap:vi/register#play で、
    其処ではちゃんと ble-decode-char を呼び出している。
    問題は CSI (M-^[) が単なる文字として通過してしまっているらしいという事。

    ble-decode-char/csi/consume はちゃんと 155 を認識している様だ。
    ble-decode-char/.getent の振る舞いを見ていると、
    "M-^[27;1;1114154" まではシーケンスの続きがあるとしているが、
    "~" が来た時点で ent= になって、シーケンスが不正であるという結果になっている。

    ? ok: 所で 1114154 というのは正しいのだろうか。
      printf '%x\n' してみると 11002a になっている。
      110000 は Unicode の最大値であり、これ以降に特殊キーを割り当てたはずなのでこれは正しい。

    "~" の処理が怪しい。調べるとこれを担当しているのは
    ble-decode-char/csi/.decode である。

    x ok: と、ここで ble_decode_MaskChar でマスクしている事に気づいてしまった。

      % これは後でマスクしない様に修正する必要がある。
      % vim-mode の register#play で特殊キーが再生される事があるという注記付きで。
      % しかしそうだとしても ent= になってしまう事の説明が付かない。
      % もう少し調べる事にする。

      改めて調べてみた所 ble_decode_MaskChar は特殊キーも入っている事が分かった。
      この名前は紛らわしいので変えるべきかもしれない。

    ble-decode-char/csi/.decode で $_ble_decode_csi_args を出録してみたら、
    _ble_decode_csi_args がクリアされていないという事が分かってしまった。
    修正する。

  * 何故か履歴項目の数が倍増している… [#D0732]

    調べてみるとやはり 5c0333e が悪い様である。
    観察してみたがそんなに変更はしていない。
    HISTSIZE を二回変更すると二倍になるという事なのだろうか。
    また調べてみる事にする。

    どうも現状の bashrc を使って調べると 5c0333e の変更を
    戻しても戻さなくても二倍になるのが再現する様である。
    更に、現在の ble.sh を直接 rcfile にすると二倍にならない。
    bashrc の中の記述との関連を調べる必要がある。

    1. どうも histappend が設定されていると2倍になる
    2. histappend が設定されていないと HISTFILE に丸ごと書き込まれる

    結局以下の設定だけで倍加する事が分かった。
    shopt -s histappend がない時には、
    起動時には二倍にはならないが最終的に二倍になる。

    | HISTFILE=A.txt
    | HISTSIZE=100000
    | HISTFILESIZE=100000
    | shopt -s histappend
    | builtin history -n


    * 何故二重にロードされるのか。
      bashrc 内部で history -n を二回実行したとしても三倍になるなどの事はない。
      つまり、bashrc の中ではちゃんと新しく追加された項目を理解している。

    * 不思議なのは何故昔の設定では二倍にならなかったのかという事。

      | →改めて試してみた所、昔の設定でも再現する様だ。
      | と思ったが、間違えて問題が発生し初めた直後の commit で試していた。
      |
      | そう思って古いもので改めて試してみたが、
      | やはり履歴が二倍になる問題は依然として存在する。
      | shopt -s histappend の有無による動作も同じだ。
      |
      | 次に ble-0.1 でも試してみる事にする。
      | ble-0.1 では問題は発生していない。
      | ble-0.2 では問題は発生している…と思ったが、
      | 0.2 は問題の commit よりも後に分岐したのだから当然である。
      |
      | 問題の commit の前でも再現した事から、もっと遡る必要がある。
      |
      | b6815e0 問題なし (master: support-vi-mode マージ前)
      | 32037b9 問題あり (master: support-vi-mode マージ直後)
      | 25db43e 問題なし (support-vi-mode: 最後の master からのマージ)
      | c521012 問題なし (support-vi-mode: 最後の他からのマージ)
      | f894ca5 問題なし (support-vi-mode: 二分法)
      | c0c7f13 問題あり (support-vi-mode: 二分法)
      | 68b1ed5 問題なし (support-vi-mode: 二分法)
      | 48bee3c 問題なし (support-vi-mode: 二分法)
      | f0fcb54 問題なし (support-vi-mode: background load of history 直前)
      | 467dfbd 問題なし (support-vi-mode: background load of history 直後)
      |
      | これだった。これは結構大きな変更だったはず。。
      | うーん。しかし、本質的には (ユーザからの入力がない内は) 違いがない筈だと思ったが…。
      | 調べてみる事にする。
      |
      | と思ったらこれより前の version では
      | bleopt_history_lazyload に空文字列以外が設定されている時に、
      | history の load を遅延するから、bashrc の中では history を初期化していないのだった。
      |
      | 明示的に bleopt_history_lazyload= を指定して先に history を初期化させてみた所、
      | 実は bashrc の中から history を初期化しても問題は発生していないという事が分かった。
      | 何が鍵なのだろう…。
      |
      | 改めてまた確認してみた所、実は古い version ではサブシェルの中で history -n を実行していた。
      | 本体の方では history -n は実行していないのであった。

      結論: 問題が発生し始めたのは idle を利用して history を load する様に変更してから。
        idle を利用する様にする前はサブシェルの中で history -n を実行していたので影響がなかった。

    * さて、ここで考えるべきはサブシェルの中で history -n を実行する様に変更するか、
      或いは、親側で history -n を実行しながらも問題が発生しない方法を探すか。
      どちらにするのが良いのかという事である。

      取り敢えず時間を計測する。10万項目を読み取るのに 0.100 秒かかっている。

      というか落ち着いて考えてみれば今まで倍加していたという事は、
      今までだって二重に履歴を読み込んでいたのである。
      今、親シェルとサブシェルで別々に履歴を読み込み様にしても遅くなる事はない。
      当初想定していた速さにはならないが、面倒なので遅くても良いからサブシェルで読み取る事にする。

2018-08-18

  * 2018-08-15 idle: ble/util/idle でバックグラウンドジョブ待ち機能を実装 [#D0731]
    history の初期化中に別の task が実行できる様になるはず。
    pid を指定してそのプロセスが生きているかどうかで判断する。
    もしくはファイル名を指定してそのファイルが存在するかどうかで判断する。

    実はこれは既存の history のコードを流用すれば簡単に実装できるのではないか。。

    以下の関数を追加した。
    - ble/util/idle.wait-filename filename
    - ble/util/idle.wait-file-content filename
    - ble/util/idle.wait-process pid
    - ble/util/idle.wait-condition command

    idle.do についても整理した。

  * auto-complete: bug bash-4.1 以下で auto_complete keymap に入ると、 [#D0730]
    何を押しても unbound keyseq の状態になる。
    isearch では問題になっていないので何か使い方が違っているという事だろうか…。
    auto_complete という名前の keymap が問題を引き起こしている?
    :isearch を含む関数は ble-decode/keymap:isearch/define しかない。
    これに同等な物は auto_complete に対しても定義している。

    そうすると何処に違いがあるのだろう…。
    そもそも何故 __defchar__ や __default__ が呼び出されないのか…。
    調べてみると _ble_decode_auto_complete_kmap_ にちゃんと登録されていない。
    先ず何故か exit-default が 9 番に登録されている。
    次に self-insert が何処にも定義されていない。
    正常に動作している時には 5 項目登録されているが bash-4.1 以下では 4 項目しか無い。
    恐らく __defchar__ や __default__ が 9 になっていて、
    先に __defchar__ で登録した物が __default__ によって上書きして 4 項目になったのだ。

    では、何故 __defchar__ や __default__ が 9 になってしまうのか。
    また isearch は何故平気なのか。

    どうやら ble-decode-kbd/.get-keycode の連想配列を使わない実装が問題である様だ。
    後、何故か fallback implementation を使う条件判定が恒偽式になっていたので修正した。
    直した。寧ろ今まで何故動いていたのかが不思議であるが…。

  * idle: 矢印キーを押しても is-stdin-ready 判定が偽になって idle.do が止まらない [#D0729]
    一体何が起こっているのか。ble-decode が保持しているキーが残っているという事なのか。
    調べてみると、別に ble-decode がキーを保持しているという訳では無いようだ。

    これは恐らく bash の readline が保持しているのだろう。
    矢印キーに一致するかもしれないシーケンスは Bash が最後まで読み取ってから
    bind で登録された関数を呼び出しているのだろう。
    従って、bind で矢印キーを構成するバイトを処理している時は、
    既に stdin が空になっているので標準入力に何もないと判定されるのである。

    decode の状態を見てキーシーケンスの途中でないかどうかチェックできる様にする必要がある。

    % 特に非 ASCII 文字がキーシーケンスを構成する事はないと考えれば、
    % ble-decode-char の途中状態だけ確認すれば十分である。

    観察した雰囲気では未確定の文字は (CSI であれ登録された物であれ)
    _ble_decode_char2_seq に溜められる様である。
    つまり、_ble_decode_char2_seq を見れば判定できる気がする。

    と思ったが、うーん? どうも ble-decode-byte の方でも
    ESC と M- の区別をする為の仕組みが状態を保持している様子である。
    _ble_decode_byte__utf_8__code これだろうか…。
    調べると _ble_decode_byte__utf_8__mode の方が良い。
    _ble_decode_byte__utf_8__code の方は使用しなくなった文字が残留する様だ。
    さて、_ble_decode_byte__utf_8__mode は現在の input_encoding に依存している。
    従って input_encoding に対する要件を増やして現在の状態を取得できる様にする必要がある。

    % よく考えたら ble-decode-key についても判定しなければならない。
    と思ったが、これについては途中状態であっても、
    ユーザからの入力を待っている状態なので、アイドルの内に入る。
    特に、ユーザが入力した時に一塊になって送信されてくる、
    文字やキーのデコードについてのみ途中状態になっているかどうかを判定すればよいのである。

  * auto-complete: 既にカーソルの右に内容が入力されている時にわざわざ表示しない? [#D0728]

    と思ったが、カーソルの右が第一候補に厳密に一致している場合にだけ自動補完を無効にしても、
    カーソルの右が第二候補以降に厳密一致している場合には対応できないし、
    或いは、"何れかの候補に厳密一致している場合には自動補完しない" という事にしても、
    本当に補完したい時に候補が出てくれず困るという事も考えられる。

    思うに、オーバーレイではなくて挿入して表示してしまっているから振動してうるさいのである。
    後、振動してうるさいという事を考えるのであれば、
    やはりカーソルの右が厳密に一致している場合に限り自動補完を無効にするというので良い気がする。

  * bugbash: POSIXLY_CORRECT に触るだけで bind -x C-i が無効になる謎 [#D0727]
    ref #D0726

    Bash-4.2 -- 5.0 で ble.sh の中で再現する。
    unset POSIXLY_CORRECT をすると起こる。
    bash --norc においては未だ再現はできていない。

    * bind -x '"\x89": ...' と bind -x '"\x9": ...' を同時に設定しても何も起こらない。

    * cache.d/$UID/ble-decode-bind.40419.UTF-8.bind をコピーして来て、
      末尾に以下の関数を追加して、bash --norc から source しても再現しない。

      function ble-decode/.hook {
        echo ble-decode/.hook: $1
        if (($1==4)); then
          # C-d で終了する
          echo exit
          exit
        elif (($1==20)); then
          # C-t で unset POSIXLY_CORRECT を実行する
          local POSIXLY_CORRECT=y
          unset -f echo
          unset POSIXLY_CORRECT
        fi
      }

      もしかすると stty と相互作用している可能性もある。
      更に stty/enter やら uvw やら加えてみたが再現しない。

    * ble.sh 本体の ble-decode/.hook を上記の様に書き換えてみた所再現した。
      結局以下のコードにまで縮小する事ができた。
      D0726.bind.source1 は bind -r が並んでいるファイルで、
      D0726.bind.source2 は bind -x が並んでいるファイルである。

      | function ble-decode/.hook {
      |   echo ble-decode/.hook: $1
      |   if (($1==4)); then
      |     echo exit
      |     exit
      |   elif (($1==20)); then
      |     local POSIXLY_CORRECT=y
      |     unset -f echo
      |     unset POSIXLY_CORRECT
      |   fi
      | }
      | source D0726.bind.source1
      | source D0726.bind.source2

      更にこれを元に再現する rcfile を作成する。
      其処からどんどん縮めていくと結局上のコードに加えて
      以下の二つのコマンドさえあれば再現する様だ。

      | set -o vi
      | shopt -s no_empty_cmd_completion

      更に縮めると結局以下のコマンドで再現した。
      どうやら set -o vi だけでしか起こらない様だ。

      set -o vi
      bind -x '"\C-t": unset POSIXLY_CORRECT'
      bind -x '"\C-i": echo C-i is pressed'

    * 試してみると bind -x でなくても生じるようだ。

      $ bash --norc
      $ set -o vi; bind '"\C-i": "echo hello"'
      $ echo hello   # <---- echo hello is inserted by typing C-i
      hello
      $ declare -p POSIXLY_CORRECT; unset POSIXLY_CORRECT
      bash: declare: POSIXLY_CORRECT: 見つかりません
      $
      Display all 4915 possibilities? (y or n)
      $

    * 取り敢えずバグ報告を書いてみる。

      % Subject: Why `unset POSIXLY_CORRECT' unbinds the key `\C-i' in the `vi-insert' keymap?
      % Subject: [PATCH] Fix the bug that `unset POSIXLY_CORRECT' unbinds the key `\C-i' in vi-insert keymap.
      %
      % Here I show a reduced case. With the following settings:
      %
      %   $ bash --norc
      %   $ set -o vi
      %   $ bind '"\C-i": "echo hello"'
      %   $ bind -s
      %   "\C-i": "echo hello"
      %
      % the string "echo hello" can be inserted by typing TAB.
      %
      %   $ echo hello
      %   hello
      %
      % However, after "unset POSIXLY_CORRECT" is executed, TAB loses its custom binding.
      % Then the readline function `complete', the readline default, is invoked by TAB.
      %
      %   $ unset POSIXLY_CORRECT
      %   $
      %   Display all 4915 possibilities? (y or n)  <----- Here I typed TAB twice
      %   $ bind -s                                 <----- Now nothing is output
      %   $
      %
      % This behavior is reproduced in all the versions of Bash, that I tried, from 3.0 to the devel branch.
      % The behavior can also be reproduced by `f1() { local POSIXLY_CORRECT; }; f1' instead of `unset POSIXLY_CORRECT'.
      % The behavior is not changed regardless of whether the shell variable `POSIXLY_CORRECT' is initially set or not.
      % The behavior is only reproduced for `\C-i' (TAB) but not for other key sequences.

      結局、バグというよりは仕様と諦めるしかない感じだという事が分かったので報告はしない。

    * bash の中に入る。

      unset POSIXLY_CORRECT は
        unset_builtin を呼び出す。
          更に unbind_variable が呼び出されて、
            makunbound が呼び出される。
              更に stupidly_hack_special_variables の中から
                sv_strict_posix が呼び出される。
                  posix_readline_initialize (posixly_correct = 0);

      何と明示的に C-i が上書きされている…。

        /* Change the readline VI-mode keymaps into or out of Posix.2 compliance.
           Called when the shell is put into or out of `posix' mode. */
        void
        posix_readline_initialize (on_or_off)
             int on_or_off;
        {
          if (on_or_off)
            rl_variable_bind ("comment-begin", "#");
        #if defined (VI_MODE)
          rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap);
        #endif
        }

      うーん。これは微妙だ。
      つまり、POSIXLY_CORRECT は一時的に有効にしようとしても
      それに応じてシェルの設定を書き換えてしまうので後遺症が残る。
      「一時的に有効にして元に戻したら上書きした設定も元に戻る」
      という様にするのはこの様な実装では難しい。

      % これは諦めるしかなさそうだ。
      % また、これを見る限りは、ユーザが一時的に POSIXLY_CORRECT を弄った場合でも
      % binding が失われてしまうので、それに対する対策をしなければならない。

      或いは…元々刺さっているのが rl_insert の時には rl_complete にし、
      元々束縛しているのが rl_complete の時には rl_insert にする、
      というように条件判断を加える事はできないだろうか。
      つまり、デフォルトの束縛の時のみに切り替える様にする。

    * bash を直してみた。

      動作確認。基底の束縛ではちゃんと切り替わっている。
      ユーザの設定した束縛はちゃんと保持されている。

      $ bash-dev --norc
      $ set -o vi
      $ bind -ps | grep C-i
      "\C-i": complete
      $ POSIXLY_CORRECT=
      $ bind -ps | grep C-i
      "\C-i": self-insert
      $ unset POSIXLY_CORRECT
      $ bind -ps | grep C-i
      "\C-i": complete
      $ bind '"\C-i": "echo hello"'
      $ echo hello
      hello
      $ bind -ps | grep C-i
      "\C-i": "echo hello"
      $ POSIXLY_CORRECT=
      $ bind -ps | grep C-i
      "\C-i": "echo hello"
      $ unset POSIXLY_CORRECT
      $ bind -ps | grep C-i
      "\C-i": "echo hello"

    * 現状では ble.sh の対策は不完全だという事が分かったので修正を行う。


2018-08-17

  * decode: 何故かコマンド実行後に vim-mode において TAB が効かなくなる [#D0726]
    初め complete の問題かと思ったがそうでも無いようだ。後で対処する。

    [原因]

    | どうも調べてみた所、少しでも POSIXLY_CORRECT に触ると問題が発生する。
    | 先ず初めに関数内で unset POSIXLY_CORRECT すると駄目。
    | 関数内で local POSIXLY_CORRECT しても駄目。
    | 関数内で local POSIXLY_CORRECT してから unset POSIXLY_CORRECT しても駄目。
    | Bash-4.2 -- 5.0 まで同様に問題が再現する。
    | (Bash-4.1 以下は別の問題によって確認する事ができなかった。これは後で)
    |
    | さて、表面上は POSIXLY_CORRECT が定義されていなければ
    | 何も問題は起こらない様に見える。
    |
    | もう少し調べる。
    | ble.sh (bashrc 時に評価) に直接 unset POSIXLY_CORRECT を書いても問題は生じない。
    | ble.sh (bashrc 時に評価) で関数内から unset POSIXLY_CORRECT としても問題は生じない。
    | ble.sh (bashrc 時に評価) で関数内から local POSIXLY_CORRECT=y; unset POSIXLY_CORRECT としても問題は生じない。
    | ble-attach の直後に関数内から local POSIXLY_CORRECT=y; unset POSIXLY_CORRECT とすると再現する。
    | ble-attach の直後に直接 unset POSIXLY_CORRECT とすると再現する。
    | ble-attach の直前に unset POSIXLY_CORRECT としても再現しない。
    | ble-decode-attach; ble-decode-detach すると回復するという事が分かった。
    |
    | どうも POSIXLY_CORRECT を少しでも触ると bind -x \t が壊れる様である。

    これは明らかに bash のバグである。しかも未だ修正されていない。

    [対策]

    取り敢えず unset POSIXLY_CORRECT の直後に再度 bind する事にすれば一応回避できる様だ。直した。

    [報告]

    Bash に報告する為にもう少し調べる事にする。
    先ず初めに bash --norc で再現させられるか。

    $ bind -x '"\C-i": echo C-i is pressed'
    $ unset POSIXLY_CORRECT
    $ function f1 { local POSIXLY_CORRECT=y; unset -f echo; unset POSIXLY_CORRECT; }
    $ bind -x '"\C-t": f1'

    うーん。再現しない。ちゃんと bind は有効である。
    上記の様に直接 unset POSIXLY_CORRECT としても、
    bind -x の内部から unset POSIXLY_CORRECT としても問題は再現しない。

    * bind -x '"\t": ...' でも '"<生のtab>": ...' でも問題は発生しない。

    * bind -x の中から直接 unset POSIXLY_CORRECT したらどうなるか?

      $ bind -x '"\C-t": unset POSIXLY_CORRECT'

      これで C-t を押してみたが、それでもちゃんと C-i は無効になっていない。
      stty 等の兼ね合いもあるのだろうか…。しかし、そうだとすると bind で直るのも変な気がする。

    うーん。謎だ。

    * 他に気になるのは、問題が起こっているのは本当に C-i だけなのだろうか。という事。
      調べてみた所取り敢えず日本語は入力できる様に見える。他に C0 制御文字も C-i 以外は全部大丈夫だった。

  * core: ble/util/isfunction func && func ... を関数にできるのでは [#D0725]

    ble/util/calliffunc 的な名前の関数で。
    これだと繋がっていて単語の切れ目が分からない。
      ble/util/call-if-func
      ble/util/call-iffunc
      ble/util/callif-func
      ble/util/callIfFunc
      ble/util/call-if-function
      ble/util/call-if-fun
    もっと良い動詞はないだろうか。存在する時だけ呼び出すという事が分かる様な。
      ble/util/try-call-function
      ble/util/try-function
      ble/util/try-fun
      ble/util/function#try
      ble/function#try
      ble/fun#try
      ble/function#callif
      ble/function#call-if
      ble/function#checked-call
      ble/function#check

  * 2013-06-06 complete: 入力する側から候補を表示? [#D0724]

    2018-08-17 取り敢えず履歴からの autosuggestions ではなくて、
    現在の位置で補完を実行した時の候補を表示する事にした。

    | 実装しなければならないもの。
    |
    | 1 候補を生成する部分を既存の ble/widget/complete から分離。
    |   取り敢えず関数を分けた。
    |
    |   * reject: 曖昧一致を無効にする必要がある。
    |     →これについては、曖昧一致になっていても候補を表示する事にした。
    |
    | 2 complete 途中状態の keymap
    |   これは実装した。region 着色の設定も行った。

    取り敢えず実装した。

    x fixed: 何故か完全一致しているのに候補が表示される…
      完全一致時を条件判断から抜いたら次の else に入っていた…。直した。
    x fixed: 候補が表示されると入力ができない?
      return の位置を間違えていた…。直した。
    x fixed: 毎回候補が再表示される?
      _ble_complete_ac_ins や _ble_complete_ac_word の取扱を調整した。
    x fixed: accept した時に _ble_edit_{ind,mark} が範囲外になる。
      ちゃんと調整するのを忘れていた。直した。

    * done: addtail 迄実行するべき。

    * done: 関数名の縮約を起こさない様にするべき。
      bleopt_complete_contract_function_names 変数を追加した。
      →実際にやってみた所、動作として微妙。
        やはり / 毎に候補を生成した方が使いやすいのではないか…。
        分からないが取り敢えず今の状態で使ってみる事にする。

    * done: 後気づいた事は曖昧一致の時には候補は縮約するべきでない気がする。
      対応した。

    * done: auto suggestion の場合 check-here による候補生成はしない方が良いのではないか。
      現在 generate では check-here と chek-prefix の両方で生成を行っている。
      generate を contexts 生成部分と、実際に generate する部分に分けるべきなのではないか。

      これは以下の二つの関数を新しく作成して、
      呼び出し元でほしい文脈の種類に応じて呼び分ける事にした。
        ble-complete/candidates/get-contexts
        ble-complete/candidates/get-prefix-contexts

    * done: completion-context 関数の関数名を
      ble-syntax/completion-context/generate に変更した。

  * 2013-06-06 [自然解消] ble-line-info の描画のタイミングを ble-edit-draw.update と同じ時にする? [#D0723]
    それ以外の時に描画したければ、必要に応じてその場で明示的に描画させる。

    2018-08-17 これは古い項目である。
    現在ではその様な実装になっている筈。いつか自然解消した。

2018-08-15

  * 2018-08-13 どうやら POSIXLY_CORRECT を使えば unset 上書きを防御できる様だ [#D0722]
    https://stackoverflow.com/questions/35916983/how-can-you-use-pure-unset-shell-builtin-can-you-write-shell-scripts-that-are-i

    試してみた所 POSIXLY_CORRECT=1 unset -f ... を使って unset 関数を削除できる。
    但し、POSIXLY_CORRECT=1 自体が POSIX 通りに環境に残り続ける所まで振る舞いとして一致している。
    なので明示的に unset POSIXLY_CORRECT をする必要がある。

    また、POSIXLY_CORRECT が設定されていると、ble.sh が動かなくなるので、
    元から POSIXLY_CORRECT をキャンセルする様にする必要はあった。
    POSIXLY_CORRECT も IFS 等と同様に記録する必要がある。
    特に unset/set 状態も記録する必要がある。

  * complete: 自動補完2 ble/util/idle 拡張 [#D0721]

    現在の idle の枠組みを拡張する必要がある。
    現在の枠組みだと各タスクについて処理が終わるか
    ユーザの入力によって中断されたかの二通りしかない。
    ユーザの入力によって中断された場合には即座に
    idle 処理自体を中断している。

    今何が必要だろうか。

    * done: ring の様な物は欲しい。

      優先順位は配列 _ble_util_idle_task に登録する番号の範囲で実現する事にした。
      現在の仕組みでは配列の添字の番号の若い方から順に調べて行って実行している。
      従って、優先順位が低い物を後ろに配置しておけばそれは自然に他の処理が全て終わってから実行される事になる。
      今後、処理を実行している途中でも task を中断して他のプログラムが動く様にする場合でも、
      添字の番号について条件判定などする様にすれば簡単に対応する事ができるはずである。
      配列を複数作るよりもずっとすっきりした実装になるのでこれを採用する。

    * done: 定期的に task を中断する機能?

      | 今までの処理では最優先の task しかなかった。
      | 従って、そのタスクが終わる迄制御を専有しても自然だった。
      | 今は優先度の高い ring にタスクが投入されたらそちらを先に実行する様にしたい。
      | 従って、定期的に task を中断して優先度の高い物がないかどうか確認したい。
      |
      | と思ったが、よく考えたら task を実行している途中に
      | 優先度の高い task が勝手に追加されるという事は考えにくい。
      | その様に考えると、実は ring を複数作るだけで、
      | 後は各 ring の task を回し続ければ良いのでは。

      これは今の所は必要にならないので実装しない。
      というか実は ble_util_idle_status に R を設定して
      return すれば良いだけかもしれない。
      その機能だけ実装した (ble/util/idle.continue)

    * done: sleep の実装が欲しい。

      [機能の議論]

      sleep 時間の記録方法と時刻の設定方法。

      | 1 時刻の計測方法
      |   先ず時刻で測るのか、時間で測るのか。
      |
      |   時刻で測るとすると保証できるのは date であり秒単位である。
      |   GNU coreutils の date だとミリ秒までは少なくとも分かる。
      |   Linux だと /proc/uptime の最初の列により 10 ミリ秒まで分かる。
      |
      |   調べると /proc/driver/rtc という物もあるようだ。
      |   https://stackoverflow.com/questions/5242296/how-can-i-get-system-time-from-a-proc-file
      |   と思ったが、実際に見てみると全然 microseconds の情報はない。秒までしか分からない。
      |
      |   仕方がないので遅延も考慮に入れて ble/util/sleep に指定した時間の和で実装し、
      |   定期的に /proc/uptime 等を参照して較正するという方法を用いる事にする。
      |   特に較正は後回しで良い。
      |
      | 2 sleep の指定方法。
      |   ble/util/idle.set-sleep を呼び出してそのまま return する?
      |   return はしなくても良いかもしれない。
      |   特別な終了ステータスを使う事も考えたが、
      |   結局 sleep 時間を別に指定しなければならない訳で、
      |   そうしたら、sleep 時間が設定されているという事だけで、
      |   終了ステータスを見なくても sleep が要求されているという事が分かるから。
      |
      |   sleep を指定したとして、それをどの様に記録するか。
      |
      |   a 例えば _ble_util_idle_task の配列に入れる文字列を
      |       "数字:何とか"
      |     の形にする等すれば良いだろうか。そうすると、現在走っている物についても、
      |     区別が付くように "R:command" という形式に変更する必要がある。
      |
      |     現在の実装では _ble_util_idle_task 配列は完全に隠蔽しているので、
      |     変更は局所的で済む。
      |
      |   b その他の方法としては別の配列に状態を記録するという物もある。
      |     然し、これは管理が面倒であるし、bash 配列の効率が悪い使い方になっている。
      |
      |   c 或いは、状態毎に配列を作成するという手もある。
      |
      |   実行しているタスクが増加して来た場合には、
      |   効率の問題から、状態毎に配列を作成するのが良さそうであるが、
      |   今の所は一つの配列で管理した方が楽である様な気がする。
      |   特に、状態毎に配列を分けるという様にすると、
      |   配列を移動したりなどの面倒な処理を実装する必要がある。
      |
      |   つまり、取り敢えずは a の方式で良いのではないだろうか。

      [実装方法の議論]

      取り敢えず最初に sleep を実装する事にする。

      | どの様にしたら良いのかで一番難しいのが時刻の分解能が低い時にどのように調整を行うかである。
      | 特に自分自身が呼び出す sleep の時間の積算によって時間が多少測る事ができるので、
      | それを使って待ち時間を計測しつつも、それだと遅延が起こるので
      | 分解能の低い時計によって修正を行って時間を測る。
      |
      | と言っても分解能の低い時計でどの様に修正する事ができるだろうか。
      |
      | a 例えば一つの方法としては基本の時計として sleep の積算を使用して、
      |   同時に低分解能の時計を用いて遅延が検出できたらその分時計を進めるという方法である。
      |   この方法の問題は sleep を設定した直後に遅延が検出されて時計の針が進められると、
      |   sleep の時間が縮まってしまう事にある。
      |
      | b その様に考えると各 sleep について遅延を検出したら時計の針を進める、
      |   というようにした方が良いのではないだろうか。
      |   では各 sleep について計測するにはどの様にしたら良いか。
      |   先ず、sleep を呼び出してからの ble/util/sleep の積算がある。
      |
      |   要するに秒 (低い方の解像度) が2回以上変化した後は、
      |   低解像度の時計によるチェックを行うという事?
      |
      | うーん。sleep 時間の表現をどの様にすれば良いのか。
      | 一つの方法は S<終了時刻ミリ秒> だったが、
      | これだと厳密に測るのが難しい。
      |
      | もう一つの方法は S<終了時刻(sleep累積)> だったが、
      | これだと sleep 累積の較正時に跳びが生じてしまう問題がある。
      |
      | うーん。sleep 時間の長さに応じて種類を変える?
      | 1秒以上の sleep の場合には較正を受ける事にして、
      | 1秒未満の sleep の場合には較正を受けない事にする。
      | 較正を受ける sleep に関しては S<絶対時刻> にして、
      | 較正を受けない sleep に関しては s<sleep累積> にする。
      |
      | sleep 累積に関してはその idle ループの初回には
      | 何らかの仮定を置かなければならないので、
      | 実際に秒の目盛りが変わった瞬間にその仮定をシフトできる仕組みを整えると良い。
      |
      | 例えば最初に initial_offset=0.5 で始めて、
      | そこから accumulated_sleep を累積する。
      | 最初に秒が切り替わった時に shift = 1.0 - accumulated_sleep だけ "シフト" を実行する。
      | "シフト" 後には全ての <終了時刻> は shift だけ加算して考える。
      | また sleep を登録する時には shift だけ引き算して登録する。
      |
      |
      | - sleep 累積のカウンタを作る。
      |   これは一つの idle.do 呼び出しに対して毎回独立にカウントする。
      |   (idle.do と idle.do の間の時間間隔が分からないので)
      |   つまり、毎回リセットする。
      |
      | - sleep 累積カウンタを参照して秒以下を拡張した時計を作る。
      |   前回の秒切り替わり時の sleep 累積カウンタを記録する。
      |   実はここで shift を入れてしまっても良いのでは。
      |
      | - sleep 累積カウンタをできるだけ正確に測る為に、
      |   平均の sleep 一回辺りの遅延時間も計測する?
      |   然し、実際の処理時間の分布はどうなっているだろう。
      |   重い処理が一回走ると過剰評価になるなどの事だと困る。
      |   結局難しいのではないか…。

      [実装]

      * 初めから二種類の sleep を区別する事にした。
        実際の時計に基づく sleep と、アイドル時間に基づく sleep。

        前者の sleep に関しては、以下の様な状況に於いて
        実質的に sleep 時間が短くなり実行されない事があることに注意する。

        - 実際の時計に基づく sleep は高精度の時計が利用できない時がある。
          その場合にはアイドル時間を用いて秒単位以下をできるだけ再現しようとするが、
          ずれがあるので時計自体の値が元々の精度以下で跳んだりする事がある。

        - 重い処理が走るなどして時間が経過した時。

        後者の sleep に関しては、アイドル状態にならなければ幾らでも実行の遅延が長くなる可能性があるが、
        必ず或る一定以上の sleep を入れる事が望ましい場合に使う。

      * アイドル時間については ble/util/sleep
      * 実際の時計についてはできるだけ軽量な方法でシステムから取得する。
        精度が足りない場合はアイドル時間を併用する。
        軽量な手段がない場合にはアイドル時間で代用する。

        Note: 因みに ble/util/sleep は 4.0 以上で read -t 0.1 (例) を使う。
          ble/util/idle の実現に使う polling (read -t 0) も 4.0 なので、
          今回の場合には常に ble/util/sleep は軽量な方法で実装されていると考えて良い。

      取り敢えず実装した。

      [動作確認]

      時計を動かすサンプルで確認した。
      初め動かなかったが幾つか修正したら動く様になった。

    * done: 割り込み待ち状態というのも欲しい。

      | 例えば補完が終了した状態になったとすると、
      | 暫くは処理をしなくても良いが、
      | sleep で定期的にチェックするのも変である。
      | 何かのイベントが起こったら再びチェックするという様にしたい。
      |
      | と思ったが、取り敢えずの所は毎回 idle で順番が回ってきた時に
      | チェックして未だだったらスキップするというので良い様な気もする。
      | 本当だろうか。例えば同じリングに A, B, C が登録されているとして、
      |
      | 1. A を呼び出して条件が満たされていないのでスキップ
      | 2. B の処理を暫くしてその後で待機状態になる
      | 3. C を呼び出すが条件が満たされていないのでスキップ
      |
      | と処理をした時に、B の処理をしている間に A 条件が満たされているかもしれない。
      | 従って、再び A, B, C とループを回したい。
      | かと言って無限ループにすると高頻度で割り込みをチェックする事になり非効率的だ。
      |
      | うーん。結局 sleep で定期的にチェックするという実装になるだろうか。

      →これは sleep で処理する。
      次のユーザ入力が来るまでは絶対に再起動しないと分かっている場合には、
      sleep 0.010 の様な物が無限に続くのは効率が悪いので、
      そういう状態を作成するのが良いのではないか。

      例えば "I:command" の様にする。

      これは実装した。動作未確認。

    * 他にサブシェルをバックグラウンドで実行している間待つ、
      という実装を考えても良いが今の所は後回し。

      これを実装すれば history の subshell を実行している間に、
      core-complete ロード等の処理を継続することができるはず。

2018-08-13

  * complete: 自動補完1 LASTWIDGET [#D0720]

    取り敢えず LASTWIDGET は実装する事にする。

    | LASTWIDGET の実装方法とし複数を考える事ができる。
    | 基本的には一番最後に呼び出された ble/widget/* であるが、
    | "呼び出す" というのはどういう事かというのが問題になる。
    |
    | 1 例えば、或る ble/widget/* の中で別の ble/widget/ を呼び出した時にはどうするのか。
    |   次回の widget において、呼び出し元の widget を LASTWIDGET とするのか、
    |   それとも一番内側で呼び出した widget を LASTWIDGET とするのか。
    |
    | 2 またマクロによって呼び出した ble/widget の場合にはどうするのか。
    |   マクロ実行後に LASTWIDGET をどの様に設定するのか。
    |   例えば、マクロ内部で一番最後に呼び出した widget を LASTWIDGET にするのか、
    |   それとも、マクロの呼び出し自体を LASTWIDGET とするのか。
    |
    | 3 マクロ実行に関しては、更に別の観点からも LASTWIDGET をどうするかがある。
    |   マクロ内部で呼び出される widget から見える LASTWIDGET は何なのか。
    |   マクロ実行の開始直前の widget なのか、
    |   それともマクロ内部で直前に呼び出された widget なのか。
    |
    | これを考えるためにはどのような用途で LASTWIDGET が必要になるのかという事を考えれば良い。
    |
    | 1 一番よくありそうなのは行移動の場合である。
    |   連続する下カーソルによる移動の時には移動を開始した時の列の位置が保持される。
    |   途中で短い行があって列が左に移動したとしても、再び長い行に移動した場合には、
    |   元々の列の位置を回復する。
    |
    |   これを実装するためには「連続する行移動」を判定する必要があって、
    |   そのために LASTWIDGET を参照する。
    |
    | 2 今回必要になるのは auto complete をどの様に起動するかである。
    |   直前が文字入力の時または明示的な要求がある時に限って auto complete を起動したい。
    |   カーソル移動などをした先で毎回 auto complete が起動していたのではうるさい。
    |
    | 思うにこれらの用途であれば ble/widget/ の内部で
    | 正式に (実装の間借りなどではなく) コマンドとして widget が呼び出されたのであれば、
    | それを LASTWIDGET に設定して良いという気がした。
    | 例えばマクロの場合には中で呼び出される一つ一つのコマンドに対して全て LASTWIDGET が更新される。
    | 或いはユーザに依る widget の実装が複数の既存の widget を呼び出す事によって実装されるならば、
    | その呼び出された個々の widget において LASTWIDGET が更新されるという様にする。
    |
    | これだと auto complete がマクロの実行直後に起動されて妙な気もするが、
    | しかし一概に auto complete が起動されない方が自然とも決めがたい。
    | LASTWIDGET の種類に複数あったり条件によって振る舞いが変わったりするようなのだと、
    | 何だかよくわからない事になってしまうので、ここでは明快さを取って、
    | 内部で呼び出される場合にもちゃんと LASTWIDGET を更新するという実装にする。

    [仕様]

    - マクロ内部で呼び出されたコマンドによっても LASTWIDGET は設定される。
    - widget から ble-decode の手続きによって呼び出されたコマンドによっても、
      LASTWIDGET は設定される。

    Emacs でどのような振る舞いになっているかについても改めて確認しておく。
    - this-command, last-command, real-last-command がある。
    - (call-interactively ...) で呼び出せば last-command が更新される
      …というような事だったと思う。

    [現状の実装]

    現状の実装についても確認しておく。
    特に WIDGET= を含む関数について確認すれば良いだろう。

    | ble-decode には以下の三つの関数が存在している。
    | - ok: ble-decode-key/.invoke-command
    | - ok: ble-decode-key/.call-widget
    | - ok: ble-decode/invoke-widget -> ble-decode/widget/call-interactively
    |
    |   うーん。これらの関数の使い分けについて考える。
    |   ble-decode/invoke-widget は vi.sh から使われている。
    |   特に bracketed-paste の実装から使われている。
    |   ble-decode-key/.invoke-command は内部から使われている。
    |   キーシーケンスが完成した時にそれに対応するコマンドの呼び出しに使われる。
    |   ble-decode-key/.call-widget は内部から使われている。
    |   _ble_decode_{key,char}__hook 経由の呼び出しで使われる。
    |
    |   | ble-decode-key/.invoke-command | DB |
    |   | ble-decode-key/.call-widget    | DB |
    |   | ble-decode/widget/invoke       | B  |
    |
    |   - D: keylog depth の更新を行う。内部では keylog は実行されない。
    |     invoke-widget において depth の更新がないのは、
    |     invoke-widget はそもそも widget の中から呼び出される事を想定しているので、
    |     既に keylog depth は設定されている筈だから、わざわざ更新しなくても良いという事である。
    |
    |   - B: __{before,after}_widget__ の呼び出しも行う。
    |     これは keymap 特有の設定である。
    |     何故 ble-decode/widget/invoke で必要なのかは不明。
    |
    |   取り敢えず整理した。関数名も多少変えた。
    |   ble-decode/invoke-widget は ble-decode/widget/call-interactively に改名して、
    |   他に hook を実行しない物として ble-decode/widget/call を追加した。
    |
    | ble-edit
    | - done: ble/widget/quoted-insert.hook
    |   WIDGET を self-insert に上書きして self-insert に委譲している…。
    |   始末が悪いので ble-decode 側の関数を経由して呼び出す様にした方が良いか?
    |   これについては後で考察する事にする。
    |   →やはり self-insert は内部で WIDGET を触っていないので、
    |   わざわざここで self-insert を WIDGET に設定する意味がない。単に削除した。
    | - done: ble/widget/bracketed-paste.proc
    |   同様。これは処理を軽くする為に一回設定すれば OK な様にしている。
    |   実は self-insert の方を改良して複数の文字を処理できる様にしても良いのでは。
    |   という気もする。と思ったが、下手に実装を変えるのも面倒そうだ。
    |   というか、そもそも self-insert を呼び出すのに WIDGET を設定している理由は何だったのか…。
    |
    |   これらの関数の中では WIDGET は参照されていない様に見える。
    |   何らかの hook が呼び出されるという事もないので、
    |   別の関数から参照される可能性もない。
    |   何故 WIDGET が設定されているのだろうか。
    |   これは vi.sh における同等の処理との対称性から無駄に設定されているだけだろうか。
    |
    |   →これも self-insert を呼び出しているだけなので WIDGET を設定する必要はない。
    |
    | keymap/emacs.sh
    | - ble/widget/emacs/bracketed-paste.proc
    |   これは上記と同様である。
    |   safe map の物と何が違うのかと思ったら、どうも update-mode-name を実行するという事の様だ。
    |   他には特に機能はない。
    |
    |   * fixed: 何と emacs の bracketed-paste mode で二重に挿入するバグだった。
    |     結局 ble-edit.sh の brackated-paste.proc を呼び出すのであるから
    |     此処で self-insert を呼び出す必要は最早ないのであった。
    |     従って、そもそも WIDGET に此処で触る必要もなかった。
    |     修正して別のコミットにした。後で 0.2 にも適用する。
    |
    | keymap/vi.sh
    | - done: ble/keymap:vi/imap-repeat/process
    |   これはまあマクロの呼び出しと思って良い。
    |   invoke-widget か何かを経由して呼び出す様に変更したい。
    |   速度が気になるかもしれないが後で考える。
    |   これは ble-decode/widget/call を用いて実装する事にした。
    |
    |   x fixed: 動作確認をする。と思ったら ble/widget/ble/widget が呼び出されてしまう。
    |     仕様を変更する事にした。今までは内部で ble/widget/ を付加していたが付加しない。
    |     ble-decode/widget/call{,-interactively} ではフルの関数名を受け取る事にする。
    |
    |   o 取り敢えず動作するという事を確認した。
    |
    | - ok: ble/keymap:vi/imap/invoke-widget
    |   これは何だろう…。
    |   これはどうやら bracketed-paste から呼び出す為に使用している。
    |   ble/keymap:vi/imap-repeat/push を呼び出す invoke-widget である。
    |   一方で、quoted-insert などからも使えそうに見えるが使っていない。
    | - done: ble/widget/vi_imap/quoted-insert.hook
    | - done: ble/widget/vi_imap/bracketed-paste.proc
    |   これらは上記の通り ble/keymap:vi/imap/invoke-widget 経由で実装できそう。
    |   後で確認をして実装を切り替える。
    |   →bracketed-paste.proc に対してはは速度低下を防ぐために
    |     invoke-widget-charwise という関数を追加した。
    |
    | - done: ble/keymap:vi/repeat/invoke
    |   コマンド . による繰り返し。これは大分特殊だ…。
    |   一番最後に ble-decode/invoke... 経由で呼び出せる様にできるかもしれない。
    |   うーん。個別に LASTWIDGET を設定するか、ble-decode の関数を呼び出して設定するか微妙。後で考える。
    |
    |   中で KEYMAP 等の変更がある。ble-decode/widget/call を使うと現在の keymap が使用されてしまうので、
    |   結局自分で全部設定した方が良さそうである。自分で LASTWIDGET の設定を行う事にした。
    |
    | - ok: ble/keymap:vi/commandline/__before_command__
    |   これは cmap でキャンセルをするために WIDGET= としている。考えなくて良い。
    |
    |   * done: これは ble-decode 側でキャンセルする為の関数を用意した方が良いのではないか。
    |     そんなに重い処理でもないので関数化して良いだろう。
    |     また、ble-decode 側で処理をキャンセルするという仕組みを明示的に提供するべき。
    |     後々の変更で WIDGET= をキャンセルと見做すという仕様が曖昧になると行けないので。
    |
    |     また Wiki で WIDGET= でキャンセルできるという事を言及していたかもしれないと思ったが、
    |     確認してみた所 WIDGET の設定に関しては元から言及が無い様である。OK
    |
    |     というか改めて調べてみた所 ble-decode 側では特にキャンセルについては意識していなくて、
    |     vi.sh の側で勝手にハックしているだけという様な気がする。
    |     また、vi.sh 側で実行しているのはキャンセルというよりは、寧ろ処理が完了しましたという事の気がする。
    |     現状の実装では __after_command__ が呼び出されていて、それは "キャンセル" にそぐわないのではないかと思ったが、
    |     実際にやっている事は、処理を行ってからキャンセルという様な事なので、
    |     これは実質処理が完了しましたという事であって、キャンセルではないので、
    |     寧ろ __after_command__ を呼び出すという動作で正しいのである。
    |
    |     新しい関数 ble-decode/widget/suppress-widget を定義した。
    |
    |   * done: ble/keymap:vi/commandline/__before_command__ は
    |     ble/keymap:vi/commandline/before-command.hook に改名した。
    |     伴って ble/lib/vim-surround.sh/async-read-tagname/.before-command.hook も改名した。
    |
    |   * done: __before_command__ を __before_widget__ に解明する可能性?
    |
    |     これは過去にも議論があった筈である。その時の結論は何だったか。
    |     特に __before_command__ に関しては、言及はあるもののちゃんと議論はしていない様だ。
    |     議論していたのは WIDGET と同様に BEFORE_WIDGET や AFTER_WIDGET も定義するかどうか。
    |     これは元々定義していなかったので、それまで通り定義しないという事になった。
    |     (必要になった時に定義すれば良い)
    |
    |     特に __before_command__ 等の名前にしておく理由もない様なのでこの際変更する事にする。
    |
    |   * done: rename ble-decode/invoke-widget to ble-decode/widget/invoke
    |     実は ble/keymap:vi/imap/invoke-widget 等との対称性もあったようだが気にしない。
    |
    | lib/vim-surround.sh
    | - ok: ble/lib/vim-surround.sh/async-read-tagname/.before-command
    |   これは上記 commandline/__before_command__ と同じ。気にしなくて良い。
    |   →これは結局 commandline/__before_command__ (commandline/before-command.hook) と同様に、
    |     ble-decode/widget/suppress-widget を呼び出す事にした。
    |
    |   * ok: 関数名は変えても良いかもしれない。
    |     →改めて確認した所、先の __beore_command__ の場合には直接 keymap に登録していたが、
    |     今回の .before-command に関しては _ble_keymap_vi_cmap_before_command 経由で呼び出される関数なので、
    |     その儘の関数名で良かったのであった。
    |
    | - ok: ble/widget/vim-surround.sh/nmap/csurround.record
    |   これは ble/keymap:vi/repeat/record で記録される内容を弄る為に使用している。
    |   これも気にしなくて良いだろう。
    |
    |   * ok: 本当は ble/keymap:vi/repeat/record 側から特別に設定する手段を与えるべきなのかもしれない。
    |     或いは ble/keymap:vi/repeat/record で設定された内容を後で上書きするべき?
    |
    |     調べてみると ble/keymap:vi/repeat/record は内部で
    |     ble/keymap:vi/repeat/record-normal を呼び出していて、
    |     その中で repeat 配列の 2 番目の要素に WIDGET が設定される。
    |
    |     | そして repeat は、vi_imap の時には _ble_keymap_vi_repeat_insert に、
    |     | それ以外の時には _ble_keymap_vi_repeat に代入される。
    |     | ble/widget/vim-surround.sh/nmap/csurround.record の中では
    |     | vi_imap ではないという前提の元で、ble/keymap:vi/repeat/record が呼び出された後に、
    |     | _ble_keymap_vi_repeat を修飾している。しかし、
    |     |
    |     | _ble_keymap_vi_mark_suppress_edit が設定されている時等に勝手に書き換えてしまうとまずいのでは?
    |     | 調べてみると _ble_keymap_vi_mark_suppress_edit=1 が設定されるのは
    |     | ble/keymap:vi/call-operator や ble/widget/vi_xmap/paste.impl において、
    |     | 外側で record を実行したい時に内部で record されると困るという場合に使っている。
    |     | つまり、内部で変な repeat 情報を記録したとしても結局外側で上書きされてしまうという事。
    |     | その様に考えると実は record の内部で suppress している意味は実はないのではないか…とも思うが。
    |     | 唯、keymap が途中で変化した場合などには上書きが保証されない…。うーん。どうなっているのか。
    |     | うーん。良くわからないが実装の綺麗さを考えると csurround の側でもちゃんと、
    |     | record の実装と整合する様にしておくべきの気がする。
    |
    |     一応 ble/widget/vim-surround.sh/nmap/csurround.record に条件は付加した。
    |     一方で後で WIDGET を修飾する様に修正すれば良いというのはやめる事にした。
    |     record が参照する為に WIDGET を設定するというのは、
    |     実の所 record のインターフェイスの問題であって、
    |     ble-decode の仕様とは切り離して考えても差し支えないだろうという事と、
    |     WIDGET が何番目に格納されるのか、というのを外側の枠組みが意識するのはよくないという事。

2018-08-06

  * 2018-08-05 complete: ble-complete/util/escape-specialchars を refactor [#D0719]

  * 2018-08-05 complete: 実は completion-context の方で既に --prefix= 等に対応していた… [#D0718]

    まあそれはそれで良い様な気がする。

    1. completion-context 側で生成した = 以降が一番優先度が高くて、
    2. それで候補が無ければ単語全体に対する補完候補が生成されて、
    3. それでも候補がなければ = または : 以降に対する補完候補が生成される。

    もし completion-context の方の条件に引っかかれば実質 1.2. の優先順位であり、
    そうでなければ 2.3. の優先順位ということで良いのではないだろうか。

    但し、似たような処理がある事をソースコード内に注記しておくと良いだろう。

  * 2018-08-05 complete: 引用符内のエスケープなどを適切に処理する [#D0717]

    % shopt -s complete_fullquote に対応する
    % →shopt -s complete_fullquote はそういう機能ではなかった。
    %   シェルの特殊文字を補完時に適切にクォートするそうである。
    %   少し試してみた所、結局何が変わるのか良く分からなかった。
    %   何れにしてもクォートするべき物というのは明らかのはずで、
    %   現在の実装ではちゃんとやっている筈なので気にしない。

    - done: initialize: 引用符内のエスケープ
    - ok: initialize: COMPS が保持されない時のエスケープ
      これは元からちゃんとなっていた。

    - done: ble/string#escape-for-bash-escape-string
      取り敢えず次の物を置換する事にする: \a \b \e \f \n \r \t \v \\ \'

    - done: ble/string#escape-for-bash-* についてテストを行う。

      - ok: bash-4.4 の ${var@E} を使えるかどうか確かめる。
        特に改行やタブなどが変換されるのかどうか。
        →どうやら ${var@E} は逆方向の変換の様だ。
        元々変数の中に入っている \r\n\t などのエスケープシーケンスを
        decode して本物の改行やタブに変換する。これは使えない。

    x done: そもそも echo 'a で補完を実行すると 7 文字目から argument が開始する。
      これが為に結局引用符を閉じて補完するという動作にならない。
      これは core-syntax.sh の方が悪い。調べる必要がある。

      x fixed: これは ble-syntax/completion-context 側で
        ble-syntax:bash/simple-word/is-simple によるチェックを行っていた為であった。
        ble-syntax:bash/simple-word/is-simple-or-open-simple という関数を追加してそれで判定する事にした。

      x fixed: しかし 'a を判定させても真にならない。
        と思ったら、正規表現を誤っていた。'a よりも前に "1 つ異常" の element を要求していた。
        "0個異常" でなければならないはずだ。直した。

    - todo: initialize の動作チェック。正しくエスケープされるだろうか。

      x fixed: 動かない。と思ったら、ble-syntax:bash/simple-word/close-open-word にもバグがあった。
        close_type の判定のために不完全引用符を切り出す所を誤っていた。
        不完全引用符の内側にもキャプチャがあるのだから、
        不完全引用符のキャプチャが一番最後のキャプチャである事は保証できないのである。
        別の方法を用いる事にした。これは直った。

      o 取り敢えず 'a や "a や $'a や $"a は動く。

      x fixed: また、"\" から補完をしようとしても正しく補完できない。
        これは bash-completion とは関係の無い問題の様である。

        というか補完が起こらない。と思ったらそもそも completion-context が生成されていない。
        構文木を調べてみると先ず、単語が全然設置されていない。
        というか nest を作成している。nest を作成している為に単語が設置されていないという事…。
        double quote の中にいる時には一旦外に出て単語を調べるという処理を実装する必要がある。
        →実装した。実行できている。

      x resolved: "\"" から連続で補完しようとすると変な補完のシーケンスが生成される。
        これも上を修正したら直った。bash-completion が入っていても問題ないようだ。

      x fixed: 完全一致している状態で補完を呼び出すと何故か quote が全て解除される。

        候補を見るとちゃんと cand_cand[0]='a b c' で cand_word[0]="'a b c" になっている。
        では何故 quote が全て剥がされてしまうのだろうか。
        →これは opt_ambiguous の時に「共通部分 common が元々の文字列に曖昧一致しない場合に、
        補完を起こさない」という所で COMPS を設定するべき所で COMPV を設定しているのが行けなかった。
        修正した。ちゃんと動くようになった。

      x resolved: quote 内部で空白を置いた後で (空白を含むファイル名の) 補完を実行しても補完されない。

        これは上の項目を修正したら自然に直った。然し、未だ次の項目の問題が残っている。
        次の項目について修正した後で、それでも問題なく動くかどうかを確かめる事にする。
        →サイド試した所動いている。問題ない。

      x fixed: 「'a b c」で補完を開始すると何故か最初のファイル名の補完で候補が全く生成されない。
        次の曖昧一致用の候補生成によって初めて候補が生成されている。
        これは要するに pathname-expansion が壊れている。後で確認する。

        これはどうやら 'a b c*' で nullglob で候補生成すると、
        'a' と 'b' と null という候補が生成されてしまうという事の様である。
        そして 'a' も 'b' もファイルとして存在していないので、
        その直後の yield-candidate の直前のチェックではねられて消える。
        スペースもエスケープする必要がある様である。

        因みに以下を試してみた所、一致した。つまり、変数に入れたパターンの場合は、
        空白に対する \ によるクォートはちゃんと除去されるという事である。

          $ globpat1='a\ b\ c'
          $ [[ 'a b c' == $globpat1 ]]

        と思って 'a\ b\ c*' で一致させてみた所、
        今度は 'a\' と 'b\' という二つの要素が生成されただけだった。
        IFS= にして実行してみる事にする。直った。

      x fixed: addtail で追加された空白の後ろにカーソルが行って欲しいがそうならない。
        →これは簡単なミスだった。修正した。

      x fixed: $' から補完を始めると何故か '$' から始まる候補が列挙される。
        →これは bash-completion の貞経している関数が悪いのだという事になった。
        bash-completion を混乱させない為には展開した後の文字列を使って構築したコマンドラインを与える必要がある?

        少なくとも bash-completion を使わない場合 (complete -r で全削除) には問題は発生していない。
        これは COMP_LINE COMP_WORDS を設定する時に、再構築する事にした。
        特に、クォートを除去した後に '' でクォートし直す事にした。
        ただし、コマンド名は compgen が壊れている事による問題が起こると嫌なので、
        クォートしない事にした (#M0009)。bash-completion では実際に問題は起こらないようだったが。

    以下の項目はこれによって解消した。

    | * 2015-02-27 complete: 引用符の中で補完を実行する方法?
    |
    |   引用符の途中でも正規な単語として認識できる様にする。
    |   引用符の中であるという情報が必要。

2018-08-05

  * complete: いつの間にかに共通部分が保持されなくなっている [#D0716]

    例えば echo $HOME で tab を押すと /home/murase に置換されてしまう。

  * complete: --prefix= などの続きの補完 [#D0715]

  * complete: コマンド名補完ができなくなっている [#D0714]

    何と compgen は普通は quote を外すが、
    command 名の候補生成の時だけは quote を外さない様だ。

    具体的にそれぞれの候補生成で確認する必要がある。

    | 以下は quote を外してくれる。
    |
    | - function: 全 bash version OK
    | - variable: 全 bash version OK
    | - arrayvar: 全 bash version OK
    |
    | 以下は quote を外してくれない。
    |
    | - command: 全 bash version 駄目
    |
    | 以下は状況によって quote を外してくれたりくれなかったりする。
    | 何らかの設定が関係しているのだろうか。
    |
    | - directory: bash-3.0 - 4.2 で OK
    |
    |   bash-4.3, 4.4, 5.0 で、bash -c から呼び出すと、外してくれない。
    |   bash-4.3, 4.4, 5.0 で、bash --norc から呼び出すと、外してくれない。
    |   ble を load せずに mshex だけだと外してくれない。
    |   ble を load していると外してくれる。
    |
    |   何の違いであろうか。何故 ble をロードすると動作が変わるのだろうか。
    |   shopt の出力は全く変わっていない。もう少し調べてみる事にする。
    |   bind -v の出力を観察すると editing-mode が先ず異なる。
    |   editing-mode を合わせて見たが別に変化は見られない。
    |   keyseq-timeout も合わせてみたが変化は見られない。
    |   stty の状態で変わるという事がありうるのか?
    |
    | - file: bash-3.0, 3.1, 3.2, 4.2, 4.3, 4.4, dev で OK
    |
    |   4.0-4.1 で bash --norc から呼び出すと外してくれない。
    |   これは ble をロードしていてもやはり外してくれない。
    |   bash-3.2 及び 4.2 以降では何も問題は起こっていない。


    [まとめ] これは memo にも転記する: #M0009

      compgen -A command   クォート不可
      compgen -A directory クォート不可 (Bash-4.3 以降でクォート除去されない※1)
      compgen -A file      クォート不可 (Bash-4.0, 4.1 でクォート除去されない※2)
      compgen -A function  クォート可
      compgen -A variable  クォート可
      compgen -A arrayvar  クォート可

      ※1 バグと思われる。ble をロードしていると何故かクォート除去されている。
        然し、--norc や ble ロードなしで実行するとクォート除去されない。
        クォート除去が実行されなくなってしまう条件が分からないのでこれは使わない。

      ※2 バグと思われる。

  * 2018-07-28 complete: 例えば ble-complete/ まで一意確定でコマンド名補完した時に、 [#D0713]
    続きの候補も同時に表示した方が便利である。

    現在の実装ではもう一度 tab を押して補完を促さないと表示されない。
    これは候補をまとめる仕組みと一意確定の仕組みに修正を加えなければならない。

  * 2018-07-28 complete: compgen に渡す文字列はクォートしなければならない [#D0712]

    | →これは本当だろうか。今試してみたところ、\ でクォートしていても動くが、
    | クォートしていなくても動く。少なくともチルダ展開は実行しない。
    |
    | '' の除去は発生する。"" の除去も発生する。
    | パラメータ展開は実行しない。
    | 閉じていない ' や閉じていない " でも除去される。
    |
    | 後 compgen の引数が空白を含む場合等にどうなるのかについても確認する。
    | →大丈夫。勝手に単語分割されることはない。

    - '' や "" の除去は実行される。閉じていない場合でも実行される。
    - パラメータ展開は実行されない。
    - 単語分割は実行されない。

    以上の事から考えると '' でクォートしておけば良い気がする。

  * complete: cd [#D0711]

    既定だと cd の補完は bash-completion による補完になっていて、機能が劣る。
    ble のプログラム補完 ble/cmdinfo/complete:$command_name に対応して、
    それを利用して cd 用の補完を実装する事にした。

  * 2018-07-28 complete: 既存部分の置き換えは一意確定以外の時は起こさない様にする [#D0710]

    未だ候補が確定していないのに共通部分で置き換えを行うと、
    今までに生成していた候補が再現されなくなる可能性があるので。

    また、途中で補完をやはりやめようという時に面倒である。
    補完のキャンセルの仕組みについては後で対応する予定ではあるが、
    キャンセルに対応したとしてもやはり動作として不自然である。

    →これは取り敢えず文字数が少なくなる様な置換だけ行わない様にした。
    それで問題が起こる様であればまた再考する。

  * 2018-07-28 complete (ble-complete/source/command/gen): compgen の使用の是非について再確認 [#D0709]

    - done: compgen -A directory と pathname-expansino の両方の実装がある理由は?
      compgen だと -- の先の単語の quote がよく分からないという事。
      一方で pathname-expansion の方を使わない理由もあった筈。
      これについてはコミットを遡れば良い。

    これはどうも nocaseglob と関係している様である #D0633
    nocaseglob の時、大文字小文字を区別しない候補の生成を行う。

    調べると bash には大文字・小文字に関して色々のオプションがある様である。

    - compgen は rl の設定に左右される。bind "set completion-ignore-case on"
      [autocomplete - getting case insensitive completions with compgen in bash - Unix &amp; Linux Stack Exchange](https://unix.stackexchange.com/questions/204848/getting-case-insensitive-completions-with-compgen-in-bash)
      % 然し、今 bind -v してもその様な rl 変数はない…
      % と思ったら bind -v の出力は別にソートされている訳でも、同じカテゴリで並んでいる訳でもなかった。
    - [[ == ]] や case は shopt -s nocasematch に依存する。
    - パス名展開は shopt -s nocaseglob に依存する。

    ble-complete では bind -v の値に従って候補生成する事にした。
    glob を用いる時には一時的に shopt -q nocaseglob を変更する。
    正規表現を用いてフィルターする時には i がある時には各文字を [aA] 等の様にする。

    以下の項目についてはこれで完了した。

    | * 2017-11-26 complete: nocaseglob 的な補完に対応する?
    |
    |   つまり、大文字小文字が違うファイルに一致した場合は、
    |   前方の文字列を書き換えてしまう。

  * 2018-07-30 complete: 曖昧一致がサブディレクトリのファイルに効かない [#D0708]

    これは何故かと言うと曖昧一致の候補生成を最初の文字だけで行っているからである。
    サブディレクトリのファイルは生成されない。
    これを正しく実行する為には COMPV 内部の / について一つずつ遡って、
    初めて存在するディレクトリに当たった箇所から候補生成を行う必要がある。

    また存在しないディレクトリ名に関しては、
    /a*/b* 等の様にして生成した候補に対して曖昧一致を試みるべきなのかもしれない。
    % その場合には .* ではなくて [^/]* で一致させる必要がある。
    % と思ったけれど、よく考えたらその場合には / の数は保存しているので、
    % [^/] としなくても、[^/] に一致せざるを得ないので問題ない。

    色々考えると実は source 側で処理するほうが懸命なのかもしれない。

    実装した。これにより以下の古い項目についても自然解消した。

    | * 2015-02-21 zsh の機能: /a/b/c 等に対してディレクトリ名の補間も行う
    |     でも、これはやった後で一意に補完できない事が分かった場合が悲しい。
    |     TAB を打つ回数が多少減るだけで何が嬉しいのか分からない。
    |     しかしながら、曖昧一致による補完機能はあった方が便利な気がする。
    |     ただ、候補を表示するに留め、無断で補完する事はやめる。

2018-07-30

  * complete: ファイル名の曖昧一致? [#D0707]

    候補が一つも生成されなかった時に曖昧一致を行う。
    然し一つも生成されなかったときというのをどの時点で判定するのか。

    a 全ての補完開始点について一つも生成されなかった時
    b その開始点に於いて一つも生成されなかった時
    c その source に於いて一つも生成されなかった時

    b に対して実行するのが妥当な様に思われる。
    然し、その為には source 側で実行するのは面倒である。
    以下の方法を考える事ができる。

    a source 側は全くフィルタリングをせずに候補を提供する。
      もしくは、曖昧一致する物も含めて全て列挙する。
      ble/widget/complete 側でフィルタリングを実行する。

      この方法はとても遅くなる気がする。
      特にコマンド名については毎回大量に生成する事になる。

      最初の文字を固定するとしても、多いのではないか。
      実際に確かめてみると b　で始まるコマンドが最多で 1500 (ble 含む)。
      p で始まるコマンドが 1371 で次に多い。

    b 或いは source に対して引数を指定できるようにして、
      最初の source 呼び出しでは無引数で行い、
      全ての source で候補が一つも生成されなかった場合には、
      曖昧一致を許すという意味の引数を指定して再度 source を呼び出す。

    c もうひとつの方法は source は何も修正せず、呼び出し側で工夫する。
      最初の source 呼び出しは通常通り行う。
      候補が一つも生成されなかった場合は、
      最初の一文字だけ与えて source を呼び出し、呼び出し元でフィルタを行う。

    これは c の方法が良いだろう。

    コマンド名についての曖昧一致はどの様にしたら良いか微妙である。
    コマンド名は大量に生成されるはずなのでそれをスクリプトでフィルタすると時間がかかる。
    sed でフィルタすれば良いだろうか。曖昧一致とは言っても、最初の文字だけは一致する様にするか。

    ? 曖昧一致に関しては正規表現を使うか。超線形になったらどうしようと思ったが、

      | よく考えれば使うのは DFA の範囲内なので問題にはならないだろう。
      | 逆に glob を使った場合にちゃんと超線形を避けられるのかは気になる。
      | [[ a{30回} =~ (*a){n回}z ]] を試したら:
      |
      |   n = 2  time 0.000s
      |   n = 3  time 0.001s
      |   n = 4  time 0.005s
      |   n = 5  time 0.024s
      |   n = 6  time 0.097s
      |   n = 7  time 0.325s
      |   n = 8  time 0.935s
      |   n = 9  time 2.338s
      |   n = 10 time 5.128s
      |
      | 明らかに超線形になってしまっている。因みに sed ではちゃんと線形になっているだろうか。
      |
      |   n = 15 time 0.005s
      |   n = 20 time 0.005s
      |   n = 25 time 0.005s
      |   n = 30 time 0.005s
      |
      | 大丈夫である。序に zsh, ksh の glob も確認する。
      |
      |   $ time zsh -c '[[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == *a*a*a*a*a*a*a*a*a*az ]]'
      |   $ time ksh -c '[[ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == *a*a*a*a*a*a*a*a*a*az ]]'
      |
      |   zsh n = 10 time 5.749s
      |   ksh n = 10 time 5.605s
      |
      | bash の glob と殆ど変わらない。同じルーチンを使っているという事なのだろうか。
      | また正規表現を試してみる事にする。これはシステムの正規表現が内部的に使用される。
      |
      |   $ time [[ xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =~ .*a.*a.*a.*a.*a.*a.*a.*a.*a.*a.*z ]]
      |   n = 10 time 0.000s
      |
      | 問題はない。キャプチャが合っても大丈夫だろうか。
      |
      |   $ time [[ xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =~ (.*)a(.*)a(.*)a(.*)a(.*)a(.*)a(.*)a(.*)a(.*)a(.*)a(.*)z ]]
      |   n = 10 time 0.000s
      |
      | 大丈夫のようだ。

      結論: glob は超線形になるので危ない。正規表現ならば Bash の物でも sed の物でも問題ない。

    取り敢えず実装した。
    時間がかかるかもしれないが、取り敢えずは Bash の正規表現を使って標準入力を確認しながら処理する。
    また、生成した候補を後から制限する方法にしたので、
    必然的に cand_{prop,cand,word,show} を並列で操作する事になるので遅い。
    然し、これは後で問題になってから配列を統合する等の処置によって改善するべきである。
    ここでは複雑な事をして改善する等の方策は取らない。

    x 実装して気づいた事は、曖昧一致による確定は色々難しいという事。
      直ぐに一意確定すれば問題ないが、複数の候補がある時に、
      単純に共通部分で補完を行ってしまうと、既に入力した部分が消えてしまう。

      然し、だからといって曖昧一致の時には遡る様な確定は行わないのだとすると、
      hello 及び hello~ がある時に hll から補完を開始した時に、
      結局何も補完できないという事になってしまう。

      % 曖昧一致の時は曖昧一致の時で共通部分を計算する必要がある。
      % しかしどの様なアルゴリズムで共通部分を計算したら良いだろうか。
      % LCS というアルゴリズムがあったはず。
      % 単純に LCS を求めると元々入力した文字列を含まない可能性もあるので、
      % 先に元々入力した文字列との関係を調べてから、
      % その間隙に対してそれぞれ LCS を求める様にするのが良い。
      %
      % x 問題点がある。求められた LCS に対するエスケープをどうするのか。
      %   特に複数の種類のエスケープが混ざっている場合に、
      %   どのエスケープをすれば良いのかが分からない。
      %
      %   逆にエスケープ後の文字列に対して LCS を求めるのはもっと問題になる。
      %   エスケープは複数の文字の組み合わせで意味があるのであって、
      %   部分列を取ってしまうと意図しない意味を持つようになってしまうので使えない。
      %   エスケープの組み合わせが分断されない様に LCS を求めるとしても、
      %   複数の種類のエスケープが混ざっていた場合にはやはりよく分からない事になる。

      余り複雑な処理にしても非直観的な物になってしまうので、
      ここでは単純に求めた共通部分が COMPV に曖昧一致していれば補完を実行するし、
      一致していなければ何もしないという様にするのが良さそうである。

    * 何れにしても曖昧一致では確定できない時の為に、
      menu-completion の様な機能は必須である。
      これは後でまとめて対応する。

2018-07-29

  * complete: 関数名の補完で / 以前を共有する物が複数ある場合には [#D0706]
    / までを補完候補として、/... と表示する様にする。
    ble-complete/source/command/gen を変更する。
    awk で実装すれば良い。bleopt を追加しても良い。

    実装し始めて思ったのだが、どういう振る舞いにするのかが不明瞭である。
    a/b/ まで入力している時に a/b/1 a/b/2 があったとして、
    その時に a/ という候補が生成されるのでは困る。

    1. 先ず初めに共通部分までは必ず補完する事にする。
    2. 共通部分以降の部分について a/ 以降が単一しかない場合には、
      最後まで確定する。それ以外の場合については、a/ を生成する。

      →最後までというよりは、単一しか無いディレクトリ階層まで
      一気に補完できるようにした方が良い。

    これを動的にできるだけ 1pass で実装する事は可能だろうか。

    % 例えば、状態として以下の様な物を考える。
    %
    %   共通部分 a/b/c
    %   候補 '' '/1' '/2' '/3' '/d/e'
    %
    % 此処で b が来たらどうするかというと
    %
    %   共通部分 ''
    %   候補 'b' 'a/b/c'
    %
    % となる。うーん。此処で a/b/c/4 が来たら単に追加するだけである。
    % ここで a/b/c/d/1 が来たら '/d/e' を '/d/' に短縮しなければならない。
    % これをどの様に実装するかは難しい所である。
    % 既に生成されている候補の一つ一つと比較しなければならないのだろうか。
    % それだと最悪 O(N^2) になってしまう。
    % ソートしておいて二分法で探索するという手もあるが、実装が大変に面倒になる。
    % 挿入できる様にする為には awk で二分木も構築しなければならない。

    よく考えてみれば初めから入力をソートして置けば、
    もっと簡単に実装できるのではないだろうか。
    / で区切られた名前を単位とする、階層が二つしか無いパトリシア木の構築と思えば良い。

    - reject: 共通部分は a/b/c の様にスラッシュの手前までの方が良い。
      a/b/c という関数と a/b/c/d ... という関数があった場合に、
      a/b/c まで入力した時に、 a/b/c と a/b/c/ が候補になるのは悲しい。
      a/b/c が共通部分になっていれば、a/b/c 及び a/b/c/d...
      が候補になってくれると思う。実装によると思うが。

      と思ったがこの方法にしていると、a/b/c/1 a/b/c/2 という候補に対して、
      スラッシュの手前またはスラッシュの直後の両方を可能にした方が良いのでは。

      これを考えると難しくなるので a/b/c と a/b/c/ を候補にする事にした。
      これだと a/b/c まで入力されているのだという情報も使わないとならない。
      動作として色々と不自然になる気がするので取り敢えず実際に気になるまで考えない事にする。

    - resolved: a/b/c と a/b/c/d に対して a/b/c を候補として生成した時に、
      一意確定してしまったらどうするのか。
      実は一意確定しない様にする事も必要なのではないだろうか。

      或いは、候補を表示する時にだけ / 以降が色々ある場合には表示を省略する、とするか。
      そちらのほうが良いのかもしれない。
      特にディレクトリ名と関数名で / 以前の部分を共有している場合なども考えられるので。

      これについては a/b/c と a/b/c/ の両方を候補として生成する事にした。

    x resolved: 実際に動作確認してみると全くフィルタできていない。何故だろうか。
      と思ったら、既存文字列に / が含まれていない場合は compgen -c の方から関数名が列挙されるのであった。
      compgen -c 及び compgen -A function の両方の出力に対して実行する事にした。

    x resolved: 何故か ble-c まで入力して補完しようとすると ble-complete が候補として列挙されない。
      →最後に END で残っている物を出力するのを忘れていた。
      取り敢えずの所動いているような気がする。

  * complete: 前の候補を覚えておいてそれに対する絞り込みにした方が速い可能性 [#D0705]

    →これは各 source でキャッシュするべきである。

    同じ補完の続きの場合には、毎回補完候補を列挙するのではなくて、
    前に生成した候補を覚えておいてそれに対する絞り込みをかけた方が速い可能性。
    しかし、同じ補完の続きかどうかを判定する必要があるし、
    最初の補完で大量の補完候補が存在する場合には、
    スクリプトで絞り込みをかけるよりも、最初から生成し直した方が速い。

    現状では、毎回候補を生成した方が速いと判断する。
    もし候補生成自体が遅い種類の source の場合には source の側で記録したほうが良い。
    どの様な状況で候補を再利用できるのかを的確に知っているのは source だけのはずなので。

2018-07-28

  * complete: source の時点で一番近い開始点にフィルターする [#D0704]

    取り敢えず手始めに開始点はできるだけ後ろの物しか用いない様に変更する。
    開始点を一番近い物だけにした場合、初めから一番近い source だけで候補生成をすれば良い。

    - done: ちょっと面倒なのは、一番近い source で候補が一つも生成されなかった場合、
      次に近い source 候補を使う必要があるという事。
      これには対応した。

    [動作確認]

    x fixed: 候補が複数あっても最後の物で確定してしまう?
      共通部分の算出がちゃんと動いていないという事だろう。
      二番目以降の要素について列挙するのは "${arr[@]:1}" であった。修正した。

    使った見た感じ他は問題は発生していない。

    [動作変更点]

    - 変更に伴って、shopt -s force_ignore は補完候補生成より前の状態を参照する様に変更した。
    - また、パターンの一致に関しては、挿入文字列 (INSERT) ではなくて候補文字列 (CAND) に対して適用する様に変更した。

  * 2017-03-18 complete: .exe が候補から消去されている場合、.e の入力仕掛けの状態での補完ができない [#D0703]

    現状の実装がどうなっているか確認する。やはり compgen を使っている。
    実際に以下を実行してみると補完候補として sort だけが生成される。
    $ compgen -c -- sort.e | sort -u

    % 補完候補が単一の場合はそれに確定して
    % ble-complete/action/command/complete が呼び出されて、更に
    % ble-complete/action/util/complete.addtail が呼び出される。
    % 其処で INSERT に ' ' や '/' などの内容が追記される。
    %
    % うーん。その部分より前の編集部分の最小化という所に問題点がある様な気がする。
    % 先ず、編集文字列 text (= _ble_edit_str) の内容を見て編集部分を最小化している。
    % 挿入文字列の quote や編集文字列の置換などが考慮に入っていないのではないか。
    % 更に、この部分では補完によって単語が伸びる場合しか考慮に入っていない?
    % と思ったら遡って書き換わる場合についてもちゃんと対応はしている様であった。
    % うーん。観察してみるとちゃんと長さが縮まる場合にも対応している気がする。

    確認してみた所、そもそも共通部分を計算する以前から、
    sort.e や sort.ex などの不完全な候補が生成されているという事が分かった。
    調べてみると ble-complete/source/command の中で呼びされている

      ble-complete/yield-candidate "$cand" ble-complete/action/command

    の中で sort が sort.e に化けているという事が分かった。
    更に中で呼びされている ble-complete/action/command/initialize の中が怪しい。
    これは   ble-complete/action/plain/initialize を呼び出している。
    ここでは既存の内容と一致する部分を置き換えない様にする為に、
    INSERT=$COMPS${CAND:${#COMPV}} 的な事をしている。これが行けない。

    ble-complete/action/plain/initialize は遡って書き換わる場合にも
    対応できる様に修正するべきである。
    場合分けで既存の内容に対する追記の場合と、
    書き換えが起こる場合に分けて処理する事にした。

2018-07-24

  * edit/history: bashrc の謎の遅延に関して [#D0702]

    #D0701 後半に関して再度整理し直す。

    色々調べて分かったこと。

    - bashrc 中で shopt -s histappend の状態で history -n をすると、
      bashrc を抜けた後に謎の遅延がある。
    - 当初 Cygwin だけかと思っていたら GNU/Linux でも同様の遅延が生じる。
      特に padparadscha ではかなり長い遅延が発生する。
    - Bash 3.0 では遅延はない。Bash 3.1 - 5.0a の全てで遅延がある。
    - 履歴項目の数から HISTSIZE, HISTFILESIZE の半分を引いた数に比例した遅延である。

    - history -n をする瞬間だけ shopt -u histappend すると遅延はなくなるが、
      histappend の効果が失われる。
        shopt -u histappend; history -n; shopt -s histappend

      以下の様にしても遅延はないが histappend の効果はない。
        shopt -u histappend; history -n
        shopt -s histappend; history -n

      以下の様にすると遅延があって histappend の効果がある。
        shopt -s histappend; history -n
        shopt -u histappend; history -n; shopt -s histappend

    再現するには以下のような bashrc を用意する。
    参照: memo/D0703.bashrc

      | # bashrc-test
      |
      | function measure1 {
      |   time1=($(date +'%s %N'))
      | }
      | function measure2 {
      |   local -a time2=($(date +'%s %N'))
      |   local sec=$((time2[0]-time1[0]))
      |   local usec=$((sec*1000000+10#${time2[1]}/1000-10#${time1[1]}/1000))
      |   echo "${usec} us" >/dev/tty
      | }
      |
      | export HISTFILE=A.txt
      | export HISTSIZE=100000
      | export HISTFILESIZE=100000
      | shopt -s histappend
      | history -n
      | measure1
      | PS1='$(measure2)'$PS1

      $ printf 'echo hello %d world.\n' {1..100000} > A.txt
      $ bash --rcfile bashrc-test

    解決の為には

    a 遅延が生じず histappend も有効にできる様な何らかの方法を見つけるか
    b サブシェルで history -n を実行するか
    c キーが入力された後に履歴を読み込むか
    d 履歴の仕組み自体を Bash の履歴とは独立な物かラップした物にするか

    実は一時的に HISTSIZE を増大させれば問題ないのでは? → 遅延がなくなった。

  * 2018-05-22 もしかすると cygwin で遅延ロードがちゃんと働いていない可能性がある [#D0701]

    使った感触でそう思っただけなので具体的に確認する必要がある。

    * done: 調べてみた所遅延ロード自体はちゃんと動いている。
      但し、履歴項目の読み込み (mapfile) に時間がかかっている様に思われる。
      有効になっている ble/util/mapfile の実装について確認した所 mapfile -t になっている。
      10万項目を読み取るのに 3.050 秒かかっている。

      Linux で3.7万項目の ble/util/mapfile の読み込みに 47ms しかかかっていない事と較べると、
      Cygwin では mapfile が20倍ぐらい遅いという事になる。
      もしかすると昔ながらの source の方が速いという事もあるかもしれない。

      1. mapfile 3.055 sec
      2. 配列のコピー 0.522 sec
      3. source 0.620 sec

      取り敢えず Cygwin に限って _ble_edit_history は source で定義して、
      _ble_edit_history_edit は _ble_edit_history をコピーする事にした。

    * 後もう一つ。.background-initialize 待機中に一度 148 で抜けると
      .background-initialize が終わるまで最後まで実行してしまう様である。
      然し、不思議である…。何処で時間を食っているのかが分からない。
      分かったこと。148 で抜ける → .background-initialize が終わるまで戻ってこない。
      .background-iniailize が終わると ble-edit/history/load async が再び呼び出される。

      何が起こっているのだろう。

      | 色々調べてみた所、どうやら問題は .bashrc が終わった直後から、
      | 最初に入力が来るまでの間にあるようである。
      | ble-attach → ble-edit/bind/.tail → ble/util/idle.do の中でジョブが投げられると、
      | 必ず 0.8-1.2 sec 程の遅延が生じる。ジョブを投げないと遅延はない。
      | ジョブが物凄く時間がかかる者であったとしても遅延は 0.8-1.2 sec のままである。
      |
      | 然し、不思議なのは小数 sleep のための background プロセスに関しては遅延が生じていないという事である。
      |
      | % →どうやら var=$(command & echo $!) で起動すると駄目の様だ。
      | % 代わりに ble/util/assign var 'command & echo $!; disown' 2>/dev/null で起動してみると遅延はない様だ。
      | % Linux でも試してみたが、Linux では違いはない様に見える。
      | % →やはり ble/util/assign var を用いたとしても遅延は存在する。
      |
      | 簡単な bashrc を作って実験してみる事にする。
      | - 簡単な bashrc を使っている限りに於いては、
      |   丁寧に </dev/null &>/dev/null にすると、
      |   ちゃんと遅延無しで動く様になる。
      | - bind -x しても遅延はない。
      | - ble-edit/bind/stdout.off の効果でも無いようだ。
      | - 関数を入れ子にしても再現しない。
      |
      | 色々試した結果、犯人は fork ではなくて、それよりも前にある history -n だと分かった。
      | history -n を bashrc の中で使うだけで遅延が生じる様になる。
      | 然し、history -n だけでは再現しない様だ。
      | - 更に調べてみると source bashrc_common.sh; history -n で遅延が出る。
      |   どちらか一方でも欠けていれば遅延は生じない。
      | - is-stdin-ready も関係しているのではないかと当初疑っていたが関係ない。

      結局、以下が bashrc に含まれていると遅延が生じるという事が分かった。
      どれか一つだけでも欠けていると再現しない。
      また順番を変更しても (特に history -n を shopt -s histappend より先にすると) 遅延しない。

      export HISTSIZE=100000
      export HISTFILESIZE=100000
      shopt -s histappend
      history -n

      a shopt -s histappend の時は一瞬だけ shopt -u histappend にして history -n を実行する?

        順番を変更した時に正しく histappend が適用されるかどうかについては確認が必要である。
        →順番を変更してみたところ histappend が有効にならないという事が分かった。
          つまり、history -n する瞬間だけ shopt -u histappend にしても、HISTFILE に全体が書き込まれる。
          shopt -s histappend にしたまま history -n すると期待通りに実行したコマンドだけが追記される。

        つまり shopt -s histappend が有効になっている時に history -n しないと駄目という事。
        この方法は使えない。

      b 或いは、Cygwin に於いては history -n
        をサブシェル内で実行するという手もあるかもしれない。
        実際にサブシェル内で history -n を実行する様にしたら遅延を改善する事ができた。

        - history -n をサブシェルで実行するという事は二回ファイルを読み込むことになって問題だが、
          history -n 自体はそんなに時間のかかる処理ではない (71ms/10万項目) ので速度的な問題は生じないだろう。

        x 問題になるとすれば二回に分けてファイルを読む途中でファイル内容が変更された時に、
          データの内容に不整合が生じてしまう可能性がある事である。

        history の仕組み自体を大幅に変更した上で再考しても良いかもしれないが、
        現段階では不整合を防ぐために遅延を甘受して一回で読み取る事にする。

      | また、この問題が実は Linux でも発生している事も確認しておいた方が良いかもしれない。
      | →Linux でも再現した。というかより遅延時間が長い @ padparadscha
      |   4万行の時は殆ど遅延がなくて10万行に達すると遅延が生じる事から、
      |   もしかすると HISTSIZE, HISTFILESIZE の上限に達する時特有の遅延なのかもしれない。
      |
      | 試しに幾らか余裕をもたせて実行してみる事にする。
      | 余裕を持たせても遅延が長いのは変わらない様だ。
      | 50000 まで減らすと遅延がなくなる。70000 だと遅延がある。
      | 色々調べると 50000 を超えた辺りから急激に遅くなる。
      | (と思っても増え具合は線形のようではある。)
      |
      |   50000   63642 us
      |   51000  308568 us
      |   52000  554410 us
      |   53000  802508 us
      |   54000 1046543 us
      |   55000 1290507 us
      |
      | HIST{,FILE}SIZE を 200000 に増やしたらまた速くなった。
      |
      |   55000   30085 us (with HISTSIZE=200000 HISTFILESIZE=200000)
      |
      | つまり、この遅延は HISTSIZE/2, HISTFILESIZE/2 より超過すると発生する。
      | 本当に、"半分" なのだろうか。また試す。やはり "半分" が閾値になっている様だ。
      |
      |   100000  123337 us (with 200000)
      |   101000 1106749 us (with 200000)

      この遅延は Linux でも生じる。特に padparadscha では遅延が著しい。
      HISTSIZE, HISTFILESIZE の丁度半分よりも超過した項目の数に比例して時間がかかる。

2018-07-19

  * ble-decode: ble-text.s2c 廃止 [#D0700]

  * 2018-07-10 LANG=C とすると c2s がおかしくなる [#D0699]

    一度キャッシュされるとそのままになってしまう。

    うーん。どうしたら良いのか謎である。
    LANG が途中で切り替わると Bash の文字のカウントなどが全て変化する。
    その様に考えると LANG=C の時には UTF-8 表現であっても保持するべきではないのでは。
    つまり '?' などの文字に変換するべきではないのか。

    すると LANG に応じて変換先の文字を変更することになるので、
    LANG が変わったら c2s のテーブルをクリアするなどの処置が必要になる。

    うーん。c2s は output charset に応じて変更するべきである。
    input_encoding の設定項目はあるが、output_encoding の設定項目はない。
    というか、output_encoding の設定項目の代わりに LC_CTYPE を用いているのだろう。
    その様に考えると c2s で変換に失敗する場合には、
    文字の幅に応じて ? や ?? になるべきなのでは?
    と思ったが c2s が使われる箇所を考えると微妙である。
    描画の瞬間にその文字になるのではなくて、
    既に文字列として保持している時点でその文字になっている。

    _ble_edit_str に何か物が入っている時に LC_CTYPE が変化するとよく
    分からないことになるが、LC_CTYPE が変わるのはコマンド実行時と考えれば、
    基本的に _ble_edit_str が空の時に LC_CTYPE が変化すると考えて良い。
    そう考えれば _ble_edit_str に壊れた文字が含まれる事はないし、
    また、座標計算などのキャッシュされたデータに齟齬が生じる事もない。
    と思ったが履歴項目が変なことになるのではないか。
    壊れた文字が含まれる事になる (但し、座標計算などがおかしくなる事はない)。
    然し、これは ble.sh を使っていなくても起こる問題であるので気にしない。

    そう考えると新しく入力される文字についてだけ適切に処理できれば良い。

    % 例えば LC_CTYPE=C 等になったとすると、どんなに頑張っても文字として保持不可能である。
    % 従って ? 等の文字に変換するしかない。? はシェルとして特別な文字なので、
    % 別の文字にしたい。もしくは \u???? の形式の文字列にする。
    % うーん。調べてみると、やはり c2s は様々なところで使用されていて、
    % 必ず一文字の結果を返すという事前提の実装になっている。

    ここで問題にしているのは c2s の結果が表現不可能な文字の時にどのように取り扱うかである。

    a "?" という文字にする。
      これはシェルの特殊文字なので誤って取り返しの付かない事をしてしまう可能性がある。
      例えば rm -rf ???? などとして大切なファイルを消してしまうかもしれない。
      これは危険である。

    b エラーにする。そもそも文字を入力できない事にする。

      そもそも文字を入力できなくすれば、文字を入力する箇所の
      c2s だけに影響が留まるという算段である。
      しかし履歴項目などに含まれている文字を消去する事はできない。
      と思ったが履歴項目に含まれている文字は別の文字として解釈されるので問題ない。

    c "\u????" という文字列に変換する。

      この方法だと情報劣化はない様な気がするが。
      実際にこの様にしたところで printf の引数に用いる時ぐらいしか意味がない。

      また、現在の c2s の使用例を調べてみるとやはり一つの code に対して
      一文字しか返さない事を前提としている様な気がする。
      と思ったが、そもそも c2s を用いた時に現在の LC_CTYPE で表現不可能な code
      を指定する可能性がある箇所というのは限られているのではないかとも思われる。

    d "_" 等の文字にする。これは "_" と違ってシェルとして特別な意味は持たないので安心である。
      また "-=" はオプションなどで使用するし、"/" はパス区切りに用いる。
      残るのは "%@+:.," 位だが、やはり "_" が最も良さそうに思われる。
      現にファイルをダウンロードする時などによく使われる置換である。

    ble/util/c2s の使用箇所についてまとめる。
    調べた範囲では ble/util/c2s の終了ステータスは使用されていない。

    - done: ble-decode.sh
      - ble-decode-kbd/.get-keyname
        input_encoding によって現在の LC_CTYPE で表現できない Unicode が入ってきうる★ -> ok
      - ble-decode-char/csi/print
        これは ble-bind -d の時に出力する内容★ -> ok
      - ble-decode-char/csi/consume
      - ble-decode-bind/c2dqs
        これは ASCII の範囲内であることが保証されている文脈
    - done: ble-edit.sh
      - ble/textarea#adjust-for-bash-bind
        これは現在位置の左にある文字の文字幅を計算するのに使う。
        現在位置の左にある文字は LC_CTYPE で切り出されるので、
        そこから s2c で得られた文字コードは必ず c2s で元の文字に戻せるはずである。
        よってこれに関しては表現不可能な文字になる可能性は考えなくて良い。
      - ble/widget/self-insert [self-insert]
        これは input_encoding を通して生成された unicode を文字列に変換するもの。
        LC_CTYPE で表現できない Unicode が入ってくる可能性を考慮に入れるべき。★ -> done
      - ble-edit/history/string#create-unicode-progress-bar
        これはプログレスバーを表示するのに使っている。★ -> done
      - ble-edit/isearch/self-insert.fib
      - ble-edit/isearch/history-self-insert.fib
        これは検索文字列を入力するもの。input_encoding 経由★ -> \uXXXX の形式でも ok
    - done: keymap/emacs.sh
      - ble/widget/emacs/append-arg
        これは bind した文字しか来ない筈だが…。★ -> won't support
        ここで得られた文字は _ble_edit_arg に追記されるが、
        そもそも参照する時に 0-9 や - のみしか使っていないので、
        それ以外の文字の取扱は正しい encoding だろうと文字化けだろうと変わらない。
        寧ろ、数字や - 以外の文字が来るとエラーメッセージが表示される気がする。
    - done: keymap/vi.sh
      - ble/keymap:vi/register#dump -> ok
        これは登録したレジスターの数字しか来ないはず。つまり ASCII だけのはず。
        と思ったが見てみると普通の文字にも割り当てられる様になっている気がする。
        しかし、これは何れにしてもユーザに対して表示する内容の生成であるので、
        \u???? の様な表示になっていても問題ない…というより寧ろ好ましい。
      - ble/widget/vi-command/append-arg
        input_encoding★ -> won't support
        これはそもそも数字以外が来ると assert で引っかかるはずである。
        また assert を通過しても結局 _ble_edit_arg に登録されるだけなので、
        問題が起こるとしても編集コマンドに対する引数が理解できないという物に留まる。
      - ble/widget/vi_nmap/record-register
        keylog で記録されたキー列を文字列にして記録する。
        input_encoding によった unicode★ -> done
        これについては CSI 27;1;code ~ 形式で記録する事にした。
      - ble/widget/vi_nmap/record-register.hook -> ok
        register名に使用している。input_encoding によった unicode の気がする。
        これはステータスに表示する "REC @?" の文字列を生成する箇所なので、
        変な文字になっても実害はない。
        寧ろユーザにわかりやすい様に \u???? の形式が望ましい。
      - ble/widget/vi-command/search-char.impl/core★ -> ok [self-insert]
        これは検索文字列に新しく追加する文字の生成である。
        input_encoding で変換されて得られたコードが来る。
        際どい所だが self-insert と同じ取扱で良い。現状ではそのまま。
      - ble/keymap:vi/text-object.hook★ -> won't support
        これは text object の二文字目の入力である。
        iw aw a[ などに於ける二文字目であり、普通は ASCII の範囲である。
        もし独自に拡張して Unicode 文字を受け取る様にしたとしても、
        現在の LC_CTYPE で表現できない様な文字に関してまで正しく動作する必要はない。
        従って、これは \u???? のままで良い。
      - ble/keymap:vi/.check-text-object★ -> ok
        これは text object の形式を確認する為の物。
        一文字目が i または a である事を確認する。
        それ以外の場合には常に false になるので、どの様に変換されても問題ない。
      - ble/widget/vi_xmap/visual-replace-char.hook★ -> ok [self-insert]
        これは範囲置換で埋めるのに使う文字を取得するのに使っている。
        self-insert と一貫していれば良い。
        幅の計算も code から計算した物を用いているがそれで良い。
        self-insert でその様にしているから。
    - lib/vim-surround.sh
      - ble/widget/vim-surround.sh/omap★ -> won't support
        これは二文字のオペレータの二文字目を取得するのに使う。
        オペレータ名に非ASCIIは恐らく使わないし、
        使うとしても LC_CTYPE でサポートされない文字の時にはその機能は使えなくて良い。
      - ble/lib/vim-surround.sh/get-char-from-key★ -> ok [self-insert]
        これは ble/lib/vim-surround.sh/async-inputtarget.hook から使われていて、
        更に async-inputtarget を使用して遅延して処理される全ての処理で使われている。
        つまり vim-surround で続きの文字を待っている時には必ずこれが使われる。
        これはどの様に処理したら良いだろう。
        操作を選択する文字という観点で言えばどうせそもそも使われないので
        \u???? のままでも良い気がする。しかし、囲むのに使う文字を入力する場合には、
        これは self-insert と一貫していて欲しい。
        取り敢えず self-insert と一貫した設計にするという事にする。


    使用箇所を調べてみて考えた事は、変換先の文字が存在しない場合には、
    一律で変換後の文字を定めるのではなくて、それぞれの場合で適切な処理をしなければならないという事。
    例えば、"?" や "_" に変換してしまうと vim-mode で意図しないレジスタが使用されることになったりする。
    また、場所ごとに適切なロケールを使用して ble/util/c2s を呼び出すというのも必要かもしれない。
    入力を処理する時には LC_CTYPE=C.UTF-8 にして行うなど?
    但し、実行するコマンド文字列に含まれる物に関してはやはり環境の LC_CTYPE を使用するべきである。

    - done: (ble-edit) self-insert は複数文字に変換されても大丈夫な様に修正した。
    - ok: self-insert insert-mode の時の複数文字の時の振る舞いは正しいのか?
      →確かめてみた所、特に問題はないようだ。

    - done: ble-decode.sh に含まれる c2s に関してはどの様に取り扱えば良いのか微妙である。

      | テーブル k2c 及び c2k に含まれる文字列の文字コードをどの様に変換すれば良いのだろうか。
      | 登録した瞬間の文字コードによる文字列を用いるのだろうか。
      | 一文字の文字の場合には c2s を用いる様にしたら良い。
      | 特殊キーの場合には…c2k と k2c を同時に登録していれば、
      | c2k に見つからなかった時点で単一の文字と確定するが…
      |
      | 或いは、これについても文字コードが変化した瞬間に
      | 登録されている文字列の文字コード変換を実行するか。
      | 文字コードの変換を実行するのは始末が悪い気がする。
      | また文字コードの変更を検出するのも面倒である。
      |
      | 調べてみたところ k2c を設定した時 c2k も一緒に設定されている。
      | また k2c が設定されるのは特殊キーとしてのみであり、
      | 普通のキーについてわざわざ k2c が設定される事はない。
      | つまり、c2k が見つからないという事は特殊キーとしてそもそも登録されていないキーという事であり、
      | 通常の文字ということである。というか、if の条件式を見ると明示的にその様になっていた。
      | その場合にはキャッシュしない様にして ble/util/c2s を必ず呼び出すことにすれば良い。
      | そもそも ble/util/c2s がキャッシュしているのだし、
      | また c2k が使用されるのは ble-bind -d の時やエラーメッセージの時など限られているのだから、
      | 速度についてはそれ程気にしなくても大丈夫のはずである。

      ble-decode-kbd/.get-keyname は ble/util/c2s の locale 毎の切り替えに一任して、特に何もしないこととした。
      但し、今までキャッシュする様にしていたのをキャッシュせずに c2s のキャッシュから読み取る事にした。
      ble-decode-char/csi/print についても同様。
      他の ble-decode.sh 内の仕様は全て ASCII の範囲内の文字に対する使用であるので、
      対応する文字が存在しないという事はないものとして扱う。

    - done: ble/util/s2c のキャッシュも問題になるのではないか。
      特にこれこそ LC_CTYPE の影響を受けて変化する物のはずである。
      bash-4.0 でキャッシュを行っている。
      これについてもキャッシュをクリアする事にした。

  * bug: LANG=C bash で起動すると動かなくなる [#D0698]

    | bind が壊れている様子である。
    |
    | - ble-bind -D や ble-bind -d を見ても異常はない。
    | - .cache/blesh/*.bind の周りを見ても異常はない。
    | - padparadscha では bash-3.0 から bash-dev まで再現するが、
    |   chatoyancy では再現しない。
    | - bind -X を見て気づいたが変な値に bind されている。
    |   例えば bind -x '"\C-@": ble-decode/.hook 128' などである。

    これは以下の通り bash のバグに起因するものであると判明した。

    - LANG=C bash --norc で起動して
      bind -x '"\C-a": echo C-a'
      bind -x '"\201": echo 201'
      としてから C-a を入力すると 201 が表示される。
      bash-3.0 から bash-dev まで再現する。

      bind -x '"\201": echo 201' だけだと、
      bind -X の表示は '"\C-a": echo 201' となるが有効にはならない。
      恐らく通常の key binding に関しては問題は起こっていないが、
      内部のコマンド文字列を保持している cmd_xmap に登録する時に問題が起こっている。

    - chatoyancy ではならない。Cygwin, padparadscha 32bit ではなる。
      32 bit 環境だとなると予想される。

    - LANG はそのままに LC_CTYPE=C とだけしても再現する。
    - 普通に起動してから LC_CTYPE=C にして、
      その後で bind しても再現しない。
      bash を起動した瞬間の LC_CTYPE が効くようだ。
      cmd_xmap の構築時の問題だろうか。

    Work around として、この問題が発生している時には
    bind -x で 80-FF に bind しないという手がある。
    もしくは別の文字を通して迂回する。

    取り敢えず bind の順番を変更して全然動かないという状態にはならない様にした。

    % [80-FF を迂回して読み取る方法を考える]
    %
    % a 何れかの文字を犠牲にするしかない。
    %   0-127 の中で遅延が起こっても
    %   問題がなさそうな文字はどれだろうか。
    %   うーん。そんな文字は存在しない気がする。
    %   制御文字も \C-@ - \C-_ として使われている。
    %
    %   と思ったが ESC に関しては遅延が起こっても問題ないのでは。
    %
    % b 或いは、何らかの方法を用いて 80-FF に
    %   bind -x する事ができるだろうか。
    %   Bash のソースコードを見たら分かるかもしれない。
    %
    %   \C-x\C-r の re-read-init-file を呼び出してみたが
    %   正しく bind できない事に変わりはない。
    %   LANG や LC_ALL を設定して実行してみても変化はない。
    %
    % [bash debug]
    %
    % 取り敢えず怪しいのは cmd_xmap の構築時である。
    % 他に怪しいのは bind_keyseq_to_unix_command 内で kseq が化けてしまっているという可能性。
    %
    % bashline.c:4312:  rl_generic_bind (ISMACR, kseq, value, cmd_xmap); の直前で、
    % kseq を print してみる。bind -x '"\201": echo 201' に対して "\\201" という文字列だった。
    % この時点では変換前ということなのだろう。
    %
    %   FILE* file = fopen("/home/murase/b1.txt", "wb");
    %   fprintf(file, "kseq='%s'\n", kseq);
    %   fclose(file);
    %
    % bind.c:378: rl_generic_bind の実装の中の rl_translate_keyseq
    % の呼び出しの直後でどの様に翻訳されているかを確認する。
    % この時点ではちゃんと "\201" という文字列になっていた。翻訳は大丈夫。
    %
    %   FILE* file = fopen("/home/murase/b2.txt", "wb");
    %   fprintf(file, "kseq='%.*s'\n", keys_len, keys);
    %   fclose(file);
    %
    % bind.c:397:       if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
    % という怪しい分岐がある。ここで meta を削除している。これなのではないか。
    % これの前後で ic がどう変化するのかを調べてみる事にする。
    % 結果として、ここで \201 が \001 (C-a) に変換されている事が判明した。
    %
    %   FILE* file = fopen("/home/murase/b3.txt", "wb");
    %   fprintf(file, "ic='%c' (%d)\n", ic, ic);
    %     中略
    %   fprintf(file, "ic='%c' (%d)\n", ic, ic);
    %   fclose(file);
    %
    % _rl_convert_meta_chars_to_ascii というオプションが怪しい。
    % bind -v してみると set convert-meta on という行がある。
    % 調べてみると、問題が発生する状況では on になっていて
    % 問題が発生しない状況では off になっているという事が分かった。
    % つまり、この変数を変更すればちゃんと bind できるのではなかろうか。
    %
    % 取り敢えず set convert-meta off にして試してみる事にする。
    % 調べてみると set convert-meta on の時には、
    % 入力された 128-255 の文字は全て Meta + 0-127 と解釈される様だ。
    % なので bind の瞬間だけ set convert-meta off にしておいて、
    % bind が終わったら元に戻すようにしたい。

    結局 bash のバグというよりは rl 変数の convert-meta の仕様(?)という事が分かった。
    仕様だとしても bind -x '"\201": echo 201' が動かないばかりか、
    既存の別の keymap を上書きしてしまうという動作は変なのではないかという気がするが…。

    bind する時だけ一時的に convert-meta off にする様にして修正した。
    と思ったがそれで日本語を入力するとメモリを大量に使って死んでしまう。
    ble.sh をロードしている間は convert-meta は off にしておくべきだろうか。
    detach する時に元に戻す。

2018-05-24

  * 2018-03-19 bash-bug: bash-4.4, dev で以下を実行するとエラーメッセージが出る。 [#D0697]

    →これは修正報告した。
      https://lists.gnu.org/archive/html/bug-bash/2018-05/msg00020.html

    2018-08-05 Note
      これは keymap 切替時に出てくる謎のエラーメッセージにより判明した (#D0692)。
      これは bash 側の問題であるし、実害も余りないので対処しない。

    $ function A { bind -x '"\C-t":A'; }
    $ A
    <C-t><C-t>...

    これは微妙な操作なのでそのまま報告しても無視されるかもしれない。
    これについても原因を解明してから対処したいものである。

    そもそも bind -x を実行している箇所は何処だろう。
    bash_execute_unix_command で実行している。
    うーん。これを解決するには

    a bash_execute_unix_command において
      実行するコマンドの文字列を予めコピーしておく。
    b builtins/evalstring.c: parse_string() において
      一つずつコマンドを実行するのではなくて、
      まとめて読み取って実行するモードを付け加える。

      然し、その為には yyparse を弄るなどしなければならず大変?

    論点

    - 微妙な操作であるがこれは reduced test case だから。
      自分はもっと複雑な処理で実際に必要と判断している。
    - コマンドを
    - 攻撃の対象になる可能性がある。
    - 少なくとも、現在実行中のものに bind しても大丈夫にするか、
      現在実行中かどうかを検出して実行中ならばエラーを吐くなどする必要がある。
      自分は使っているので大丈夫なようにする方を望む。
      また大丈夫なようにするのは比較的簡単で、
      cmd をコピーすれば良い。

      コストが大きいように感じるかもしれないが、
      どうせ evalstring で command を parse するなどするので、
      元々のコストが大きいので気にしなくても良い。
      また、キーボード入力の解釈にそんなに性能は不要のはず。

  * 2018-05-22 どうも history search で見つからない場合に無限ループになる様だ。 [#D0696]

    →無限ループではなく処理に時間がかかっているだけだった。
      問題は .bash_history に 55KiB の履歴行が魂友していた事にある。
      何故その様な行が入っていたのかのはっきりした理由は分からないが、
      それは再度発生した時に確認することにする。

    これは大層困ったバグである。直ちに修正する必要がある。
    先ずは何処か適当な場所で何か出力する様にする。
    先ずは ble-edit/isearch/next-history/forward-search-history.impl に仕掛けてみたが通過しない。
    謎だ。ちゃんと反映されているのだろうか。
    と思ったら backward search の時には特別に blockwise search を使うのだった。

    どうも原因は isearch/process の外で起こっている様だ。謎だ。
    一致が起こって検索が完了した後に無限ループになっている。描画関係だろうか。
    もっと外側で調べなければならない。

    ble-decode/PROLOGUE, ble-decode/EPILOGUE を確かめてみたがそれでも動かない。
    更に外側で起こっている? というか idle ループが問題になっているのでは?
    と思ったが、改めてよく見ると EPILOGUE の最後の最後で止まっている様だ。
    ble-edit/bind/.tail である。
    更に ble/textarea#render の中で起こっている。
    その中の ble/textmap#update で起こっている。
    何と分かったことは、bash_history の中に意味不明に長いコマンドが登録されている事だった。
    55 KiB ある行が二つ登録されている。実際にこのような長いコマンドを入力した記憶はない。

    だとすれば何らかの問題によって、このように長い偽コマンドが登録された事になる。
    普通の bash ではそのような事が起こるとは思えないし、
    やはりこれは ble.sh の問題のような気がする。
    うーん。(history -p -- 'echo *') も ble/uti/assign aaa 'echo *' も異常はない。
    前後に echo * を展開したらしきものもあったので、
    これは何か特殊な操作を実行した時のテストで生成された結果だったのだろうか。
    うーん。何れにしても、ble.sh 自体に無限ループがある訳ではないようだし、
    その様な変な履歴項目が生成される確率も低い (もしくは一時的なものだったかもしれない) ようなので、
    この問題についてはこれ以上考えなくて良いものと判断する。

2018-03-19

  * bash-bug: bash-dev で ble.sh をロードするとクラッシュする [#D0695]

    取り敢えず何処でクラッシュするのかだけは特定しておきたい。
    どんどん絞っていくと以下を実行しただけでクラッシュする。
    ~/.bashrc の先頭に書いても其処でクラッシュするので ble.sh の影響ではない。

    bind -r '\C-j'
    bind -r '\C-m'

    gdb で実行して bt で backtrace を見ると
    rl_generic_bind でクラッシュしている。
    bash-dev で見てみると lib/readline/bind.c で実装されている。
    どうやらクラッシュは、最後の方の

    lib/readline/bind.c:460:  (FUNCTION_TO_KEYMAP(prevmap, prevkey) == rl_binding_keymap) &&

    で起こっている。FUNCTION_TO_KEYMAP は (Keymap) prevmap[prevkey].function に変換される。
    prevmap 及び prevkey を出力してみると prevkey が滅茶苦茶な負の値になっている。

    →これは報告した https://lists.gnu.org/archive/html/bug-bash/2018-03/msg00155.html

2018-03-18

  * bug: [再現せず] bleopt_suppress_bash_output= で、入力された文字が表示されない [#D0694]
    これは initialize の -echo を消したら直ったが、
    何故これで直るのかが分からない。
    後で調べる必要がある。

    これは chatoyancy での振る舞いである。
    これは padparadscha では再現しない。
    bash-4.4 でも再現しない。
    再度 chatoyancy で試してみたが再現しない。

  * bug: bleopt_suppress_bash_output= で、一文字表示位置がずれる [#D0693]

    | 元々、Bash が文字を出力する事を見越して一文字戻した位置にしているが、
    | その文字が実際には出力されていない、という事のような気がする。
    |
    | 因みに bash-3.2 以下ではずれは発生していない。
    | →これはそもそも adjust を使用していないからだった。
    | adjust を使用するのは READLINE_LINE に文字列を設定して置かないと、
    | C-d を検出する事ができなかったからである。
    | しかし bash-3.2 ではそもそもそれも出来ないので adjust はしない。
    |
    | bash-4.0 以上では READLINE_LINE に文字を設定して C-d で exit しない様にしつつ、
    | READLINE_LINE の描画が行われる事を前提として調整を行う。
    | しかし、いつの間にかに READLINE_LINE の内容が描画されない様になっていた。
    | 昔は確かに描画されていて問題になっていたので、これでちゃんと調整できていたはずだ。
    |
    | stty などの何らかの設定の影響を受けて描画されたりされなかったりするのかもしれない。
    | →どうやら stty -echo の状態だと何も出力されないという事の様だ。

    結論: stty -echo にすると Bash は何も出力しなくなるので、
      READLINE_LINE に有限の長さの文字列が入っていても問題は起こらない。

2018-03-18

  * bash-bug: chat で "set -o vi/emacs" すると直後にエラーメッセージが出る [#D0692]
    →これは結局 bash-4.4 のバグの様に思われる。
      set -o vi/emacs でエラーメッセージが表示されるだけで実害はないので対応はしない。

    エラーメッセージは stdout.off の間に起こっている様である。

    stdout.off stdout.on の呼び出しを観察してみると on が連続で二回呼び出されている箇所がある。
    (単に、これは stdout.off が呼び出される前にエラーで中断したという事かもしれないが。)

    うーん。エラーメッセージは前回の off とその直後の on の間に起こっている筈である。
    先ず stdout.off に関しては
    ble-edit/exec:gexec/.end -> ble-edit/bind/.tail -> stdout.off と呼び出されている。
    ble-edit/bind/.tail は stdout.off を最後に呼び出しているので、
    ここでエラーメッセージが出る事はない。
    ble-edit/exec:gexec/.end についても ble-edit/bind/.tail を最後に呼び出している。
    そうすると $_ble_decode_bind_hook に設定されている値が怪しい。

    うーん。エラーメッセージが出た可能性のある時の _ble_decode_bind_hook の値は
    以下の通りである。特に怪しい所はないし gexec/.end は実際に呼び出されているし、
    gexec/.end より後に実行されている物も存在しない。

    | ble-edit/exec:gexec/.begin
    | builtin eval -- 'ble-edit/exec:gexec/.eval-prologue '\''set -o vi'\'' "$_ble_edit_exec_lastarg"
    | set -o vi
    | ble-edit/exec:gexec/.save-last-arg'
    | ble-edit/exec:gexec/.eval-epilogue
    | trap - INT DEBUG
    | ble-edit/exec:gexec/.end

    という事は、 stdout.off の直後ではなくて、stdout.on の直前が怪しいという事になる。
    呼び出しの順序は ble-decode/.hook → ble-decode/PROLOGUE → ble-edit/bind/.head → ble-edit/bind/stdout.on
    の様になっている。chat では特に $bleopt_suppress_bash_output を弄っていないので、
    この時には ble-edit/bind/.head は単に stdout.on を呼び出すだけである。
    ble-decode/PROLOGUE を見てみると .head より後に何か呼び出している。と思ったが、
    エラーメッセージが出てくるのは直後ではなくて直前のはずなので、
    .head より後に呼び出している物に関しては気にしなくても良い。
    そうすると ble-decode/.hook が悪いという事になるが、
    IFS を設定している以外には PROLOGUE より前には何も実行していない。

    こうなってくると次に怪しいのは bind の中身である。
    更に気付いた事は、これは chat に特有というよりは bash-4.4 に特有の様である。
    padparadscha の bash-4.4 でも再現した。
    何れにしても調査を続ける事にする。
    うーん。bind -spX の出力は stdout.on, off で見張っても変化していない。

    - detach/attach の前後で出力してみようと思ったが…。
      これらは gexec の実行過程に組み込まれているので、
      タイミング的には set -o emacs/vi したのと同じ時に実行されている。
      なので、エラーメッセージがこの時に表示されるという事は元々ない。

    - 或いは、bleopt_suppress_bash_output= として見たら状況は変わるか?

      そうすると今度はまともに動かない…。何故だろう。
      -echo を指定したせいだろうか→その様だ。
      うーん。bleopt_suppress_bash_output と stty で何が関係しているのだろう?
      これについては後で調べる必要がある。
      取り敢えず調査の為に -echo は外しておく事にする。
      後、座標の位置が一文字ずれている…。
      Bash によって出力されると予想される物が出力されていないという事の気がする。

      何れにしても bleopt_suppress_bash_output= でも再現した。
      (この場合には画面に直接エラーメッセージが出力される事になる)。

    - もしかすると set -o emacs; set -o vi としただけでもエラーメッセージが出るかもしれない。
      と思ったが何も起こらなかった。やはり binding を弄るとなるという事なのか?

    - 或いは、set -o emacs は全然関係なくて単に ble-decode-detach 及び ble-decode-attach
      だけでもエラーメッセージが発生するのかもしれない→再現した…。
      更に、ble-decode/unbind; ble-decode/bind でも再現するか→再現する。
      これらの関数は基本的に source しているだけである。
      % と思ったら source しているファイルを cat してくっつけて、それを source すると再現しない。
      % % source *.unbind; source *.bind をしても再現しない。
      % % 関数の中では他に特別な事をしている様には見えない。
      % % という事は関数内から source すると駄目なのか。
      % % →やはり再現した。
      →source b.sh (b.sh は unbind と bind をくっつけたファイル) でも再現した。

    - 次に b.sh を編集して試す。先ず初めに bash-4.3 と bash-4.4 の違いと言えば
      ^X を明示的に bind しているかどうかである。
      ^X を含まない b.sh を作ってみるとエラーメッセージは再現しなかった。
      ^X を含む行だけの b.sh を作ってみてもエラーメッセージは再現しない。
      改めて両方を含むファイルを source するとちゃんと再現する。うーん。

      何と、中身を sort してみたら再現しなくなった。
      また、ble-decode/bind だけでも再現する。
      どんどん小さくしていくと、最終的に以下の一行を含むスクリプトで既に再現する。

        bind -x '"\C-m":ble-decode/.hook 13; builtin eval "$_ble_decode_bind_hook"'

      source せずに直接実行しても再現するという事を確認した。
      更に、これは C-j を使って実行している時には再現しない。

    - つまり、bind -x において現在実行しているキーマップに
      -x を指定するとエラーになるという事だろうか。
      と思って bash --norc で以下を試してみた所、再現する。

      $ function A { bind -x '"\C-t":A'; }
      $ A
      <C-t><C-t>...

      これは明らかに bash-4.4 のバグである。
      bash-dev でも確認してみたが未だ治っていない。
      そして、これは ble.sh 側では何ともならない…というか頑張れば何とかなる可能性もあるが、
      現在の方法を滅茶苦茶に変更しなければならない気がするので非現実的である。

      これは保留という事にする。

      というか bash-dev で ble.sh をロードするとクラッシュする…。

  * bug: "set -o emacs" もしくは "set -o vi" で切り替えた直後に stty が変 [#D0691]

    何度か繰り返しても同じ様である。つまり初回だけなる等の事ではない。
    うーん。調べてみると、ble/term/finalize して ble/term/initialize している筈である。

    →どうも ble/term/stty/initialize と ble/term/stty/enter で微妙に違いがある。
    前者の stty に -echo が指定されていない。今回は、新しく指定する事にした。
    ちゃんと動くか確かめる。

    - ok: set -o vi 及び set -o emacs で動作する。
    - ok: source ble.sh で動く。
    - ok: bashrc からの読込でも動く。
    - ok: ble-detach & ble-attach でも動く。

  * bug: mintty (横幅 56) で起動すると unbound keyseq ... 等の表示が欠ける [#D0690]

    ble/term/visible-bell を手動で呼び出しても中途半端な所で欠けて表示される。
    調べてみた所、何と横幅を取得する所で行数を使っていた。

    mintty で起動したらなったと書いたが、
    実際には縦の行数が少ない環境で実行するとなるバグだった。

  * bug: insert mode で C-c にしても disabled の着色にならない。何か変だ [#D0689]

    これは overwrite_mode レイヤーがキャッシュした着色を更新せずに使っていたのが悪い。
    overwrite_mode ではカーソル位置も文字列内容も変更がなかった時に、
    キャッシュした内容をそのまま使う様になっている。
    しかし、実際にはその他の要因 (_ble_edit_line_disabled など) で着色が変わるので、
    本来は毎回着色を変更するべきなのである。

    しかし、それを言い出すと様々な箇所でキャッシュを使えるかどうかが微妙になって来る。
    _ble_highlight_layer__list=(plain syntax region disabled overwrite_mode)
    この設定の下で、より後に来る layer は前の layer の
    PREV_UMIN..PREV_UMAX について更新しなければならない。

    というか、実は他にも表示が崩れるケースが有る。
    region 変化を overwrite_mode で検出していないので、
    $ echo hello world で overwrite-mode で "hello worl" の範囲を選択して home を押すと、
    "echo " だけが反転されるべきだが、"hello world" の選択着色が残ってしまう。

    →実は、これは DMIN ではなくて PREV_UMIN を見て判定すれば良いだけなのでは。
      実際に変更があったかどうかは PREV_UMIN..PREV_UMAX を見れば分かる。
      なので、これだけ見て更新があったかどうかを判定すれば良いのだ。
    →実装した。動いている。

    それとは別に disabled したのに overwrite_mode のカーソル位置が残るのは変なので、
    disabled は overwrite_mode レイヤーよりも後に持ってきたほうが良さそうだ。

  * bug: PS1 で \v が空文字列である [#D0688]

    後、\s にハイフンがない? と思ったら、これは ssh からのログインシェルだと
    -bash になるというだけの事の様だ。これは大丈夫。
    →これは単純なミスだった。直した。

  * bug: bash-3.2 以下で _ble_syntax_attr: bad array subscript のエラーが出る [#D0687]

    これは空文字列で確定をした時だけに起こる。
    調べてみると構文的に完結しているかどうかを判定する関数が悪かった。
    bash-3 では ((iN>0&&_ble_syntax_attr[iN-1])) だと iN=0 の時にエラーになってしまう。
    これは直した。

2018-03-15

  * 単語着色の問題 (2017-11-26 reported by cmplstofB) [#D0686]

    これについては項目が既にあるかと思ったが今探してみた所なかった。
    恐らく以下の項目が実装途中で放棄されているので、
    これに関連して起こっている物と解釈されて放置されていたのだろう。

    | * 2015-08-16 入れ子構造を考慮に入れた効率的な単語着色

    この単語着色の適用範囲の問題は以下の手順で再現する。

    | $ touch abcdef
    | $ echo abc def ghi jkl
    | この状態で abc と def の間の空白を削除する。

    さて、この時一体どの様な処理が走っているのかという事を確かめる。
    先ず、連結した瞬間に更新される単語は連結された単語だけであった。
    これは妥当である。

    単語の着色を調べるとちゃんと範囲内に着色している。
    問題が起こるとすれば sgr を設定する箇所だと考えていたが、
    どうやら単語の着色を行う部分では単に属性値を配列に設定しているだけで、
    sgr を生成して出力する為の文字列を生成している箇所は別のところにある様だ。

    highlight-layer:syntax で使用している buffer は、
    _ble_highlight_layer_syntax_buff であり、この配列に設定を行っているのは
    ble-highlight-layer:syntax/update である。
    確認してみると ble-highlight-layer:syntax/update で設定を行っている範囲が、
    umax の一つ手前までになっている。sgr を弄っているのだから、
    その次も更新しなければならないはずである。
    (描画範囲外なので更新しなくても良い様に思われたが、実際には後で再描画するかもしれないし、
    或いは更に上の layer で範囲が拡大される可能性もあったのである)。

    修正した。

  * 古い ToDo 項目の整理 [#D0685]

    以下の物は対応済み、または、自然解消したものである。

    | 2015-12-03
    |
    | * undo, redo
    |
    | * 色コード ble-color-gspec-list
    |   → ble-color-show
    |
    | * bash-3 で C-d を捕獲する為のメッセージについて
    |
    |   ignoreeof-messages.txt に入れてそれを grep -F で検索する様にした。
    |   しかしながら ignoreeof-messages.txt の中身を読み込んでしまった方が速いかもしれない。
    |
    | 2015-12-01
    |
    | * vi bind
    |
    | 2015-11-18
    |
    | * complete: 存在しない変数名で補完しようとすると \ が挿入される。
    |   ここは何も実行しないで欲しい所である。
    |
    | 2015-08-14
    |
    | * 高速化: $(type -t), $(printf), $(jobs) をファイル書き出し・read読み出しに変更する
    |
    |   $() を read で実行する為の関数 ble/util/assign を作成した。
    |   cygwin 環境で特に遅くなる原因と思われる部分についてはこれに置き換えた。
    |
    | 2015-06-28
    |
    | * complete: 沢山の補完候補が存在する時に表示する内容を絞る
    |
    | 2015-03-01
    |
    | * ble-edit: ble-bind -xf 対応
    |
    | 2013-06-01 以前
    |
    | * ble-decode
    |   + ble-bind: -x オプションに対する対応: BLE_LINE, BLE_POINT, 再描画

    以下のリロード可能にする機能については、
    動機である complete.sh の不整合が遅延ロード対応によって解消されたので、
    そもそも実装する意義を失った。今後も強い需要が出てくるとは考えにくいので削除する。

    | 2017-09-25
    |
    | * ble.sh リロード機能?
    |
    |   complete.sh の不整合で度々に問題になるのでリロード機能ぐらいはあっても良いのでは。
    |   また complete.sh はそれ自身として対策は考えたほうが良い気はする。
    |   例えばバージョンごとにディレクトリを作成してその中で管理するなど。
    |
    |   以前 declare -ir だったものを全て消した。
    |   実はリロードできるのではないか。
    |   但し注意するべき点はいくつかある。
    |
    |   先ず bind を再度実行すると変なことになると思われる。
    |   これについては何らかの変数で現在 bind 中かどうかを判定していたはず。
    |   現在の状態に関する類似のものは色々あるが、これらについては上書きしないようにする必要がある。
    |
    |   また bash-3.0 の C-d 対策に使用する子プロセスや、
    |   stdout/on, off の状態などにも気をつける必要がある。

  * 2017-10-22 edit: RET 文法に基づく改行挿入 [#D0684]

    shopt -q cmdhist &>/dev/null を参照してこれを有効・無効にするのが良い。

    - if .. fi, do .. done, { .. } の対応を取ることを考えていたが、
      よく考えてみると、実は、数を数えてバランスしているかを確かめれば良いのでは?
      後は case esac がある。これらは絶対に対になっているはずである。
      if があれば必ず fi が来る。case があれば必ず esac が来る。他の終わり方はない。

    - for/until/while/select などは do .. done, { .. } で必ず囲まれるので
      本体の中身がバランスしているかどうかは上記の方法で終わっている。

      然し、for/until/while/select が孤立して存在している場合もチェックしなければならない。
      これも for/while/until/select の数と do/{ の数を数え上げればいい気がする。

      どうやって数えるのが良いだろうか。毎回 tree-enumerate したり、
      for in "${_ble_syntax_attr[@]}" するのは遅そうな気がする。
      例えば _ble_syntax_attr に特別な属性を指定しておいて、
      IFS= concat="::${_ble_syntax_attr[*]/%/::}" として、
      後は $concat に対する処理で何とか各属性の数を抽出できないだろうか。

        pat=:$ATTR_KEYWORD_B: a=${concat//$pat}; bcount=$(((${#concat}-${#a})/${#pat}))
        pat=:$ATTR_KEYWORD_L: a=${concat//$pat}; lcount=$(((${#concat}-${#a})/${#pat}))
        pat=:$ATTR_KEYWORD_R: a=${concat//$pat}; rcount=$(((${#concat}-${#a})/${#pat}))

      実際にループで回すのとどちらの方が速いかである。

    - また、文脈値によっては未だ終了してはならない物が決まっているのでそれを見る。
      例えば function aaa() の直後などもこれに含まれる。

    - nest の状態も見る。
    - ヒアドキュメントの待ちキーワードも確認する

    その他のエラーについては、"続きが必要" という種類のものではないので、
    RET を以て改行を挿入して続きを入力するという機能にする必要はない。

    [実装]

    取り敢えず一番簡単な物から実装していく事にする。

    nest の状態を見るのが良い。
    ble-syntax/parse の最後で nest のチェックをしているので、
    それと同等のチェックを行う様にすれば良い。

    というかその前にチェックを行う関数を何処に定義するのか決めなければならない。
    実際の実装は ble-syntax の内部実装に関わって来るので、
    これは syntax 側で実装するようにするのが良い。

    - done: nest が設定されていない事を確かめる
    - done: ヒアドキュメントの予約がない事を確かめる
    - done: 最後の文字にエラーが設定されていない事を確かめる
    - done: 最後の解析再開点の文脈がその場で終わっても良い様なものか。

    % if..fi, do..done, {..}, case..esac については数が一致している事を確認すれば良い。
    % if..then, elif..then, for/until/while/select..do/{ に関してはどの様にチェックすれば良いか。
    % 特に { に関しては孤立して現れた { なのか、構文の一部としての { なのか区別が付かない。
    %
    % うーん。特に { の場合には for/select の直後のコマンドが { であるべきである。
    % (調べてみた所 while/until の場合は {..} ではなくて必ず do..done の様だ)。
    % そしてこの時、文脈値が特別な値になっているのではあるまいか。
    % と思ったが ; の後に {..} が来るパターンには対応していない。
    % というか現在の実装だと ; の直後に何もコマンドがない場合でもエラーにならない。
    %
    % ; の直後に { または do を要求する文脈というのを追加しても良いのではないだろうか。
    %
    % →これらに関しては、do..done ではなく while..done の組にする事にしたので、
    %   改めて考察し直すことになった。

    [どのように対を判定するかの議論]

    a そもそも対になっているものをどのように判定するのが良いだろうか。
      一つの方法は、上で提案された様に対になるものについて特別な attr
      (ここでは begin と end とする) を設定して、
      最終的にその数があっているかを確認する物である。

      この方法だと数が一致しているだけで順番が滅茶苦茶な場合でも accept してしまう。

      # 或いは、_ble_edit_attr に現れる順番も含めて検査するという手もある。

    b もう一つの方法は nparam によって現在どのような構文の中にいるかを記録するもの。

      % この方法だとインデントの実装が楽になる。
      % というか、最終的にインデントを実装しようとしたら、
      % 結局この様な方法に頼らざるを得ないのではないか?
      %
      % と思ったが a の方法を採用していたとしてもインデントは処理できる気がする。
      % 現在の入れ子の開始点から現在位置までの間に何個の begin と end
      % があるかを数えれば良いだけである。

      x この方法だと解析をやり直す範囲が増大する。

      - ちゃんと構文が閉じているかの判定にかかる処理量が減少する。
        と思ったが、構文が閉じていることの判定は RET を押した時ぐらいにしか行わないので、
        この点において効率化しても仕方がない。

      つまり、構文が閉じているかどうかを判定する頻度は少ないのだから、
      できるだけ解析時の処理量は少なくして、実際に判定が要求された時に、
      判定が可能になるような最低限の情報を埋め込むというのが望ましい。

      その様に考えるとこの方法は若干処理が複雑になるので避けたい。

    やはり基本的には当初の考えの通り、a の方針で実装する事にする。
    従って、やはり while/until/for/select の直後に文を要求する。

    [どの予約語の間で対にするべきかの議論]

    a while, until に関しては…現在の実装ではすぐに通常の CTX_CMDX1 に移行する。
      従って、2つ目のコマンドに対して do を要求するというのを実装するのは、
      文脈値で処理するのは難しいように思われる。
      これにこそ nparam を使うという考え方がある。
      次に do が現れるまでを範囲とする。

    b 然し… while .. do .. done / until .. do .. done という構成を考えると…。
      寧ろ、while..done, until..done で対応を取ったほうが良い様な気もする。
      同様に for..done と select..done で対応を取る。
      そして for .. { .. } と select .. { .. } を例外として特別に処理する方が良い。
      for .. { の時は "{" には begin を設定しないという様にするのはどうだろうか。
      for/select については直前まで特別な文脈値で処理するので、
      "{" に対して特別な取り扱いを行う事は比較的簡単のはずである。

    [for/select 直後の文脈の調整]

    | 特に for/select が終わった後の ; の直後として do または { だけを許す文脈値を作れば良い。
    | その文脈値の時には { に begin 属性をつけない様にする。
    | と思ったら既に CTX_CMDXD という文脈値がある。これだろうか。
    | と思ったが、この文脈値は他に ";" も許す文脈であった。
    | つまり、今必要なのでは CTX_CMDXD の ";" を許さない版である。
    |
    | % うーん。或いは、CTX_CMDXD で "; do" まで一気に読み取ってしまうという手もあるのかも。
    | % →いや、これは微妙である。何故なら途中にコメントが入る事もあるし、
    | %   また改行が複数入る可能性もある。
    |
    | 現在の for 及び CTX_CMDXD の実装が色々変だ。
    |
    | - 先ず初めに CTX_CMDXD の直後に ; が来ることが許されている。この時 CTX_CMDX に切り替わる。
    | - for a in 1 2 3 ; の直後で CTX_CMDXD の状態になっている。
    |   つまり、この時更に ; を重ねてから do を書いても構文エラーにならない。
    |   しかし、実際にはこれは構文エラーである。
    | - for (()) を出た瞬間の文脈は CTX_CMDXD だが、; が来ると CTX_CMDX に切り替わる。
    |   つまり for (()) echo は構文エラーを検知できるが、
    |   for (()); echo は構文エラーを検知できない。
    |
    | 以下の様に実装を変更したい。
    |
    | - CTX_CMDXD の直後に ";" が来ることは許さない。改行は OK
    | - for a in 1 2 3 ; の直後は CTX_CMDXD のままで良い。
    |   select に関しても同様の処理で問題ない
    |   (というか select も FARGX3 を使うので特別に気にしなくて良い)。
    | - for (()) の直後は特別な文脈にする。
    |   ";" または "改行" などが来て初めて CTX_CMDXD に移行する。
    |
    | さて、現状の実装で CTX_CMDXD の直後に ";" が来ることを許容しているのはどの部分だろうか。
    | 少なくとも、CTX_CMDX は ";" を許容しないので CTX_CMDXD について特別の判定をしている筈である…。
    | 見つけた。以下の行である。
    |
    |   _ble_syntax_bash_command_Opt[CTX_CMDXD]=1
    |
    | この行を削除しても問題ないだろうか。
    | 先ず _ble_syntax_bash_command_Opt は一箇所でしか使われていない。
    | 次に、これは delimiters が来た時に使われている (改行が来た時には使われていない)。
    | →この行は削除してしまって問題ないだろう。
    |
    | 次に for (()) の直後に来るべき文脈について考える。
    | これについては実のところ CTX_CMDXD の複製で問題ない様な気がする。
    | 取り敢えず現状の CTX_CMDXD を複製した。
    |
    | - done: あと調整しなければならないのは、
    |   ";" が来た時に CTX_CMDXD0 から CTX_CMDX になるのではなく、
    |   CTX_CMDXD になるという事。対応した。';' が来た時に FARGX3 と同様に処理すれば良い。
    |
    | - done: 改行が来た後に CTX_CMDXD0 から CTX_CMDXD に移行するという事。
    |   これも同様に改行が来た時に FARGX3 と同様に処理すれば良い。
    |
    | x done: 試してみると for a ; の直後の文脈が CTX_CMDX になっている。これについても処理する。

    [対にする処理の実装]

    既に決定した様に _ble_syntax_attr を用いて判定する。

    - done: 新しく文脈値(属性)を用意する。

      - ATTR_CMD_KEYWORD → ATTR_KEYWORD
      - new ATTR_KEYWORD_{BEGIN,END,MID}
      ATTR_KEYWORD_MID は後でインデントを実装する際に使用する。

    - done: 次に各キーワードに ATTR_KEYWORD_{BEGIN,END,MID} を割り当てる。
      正しく実装できている事を以下のコードで着色して確かめた。

      | ble-color-defface command_keywordB     fg=blue,bg=225
      | ble-color-defface command_keywordE     fg=blue,bg=192
      | ble-color-defface command_keywordM     fg=blue,bg=195
      | _ble_syntax_attr2iface.define ATTR_KEYWORD_BEGIN command_keywordB
      | _ble_syntax_attr2iface.define ATTR_KEYWORD_END   command_keywordE
      | _ble_syntax_attr2iface.define ATTR_KEYWORD_MID   command_keywordM

    後は、_ble_syntax_attr で該当項目の数を数えれば良い→実装した。

    以下の項目は自然解消したと考える。
    当初はエラー着色がある場合には常に実行しないという案もあったが、
    ただ単に ble.sh の構文解析の不足によってエラー着色が起こる場合もあるし、
    構文エラー以外の理由でエラー着色がある場合も考えられるので、
    取り敢えずの所は明らかに構文が閉じていないなどの時にだけ改行挿入する事にする。

    | 2015-08-20
    |
    | * エラーがある時にはコマンドを実行できない様にする
    |
    |   一番明らかな物は一番初めのコマンドが見付からない場合である。
    |   また、文法構造にエラーがある場合も含まれる。
    |   文法構造にエラーがある場合は ATTR_ERR が指定されている筈である。
    |   然し乍らそれ以外にはエラーを得る情報が無いとも言える。
    |   エラーがある時のコマンド実行について考える前に、
    |   先ずはエラーの処理について再考しておいた方が良いような気がする。
    |
    | 2013-06-01 以前
    |
    | * 問題点
    |   + コマンドが完結していない状態で accept-line すると
    |     既定の動作では続きを入力する事が出来るが、
    |     eval をすると単にエラーになってしまう。
    |
    |     →これは寧ろこの様な動作の方が分かりやすいかも知れない。
    |       取り敢えずそういう仕様と言う事にする。

2018-03-14

  * 2017-09-23 emacs mode でも複数行のときにはそれが分かるような表示を行いたい [#D0683]

    これを実際に実装するためには _ble_edit_str に変更がある全ての箇所で、
    複数行モードになったか、或いは逆に単一行モードになったかをチェックする必要がある。
    とは言っても _ble_edit_str を変更する箇所はそんなに多くないはずである。

    それとは別に現在の引数の状態も表示したい。
    これには _ble_edit_arg が変更された箇所でも変更を行う必要がある。

    表示は keymap/vi の時と同じ様に ble-edit/info/default raw "..." で実行すれば良い。

    a さて、問題は具体的に一つ一つの widget について
      モード表示の変更の可能性がある操作の直後に更新をチェックするか、

    b 或いは、__after_command__ にチェックのコードを挿入してしまうか。
      実は、既に __after_command__ で undo のチェックをしているのではないか?
      と思って確かめてみた所、それは __before_command__ の方だった。
      しかし、どうせ __before_command__ に設定しているのだから、
      __after_command__ に処理を追加しても良い様な気もする。
      何より沢山一度に入力した場合には描画を省略するなどして処理を軽くするのだから、
      __after_command__ 程度なら実行しても良い気がする。
      (と思ったが、貼り付けなどで大量に入力した時の待ち時間が長くなる気がする。)

    取り敢えず __after_command__ で対応する事にした。

    実装した。然し、quoted-insert を用いると実行されない。
    quoted-insert は _ble_decode_char__hook を使って実装されているからである。
    _ble_decode_char__hook は .call-widget を呼び出し、
    .call-widget は直接 eval するのみである。

    a 一つの可能性は .call-widget を改造して __before_command__
      及び __after_command__ を実行する様にする事である。
      実のところ hook を利用して実行する頻度は低いので効率的な面では問題はない。

      次の問題は、既存のコードの動作に対する影響である。
      実のところ、.call-widget を呼び出しているのは、
      _ble_decode_char__hook と _ble_decode_key__hook の二つだけである。
      従って、そんなに影響範囲は大きくない。

      しかし __before_command__ は undo を設定するのに使われている。
      また keymap/vi ではもっと複雑な事をするのに使われているのではなかったか。
      これらについて確認する必要がある。

      - vi-imap/quoted-insert に関しては、寧ろ quoted-insert.hook で
        __before_command__ の真似事をしているので、
        .call-widget で __before_command__ を呼び出した方が良い。
        そうすれば self-insert を直接指定する事ができる気がする。

      - 然し ble/keymap:vi/commandline/__before_command__ に関しては、
        特別なキーの組み合わせで処理をすりかえるのに使っている。
        これは _ble_decode_char__hook (quoted-insert) の時には素通りして欲しい。
        つまり、__before_command__ を使って key binding を動的に判定するのに使っているので、
        quoted-insert の様な key bindings を無視して文字を受け取りたい場合と相性が悪い。

        これについては _ble_decode_key__hook 経由で呼び出している時には、
        無視するなどの対策を行うこともできるが、どうだろうか。直観的と言えるか。

      - 更に ble/widget/bracketed-paste でも __hook が使用されている。
        vi_imap/bracketed-paste では最終的に実行する時に、
        一つ一つ imap-repeat/push を実行している。
        実は、__before_command__ が有効であれば一つずつ実行する必要がなかった可能性がある。
        但し、その時には paste の終端シーケンスを見つけたら、
        その終端シーケンスに対応するバイト数だけ imap-repeat/pop を実行しなければならなくなる。
        どちらの実装のほうが綺麗かというのはよく分からない。

    b 結局、.call-widget で __before_command__/__after_command__ を呼び出す様にすると、
      色々と面倒な事が起こりそうな雰囲気である。

      keymap/vi の quoted-insert でやった様に、
      emacs 専用の quoted-insert を用意して処理したほうが良さそうである。
      後、bracketed-paste に介入する。

    今回は b の方針で実装した。

  * 2018-02-23 起動時間: ble-edit, ble-syntax の読み込み遅延の可能性 [#D0682]

    これで、現在時間がかかる要因になっているのは恐らく ble.sh 本体のロード時間だけである。
    ble.sh 本体のロード時間を短縮するには ble.sh 自体を短くするしかない気がする。
    実際にそれを確かめる為に計測を行ってみる。
    source ble.sh にかかる時間と、ble.sh の中身全体を time { } で囲んだ時の時間から、
    ble.sh の構文解析にかかる時間と、ble.sh の実行にかかる時間を別々に評価できる。

    ble.sh 読み取りと実行 real  0m0.245s
    \_読み取り            残り  \_0m0.162s
    \_実行                real  \_0m0.083s
      \_prologue          real    \_0m0.014s
      \_ble-core.sh       real    \_0m0.008s  1653L   49647B
      \_ble-decode.sh     real    \_0m0.013s  1924L   60832B
      \_ble-color.sh      real    \_0m0.002s   779L   26038B
      \_ble-edit.sh       real    \_0m0.016s  6983L  223652B *一部だけでも遅延可能か?*
      \_ble-form.sh       real    \_0m0.001s   147L    4384B
      \_ble-syntax.sh     real    \_0m0.013s  5082L  178816B *遅延可能か?*
      \_ble-initialize    real    \_0m0.010s
      \_その他            残り    \_0m0.006s

    やはり ble.sh の読み取りに時間がかかっている。
    また行数・バイト数の内訳で見ると ble-edit が一番重くて、
    次に ble-syntax.sh が重い。ble-edit の編集関数部分と、
    ble-syntax については遅延する事も可能な様に思われる。

    2018-02-28 ble-syntax に関しては #D0680 で遅延読み込みに変更した。動作している。
      全体の読み取り時間は 0m0.185s にまで短くなった。実行は 0.070s である。
      単に ble-syntax.sh の部分が 0.013s から 0.001s になったのを反映している。
      結局読み取り時間は 0.115s になったと考えて良い。
      因みに、遅延評価に基づく core-syntax.sh の ble-import は 0.067s かかっている。

      またコメントなどを除去したインストール版を使うと
      ble.sh のロード時間は 0m0.149s にまで短くなった。
      ble-attach の時間は (vi.sh の読み込みも含めて) 0.354s もかかっているが、
      実際の所、プロンプトの表示までにかかる時間は 0.036s である。
      インストール版を使うと ble-attach は 0.336s になるが、
      プロンプトの表示までにかかる時間は 0.036s で変わらない。

      何れにしても現在の実装 (インストール版) では
      プロンプト表示までに合計で 0.185s かかる事になる。

    ble-edit の遅延読み込みに関しては。
    前半の textarea の部分まではすぐに使うので遅延できない。
    widget 群に関しては遅延しても良いがそれほど効果を期待できるかは分からない。
    一部の使用頻度の低そうな widget に関しては遅延しても良いかもしれないが、
    ロードに失敗して何も出来なくなったりするのも嫌なので、やはり含めて置いた方が良いような気もする。
    実のところ、最近のコンピュータは十分速いので現状でもロードに 0.030s しかかからない様である。
    そういう事であれば、苦労して高速化する必要もないのではという気もする。

    それとは独立に ble-edit.sh の中を整理したい気もする。

    2018-03-14 高速化する為には ble-edit.sh を何千行と減らさなければならない。
      しかし、現状では雑多な機能が詰め込まれていて遅延読み込みにするのも面倒そうである。
      実のところ新しい計算機ではそんなに重くないということなどから、
      取り敢えずは ble-edit.sh のち円読み込みには対応しない事にする。
      ble-edit.sh の中の整理に関しては、遅延読み込みとは関係なく少しずつ薦めていきたい。

  * 2016-09-11 やはり履歴のロード時間が気になる [#D0681]

    | time test1=$(ble-edit/history/.generate-source-to-load-history)
    | real    0m3.211s
    | user    0m3.661s
    | sys     0m0.535s
    |
    | time eval -- "$test1"
    | real    0m2.472s
    | user    0m2.383s
    | sys     0m0.080s
    |
    | time _ble_edit_history_edit=("${_ble_edit_history[@]}")
    | real    0m1.552s
    | user    0m1.526s
    | sys     0m0.022s

    generate-source-to-load-history が思いの外遅い。

    time history | cat >/dev/null
    real    0m0.321s
    user    0m0.134s
    sys     0m0.433s

    history 列挙自体はそんなに時間はかからない様だ。
    time command awk ... 2>|~/a.txt
    3.08user 0.02system 0:03.13elapsed 99%CPU (0avgtext+0avgdata 3096maxresident)k
    0inputs+0outputs (0major+281minor)pagefaults 0swaps

    何か変な表示になったが…。
    何故かは分からないが /bin/time が呼び出されている様だ。
    どうやら hoge | time ... とすると time は /bin/time になる様だ。知らなかった…。
    何れにしても awk における処理自体が 3 秒かかっているという事が分かった。
    と、ここで使っている awk の version が古いという事に気づいた。最新版に更新する。
    序に CFLAGS='-O3 -march=native' でコンパイルしてみる。2.5s になった。
    調子に載って icc でも試してみたら 2.6s になった。
    オプションは -fast にしたらリンク関係で失敗したので、-O3 -march=native にした。
    padparadscha の動作が重いようなと思って再起動したら 0.677s にまで短くなった。
    Server というのは長時間起動していると遅くなるものなのか…。
    或いは、kernel のアップデートをする度に何らかの thunk が登録されて動作を置き換えているとかそういう事なのかもしれない。
    という訳でずっと起動しながらアップデートを続けていくとどんどん重くなっていくとかそういう事だったりするのだろうか。

    a 或いは history を配列上に展開するということをしないほうが良いのだろうか。
      つまり ble/util/assign result history ... を用いて各行毎に値を取り出す様にする。
      これは ble/util/assign と配列を辿る速度の差がどれくらいあるかに依存する。
      と思ったが、そもそも history を探してみたが特定の番号の項目だけを抽出する方法がない。
      ということは sed などを起動して目的の行だけを抽出する必要があって、
      アクセス速度はシステムの fork の速度によって律速される。
      つまりとても遅いので使いものにならない。

    b 或いは、必要になった部分だけを少しずつロードするという手もあるかもしれない。
      しかし、そうすると例えば検索で存在しない文字列を入力したりすると、
      何度もロードし直す事になり、余計に時間が掛かる様になる。
      実装が面倒な割に対して効果も得られなそうだ。

    c それとも初めに history の内容を何処か別のファイルに変換してすぐ source できるようにしておいて、
      違いのある部分についてだけ更新を実行するという手もあるかもしれない。
      しかし、必ずしもファイルが後尾に追記されるだけとは限らないし、
      それに対処するために diff などを呼び出し始めると余計に時間が掛かる事になる。
      或いは、history コマンドとは完全に独立に履歴を管理して、
      自分の管理している履歴から bash_history を生成して、
      bash の開始時にはその自分の管理している history を読みこませるという手もある。

    というかこれに関しては既に色々と議論している筈だ。
    → 2016-07-15 #D0346 に記録が残っている。そちらの方が詳しいはず。

    2017-11-11 実は ~/.bash_history を直接読んでしまった方が速い可能性?
    具体的にどれぐらいの時間差があるのかについて調べる。

      $ time mapfile -t array1 < ~/.bash_history

      real    0m0.049s
      user    0m0.038s
      sys     0m0.011s
      $ len=${#array1[*]}; echo len=$len; rex='^eval -- \$'\''([^\'\'']|\\.)*'\''$'
      len=34093

      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} =~ $rex ]] && echo yes; done
      | real    0m2.205s
      | user    0m2.197s
      | sys     0m0.005s
      |
      | 高速化を試みる。
      |
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]::4} == eval && ${array1[i]} =~ $rex ]] && echo yes; done
      | real    0m1.004s
      | user    0m1.002s
      | sys     0m0.001s
      |
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == 'eval -- $'* && ${array1[i]} =~ $rex ]] && echo -n yes; done
      | real    0m0.925s
      | user    0m0.923s
      | sys     0m0.001s
      |
      | 判定を分けて見る。少し速くなる。25ms
      | $ function check1 { [[ ${array1[i]} =~ $rex ]] && echo -n yes; }
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == 'eval -- $'* ]] && check1; done
      | real    0m0.900s
      | user    0m0.897s
      | sys     0m0.002s
      |
      | もっと判定を短くしてみる。クォートはない方が速い (11ms)
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == 'eval'* ]] && check1; done
      |
      |         'eval'*   eval*
      | real    0m0.877s  0m0.866s
      | user    0m0.876s  0m0.865s
      | sys     0m0.000s  0m0.001s
      |
      | ${array1[i]::4} とすると遅いようだ (114ms)
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]::4} == eval ]] && check1; done
      |
      | real    0m0.980s
      | user    0m0.973s
      | sys     0m0.005s
      |
      | 判定で空白まで含めると遅くなる。逆に短くすると速くなる。
      | しかし短くしすぎると偽陽性が多くなるので遅くなる。まあ eval が妥当な所だろう。
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == eval\ * ]] && check1; done
      |
      |         eval\ *   eva*      ev*       e*
      | real    0m0.873s  0m0.859s  0m0.856s  0m1.101s
      | user    0m0.872s  0m0.857s  0m0.846s  0m1.099s
      | sys     0m0.000s  0m0.001s  0m0.008s  0m0.001s
      |
      | for in でループを回す様にしたが寧ろ遅くなった。
      | $ i=0; time for data in "${array1[@]}"; do [[ $data == eva* ]] && check1; let i++; done
      |
      |         let i++   ((i++))
      | real    0m1.320s  0m1.161s
      | user    0m1.306s  0m1.154s
      | sys     0m0.012s  0m0.005s
      |
      | 配列の中身を修正するようにしても特に速度低下は見られない
      | $ function check1 { [[ ${array1[i]} =~ $rex ]] && array1[i]=${array1[i]:8}; }
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == eval* ]] && check1; done
      |
      | real    0m0.853s
      | user    0m0.852s
      | sys     0m0.000s
      |
      | 実際に目的の補正を実施してみる。
      | $ time mapfile -t array1 < /tmp/hello.txt
      |
      | real    0m0.056s
      | user    0m0.048s
      | sys     0m0.008s
      |
      | $ function check1 { [[ ${array1[i]} =~ $rex ]] && eval "array1[i]=${array1[i]:8}"; }
      | $ time for ((i=0;i<len;i++)); do [[ ${array1[i]} == eval* ]] && check1; done
      | real    0m0.864s
      | user    0m0.863s
      | sys     0m0.000s


      或いは、~/.bash_history でなくて history を何処かに出力するというのでも良い。
      $ time history | sed 's/[[:space:]]*[0-9]\{1,\}[[:space:]]*//' > /tmp/hello.txt

      real    0m0.146s
      user    0m0.167s
      sys     0m0.049s

      もしこれをする位であれば、現状の方法で eval をする代わりに mapfile で読み出せる様にした方が良い?
      と思ったが、改行を含む場合に何ともできないのでやはり駄目だ。
      しかし、配列の複製よりも mapfile の方が速い様だ…。

      $ time array2=("${array1[@]}")

      real    0m0.590s
      user    0m0.577s
      sys     0m0.012s

      現在の読み取りの枠組みでどれだけ時間がかかっているのかについても確認しておく。

      $ time ble-edit/history/load

      real    0m2.320s
      user    0m2.453s
      sys     0m0.228s

      うーん。mapfile による実装を合計すると大体同程度なのでは。

      history > tmp 146ms
      mapfile       56ms
      複数行補正    864ms + α
      配列コピー    590ms
      --------------------
      合計          1656ms (71% of 2320)

      計算してみると多少短くなっているが、そんなに変わらない。
      しかし、この新しい方法の利点は何かというと、
      一番処理に時間のかかる部分がループになっているので、
      処理を分割して少しずつ裏で更新を行うことができる点にある。

      さて。この方法の問題点は shopt -s lithist の時に、
      改行を含むコマンドが分割されてしまうという事にある。
      改行を含む場合には eval -- の形に変換するなどの工夫が必要になる。
      しかし其処まで行くと、awk でできるだけ処理してからという事もできる。

    2018-03-12 本格的にこの方針での実装について考える。
    先ず初めにファイルに出力する。

      複数行に亘る history entry が登録されている場合の為に、
      awk または sed で処理する必要がある。
      実際に両方で実装してみた所、awk の方が微妙に速かった。

        history | awk ... 0m0.574s for 37002 entries
        history | sed ... 0m0.634s for 37002 entries

        | # 0m0.634s for 37002 entries
        | time builtin history | ble/bin/sed '
        |   s/^ *[0-9]\{1,\}\*\{0,1\} \{1,\}__ble_ext__)//
        |   s/^ *[0-9]\{1,\}\*\{0,1\} \{1,\}??//
        |   tF
        |   ${H;s/.*//;bF;}
        |   H;d
        | :F
        |   x;s/^\n//
        |   /\n/ {
        |     s/['\''\\]/&/g
        |     s/\n/\\n/g
        |     s/.*/eval -- $'\''&'\''/
        |   }
        |   p
        |   ${s/.*//;x;/./{x;bF;};x}
        |   d
        | ' > "$tmpfile"

      awk 版を採用する事にする。
      さて、この操作は時間がかかるので background で実行する?
      sleep ring だとかを実装すると良いかもしれない。
      うーん。取り敢えずは sleep ring だとかは考えずに
      同期的に待機して処理を行うことにする。
      少しユーザを待たせることになるが、対策は後で行えば良い。

      次に実行するのは mapfile である。
      配列を走査して複数行コマンドを修正するのも実装した。
      _ble_edit_history_edit については、
      配列の複製は時間がかかるので、これも mapfile で処理することにする。
      但し、配列は走査せずに _ble_edit_history で修正を行った要素の番号を記録する方法を取る事にした。
      そうすると 11ms で書き換えは終わった。

      | progress の表示
      |
      | 配列を走査している間は progress を info に表示する様にした。
      | progress を Unicode の文字を使用して描画するとずれる。
      | 調べてみると blesh 及び Poderosa は幅 1 と認識しているが、
      | screen が幅 2 と認識している様だ。
      | 使っている screen は ~/local/bin/screen である。
      | cjkwidth emacs は .screenrc に書かれている。
      | もしかすると cjkwidth のコードが誤っているという可能性もある。
      |
      | ずれは \r を最後に出力すれば収まる。
      | 但し、これで問題が発生しないのは端末の幅が十分にある時のみである。
      |
      | todo: screen の cjkwidth emacs のコードを確認する?
      | todo: progress を表示するより効率的な枠組みを作成する?

      →これに関しては新しく独立した項目を立てる事にした。

    2018-03-13 実は awk で書き換えが必要な index を調べておけば、_ble_edit_history も 11ms で終わるのでは?

      | これを実現する為には awk で別のファイルに書き出せる様にしなければならない。
      | もしくは /dev/stderr に書き出す? /dev/stderr は GNU awk では特別扱いの対象である。
      | POSIX awk では /dev/stderr が存在する事が保証されているだろうか。
      |
      | 調べてみると保証されていない様だ。そして実際に AIX には /dev/std??? は存在しない。
      | https://unix.stackexchange.com/questions/338667/unix-systems-without-dev-stdin-dev-stdout-and-dev-stderr
      |
      | POSIX awk のページを見てみると、少なくとも redirection には対応しているので、
      | これを使ってファイルを保存すれば良い。

      実装した。両配列について 22ms で書き換えが完了する。

        0m0.523s history | awk > tmpfile
        0m0.049s mapfile -t _ble_edit_history
        0m0.047s mapfile -t _ble_edit_history_edit
        0m0.022s 複数行コマンド履歴の補正 (107項目)

      これで合計 641ms になった。

      結局、走査するループがなくなったので progress は使われなくなった。
      以下に progress を表示するのに使っていたスクリプトの断片を残しておく。

        local ret
        ble-edit/history/string#create-unicode-progress-bar "$i" "$len" 6
        local bar=$ret
        ble-edit/info/immediate-show raw $'processing multiline history [\e[38;5;63m'"$bar"$'\e[m]\r'

    2018-03-14 次に修正するべき事は、history | awk > tmpfile の高速化である。

      history -n に 37ms かかっている。
      その後の history | awk 本体が 481ms である。
      因みに history | awk '{print}' > tmpfile だと 188ms なので、
      具体的に awk で実行している処理によって 300ms 程度時間を消費している事になる。
      これについては短縮のしようがない様に思われるので、background process を作成する。

      実装した。動く様になった。と思ったら、実行した background process がジョブに登録されている。うーん。
      % これは subshell の中で shopt -u huponexit で & echo $! を呼び出す様にして、
      % それを ble/util/assign から読み取る様にした。
      と思ったが ble/util/assign で subshell を作るぐらいなら、単に result=$(...) を使えば良い。

      これで background で素早くロードすることが可能になった。気にならない。

    これを以て履歴ロードの高速化は解決したものと考える事にする。
    以下の項目は自然解消した。

    | 2016-07-07
    |
    | * _ble_edit_history, _ble_edit_history_edit 初期化高速化について
    |
    |   これについての詳細な議論は 2016-07-15 #D0346 に残す。ここでは概要について述べる。
    |
    |   時間計測すると 40% が generate-source-to-load-history (awk) であり、
    |   40% が eval -- '_ble_edit_history=(...)' であり残りの 20% が
    |   _ble_edit_history_edit=("${_ble_edit_history[@]}") である。
    |   どのステージでも高速化の効果が同程度にあると見て良い。
    |
    |   現在現実的な手法として残っているのは以下である。
    |   - _ble_edit_history_edit clone 遅延
    |   - generate-source の非同期実行
    |
    |   記述の汚さの割に大幅な高速化が見込める訳ではないので現在は採用していない。
    |   今後高速化で問題になる様なことがあれば上記の項目・その他について考える。

2018-02-27

  * 2018-02-23 idle: ble-syntax.sh の遅延読み込み [#D0680]

    ble-syntax は比較的重いモジュールなので遅延読み込みにできるならばそうしたい。
    ble-syntax は外から利用している関数が少ない (疎結合) なので分離可能と判断した。

    [API確認]

    ble/util/idle の仕組みを整えたので改めて考え直す。
    先ず公開インターフェイスの小さそうな ble-syntax について考える。
    ble-syntax.sh で定義されている関数について調べると、以下の様な物がある。

    - ble-syntax/*
    - ble-syntax:*
    - ble-highlight-layer:syntax/*
    - _ble_syntax_attr2iface.define

    これらの内他のファイルから呼び出される関数は以下の通り:

    - ble-syntax/completion-context
    - ble-syntax/parse
    - ble-syntax:bash/extract-command
    - ble-syntax:bash/simple-word/eval
    - ble-syntax:bash/simple-word/is-simple
    - ble-highlight-layer:syntax/update
    - ble-highlight-layer:syntax/getg

    ble-syntax/parse, ble-syntax/completion-context 以外に関しては
    complete.sh もしくは command-help から呼び出される物であり、
    半ば ble-syntax/parse が終わっている事が前提になっている物である。
    従って、ble-syntax/parse 及び ble-syntax/completion-context についてだけ
    autoload に登録しておけば良い様な気もするが、実際に誤って使う事もあるかもしれないので、
    これらの関数についても ble-autoload しておいた方が無難であろう。

    他に ble-syntax.sh で定義されている変数を参照している箇所は。

    - _ble_syntax_VARNAMES (ble-edit.sh)
    - _ble_syntax_ARRNAMES (ble-edit.sh)
    - _ble_syntax_lang (ble-edit.sh)
    - _ble_syntax_bash_simple_rex_element (complete.sh)
    - _ble_syntax_lang (vi.sh)

    ble-edit.sh で参照している変数は何れも単に最初に設定すれば済む話である。
    vi.sh で参照している変数もこれは最初に設定するので問題ない。
    complete.sh で参照している部分に関しては…これは ble/widget/complete
    の呼び出し時に ble-import syntax.sh するしかない。

    [実装方法]

    さて、問題は ble-syntax/parse を如何に遅延するかという事である。

    | a 一つの案は text が空の場合には ble-syntax/parse は呼び出さないという物である。
    |
    |   x しかし、それだと有限の長さの文字列から ble-syntax/parse になった時の更新が為されない。
    |
    |   x ok: 更に、初回の ble-syntax/parse の呼び出しで設定されるべき初期値が変な値になるのではないか?
    |     と思ったが、よく考えたら ble-syntax/parse では、解析開始点が文字列先頭の時には既定の設定を用いるのだった。
    |     従ってこれについては問題はない。
    |
    | b 或いは、syntax.sh を読み込むまではダミーの ble-syntax/parse を置いておいて、
    |   このダミーの ble-syntax/parse では何も実行しないなど?
    |   そういう意味で言うと ble-highlight-layer:syntax/update 及び getg についても
    |   それに合わせた実装にしなければならない。

    (結局最終的に b に近い実装になった)

    ble-edit の実装を観察してみると ble-syntax/parse は _ble_edit_str.update-syntax から呼び出している。
    他からは呼び出していない。なので、弄るとすればここを弄れば良いだろう。
    扨、観察してみると実は変更範囲がない時には ble-syntax/parse は呼び出されない。
    つまり、ble-syntax/parse に関してはそのまま ble-autoload しても良さそうに思われる。
    がしかし…入力したそばから何か入力した場合には、取り敢えず無着色でも良いから呼び出すという態度も考えられる。
    この辺りはどちらでも良い様な気もする。

    というか ble-syntax/parse を呼び出さないと何が起こるのだろうか…。試してみる価値はある。
    →試してみた所、何事もなく動いている。着色がされず補完ができないというだけである。

    次に、ble-highlight-layer についても考えてみる。実は既定で region 等は読み込まれるので、
    これらについての着色はすぐに有効になるのが自然である。
    問題は syntax をどの段階で処理するのか…という事である。
    うーん。これについては適当なダミーの ble-highlight-layer を最初に定義すれば良い気がする。
    ダミーの ble-highlight-layer は選択範囲がない場合の region と同じように動作すれば良い。

    [実装]

    どうやら技術的に可能の様に思われるので ble-syntax.sh の分離を実行する事にする。

    →実装した。動いている。ロード中に補完まで呼び出した場合でも動作する。

    x 但し、ロード中に一頻り何か入力して、その後アイドルになって syntax がロードされたとしても、
      その場では着色されず、次に何らかの操作があった時に初めて着色される。
      idle の後には textarea#render を折角実行しているのだから、
      core-syntax.sh がロードされた瞬間に全体を invalidate すれば良さそう。

      a ×: 文字列全体を reset すれば良いのではないかと思ったが、
        textarea#render は賢い作りになっていて、文字列の内容が同じならば反応しないようだ。

      b 結局 ble/textarea#invalidate を呼び出すしか無さそうだ。
        しかしプロンプトの計算も個別にキャッシュされているのでそんなには重くはなさそうだ。
        単に全体を再描画するシーケンスを出力するというだけである。

      OK ble-syntax.sh の末尾で ble/textarea#invalidate を実行するようにしたら大丈夫。

    o bash-4.0 でも動作するか。
    o bash-4.1 でも動作するか。
    o bash-4.4 でも動作するか。
    o bash-3.2 でも動作するか。
    o bash-3.1 でも動作するか。
    o bash-3.0 でも動作するか。

    何れの version でも問題なく動作している。

  * 2017-11-25 complete: 更新する度に complete.sh の不整合が問題になっている [#D0679]

    % やはり、遅延読み込みはやめた方が良いのでは。
    % 然し、それを言い出すと今後対応する予定である
    % cmdinfo の類についても遅延読み込みできなくなる。
    % もしくは、安定した API の下での実装という事になる。
    %
    % 或いは別の方法として ble.sh の細かい version 毎に
    % complete.sh をインストールするという手もある。
    % version の管理は面倒なので ble.sh の日付をそのまま使っても良い。
    % 或いは、起動時にファイル一式を何処かにコピーする。

    →これは idle になった時に遅延読み込みするという方法が良い。
    history の load 高速化も含めてその仕組みを作りたいので、
    その時に実装する様にする。

  * idle 時に何かを実行する為の枠組みを整える [#D0678]

    以下の箇所で待ちを行う必要がある。

    - ble-attach
    - eval "$_ble_decode_bind_hook" 周辺

    read -t 0 (というか ble/util/is-stdin-ready) を実行して何も来ていなければ idle 処理を実行する。
    idle 処理の内部では ble/util/is-stdin-ready を定期的に実行して
    何か文字が来たら即時中断できる様に実装する。
    更に続きの処理を実行できる様に中断時に状態を記録する。

    | - _ble_decode_bind_hook 周りに関しては多少考察が必要になる。
    |   現在の実装では _ble_decode_bind_hook は専ら exec:gexec で使用される。
    |   というか、他の場所で値が設定される事はない。
    |
    |   もう少し詳しく見る事にする。
    |
    |   | 先ず初めに ble-edit/exec:gexec/.setup の中で設定される。
    |   | 設定内容は以下を含む。
    |   | - ble-edit/exec:gexec/.begin
    |   | - コマンドの個数だけ以下を繰り返し実行:
    |   |   - ble-edit/exec:gexec/.eval-prologue ...
    |   |   - コマンド実行
    |   |   - ble-edit/exec:gexec/.save-last-arg
    |   |   - ble-edit/exec:gexec/.eval-epilogue
    |   | - trap - INT DEBUG
    |   | - ble-edit/exec:gexec/.end
    |   |
    |   | 次に $_ble_decode_bind_hook 経由で実行が実際に行われる。
    |   | 一番最初に呼び出される ble-edit/exec:gexec/.begin の中で
    |   | $_ble_decode_bind_hook はクリアされる。
    |   |
    |   | 最終的にコマンドが実行された後に、
    |   | ble-edit/exec:gexec/.end が呼び出される。
    |   | 内部で以下の関数が呼び出される。
    |   |   ble/term/enter
    |   |   ble-edit/bind/.tail
    |
    |   この様に考えてみると、実のところ特別に新しく hook を用意するのではなくて、
    |   単に ble-edit/bind/.tail 辺りで idle 処理を実行すれば良い様な気もする。
    |
    |   因みに ble/term/enter は "ble/term/leave → コマンド実行 → ble/term/enter"
    |   の流れを構成する物であって、ble.sh による処理はこの外側で実行するべきものの様に思われるので、
    |   ble/term/enter の中で処理するなどの可能性は最初から除外して良い。
    |
    |   さて。ble-edit/bind/.tail の中では info/reveal して textarea#render して stdout.off している。
    |   アイドル時には textarea#render の後で ble/util/buffer.flush >&2 してから入れば良い。
    |   stdout.off はそれよりも後で最後に実行すれば良い。
    |
    | - ble-edit/bind/.tail がどの状況で呼び出されるのかについて確認しておく必要がある。
    |   →これは基本的に ble-decode/EPILOGUE で実行される。
    |   コマンドの実行予定がある場合には ble-edit/exec:$bleopt_exec_type/process を呼び出した時に、
    |   内部で ble-edit/bind/.tail が予約されるので、そのまま抜ける。
    |   コマンドの実行と共に $_ble_decode_bind_hook の内部で最終的に ble-edit/bind/.tail が呼び出される。
    |
    |   ble-edit/bind/.tail-without-draw については、忙しい時に呼び出される物なので、
    |   アイドル処理を行うかどうかについては確認しなくて良い。

    これらの様子を総合すると、ble-edit/bind/.tail の textarea#render の直後で
    アイドル処理を実行する様にすれば良い。

    ble-attach の最後の部分でも ble-edit/bind/.tail を呼び出す事にした。

    o ok: 取り敢えず以下の様なダミーの処理が違和感なく動いている事を確認した。
      どうも 0.05 程度の遅延が違和感の無いぎりぎりの様に思われる。

      | function ble-edit/test/count-up {
      |   while ! ble/util/is-stdin-ready; do
      |     ble-edit/info/show text $((_ble_test_count++))
      |     ble/textarea#focus
      |     ble/util/buffer.flush >&2
      |     ble/util/sleep 0.05
      |   done
      |   return 148
      | }
      | ble-edit/idle/push ble-edit/test/count-up

    o ok: 試しに以下の様にして見たところ、ちゃんと ble-attach 時に既に入力がある場合には、
      それらの入力を処理してから履歴のロードが始まるという事を確認した。
      つまり ble-attach (from bashrc) でも ble/util/is-stdin-ready が正しく認識できている。

      | ble/util/isfunction ble-edit/idle/push &&
      |   ble-edit/idle/push ble-edit/history/load

    序で complete.sh の遅延ロードに対応した。動いている。

  * 2017-11-03 vi-mode (extract-block): [Optimize] 現在の実装では毎回フルに矩形を計算している [#D0677]

    しかし、一部のコマンドでは一部の情報しか必要としないものも多い。
    例えば xmap I, xmap A では sub_ranges[0] と sub_x1, sub_x2 しか使用しない。
    また xmap O では sub_ranges[0] と sub_ranges[最後] しか使わない。
    extract-block に途中の行について取得しないオプションがあっても良い気がする。

2018-02-23

  * bash-3.0: コマンドの着色が常にエラーになっている [#D0676]
    これは ble-highlight-layer:syntax/word/.update-attributes/.proc の中に
    local var=() の形式の変数代入があったのが原因だった。直した。

  * 起動時間: プロンプト表示までの時間の短縮 [#D0675]

    起動時間がどんどん肥大化していく。起動時間を短縮する事はできないだろうか。

    - 例えば、一番最初にプロンプトだけは表示してしまうなど。

      1 プロンプトを表示する
        この為には ble-form.sh 及び ble-edit.sh の描画関連は読み込んでいる必要がある。
        更に着色関連で ble-color も読み込んでいる必要があるかもしれない。

      2 次に ble-decode-bind の設定を行う
        これを実行しないとキーボード入力を受けても反応する事ができない。
        ただ、多少遅れて処理を行っても問題ない様な気もする。

        現状の実装では ble-decode-bind を実行した時点で
        __attach__ 等の処理も実行する必要がある。

      実は現在の実装では先に 2 を実行してから 1 を実行している。
      これを逆にするだけでも体感が異なるのではないかという気がする。
      取り敢えずそのようにした。

    - 更に、keymap の初期化も遅らせる事ができるのではないだろうか。と思ったが難しいかもしれない。
      というか現状で一番時間を食っているのは vi.sh の読み込みのような気もする。
      vi.sh の読み込みを遅延させるとすると…
      vi.sh 側でキーマップ初期化時に呼び出すべき hook を提供するという手もある。
      しかし、そうしたとしても結局、実際にコマンドを入力できる様になるまでの時間は変わらないので、
      あまり意味が無いのではないかという気もする。うーん。

      実際に実装してみた。bashrc の中で ble-bind を実行するとその場で読み込んでしまうので、
      それぞれの keymap に load_hook を用意してそれに登録してもらう事にした。
      実際にやってみると遅延してロードする様になった。
      やはり体感としてはできるだけ早くプロンプトを出した方が安心できる気がする。

2018-02-22

  * vi-mode: BUG 行指向の貼り付けが動かなくなっている [#D0674]
    調べるとそもそも記録された時点で charwise になっている。何故だろうか。
    更に Vy としても charwise になっている。全然駄目だ。
    →直した。と思ったが何故これで全部直ったのかは謎である…。
    何らかの勘違いもあったかもしれない。現状では動いているので良しとする。

    直前の問題の Y や yy でカーソルが動く問題も
    これが関係しているかと思ったが関係なかった。

    x fixed: :reg において既定のレジスタ "" が表示されていない。直した。

  * 2018-02-21 vi-mode: Y で行頭には動かないのが正しい動作 [#D0673]
    というか yy でも動かないのが正しい動作。
    試してみると g~~ では動く。という事は y の時だけ特別扱いという事か。
    もしくは、何も編集が起こらなければカーソル位置は動かさないということなのか。
    しかしだとすると charwise の y の時に動くという事の説明が付かない。
    やはり linewise y だけ特別にカーソルを移動しないという振る舞いなのだろう。

    - done: という訳で operator:y の line の箇所を変更する。

    - done: また、operator:d の実装を operator:y の実装に頼っているのは
      operator:y 独自の動作を実装するのに不都合であるから、
      operator:d はそれ自体で完結する様に実装し直した。

  * vi-mode: support smap [#D0672]

    | 2017-09-17
    |
    | * cmplstofB: ビジュアルモード・選択モード?
    |
    |   * 選択モードは範囲に対する挿入モードのような気がする。
    |     選択モードは取り敢えず対応しないことにする。

    * 選択モードは範囲に対する挿入モードのような気がする。
      選択モードは取り敢えず対応しないことにする。

    - done: 選択モードにもビジュアルモードと同様に3種類のモードが存在する。
      vi_xmap と似た別の keymap (vi_smap) を作成すれば実は直ぐに対応が完了してしまうのではないか。

    - done: 選択モードではテキストオブジェクトは呼び出されないと考えて良い。
      しかし、やはり後になって呼び出したくなったりすると行けないので取り敢えず xmap と同じ動作で対応する事にする。

    - done: Select-mode: この説明によるとシフトを押さずに移動コマンドを実行すると
      選択モードを抜けるという事になっているが実際にやってみるとそんな事はない。
      と思ったが、これはどうやら keymodel 変数の値によって振る舞いが変化する様だ。

    - done: 後は通常の文字及び C-m を入力した時に operator c に続いて何か入力したのと同じ状態にする。

    x fixed: C-g で切り替えた時にモード表示が更新されない。修正した。

    x fixed: 文字を入力した時に無限ループになる。そして segfault した。
      これは operator が vi_smap を認識していないのが原因だった。

    - done: 何か入力した時の . で記録される内容はどうするか。
      普通に operator c が指定された場合にはどの様な振る舞いだったか?

      因みに現在の実装で試しに実行してみた所 a が重複して再生されている。
      実は ble-decode-key で呼び出さずに直接 self-insert して良いのかもしれない。

    - done: vi-command/operator で .save-visual-state するべきだろうか。
      vim で試してみると実際に記録している様だ。復元時はビジュアルモードになる。
      現在の ble.sh の実装でもその様に動いている。

    x fixed: C-v で矩形ビジュアルではなくて矩形選択に移行している。直した。

    以下の機能には対応しない

    - gV という機能の説明が謎である。
    - keymodel=startsel の時に "S-移動コマンド" で選択モードに移行する機能

  * ble-edit: ble/widget/.goto-char 廃止 [#D0671]

    #D0407 に多少記録が残っている。
    現在ではこの関数は単に _ble_edit_ind を設定するだけで何もしていない。
    _ble_edit_mark に対する代入との非対称性が気になるので、この関数は廃止する事にする。

    また、現時点でも幾つかの箇所で _ble_edit_ind を直接変更している物がある。
    もし仮に将来的に再度 _ble_edit_ind の設定を検出しなければならない状況になったとしても、
    改めてこれらの箇所について一つ一つ必要かどうかを判定する必要が出てくるだろうし、
    また同時に _ble_edit_mark の検出にも気を配らなければならない。

  * vi-mode (xmap txtobj quote): xmap での振る舞いに対応 [#D0670]

    振る舞いについて調べる必要がある。

    | 先ず初めに行を跨ぐことはない。既に行を跨いでいる場合には i" も a" もベルになる。
    | また、行頭から数えて奇数番目の " から偶数番目の " を一つの <quote> として捉えている様だ。
    |
    | 先ず i" の前方拡張について調べる。つまりマーク < 現在位置の時の振る舞い。
    |
    |   % 先ずマークと現在位置の間に <quote> 境界がない場合について。
    |   %   現在位置が quote の外側にいる場合には次の <quote> の内部を選択する。
    |   %   現在位置が quote の内側にいる場合には現在の <quote> の内部を選択する。
    |   %   但し、既に内部を選択している場合には <quote> の外側を選択する様に拡張する。
    |   %
    |   % 端点が <quote> 境界を跨いでいる場合にはその端点は動かさない様だ。
    |   %   % - 現在位置が <quote> の外側にいる場合には次の <quote> の内部の終点に行く。
    |   %   % - 現在位置が <quote> の内側にいる場合には現在の <quote> の内部の終点に行く。
    |   %   % - 既に <quote> の内部終点にいる場合には動かない。
    |   %   %   但し引数として 2 以上を指定すると外部終点に移動する。
    |   %   %   どんなに大きな引数を指定しても単に現在の <quote> の外部終点に移動するだけである。
    |   %
    |   %   % <quote> の内部にいる場合にはその <quote> の内部終点に移動する。
    |   %   % 引数として 2 以上を指定すると外部終点に移動する。
    |   %   % 3 以上の引数を指定しても 2 を指定した時の振る舞いと変わらない。
    |   %
    |   %   現在位置以降にある <quote> の内部終点まで範囲を拡張する。
    |   %   もし現在位置以降に閉じた <quote> がなければ孤立 " の手前まで拡張する。
    |   %   もし孤立 " もなければベル。
    |   %   引数が 1 以下の時、その <quote> の内部終点に移動する。
    |   %   引数が 2 以上の時、1 文字拡張して " を範囲に含める。
    |   %
    |   % 丁度現在位置に " がある場合…。
    |   %   この場合は <quote> 関係なく、現在位置の次の文字から "..." ペアを見つけて
    |   %   それを <quote> と考える。後は、上と同じ振る舞いをする。
    |   %
    |   % 端点が " の上にある時、これは "<quote> 境界を跨いでいる時" と同じだ。
    |
    |   先ず丁度現在位置に " がある場合、
    |     その次の位置以降から "..." ペアを見つけて終端の " の位置を A とする。
    |     一つしか " がない場合には、その " の位置を A とする。
    |   それ以外の場合、
    |     現在位置の次の位置以降から <quote> の終端になる " を見つけて、その位置を A とする。
    |     その様な " が見つからない場合にはベルを鳴らして中止。
    |     更に、マークの一つ前から現在位置の範囲に " が含まれない場合、B = 1 を設定する。
    |
    |   a" の場合、
    |     A の位置に移動する。続いて空白がある場合にはそれも取り込む。
    |     B == 1 ならば、マークを A よりひとつ前の " の直前まで移動し、その前に空白があればそれも取り込む。
    |   引数が 2 以上の時、
    |     A の位置に移動する。B == 1 ならば、マークを A より一つ前の " の直前まで移動する。
    |   引数が 1 以下の時、
    |     A の手前に移動する。B == 1 ならば、マークを A より一つ前の " の直後まで移動する。
    |
    | i" で、マークと現在位置が同じ位置にある場合には明らかに振る舞いが変化する。
    |
    |   % <quote> 内部にいる時にはその <quote> を A とする。
    |   % <quote> 外部にいる時は、
    |   %   先ず backward に " を探して見つからなければ forward に " を探す。
    |   %   もし見つかったら、次にそれより後にもう一つ " を見つける。
    |   %   このペアを A とする。もし見つからなければベルを鳴らして中止する。
    |
    |   先ず [行頭, ind+1) から最後の " を探す。見つからなければ forward に " を探す。
    |   もし見つかったら、次にそれより後にもう一つ " を見つける。
    |   このペアを A とする。もし見つからなければベルを鳴らして中止する。
    |
    |   a" の場合、範囲A全体とその周りの空白を選択する。
    |   引数が 1 以下の時は範囲 A の内部を選択する。
    |   引数が 2 以上の時は範囲 A 全体を選択する。
    |
    | i" で、現在位置がマークより前にいる時も調べる必要がある。
    |
    |   % 現在位置に " がある場合、それより前の <quote> 開始点を A とする。
    |   % 実は現在位置に " があるかどうかは関係ない様だ。
    |
    |   現在位置より前の <quote> 開始点を A とする。
    |   見つからない場合にはベルを鳴らして中止する。
    |   [現在位置, マーク + 2) の範囲に " がなければ B = 1 を設定する。
    |
    |   a" の時は、A直前まで移動して更に空白を取り込む。
    |     B == 1 ならばマークを対応する " の直後まで移動し、空白があれば取り込む。
    |   引数が 2 以上の時は A の位置まで移動する。
    |     B == 1 ならばマークを対応する " の直後まで移動する。
    |   引数が 1 以下の時は A の直後まで移動する。
    |     B == 1 ならばマークを対応する " の直前まで移動する。
    |
    | % a" についても同様に三通り調べる必要がある。
    | % どうも a" の場合は引数を指定しても効果は無いようだ。
    | % そして i" の時と違って <quote> の外側に隣接する空白も取り込む様だ。

    現在の選択範囲が複数行に亘っている場合には throw (ベルを鳴らして中止) する。
    以降は行内での拡張を考える。
    行頭から偶数番目の " を 右" とし、右" の一つ前にある " を左" として区別する。
    行頭を beg とし、行末を end とする。現在位置を ind とし、支点を mark とする。
    選択範囲は [min(ind,mark), max(ind,mark)+1) になる。

    a" の時 mode = a, i" で引数が 2 以上のとき mode = q, それ以外の時 mode = i とする。
    mode = i は " を含まないような範囲である。もし "" 等の様に中身がない場合は q と同じ様にする。
    mode = q は丁度 " を含むような範囲である。
    mode = a は mode = q から更に右側の空白も取り込むように拡張を行う (左側の空白は取り込まない)。

    mark == ind の時、
      A1 = [beg, ind+1) にある最後の " || [ind+1, end) にある最初の " || throw
      A2 = [A1+1, end) にある最初の " の終端位置 || throw
      mode に応じて [A1, A2] を囲む。
    mark < ind の時、
      ind の位置に " がある時
        A = [ind+1, end) にある最初の "
        A = [A+1, end) にある最初の " || A
      それ以外の時
        A = [ind+1, end) にある最初の 右" || throw
      B = [mark-1, ind+1) に " が含まれない
      ind を mode に応じて終端点 A に移動する。
      B = true の時、mode に応じて mark を [beg, A) の最後の " (必ず存在) の位置まで移動する。
    ind < mark の時、
      A1 = [beg, ind) の最後の 左" || throw
      B = [ind, mark+2) に " が見つからない
      mode に応じて ind を開始点 A に移動する。
      B = true の時、mode に応じて mark を 右" に移動する。

    [動作確認]

    x fixed: 動作がおかしい。と思ったらどうも surround S の振る舞いが変だ。
      囲んでいる範囲の末端にある空白を範囲から外してしまう様になっている。
      調べてみると explicit にそういうコードになっている。
      これが適用されるか適用されないかの条件があるということだろうか。
      ysw の時には確かにその様な動作になっている。
      テキストオブジェクト ysaw の場合にもそうなっている。
      他は全て linewise な operator かもしくは vS, vgS である。
      つまり、末端の空白を範囲から除外するのは ys の時だけである。
      直した。

2018-02-21

  * vi-mode: vi_test で qx..q マクロについてのテストを追加 [#D0669]

    と思ったら動かない…。

    何となくテストを追加してみた所 @x によってマクロが実行されない。
    手で実行すると正しく実行されるので変だ。
    マクロを実行する何らかの条件があっただろうか。
    或いは単にバグかもしれない。調べる必要がある。

    どうやら register#play 迄は到達している様だが、
    再生するべき文字列を取得した時点で空文字列になっている様だ。
    :reg で確認してみるとやはり空文字列になっている。
    これは再生の問題ではなくて記録の方の問題である。

    →どうも ble-decode/keylog/end して入力されたキーを読み取った時点で空の様だ。
    結局、原因は分かった。_ble_decode_keylog 配列に対する記録は ble-decode-key で行われているが、
    この時 _ble_decode_keylog_depth=0 かどうかを確かめている。
    これは実際に入力されたのではなくて二次的に呼び出された ble-decode-key を記録しない為の物である。
    テストを実行する為には _ble_decode_keylog_depth=0 を一時的に実行して keylog を有効化しなければならない。

  * vi-mode: registers "0 "1 "- について。 [#D0668]

    どうも y や d でコピーされた文字列がどのレジスタに登録されるかは複雑の様である。

    - 先ず、何れの場合でも register として "" 以外のものが指定された時には設定されない。
    - y の場合には "0 に登録される
    - d や c の場合には改行が含まれるかまたは % ( ) ` / ? n N { } と組み合わせた時に "1 に登録される
    - それ以外の時には "- に登録される
    - "2 .. "9 に関しては "1 が設定された時のみにシフトされる。

    % ( ) ` / ? n N { } に関しては特別扱いで WIDGET を参照する事にすれば良い。
    元々の vim でもこれは vi と互換性を持たせる為の振る舞いであると書かれているので、
    少しでも違うコマンドで実行された場合には、特別扱いしないという事で良い気がする。

    所で… ( ) というコマンドはあっただろうか…。
    →調べてみた所、存在した…。カーソルを N 文先に進める or 戻すという動作の様だ。
    更に { と } も同様のコマンドである。
    これについては別の項目を立てて対応する事にする。

  * vi-mode: マクロで記録される内容に空白が挿入されている。 [#D0667]

    これは何処かの連結で変な事が起こっている。やはり連結だった。

    動く例:
      IFS= eval 'value=${arr[*]}'
      IFS= eval 'value="${arr[*]}"'
      IFS= eval 'local value="${arr[*]}"'

    動かない例:
      IFS= eval 'local value=${arr[*]}'

    これは罠である…。Memo にも記録しておく事にする。

  * 2018-02-18 vi-mode: register 0..9 に対応する [#D0666]

    https://qiita.com/nakabonne/items/84d61ae5e89e20de0157

  * 2017-10-17 vi-mode: support :reg [#D0665]

    内容を escape したい。これは info text と同じ仕組みを使えば良いはず。
    →調べてみると info では ble-edit/info/.construct-text で変換している。
    そしてこれは座標計算もしている。其処までは必要ない。
    代替になるものを実装する必要がある。基本的に .construct-text を簡単化すれば良い。
    文字幅を計算しなくて良いので [[:print:]]+ で読み飛ばしてしまっても良い気がする。

    取り敢えず実装した。

  * complete: 解析再開点の記録抑制により正しく補完できないケースがある [#D0664]

    Cygwin 上で何故か g++ の引数が補完されない。

    gcc など他のコマンドについてはちゃんと補完される。
    complete には何も登録されていない。
    候補の表示まではちゃんと動いている。

    [原因]

    | - どうも he まで入力しているのに a.exe や a.txt などの
    |   一致しないファイル名が候補として列挙されている。
    | - コマンド名に + が含まれていると駄目の様だ。
    |
    | そもそも単語切り出しに失敗している。
    | he まで入力しているのに COMPS="" になっている。
    | 遡ると context の生成の時点で振る舞いがおかしい。
    | ble-syntax/completion-context の方を見に行く。
    | ble-syntax/completion-context/check-prefix が悪そうだ。
    | check-prefix の CTX_ARGX の部分を、echo だと通過するのに g++ だと通過しない。
    | 何か変だ。調べてみるとそもそも解析の時点でおかしい。
    | echo he だと h の位置に解析再開点が設置されているが、
    | g++ he だと h の位置に解析再開点が設置されていない。
    | Linux の方では解析再開点はちゃんと設置されれている。
    | bash-4.4 で試してもちゃんと設置されている。
    |
    | うーん。調べてみると parse_suppressNextStat が設定されている。
    | コマンド名に + が含まれている場合、後の編集によって変数代入に化ける事があるので、
    | その次の解析再開点の設置を抑制するというのが目的である。
    | そして現状では parse_suppressNextStat はこの用途のみの為に存在している。
    | 導入の事情は #D0318 に書かれている。
    | 一時期 time -p の解析 #D0320 でも用いられたが、現在は用いられていない。
    | #D0318 を見てわかったのは、var+ となっている時、
    | check-variable-assignment では var+ まで読んで parse_suppressNextStat を設置して抜ける。
    | 次にコマンドの読み取りで var まで読んで其処に解析再開点を設置しようとするが、
    | 其処で parse_suppressNextStat が効いて解析再開点が設置されいないという仕掛けになっている。
    | わざわざ var までしか読まないのはそれが extglob +() を構成する + かもしれないからである。
    |
    | ここで magnate (Cygwin) と padparadscha (Linux) での違いが分かった。
    | magnate 上では extglob が設定されていなかったので、実は次のコマンドの読み取りで var+ まで読んでしまう。
    | するとそのまた次の解析再開点が抑制されてしまい問題になるのである。

    これの解決方法は簡単である。確か parse_suppressNextStat とは別の仕組みで
    % 解析再開点の設置を抑制する仕組みを整えた筈である。
    parse_suppressNextStat を廃止してそれに統合するのが良い。

    [対処]

    解析再開点の設置を抑制するのではなくて解析再開点に参照範囲も記録することで、
    再開時に dirty-range に応じて再開点を無効かどうか判定できる様にする仕組みだった。
    これに使うのは ble-syntax/parse/set-lookahead という関数だった。
    この関数は現在位置を基準に何文字先まで先読みしたかという事である。
    #D0601 で導入されている。

    [実装] set-lookahead を設定する様にした。補完は動いている。

    x fixed: しかし、今度は解析がちゃんとできなくなった。
      不思議な事に lookahead が設定されていない…。どういう事だろう。
      よく考えてみたら lookahead する文字数が足りない。
      variable assignment は + の次の文字が = でない時に失敗するのだから、
      + の次の文字まで先読みしたという事を記録しなければならない。

    動いている。

2018-02-14

  * 2017-10-05 vi-mode: 最終行付近で + _ g_ などを呼び出したときの振る舞いが異なる。 [#D0663]
    この辺りの振る舞いについては色々調べる価値はある。

    - vim では最終行で 2_ を押すとベルが鳴る。移動しない。この動作は同じ。
      vim では最後から2行目で 3_ を押すと最終行の行頭に移動する。ベルは鳴らない。
      しかし同じことを今の実装で行うと何故かその行の行頭に移動する。これはバグだ。

    - + についても調べる。vim は + も同様の振る舞いをする。
      そして現在の実装も何故かその行の非空白行頭に移動する。

    - 現在の実装では g_ は最終行の行末に移動する。この動作は vim と同じだ。
      しかし最終行にいる時 2g_ とすると vim はベルを鳴らして動かないが、
      現在の実装ではそのまま現在の行の行末に移動してしまう。

    + 及び _ に関しては明らかにバグであった。
    指定された量だけ履歴項目内で移動できず、履歴移動にも失敗して、
    それでも履歴項目内で少しは動けた時は、nolx を修正して其処に移動する実装の筈だった。
    しかし、コードの共通部分を利用するためにこれを first-non-space に置き換えたのが行けなかった。
    コードは同じであるがローカル変数 nolx は同じ値ではないのでこれだと正しく動作しないのだった。

    g_ に関しては常に成功する実装になっていたので、失敗する条件を追加した。
    行移動を要求された (引数 2 以上) のに、1行も移動することができなかった場合にベル。

  * undo: 戻った後の位置、進んだ後の位置が不自然 [#D0662]

    現状の実装では初めてその状態になった瞬間のカーソル位置に移動している。
    しかし、この動作は自然だろうか。redo で進んだ時はそれで良い。
    しかし、undo で戻った時には、最後にその状態だった瞬間のカーソル位置に移動するべきなのではないか。

    或いは別の実装方法として、履歴移動が起こった時には diff を取って、
    一番最初の変更点 (または最後の変更点) にカーソルを移動するという手が考えられる。
    vim の実装はこれになっている様な気がする。

    この場合には _ble_edit_str.reset-and-check-dirty の中で計算した値を使えば良い。
    と思ったが _ble_edit_str/update-dirty-range で記録しているのは描画・構文解析・配置についてだけなので、
    現在の undo によって変更された範囲というのは求めがたい。
    結局、処理が二重になってしまうかもしれないが呼び出し元で common-prefix / common-suffix を求める事にする。

    うーん。コレに関しては様々な考え方がある気がする。

    a 初めにその状態になった瞬間のカーソル位置
    b 最後にその状態だったカーソル位置
    c 変更範囲の開始点
    d 変更範囲の終端点

    設定項目 bleopt_undo_point として提供する事にした。

  * vi-mode: xmap <C-a>, etc. の動作について [#D0661]

    - V<C-a> の場合は各行の最初の整数について 1 ずつ増加させる。
      v<C-a> の場合にも同様である。<C-v><C-a> の場合も、
      矩形を構成する各行の一番最初の整数について増加させる。

    - Vg<C-a> の場合は各行の最初の整数について 1, 2, 3, ... ずつ増加させる。
      引数を指定した場合には {N}, 2{N}, 3{N}, ... ずつ増加させる。
      k個目に見つかった整数は k 倍になるということである。
      (k行目の整数が k 倍ということではない。数字がない行についてはスキップする)

    - v 及び <C-v> において整数の途中で領域が切れている場合、
      領域内に入っている部分だけで解釈される。左端も右端も。

    - 098 を 1 増やすと 99 ではなく 099 になる。
      099 を 1 増やすと 100 になる。
      000 から 1 減らすと -001 になる。
      つまり動かす前の 0 padding を覚えているという事になる。

    - 範囲内に数字が見つからなかった場合は `[`] は設定されないが . は設定される。

    実装の方法としては vi_xmap/visual-replace-char を参考にすれば良い。
    また nmap <C-a>, <C-x> についても 0 padding に対応する必要がある。対応した。

    x fixed: 一番最初の行しか変換されない。
      調べてみると何故か delta が 0 になっている。
      何と .repace-range で変数 delta が leak していた。直した。
      ちゃんと動くようになった。

    o 境界を跨ぐ数字について。右境界・左境界共にOK
    o 行内に複数の数字がある時、一番最初の数字だけ。
      V, v, C-v で確認。C-v に関しては矩形内で最初の数字。
    o 引数がちゃんと使えるということ。
    o g<C-a>, 2g<C-a> で等比数列で増加するという事。
    o g<C-x> で数字がない行があっても、ちゃんと行番号ではなくて
      見つかった数字の数で倍率が決まっているという事。
    o 範囲内に数字がない場合 `[`] は設定されないが . は設定される。
    o 098 → 099, 099 → 100, 000 → 001, -001 → 000, -000 → 001
    o 099 → 098, 100 → 99, 002 → 001, 000 → -001

    x ok: undo した時のカーソルの位置が変だ。

      % これは xmap r{char} でも同様に変だ。
      % xmap c ... ESC で試してみると xmap を解除する瞬間のカーソル位置が変。
      %
      % 調べると undo 後の位置は記録されていた位置をそのまま再現するだけである。
      % 記録は undo/add した瞬間の _ble_edit_ind と _ble_edit_str を記録している。
      % 一緒に記録しているので異なる _ble_edit_str の時の _ble_edit_ind が再生されるなどの事は考えにくい。
      %
      % これはどうも最終的な位置に移動する前に set-previous-edit-area を実行しているのが原因の様な気がする。
      % 取り敢えず最終的な位置を調整してから set-previous-edit-area を実行してみる事にする。
      %
      % 直っていない…と思ったがよく考えたらこの動作で良いのである。
      % 何故ならば最後に編集が起こった時のカーソル位置を記録しているのであって、
      % その操作を実行する直前の位置を記録しているわけではないのである。
      % しかし、これは意図した動作であるとはいえ vim ではどの様に扱っているのか確認する必要がある。
      % →vim の場合にはま編集を行う直前にいた位置に戻るようである。
      %   一方で C-r で進む場合にはその操作を行う直前の位置に行く。
      %   つまり、文字列の状態と位置を紐付けている訳ではない。
      %
      % どうも u で戻った時には戻した編集が起こった位置に移動し、
      % C-r で進んだ時には進んだ編集が開始した位置に移動する様だ。
      % u で戻った時は戻った後の記録の次の記録の記録点で、
      % C-r で進んだ時は進んだ後の記録の記録点と考えれば良いだろうか。
      % うーん。然し、その様にすると不整合が生じる可能性がある。
      % 或いは、戻った時の diff を取って編集が起こった先頭に移動すれば良いのかもしれない。
      % 現に、 _ble_edit_str.reset-and-check-dirty を呼び出しているのであるから、
      % その dirty の先頭に移動すれば良いのではないだろうか。或いは末端のほうが自然か。
      % vim の振る舞いを見ると変更範囲の先頭に移動している様に見える。

      結局、これは undo の問題なので別項目で考えることにする。

  * 2018-02-13 bug: ヒアストリングで $ret を指定すると以下のエラーメッセージ [#D0660]

    ((: ret: 式の再帰可能レベルを越えました (エラーのあるトークンは "ret")

    再現できた。原因は ble-syntax:bash/simple-word/eval-noglob '$ret' である。
    →単純なミスであった。要素数を調べるのに誤って中の文字列を展開していた。直した。

    念のために他にも同様のミスがないが検索してみたが特にはない様だ。
    grc '\(\([^[:space:]]*\$\{[[:alnum:]_]+\[@\]\}'

  * vi-mode: g?? は rot13-encode lines だが g~? は backward-search switch case である [#D0659]

    - 現在の実装では vi_omap は "operator rot13" に紐付けているが、
      g~ g? の様に異なる組み合わせのオペレータを組み合わせた時は元々の motion ? の意味を取り戻す。
    - 因みに g~ gu gU gq に対応する omap ~, u, U, q に関しては
      元々 motion ではないので vi_omap で認識できる必要はない。
    - gw に対応する omap w は単語の意味であって gww の様な重ね方には対応していない。

    a operator を二つ重ねた時の振る舞いについて調整が必要である。

    b もしくは omap ? を特別な処理に差し替えるという事も考えられる。
      つまり opfunc を見て rot13 ならば operator rot13 を実行し、
      そうでなければ motion ? を実行する。

    今回は b の方法で対処する事にした。

  * 2017-11-03 vi-mode (map / ? n N): backward search の一致の仕方が異なる。 [#D0658]
    現在の実装では一致範囲が現在の位置以前にある一致の最後のものが当たる。
    しかし vim を観察すると、"一致範囲の開始位置" が現在の位置より前にある一致の最後のものが当たる。

    また、vim では一致する物がそれ以上ないときに cyclic に一致するが、
    ble.sh ではこれについて敢えて対応していない。

    - fixed: 2017-11-06 更に試して気付いたのだが、
      / や ? で新しい検索を始めるときでも、
      現在位置にある単語には一致しない。
      現在の ble.sh の実装では以前の一致の上にいる時には現在位置には一致せず、
      新しい一致を始めるときには現在位置に一致するようにしているが、
      これは全く無意味な処理である気がする…。

      これは ble/keymap:vi/search/invoke-search で制御している振る舞いである。
      % 単に条件の "|| ! ble/keymap:vi/search/matched" の部分を削除すれば良いだけでは?
      % これについては具体的に動作を調べながら修正する。

      と思ったら、この部分を削除すると検索開始位置が変な事になる。
      初回の検索位置は飽くまで初回の検索位置として処理するが、
      その位置を微修正するという方向で対策が必要である。

      取り敢えず直った様な気がする。
      bleopt_keymap_vi_search_match_current=1 の時、以前の動作に戻る。

    さて、然し backward search に関しては振る舞いは未だ異なる。

    これは ble-edit/isearch/search 自体の振る舞いを弄らないと行けない。
    取り敢えず正規表現を使って "開始位置" が現在の位置より前にある物を探す方法を考える。
    これについては先頭の .{数} の部分を調整すれば良い気がする。
    →ble-edit/isearch/search に新しい方向 B を用意した。
      従来の - と違って開始点が現在位置より前ならば一致する。

    新しい方向 B を使って実装してみたが今度は重複して一致する事が可能になってしまった。
    つまり、aiai[aiai] に一致している時に n を押すと [aiai]aiai になるべきだが、
    現在の実装では ai[aiai]ai になってしまう。
    これについては、再一致の時は dir を変更するという様にすれば良い。
    直した。動いている。

2018-02-13

  * [bug] ble-bind: ble-decode-unkbd があらゆる文字について ESC を返す様になっている [#D0657]

    連想配列の添字の $keycode を keycode に変えたのがいけなかった。
    というかそもそも何故連想配列になっているのだったか…。
    keycode は常に整数なのではないだろうか。
    →どうもそのようにしか見えないので _ble_decode_kbd__c2k
    を連想配列から通常の配列に変更した。

  * オペレータ ! や ys において、作用対象を着色 [#D0656]

    オペレータ ! や ys では続けてどの様な操作をするかを決定する為にユーザの入力を待つ。
    ユーザの入力を待っている間は、作用対象の文字列範囲を着色するのが良い。
    取り敢えず対応した。

    - ok: 先ず着色する色は通常の領域選択と異なる色にしたい。
      これには対応した。highlight-layer:region において色 (sgr) も一緒に記録する事にした。

    x fixed: 矩形ビジュアルモードで S を押して ysurround を呼び出した時、着色されない。

      これは call-operator-blockwise を呼び出す時に、
      一時的に _ble_edit_mark_active を古い値に戻してから、
      呼び出した後で新しい値 (つまり vi_xmap/exit で設定された空文字列)
      に書き戻しているのが原因だった。

      そもそも call-operator-blockwise の呼び出しで _ble_edit_mark_active を指定する必要があったのは、
      矩形領域を決定する為に、現在の選択の方法が block なのか block+ なのかを区別する為である。
      この目的の為に新しくローカル変数 ble_keymap_vi_mark_active を導入する事にした。
      このローカル変数に _ble_edit_mark_active の古い値を設定してから
      call-operator-blockwise を呼び出す。call-operator-blockwise は extract-block
      を呼び出す時だけ _ble_edit_mark_active を復元する。

    - ok: csurround でも同様に設定したい。
      と思って実装を確認したら csurround の作用対象の範囲は csurround.core の中で決定していた。
      作用対象の決定部分と実際に挿入内容を決定した後の挿入の部分を二つの関数に分ける必要がある。

      と思ったが、二つの関数に分けたとしても text-object を用いて範囲の決定をしている場合は困難が残る。
      text-object.impl を用いると演算子の呼び出しにまで到達するが…。
      →結局、特別なオペレータを定義して範囲を抽出することにした。

      また、途中状態の保持方法を大幅に変更する事にした。
      処理を二つに分けた事によって、受け渡ししなければならない変数が増えた。
      これらを配列に格納することにしたが、既存の変数 type arg reg del についても同じ配列に記録する事にした。
      csurround の処理を (1) type arg reg の設定、(2) del の設定、(3) ins の指定で実行 の三つに分けて定義した。
      これらを必要に応じて呼び出す事で実際の処理 (cs や ds や . による繰り返し) を定義する。

2018-02-12

  * 2017-09-12 vi-mode: operators [#D0655]

    % ydc の他にも色々ある。
    %
    % http://vim-jp.org/vimdoc-ja/motion.html#operator
    %
    % ! = > < gq zf g@
    %
    % この内 g~ gu gU g? g@ は y と同様に文字列の長さを変えないものである。
    %
    % また ! = > < gq zf は例え文字列単位の範囲であっても行単位の操作に変換する。
    % 従って、処理を行った後の beg 及び end の位置は変更を受けることになる。
    % これは operator:* 関数内からいじっても良いということにすれば現在の枠組みで十分対応可能である。
    % 何れにしてもそれぞれの機能の動作について調べてから実装する必要はある。
    %
    % →実際に < > の実装で (type == char のときに) beg を修正することにした。
    % ! = gq zf の実装では < > の実装を参考にすれば良い。

    > gq, gw #D0652
    > ! #D0653
    > g@ #D0654
    * todo = #tmp0001

    * zf は領域の折り畳み。対話シェルでは長いコマンドの編集は推奨されないし、これには対応しない。
    * gq の formatexpr, formatprg には未対応。

    取り敢えず = 以外は実装したのでこの項目は Done に移動する事にする。
    残っている事柄については新しい項目 #tmp0002 を立てる。

  * vi-mode: operator g@ の実装 [#D0654]

    | 2017-09-12
    | * opfunc/g@ はどうやら Vim script のキーボードマクロで使われるようだ。

    実際に需要があるかどうかはともかくとして対応することにした。
    これは bleopt 変数 keymap_vi_operatorfunc を定義することにした。
    この変数に operator:NAME の NAME 部分を指定する。

  * vi-mode: operator ! の実装 [#D0653]

    `nmap .` による繰り返しの登録については ble/lib/vim-surround.sh/ysurround.repeat/{entry,record} の使い方を参考にする。
    vim-surround では 繰り返し時のオペレータの名前を変更する事によって区別することにしていたが、
    今回の実装では $_ble_keymap_vi_repeat_invoke が設定されているかどうかで判定する事にした。

  * vi-mode: operator gq, gw [#D0652]

    取り敢えず、与えられた文字列を変換する関数を書く。
    先ずは、文字の幅を考えずに文字数だけで実装する。

    | 2017-09-12
    | * gq の整形とはどういう整形だろう。調べると gw というのもある。
    |   http://h-miyako.hatenablog.com/entry/2015/01/31/185620 によると折り返しと関係する?
    |   試してみた所 80 桁に収まるように単語の切れ目で折り返しをする。
    |   単語は空白区切りであり w による単語とは異なる。
    |   gw と gq の違いは簡単に試した限りではない。後で help を見る。
    |
    |   - 行は初めに連結される。空行(空白だけの行)は連結されない。
    |
    |   というか面倒なので fold コマンドに流し込めば良いのでは?
    |   と思ったが fold は行を連結してはくれない。
    |   やはり自分で書いたほうが良いかもしれない。

    動作について

    - done: 行指向のオペレータである。
    - done: 元々合った空白については保持される。
    - done: 行末に来る空白は削除される。
      単語と単語の間のタブは保持される。
    - done: どうも 80 文字丁度ぴったり収まる場合は行に収まるとは判定されない様だ。
      表示文字が 79 列以下になるように整列される。

    - done: gw の時は元々カーソルがあった文字に対応する位置に移動する。
      gq の時は最終行の非空白行頭に移動する。
    - done: 改行直後の空白類は潰れてなくなる。

    - done: 最初の行のインデントは継承される。
      % 行頭は必ず非空白文字になる→これは違った。

    具体的な折り返しの処理は ble-edit/info/.construct-text を参考にすれば良い気がする。
    と思ったが、結局大きく異なる実装になった。何れにしても取り敢えず実装した。
    動作確認を行う事にする。

    x fixed: 段落の末端の改行が欠けてしまっている。
      fold の処理で最後の改行が出力されないので、末端に改行を連結するように直した。

    x fixed: 元々合った文字列が残ってしまう?
      →もう変換できる段落がなくなって、
      最後に未変換文字列を連結するところで全体文字列を連結していた。直した。

    x resolved: gq 後のカーソル位置がおかしい。
      replace-range 後の末端位置を基準に計算する様に修正した。
      しかし、それでもやはり駄目だ。というかもしかして find-non-space は行頭でなければならない?
      →これは次の項目を直したら直った。

    x fixed: 不思議な事に前回の gq の影響が残っていて、
      前回の内容が付加されている様に見える。
      これは out なる変数がリークしていたのが原因だった。他にも変数 new が漏れていた。

    x fixed: 幅が 80 以上になっている。

      どうも内部の計算を見てみると空白の幅が考慮に入れられていない様だ。
      と思ったら .get-interval の中の iN が変な値で初期化されていた。
      直した。と思ったら今度は単語一個ずつ開業されるようになってしまった。
      インデントの幅が 210 になっている→ iN の初期化が未だ間違っていた。直した。

    x fixed: gq 後のカーソル位置が先頭行の非空白行頭になっている。
      と思ったら preserve_point の判定が逆転していた。

    x fixed: gw でカーソル位置が保たれない。どうも行頭に行ってしまう。
      どうやら、これはオペレータを適用した後のカーソル位置の調整による物の様だ。
      調べてみた所、現状ではオペレータの呼び出し元での調整を抑制する方法はない。

      新しく _ble_keymap_vi_operator_index というローカル変数を導入する事にした。
      調べてみると beg を修正する事によってオペレータ作用後のカーソル位置を
      指定しているオペレータは他に operator:indent.impl しかなかった。
      影響範囲は小さいので今の内に仕様を変更する事にする。

      % 実は beg や end と同様に単純な変数名でも良いのではないだろうか。
      % _ble_keymap_vi_operator_index を単に短くすると index になる。
      % しかし、これだと何の index か分かりにくい。
      % 寧ろ、ind にした方が _ble_edit_ind との対応がついて分かりやすいかもしれない。
      % また beg, end と同じく三文字であるという共通点もある。
      % 然し、ind にすると、其処に何らかの意味のある情報が格納されている様にも思われる。
      % 実際には既定値は空であり、専ら出力専用の変数である。
      % やはり混乱の元の様な気がするので取り敢えずは長い変数名という事にする。
      % 後で面倒になって来たら短い変数に変える事を考える。
      % 但し、その時でも通常の変数と違って出力専用の変数であるという事が分かる名前にする。

      _ble_... で始まっているとグローバル変数とも勘違いしやすい。
      検索するとローカル変数の場合は ble_... で始めている事が多いようなので、それに倣う。

    o 元々合った空白の保持
    o インデントの継承
    o 行末に来る空白の削除
    o 80 桁ではなく 79 桁に収まる様にする。
    o 改行直後の空白類は潰れる

  * 2018-01-19 誤って PATH に変な値を設定してしまうと動かなくなる。 [#D0651]

    呼び出している外部コマンドの一覧を作って、
    更にそれらのコマンドをフルパスで呼び出す様に修正する必要がある。
    その為には command -p 付きで呼び出すようにするか、
    或いは起動時にそれぞれのコマンドのパスを何処かに記録すれば良い。

    (実のところ command ... となっている物について修正を行えば良いだけかもしれない)

2018-02-11

  * vi-mode: nmap C-a C-x 対応 [#D0650]

    [振る舞い]

    先ずは振る舞いについて調べる。

    現在行が空行の時は何もしない。
    現在位置から現在行末までから数字を探し、
    その数字から前方・後方へ拡張する。符号 - も拡張する。符号 + は無視する。
    引数 (既定値 1) を加算・減算した文字列で置き換える。
    変更後のカーソルの位置は最後の数字の一つ前。

    `[`] は置き換えた範囲になる。. はそんなに考えなくて良い。

    念のため help の記述についても確認しておく。

    | CTRL-X                  Subtract [count] from the number or alphabetic
    |                         character at or after the cursor.  {not in Vi}
    | CTRL-A                  Add [count] to the number or alphabetic character at
    |                         or after the cursor.  {not in Vi}

    特に目新しいことは書かれていない。

    [実装]

    さて、`[`] 及び . に関連して参照実装として何を選べば良いだろうか。
    例えば、ble/widget/vi_nmap/forward-char-toggle-case が replace-range を呼び出している編集関数である。
    実装した。動作確認をする。

    x fixed: その行の一番最後の数字について変更が行われている。
      正規表現において prefix (.*) の部分に数字を許しているのがいけなかった。
      これは ([^0-9]*) に書き換えることにする。

    x fixed: 負号より前にカーソルが合った時に負号が考慮に入れられていない。
      これも正規表現の都合である (.*) によって負号が先に読み取られてしまうので prefix と解釈されている。

    o 空行では何も起こらない。行内で現在位置よりも後に数字がない時はベル。

    o `[`] は設定されている。. も正しく設定されている。

  * 2017-12-03 keymap/emacs: undo/redo に対応する。 [#D0649]

    現在はそもそも記録を行っていない。
    後、各 widget について対応を行うとすると vi_imap とかち合うので注意が必要である。
    特に、今までの機能は全て safe キーマップの機能という事にして、
    新しく emacs.sh に実装を追加した方が良いのかもしれない。

    emacs mode では何処で undo/add を呼び出すべきだろうか。
    変更の発生するすべてのコマンドに一つずつ undo/add を追加するべきだろうか。

    vi では ble/keymap:vi/mark/set-previous-edit-area からしか undo/add を呼び出していない。
    vi_imap での変更はどの様な過程で検出されるのだろうか。
    どうやら _ble_keymap_vi_imap_white_list で指定されたコマンドが実行される時以外は、
    ble/keymap:vi/mark/end-edit-area が呼び出され、其処から undo/add が実行される様だ。

    従って、emacs mode でも white_list を作って、
    其処に登録されていないコマンドが呼び出される時には必ずと undo/add を実行するという事にすれば良いだろうか。

    Note: delete-backward-char は取り敢えず undo/add する事にした。
    本来の emacs では複数の連続する delete-backward-char がまとめられる。
    しかし面倒なので一文字ずつ記録することにしてしまう。
    その様に考えるとその他の delete-*-?word などについても undo/add して良い気がする。
    という訳で delete-*-?word も white list から除外した。

  * 2018-12-04 keymap/vi (nmap u, U, C-r): 引き数に対応する。 [#D0648]

  * getindex/getcount の関数名を変更 [#D0647]

    refactor getindex, getcount → get-index, get-count

  * 2017-12-04 keymap/emacs: 引き数 [#D0646]

    - done: ble/widget/insert-string

      取り敢えず clear-arg しているが、
      本当は繰り返し挿入にした方が良いのではないか。
      →繰り返し挿入にすることにした。対応した。

    - done: ble/widget/transpose-chars

      これはカーソルの左の文字を N 文字右に移動するという効果である。
      また引き数を指定しないとき、行末にいるならばその前の二文字を入れ替える。

    - done: ble/widget/delete-forward-char

    - done: ble/widget/delete-backward-char

    2018-02-10 暫く置いてしまったがリリースの機会を逸したので、
    またこれから少しずつ編集してきりの良いところでリリースする事にする。
    取り敢えず emacs mode における引き数の対応の途中で止まっていた。

    - done: kill-backward-logical-line の動作確認を行う。
      実際に動かしてみると動かない…と思ったら kill-backward-line なので、
      kill-backward-logical-line は実際には呼び出されていなかった。
      - ok: 引き数を指定しない場合は行頭までを消す。
      - ok: 正の引数 a を指定する場合は a 行前の行の行末まで消す。
      - ok: 引数 0 を指定した場合は現在行の行末まで消す。
        既に行末にいる時には何もしない (空文字列をコピーする)。
      - ok: 負の引数 -a を指定した場合は a 行後の行の行末まで消す。

    - done: 次に kill-forward-logical-line の動作確認も行う。
      - ok: 引数を指定しない場合は行末まで。
      - ok: 正の引数 a を指定した場合は a 行語の行頭まで消す。
      - ok: 0 を指定し場合は行頭までを消す。
        元から行頭にいる場合には何も変更せず空文字列をコピーする。
      - ok: 負の引数 -a を指定した場合は a 行前の行頭まで消す。

    - done: kill-forward-logical-line.impl が実装の途中である。
      先ず仕様を明確にする必要がある。
      現在の実装では正負・↑↓について対称である。
      引数として 0 を指定した場合は移動は行わない。

      - 履歴項目の移動の実現方法に関して

        また別の現在の問題として現在の履歴項目を越えて移動する場合の動作についてである。
        forward-logical-line が独立して動作する為には、
        一番上から更に移動しようとした時に何行移動しようとしたかを呼び出し元に伝達する必要がある。
        或いは、vim-mode での実装を真似して forward-logical-line の内部から履歴項目の移動を呼び出すという手もある。
        現在の所、履歴項目の移動についても引数に対応していないので、
        これを現状で実装しようと思ったら履歴項目の移動についても対応する必要がある。
        何れにしても二種類の実装方法が考えられる。

        a 呼び出し元に残っている移動行数について何らかのローカル変数を介して伝達する。
          (現在の実装では終了ステータスを用いて移動できたかできなかったかの二値で対応する情報を伝達している。)
        b 或いは、別に履歴項目を移動するコマンドを用意しておいて、
          移動行数が満たない場合には forward-logical-line.impl の中から、
          その履歴項目を移動するコマンドを呼び出す様にする。
          実際に履歴項目を伴うか伴わないかについての制御は引数を用いて行う。

      - 選択範囲が有効になっている場合には履歴項目の移動は行わない。

      取り敢えずは履歴項目の移動以外については実装を行う。
      動作確認を行う。

      x fixed: 引数を指定した場合は全然動かない。
        何故か行末に移動して bell を鳴らす。行数は問題ない。
        →これは実際に移動した個数 \n を数える所で、
        移動量が正であるかどうかの判定で不等号の向きが誤っていた。
        更に、_ble_edit_str ではなく _ble_edit_ind の中を数えていた。直した。

      x resolved: 引数を指定しない場合はちゃんと動く。
        と思ったら勘違いだった。引数を指定した時と同様に動かなかった。
        これは引数を指定した時の動作と同時に修正された。

      - ok: 引数 0 を指定した時は、期待通りに何もしない。

    - beginning-of-line / end-of-line
      これらは beginning-of-graphical-line / end-of-graphical-line に分離した。
      動作確認。

      - ok: 範囲内の移動であれば 引数を指定しなかった時、0 を指定した時、
        正の数を指定した時、負の数を指定した時、何れも動いている。

      - ok: 範囲外への移動の場合でも、一番最初の行の行頭、または一番最後の行の行末に移動する。
        end であっても正しく行頭に移動するし、home であっても正しく行末に移動した。
        これは意識して実装した訳ではなかったが textmap による幾何的な実装で自然にそうなっていた。

    - done: self-insert で、"M-- 1 0 a" で bell を出すようにする。

    - kill-backward-graphical-line / kill-forward-graphical-line
      これも kill-backward-line / kill-forward-line から分離する。
      動作確認を行う。

      - ok: forward-line に関しては、引数なし、引数 0、引数 1、引数 -1、
        引数 2 において正しく動作している。

      x done: backward-line に関しては、引数の正負を逆転した方が良いのではないか。
        というか、コメントにはその様に書いている。

        →コメントに書かれている動作になるように修正した。
        負の引数について試した。引数 0 引数 1 引数 2 について試した。

    - done: find-graphical-eol の引数に axis を取る様にする。
      find-logical-bol に合わせて → 直した。

    - forward-graphical-line / backward-graphical-line
      これは forward-line / backward-line から分離して統合した。

      動作確認を行う。

      x fixed: 移動できない。というか履歴項目の移動を行ってしまう。
        これは、forward-graphical-line.impl の終了ステータスの問題だろう。
        と思ったが、.bell は必ず 0 を返す。ということは原因は他にある?
        →よく見たら移動後の 位置を求める時に --prefix=a を指定するのを忘れていた。直した。

      x fixed: 履歴項目の移動がそれ以上できなかった時に、
        カーソル位置が移動せずに終わってしまう。これは駄目だ。
        履歴項目の移動を呼び出す前に履歴項目内で移動を行うべき。
        これは forward-logical-line.impl でも同様に修正した。

      - ok: forward/backward 両方について、
        引数なし、引数 0、引数 1、引数 2、負の引数
        について確認した。問題なく動いている。

    - accept-and-next
      引数で指定した分だけ移動しても良いのではないかと思ったが、
      readline の動作を見てみると引数は効果を与えないようなので、取り敢えずそれに倣う。

    - forward/backward-line-or-history-next
      これについては実装し直す必要がある。
      特に埋め込む形で実装する様にする。
      行数は logical-line で数えるという事で問題ないだろう。

      % また、その後で廃止する事にする。
      % history を移動しない形での移動コマンドを提供する可能性もあるが、現在のところは対応しない。
      と思ったが、よく考えたらサブのプロンプトなどでは履歴移動を伴わないものが欲しくなる可能性がある。
      履歴移動を伴う可能性がある場合には widget の引数で opts を指定してもらうことにする。

      →forward-history-line.impl を実装した。動いている。
      →forward/backward-line-or-history-next/prev は廃止し、
        代わりに通常の forward/backward-line に引数 "history" を指定して登録する。


2017-12-03

  * 絵文字の文字幅に対応する [#D0645]
    https://github.com/vim-jp/issues/issues/1086 の表を用いる

  * 2017-09-17 cmplstofB: undo これは vi-mode の実装が終わってから考える [#D0644]

    - xmap I, A で undo は 2 回に分割される。初めの入力と後のコピー。

    vi-mode が落ち着いて来たので改めて考える事にする。
    これはやはり vi-mode を公開する前に簡単でも良いので対応したい。
    先ずは、基本の枠組みだけでも作成する。

    先ず初めにこれまでの考察に関してまとめる事にする。

    | 2015-03-01
    |
    | * undo の実装について
    |
    |   どの様な振る舞いにするのがよいかというのが問題である。
    |   他の shell でどの様に実装されているかについて確認する。
    |
    |   zsh における undo について
    |
    |   履歴行に関係なく "表示されている文字列" の redo undo の様に見える。
    |   つまり、履歴で上へ行ったり下へ行ったりするとそれも含めて undo される。
    |   これが分かり易いのかどうかは不明。というか分かりにくいと思う。
    |   また、一旦 accept した後はそれ以前の履歴にはアクセスできない。
    |
    |   bash における undo について
    |
    |   bash で試してみるとコマンド履歴の行毎に編集履歴は記録されている様である。
    |   また、accept した後でも編集が残っている。
    |   但し、accept した編集行については中身が編集前の状態に戻る。
    |   (つまり、後で実際に実行されたコマンドを確認するには undo しきらなければならない)
    |   これも分かり易いのかどうかは分からないが、少なくとも zsh よりは良い様にも思う。
    |
    |   とはいいつつも accept-line した後も編集が残っているのは良いのか微妙である。

    a 実のところ二重配列は bash にはないのでやはり一つの配列に全部入れたほうが良いかもしれない。
      例えば、undo の個数に制限をかけて 1000 個までとする。
      この時、1000 * hindex + undo_index 番目の要素に格納するなどする。

      しかし、これだと上限に達した時の処理が面倒である。
      新しい編集を行う度に shift を実行しなければならない。
      1100 まで増やして 1100 に達したら 100 だけ shift するなど
      ということにすれば毎回 shift するのは避けられる。
      しかし、其処までしてもやはり上限が存在するという事実は変わらない。

    b 或いは、現在の履歴項目の undo 履歴だけを配列に格納し、
      他の履歴項目に移る時にはシリアライズして別の配列に格納するという様にすれば良い。

      実際 keymap/vi.sh の mark で似たような運用方法を取っている。
      % 同様に履歴項目を移動する時に保存・復元を行えば良い。
      改めて実装を見てみたら、必要になった時に hindex と記録した hindex を比較して、
      もし異なっていれば save/load を行うという実装になっていた。

      コマンドを実行して erasedup などによって項目が移動する事はあるが、
      それに関してはコマンドを実行する度に履歴項目を全てクリアするという様にして対応する?
      そもそも _ble_edit_history_edit ですら shift ではなくて全クリアにしている。
      従って、undo についても全てクリアするという事で問題ないだろう。

    取り敢えず実装してみた。

    - vim の動作を調べてみると undo/redo をしても . による repeat は設定されない様だ。
    - また、`[`] は変更があった部分の最初の位置に設定される?

    意外と簡単に実装できてしまった。
    `[`] の枠組みを整備していたお陰でそれに沿って実装できたのが大きい。

    `U` に関しては readline "revert-line" と同じ効果になる様にした。
    U 自身を記録すると訳が分からなくなるので記録しない。

  * 2017-11-29 そう言えば read -e の問題についてここに書いていない [#D0643]
    と思ったら上の "制限" に書いていた。少なくとも警告ぐらい出すようにするべきなのでは。

2017-12-02

  * 2017-11-29 set -u にすると動かないに違いない [#D0642]
    やはり動かない。動かない原因を少しずつ除いていく。
    と思ったら、set -u だと arr1=(); arr2=("${arr1[@]}") すらできない。
    各配列の要素があるかないかで "${arr[@]}" を切り替えるのは困難である。
    仕方がないので、やはり set -u は毎回コマンド実行前に復元・保存する事にする。

  * 2017-11-29 README.md に GitHub アカウントを持っていない時の記述方法を書くと良いのではないか [#D0641]
    と思ったら元々 GitHub アカウントを持っていない時の記述であった。

  * 2017-11-29 update blerc -> bashrc [#D0640]
    やはり名称の変更は行わない。中身は更新した。

  * 2015-08-14 DECSET 2004 に対応する? (ref http://srad.jp/~doda/journal/506765/) [#D0639]

    bash-4.0 未満では read -t 0 がないので貼付などが行われた時に長く待たされる事になる。
    DECSET 2004 を用いて貼付を検知するなどの対策が必要。

    2017-11-29 @cmplstofB さんからの要望

    vi-mode における振る舞いを調べる。

    - 置換モードで実行すると上書きされる。
      改行は新しい行の挿入。
      つまり、一文字ずつ上書きした時と同じ振る舞いである。

    - ビジュアルモードで実行すると範囲を削除してから挿入を実行する様だ。
      挿入が終わった時にはノーマルモードになっている。c ... ESC だ。

      . を実行すると先に貼り付けたのと同じ内容が繰り返される。

    % うーん。色々考えると bracketed paste mode として特別に処理するよりは、
    % 今まで通りに処理する方が楽かもしれない。
    % ただし _ble_keymap_vi_paste 等のフラグを立てて、
    % コマンド実行などの操作を抑制する。
    % しかし貼り付け内容にキーシーケンスが含まれている場合などはどう扱うのだろう。
    % →試してみるとそのまま入力された。つまり、やはりキー入力をとして受け取るのではなくて、
    % 文字として受け取るのである。従って、今までと同様の処理では駄目だ。

    一方で、\e[201~ はどの様に検出したら良いのだろうか。
    文字列として溜めておいて末端が \e[201~ になったら
    其処で抜けて挿入操作を開始するという方法が良いのか?

    うーん。vi-mode で実装する前に emacs mode で実装した方が良い気がしてきた。
    そして、それを参考にしつつも独立に vi の各 mode での bracketed-paste を実装する。
    実装した。動いている。改行は CR LF も CR も LF に変換することにした。

    次は vi-mode における実装である。

    % 今見たら vi-mode で quoted-insert が white list に登録されていない。
    % と思ったが、よく見たら手動で登録していた。というより vi_imap/quoted-insert が定義されていた。

    - vi_imap/bracketed-paste は実装した。動作を確認する。
      何か二回挿入される。これは実装途中だった。直した。

    - 次に vi_nmap での実装を行う。これは思うに i ... ESC と同じと考えれば良い。
      調べてみると寧ろ a ... ESC の様である。
      更に、行頭に位置していた時には i ... ESC になるが、
      "." で繰り返す時には常に a ... ESC になる。
      ble.sh の実装では a <元々行頭なら行頭に戻る> ... ESC として、
      <もともと行頭なら行頭に戻る> は記録しないというようにする。
      動くことを確認した。

    - vi_xmap も同様に operator c を実行する様に実装する。
      v に対しては期待通りに動いている。

      しかし、C-v に対しては思ったとおりの動作をしない。v と同じ動作になっている。
      更に、V に対しても v と同じ動作になっている。何故だろうか。
      一旦、operator c の直後で中断してみることにする? と思ったが、
      それより後で複数行に亘って削除するようなコマンドは存在しないので、
      operator c を呼び出した時点で誤った結果になっているというのは明らかである。
      しかし普通に xmap で c を呼び出してもちゃんと linewise/blockwise になっている。
      念のため、bracketed-paste でも operator c の直後で中断してみると、やはりこの時点で失敗している。
      linewise/blockwise に切り替えるのは _ble_edit_mark_active を参照している。
      と思ったら、_ble_edit_mark_active が ble/widget/bracketed-paste によってクリアされているのだった。
      _ble_edit_mark_active を記録する様にした。ちゃんと動いている事を確かめた。

    - vi_omap ではエラーになる。
      続きの貼り付けないようがコマンドに渡されるということもないので、
      単に paste_begin を束縛しないのではなくて、
      貼り付け内容を破棄する様に実装する必要がある。

      エラーになった後の状態は何か。調べるとノーマルモードに戻っている。
      その様に修正した。

    - 引数に対する応答を調べる

      "x は無視される xmap の場合でも消えた文字列が "x に入っていく事はない。
      nmap の時は勿論無視される。

      数字の引数がある時には一文字進んだ状態で nmap -> imap になる。
      恐らく append-mode に入ってその時点でエラーになるなどするのだろう。
      これはもしかすると vim のバグかもしれない。
      xmap で数字の引数を指定した時は、完全に無視されて分からない状態になる。

      更に気付いたことは実は block-insert は起こらないという事。
      面倒なので、そのままにする。現在の実装の方が自然である。

2017-11-29

  * 2017-11-27 core: 端末の状態設定・復元とカーソル形状の対応 [#D0638]

    先ずそのタイミングについて調べる必要がある。
    結局 ble-stty/* と全く同じタイミングで全て調整する事にした。

    カーソルに関しては ble/term/cursor-state/* において
    hidden 及び 整数値 に対応した。

    しかし、実際に動かしてみると微妙である。
    overwrite mode 用の highlight-layer が、
    カーソルの hidden を解除するので、
    その時に既定のカーソルになってしまう。
    よく考えてみると overwrite mode であっても、
    文字の上にカーソルがない時には予め指定したカーソルの形状にする。

    これに対応するためには二種類の方法がある。

    a overwrite mode 側でカーソルを表示している時の
      カーソルの形状を保持する。
      vi.sh からは overwrite mode 時のカーソルの形状を指定する様にする。
      つまり、vi.sh とは独立にカーソルの形状をカーソルに紐付ける。
      そして表示・非表示に関しては overwrite mode が管理を行う。

      よく考えるとこの様な方法にするのだとしたら、
      結局 ble-edit のレイヤーでカーソルの形状と表示・非表示を管理するのに等価である。
      一応、既定のカーソルの形状の設定として "非表示" というものを許し、
      ble-edit のレイヤーで合成した結果を ble/term のレイヤーに適用するなどの事はできるが、
      そのようなことをしても余り利点はないように思われる。

    b もう一つの方法はカーソルの形状と表示・非表示は別の設定項目にする。
      カーソルの表示・非表示に関しては完全に overwrite mode 側に委ねる。
      カーソルの形状に関してだけ vi.sh から設定を変更する。

    結局 overwrite mode のために非表示機能は予約されているのだから、
    カーソルの表示・非表示の設定と形状の設定を統合する意味はない。
    もし将来的に必要になったらその時に統合すれば良いだろう。
    従って、 b の方法に書き換えることにする。

    動かしてみた。動いている。
    と思ったが external に移動する時に正しくカーソルが既定の状態に戻されていない気がする。
    実際に調べてみると external のカーソル形状に戻す部分は呼び出されている。
    →実は制御シーケンスが flush されていないというだけでなのでは?
      そうだった。flush するようにしたらちゃんと external のカーソル形状が反映される様になった。

2017-11-27

  * syntax: 変数代入の各括弧式とチルダ展開 [#D0637]

    #D0636 では角括弧式の中に : が含まれる場合には各括弧式をキャンセルするという実装にした。
    しかし、改めて試してみるとそうでも内容だ。

    $ echo a=[:~:] はチルダ展開が実行され角括弧式は意味を失う。
    $ echo a=[:+:] はチルダ展開は起こらず、角括弧式として解釈される。
    $ echo a=[:~mura:] はチルダ展開に失敗し、角括弧式として解釈される。

    つまり、実際にチルダ展開が起こったかどうかで、
    各括弧式が各括弧式として解釈されたかどうかが決まる。
    つまり、角括弧式の中でもチルダ展開は解釈することにして、
    チルダ展開であるということが明らかになった時に初めて
    角括弧式を解除することにする。

    角括弧式の終端はチルダ展開の終端または ":" の位置に置く事にすれば良い。

  * 2017-11-24 syntax: 変数代入に於けるチルダ展開 [#D0636]

    [bash の振る舞い]

    - 変数代入では値の : または = の直後でチルダ展開が始まることが許される。
      つまり、a=~:~ では両方のチルダについて展開が起こる。
      a=~=~ では後者のチルダについて展開が起こる。

    - [追加] 因みに a=(~:~) に関しては最初の ~ しかチルダ展開の対象にはならない。
      つまり、:= による区切りが有効になるのは本当に CTX_VRHS の文脈のみの様だ。

    - [追加] 気付いてしまったのだが、通常の単語でも = の直後でチルダ展開は有効のようだ。
      echo var=~ は展開される。一方で echo var:~ は展開されない。
      これについて man bash に何か記述はあったろうか。やはり探してみたが見つからない。
      更に、LANG=C man bash で見てみても見つからない。

    - [追加] 更にまた振る舞いの違いを見つけてしまった。
      : はチルダプレフィックスの終端になるが = はチルダプレフィックスの終端にはならない。
      これについては現在の実装で正しく実装することができている。

    [どのように実装するべきか]

    現在の実装ではチルダ展開が有効かどうかを一つ前の文字を見て決めている。
    しかし、やはりひとつ前の文字を読むのは解析再開用ルールの違反である。不整合になる。
    例えば a=~:~ にしておいて : を消すと2つ目の ~ がチルダ展開のままになる。

    a 例えば変数代入の時には : 区切りで単語を設置する様にする。
      そうすれば着色の際にも値についてファイル名の存在確認が取れる。

    b 或いは : と = の前後で文脈値を切り替えるなどして、
      次の文字に移った時に前が := の何れかであるかどうかの状態を保持する様にしても良いが、
      文脈値が無駄に増えるということと、結局補完の際にはまた特別な処置が必要になる。

    % ここは迷わず a の方針で考えることにする。
    % 但し、注意しなければならないことは、
    % この変更により単語が設置されるが、
    % これにより既存の補完などの枠組みに問題が生じないかということ。
    %
    % - extract-command に与える影響はどうだろう
    %
    %   | 先ず、単語はどの様に設置するべきだろうか。
    %   | 例えば変数代入自体を一つの大きな単語として、
    %   | その中に入れ子で単語の集合を設置するのか、
    %   | 或いは、親の文脈で一つの変数代入に対して複数の単語を設置するのか。
    %   |
    %   | 文法構造という観点からいうと入れ子にして設置したほうが良い気がする。
    %   | しかし、補完などの観点からいうと extract-command した時に変な切り出し方をされると嫌だ。
    %   | と思ったが、既にリダイレクト (ctx-redirect) や配列 (ctx-values) などの場合には内部に入れ子構造を作っているのだから、
    %   | extract-command で問題になったりしそうなものである。これについては現在の振る舞いを確認する。
    %   | →どうも調べてみると現状の extract-command だと、
    %   | リダイレクトや配列の代入の中では親のコマンドを正しく抽出できていないという事が分かった。
    %   | 従って、extract-command を改修して入れ子になっていても大丈夫な様にする必要がある。
    %   | そしてその様に改修した暁には変数代入に関しても入れ子にして問題ないだろう。
    %
    %   従って extract-command 関係については以下の様に対応すれば良い。
    %
    %   1 extract-command を改修して一番最初にコマンド単語 (CTX_ARGI) のあった階層で抽出する様にする。
    %     これにより echo hello; arr=(hello @world) など (@ はカーソル位置を表す) に対して
    %     echo hello が抽出される様にする。同様に echo world > te@st に対して echo world が抽出される様にする。
    %
    %   2 extract-command のコマンド単語抽出の方法について再確認を行う。
    %     コマンドの引数単語は常に CTX_ARGVI または CTX_ARGI と決まっていただろうか?
    %     またコマンド単語は常に CTX_CMDI と決まっていただろうか?
    %
    %   3 その上で変数代入に関しては、それ自体を一つの単語とすると同時に、
    %     内部に入れ子で単語を導入する様にする。
    %
    %   4 実は declare var=hello の右辺でも同様にチルダ展開が有効になるはずである。
    %     これについても同様に内部に入れ子で単語の構造を導入する事にする。
    %
    %   1, 2 に関しては #D0635 で取り扱う事にした。
    %
    % - もう一つの懸念事項は既存の補完で変数代入の右辺について何かあっただろうか。
    %
    %   % これに関してはまた確認する必要がある。実の所、現状では何も補完できていないので、
    %   % 何か実装しようとしていたとしても表面上は破壊する事にはならないだろうが。
    %   % 念のために確認しておく事にする。
    %   % →調べてみると ctx==CTX_VRHS で file を設置している。
    %
    %   実際に補完してみたら補完された。動いている。
    %   completion-context で ctx が CTX_VRHS の時に file を設置している。
    %
    %   補完開始点はその CTX_VRHS の先頭になっている。
    %   つまり、CTX_VRHS で複数回数で解析を行っている場合補完が働かなくなる。
    %   実際に var='w'or@ において補完を実行しようとしても補完できなかった。
    %   これは独立した項目で処理する事にする。#D0627
    %
    %   何れにしてもこの補完が動く様にする為には文字列を開始する必要がある。
    %
    % うーん。ここで通常コマンドの引数でも = の直後でチルダ展開が有効になるという事を発見した。
    % という事は、上記の方法を取っている限りは全ての単語について入れ子構造を導入しなければならない。
    % その様に実装すると余計に複雑になる。この方法はやはり駄目である。

    c =~ や :~ の連なりを見てチルダ展開を実行する様にすれば良い。
      これならば問題は起こらないはず。

    どうもまた色々試すと思っていたよりも複雑の様だ。
    先ず、echo a=~:~ とすると両方共展開される。
    また echo ~:~ だと前者しか展開されない。
    echo a+b=~:~ だと展開されない。
    echo a=~:b=~ だと前者しか展開されない。
    echo a=b:~ だと展開される。
    echo a+=~ だと展開され、echo a-=~ だと展開されない。
    a=b=~ は展開されない。
    echo a[$((1+2*3))$(echo 1)]=~:~ などでも有効になる。

    以下の様な規則になっていると思われる。
    先ず初めに通常の単語であっても変数代入と同様に解釈される。
    変数代入の右辺の初め、または、途中の : の直後ではチルダ展開が有効になる。

    これに対応するためには通常の単語であっても変数代入と同様の解析を行う必要がある。

    - どうも対応が微妙になってきた。そもそも配列代入の解析は正しく出来ていたのだったか?
      怪しい振る舞いをしていたので調べてみたが、それは解析の問題ではなかった #tmp0003

    [実装1]

    改めて考え直す必要がある。
    取り敢えず変数代入に関しては正しく動く様に実装できたと思う。
    通常の単語については以下の対策が必要である。
    結局通常の単語に関しても変数代入の形式の読み取りを実施しなければならない。

    - v= の形式の時 CTX_VRHS 的な別の文脈に移動する。
      これは取り敢えず CTX_ARGI のクローンとして実装すれば良い。
      例えば CTX_ARGIR という名前にする。

    - a[...]= の形式の時、通常の単語の場合には [] の中身は CTX_BRAX で読み取る。
      CTX_BRAX を抜ける時に ntype を見て 'a[' ならば、
      続きが ]= であることを確かめて CTX_ARGIR に移行する様にしかける。
      移行した時には変数代入の時と同様に tilde-expansion のチェックをその場で行う。

    取り敢えず、ARGVI, ARGI, FARGI3, CARGI1 それぞれについて
    変数代入の右辺になった時の文脈値を定義した。実装した。
    通常の引数について動作のテストを行う。

    x fixed: stackdump が出る。これは _ble_syntax_bash_command_isARGI が整数値のはずなのに、
      文字列として扱おうと考えて "a" などの値を入れたのが悪かった。
      結局文字列の値は使わないことになったので "a" から "1" に戻した。

    x fixed: echo a[i]=1 において CTX_BRAX から抜けた時の着色が変だ。
      等号は ATTR_GLOB で塗らない。直した。

    x fixed: 変数代入の後に ctx=CTX_UNSPECIFIED になっている。
      単語の形成にも失敗している。直した。

    x fixed: declare var=value の value の着色が変だ。
      これは上の項目と同じ原因だった。直った。

    x fixed: declare var=value の後の文脈がコマンドを受ける文脈になっている。
      CTX_ARGVX に戻るべき。これは _ble_syntax_bash_command_EndCtx[CTX_ARGVIR] の値を誤っていただけだった。
      CTX_VRHS の設定をコピーしただけになっていた。直した。

    o ok: チルダ展開が有効でないはずのものはちゃんとチルダ展開以外になっている。
    o ok: declare arr[123]=~:~ なども期待通りに動いている。

    x wontfix: 実は echo a[]=~ もチルダ展開として有効である。
      しかし、現在の実装では [ の直後の ] は "]" を閉じる力がない。

      改めて試すと echo a[]b]=~ はチルダ展開が有効にならない。
      つまり、チルダ展開としては "a[]"b]=~ の形式であると見做し、チルダ展開は起こらない。
      一方で 'ab=~' という名前のファイルに一致するのでパス名展開としては echo a["]b"]=~ と解釈している。
      これについては blesh は パス名展開の方が正しく着色されるようにする。

    o ok: for var in args... や case arg in の arg の部分でもちゃんと動いている。

    [実装2]

    未だ残っている。ctx-values や ctx-conditions でもチルダ展開は有効である。
    ctx-values については対応した。ctx-conditions にも対応した。

    * 変数代入形式の単語の右辺でブレース展開を使うと、チルダ展開は無効になる。
      % echo a=~:{a,b}:~ とするとチルダ展開は有効にならない。
      % ブレース展開があると駄目なのだろうか。
      % 規則がよく分からないのでこれは保留にする。
      と思ったが後で対応するのも面倒なので分かる範囲で対応することにした。

2017-11-26

  * 2017-11-24 syntax: extract-command の実装を再確認する [#D0635]

    これは元々 #D0636 の方法 b を整備する時に
    extract-command の実装を確認した時に気がついた extract-command 自体の問題。
    結局方法 b は棄却されたので、独立させてここで実装する事にする。

    | 1 extract-command を改修して一番最初にコマンド単語 (CTX_CMDI) のあった階層で抽出する様にする。
    |   これにより echo hello; arr=(hello @world) など (@ はカーソル位置を表す) に対して
    |   echo hello が抽出される様にする。同様に echo world > te@st に対して echo world が抽出される様にする。
    |
    | 2 extract-command のコマンド単語抽出の方法について再確認を行う。
    |   コマンドの引数単語は常に CTX_ARGVI または CTX_ARGI と決まっていただろうか?
    |   またコマンド単語は常に CTX_CMDI と決まっていただろうか?

    2 に関しては ble_debug を見て試した限りでは問題ない様に見える。
    1 に関しては現在の実装を改めて見ないと分からない。
    実装を改めて読む。そもそも tree-enumerate は一体どのような実装になっていたのだったか。

    | 先ず初めに tree-enumerate/.initialize を見る。
    | 出力する変数は tree と i と nofs である。
    | 恐らく .initialize では未だ閉じていない入れ子を末端位置で仮に閉じた時に、
    | _ble_syntax_tree[iN-1] がどの様な値になるかを計算している。
    | - _ble_syntax_tree[i-1] は境界 #i で終わる範囲の情報を格納することに注意する。
    | - 範囲は二種類ある。word と nest である。
    | - word は word を直接子に持つことはない。
    | - inest は範囲の開始点であり、_ble_syntax_nest[inest] に範囲の開始情報が格納されている。
    |
    | 次に tree-enumerate/.impl を見る。
    | - 同じ位置で複数の階層の範囲が終端するとき、
    |   それらの情報は連結されて _ble_syntax_tree[i-1] に格納される。
    |   外側の範囲の情報の方が左側に格納される。
    | - tclen tplen を用いてこれらの範囲情報は互いに参照する。
    | - 他の位置から参照されるときは必ず一番外側の情報を参照する。
    |   同じ位置から参照されるときに限り一つ右の情報を参照する。
    | この関数は同じ階層に位置する兄弟を末尾から列挙して指定した関数を呼び出す。
    | 範囲の情報は wtype wbegin tprev tchild nofs を用いて渡される。

    結局 tree-enumerate は一番外側の階層の範囲を列挙し、
    tree-enumerate-children は現在の範囲の中に下の階層があれば、
    その階層について範囲を列挙するということをする理解は正しい。
    使える変数は wtype wbegin tprev tchild nofs であり、
    通常用途であれば直接ユーザが使用するのは wtype wbegin である。
    tree-enumerate-break は強制的に tprev=-1 にする事で
    兄要素がないことにし、そこで兄弟の列挙を停止させる。

    ble-syntax:bash/extract-command/.scan では、
    現在位置が含まれる一番下の階層の単語を探している。
    先ず初めに現在以前で始まる範囲まで見送る。
    範囲が現在位置よりも左まで行ったら中断する。
    現在位置を含む範囲を見つけたらその中に潜るというのを繰り返す。

    その階層に単語 (wtype/ntype が整数値の範囲) が含まれる場合には isword を設定する。
    isword は、一つ上の階層で construct を呼び出して貰うためのマーカである。
    この isword は一番最初に見つかった単語である。
    つまり、現在位置以前に始まる一番最後の単語の wtype になる。
    そうは言っても誰も使っていない様である。
    isword は分かりにくいので extract_has_word に変数名を変更した。

    うーん。結局 iscommand=1 (改め extract_command_found=1) の位置を変更するだけで良い気がする。
    試してみる。動いている。OK

    ? fixed: _ble_syntax_tree の構造を見ていて気付いたが、
      よく考えると _ble_syntax_tree であっても、wtype に任意の文字列が入りうるから、
      node=(${_ble_syntax_tree[i]}) とすると failglob で不味いのでは?

      と思ったが、ntype としてグロブパターンになる物がなければ大丈夫のはず。
      これは nest-push を全て確認すれば分かる。a[ や v[ など怪しい物もあるが、
      現状ではグロブパターンになる様なものは含まれていない。
      将来的なことを考えると本当はグロブパターンが含まれることも
      想定して修正した方が良いのかもしれないが。

      現状では問題ないが、やはり後々のためにちゃんと安全な方法で split する事にする。直した。

  * edit: history 初期化で先頭行に行く (reported by cmplstofB) [#D0634]

    > 起動直後に履歴を遡る (というより ^P を押下する) と一番始めの履歴にまで戻ってしまいます。

    送ってもらったログを見て分かった。
    failglob の為に history_line=($history_line) を
    ${history_line%%[$IFS]*} に変更したのが原因だった。
    どうやら history で出力される履歴番号は printf %5d で出力されている為に、
    履歴項目の数が 5 桁より小さい時には先頭にスペースが入るのだ。

  * complete: failglob 時の問題 (3) (reported by cmplstofB) [#D0633]

    > コマンドに glob が含まれている場合などはいいのですが，
    > 存在しないパスを補完しようとすると不具合が発生します。

    うわ。未だ残っている…。うーん。
    候補生成にパス名展開を使っているのが悪い。
    試しにエラーメッセージを殺す方向で試してみたが、
    すると今度は ble.sh の処理自体が其処で死ぬ。

    % 先に対応したパス名展開では死んでいなかったが何故だろう。
    % 見てみると eval している。試してみると eval だと大丈夫のようだ。
    % 関数を作る。ble/util/eval-pathname-expansion
    % 一応パス名展開をしているところはこれに置き換えた。
    % エラーメッセージは出ていない。
    結局この実装は以降の修正により使わない事になった。

    x fixed: 後、shopt -s nocaseglob も現在の実装だと不味い。
      パス名展開で候補を生成しているので、
      a.txt に対して A@ で補完を実行すると A.txt になってしまう。

      そもそも何故 compgen -A file -- ... を使わずに、
      "$COMPV"* を使っていたのだったか。
      先ず初めに compgen は fork またはファイルへの読み書きをしないと結果を取得できないので遅い。
      次に、何故か prefix を認識してくれないことが過去にあったから。
      今試してみるとちゃんと動いている様に見えるが、実のところ良くわからない。
      更にディレクトリ名を / を付きで生成するのも楽である。

      今 nocaseglob に合わせて、既に存在している文字列を
      書き換えてしまうという手も考えられるが、quote がある場合など諸々を考えると面倒だ。
      後でまとめて対応する様にした方が良い気がする。
      この大文字小文字の違う候補でも補完できるようにするのは独立した項目にする。

      今は compgen で候補を生成する事にする。

    x fixed: 起動時に一時ファイルを消すところでもパス名展開を使っている。
      これも対処しないとそもそも ble.sh のロードに失敗する筈。

      これは起動時の処理なので ble/util/* などの高等な機能は使えない。
      従って、shopt -u failglob して処理する事にする。

  * 変数が漏れている。ret が定義されている [#D0632]

    1 先ず emacs mode でも定義される。
    2 ble-syntax/parse で local ret としてみても変わらない。
    3 ble/textarea#render で local ret としてみても変わらない。

    逆に外側から絞っていく事にする。
    4 ble-decode/.hook で local ret としたらさすがに大丈夫だ。
    5 ble-decode/PROLOGUE, EPILOGUE は関係ないようだ。
    6 ble-decode-key で local ret としたら大丈夫だ。
    7 eval -- "$WIDGET" の前後で ret が設定される様だ。
      ret の値が破壊される時の WIDGET を出力させると以下の様になった。
      ret=0:WIDGET=ble/widget/vi_imap/accept-single-line-or vi_imap/newline

    どうも複数存在する様である。一つは _ble_edit_str/update-dirty-range から。
    見つけた。以下で漏れている。

      ble/keymap:vi/mark/set-global-mark
      ble/keymap:vi/mark/set-local-mark

    直したら取り敢えず ret の値は保持される様になった。
    実は他の箇所でも漏れがあったような気がしたが、今の所は再現していない。

    x 更に、一回 normal-mode に入ってそれから insert-mode に入ると ret が消える。
      これも ret が漏れている証拠である。どうも normal-mode に入る瞬間に駄目の様だ。
      と思ったが当たらない。どうも実行直前に insert-mode に入っていて、
      insert-mode の実装で ret を宣言するのを忘れていたということのようだ。

      さて、これは直したと思ったが、未だ直っていない。
      insert-mode で local ret したが反応しない。と思ったら xmap/insert-mode を見ていた。
      そう思って nmap/insert-mode で local ret をして見たがそれでも直らない。
      vi_imap/normal-mode-without-insert-leave の方でも修正したがそれでも駄目。
      もう一度外側から絞っていくしかないのだろうか。もう一度 ble-decode にしかける。

      | local ret=trap1
      |   builtin eval -- "$WIDGET"; local exit=$?
      | [[ $ret == trap1 ]] || echo "ret=$ret:WIDGET=$WIDGET" >> a.txt
      |
      | 結果
      | ret=<U+009C>:WIDGET=ble/widget/vi_imap/normal-mode-without-insert-leave
      | ret=<U+009C>:WIDGET=ble/widget/vi_nmap/insert-mode

      うーん。何と両方で ret が書き換わっている。道理で片方だけ書き換えても反応しない訳だ。
      というかよく考えたら local -r ret すれば犯人が分かるのでは?
      と一瞬思ったが駄目だ。local -r ret すると新しいローカル変数の定義も禁止されてしまう。

      normal-mode-without-insert-leave に潜る。ble/keymap:vi/update-mode-name が駄目だ。
      中を覗いてみると呼び出している関数は ble-edit/info/default しかない。やはりそうだ。
      辿っていくと ble-edit/draw/trace.impl にまですぐに行く。見つけた。

      改めて ble-edit.sh についても ret のリークがないか調べる必要がある気がしてきた。
      他に 2 箇所同様の ret のリークを見つけた。直した。
      心配になったので ble-syntax.sh と ble-decode.sh も確認する。問題は見つからなかった。
      ble-color.sh も確かめた。一つ上の階層で local ret している例を見つけたが、
      実際の処理内容を見ると不自然なので local ret は中に移動した。
      (ble-highlight-layer:plain/update / ble-highlight-layer:plain/update/.getch)

    x done: keymap/vi.sh の実装について一通り ret の使用を見てみたら、
      かなり local ret を忘れている箇所が見つかった。見つかった物は直した。

    * また最初の調査で "emacs mode でも定義される" と書いたが、
      これは _ble_edit_dirty_observer に登録した
      ble/keymap:vi/mark/shift-by-dirty-range がそのまま動いていて、
      更にこれの中で ret が上書きされていたのが行けなかったようである。
      これについては emacs mode に入る時には _ble_edit_dirty_observer
      から消去する等の対策が必要な気がする。

2017-11-25

  * 2017-11-23 complete: bug 補完で謎の現象が起こっている。空白が補完される [#D0631]
    というか echo [a でも同様に空白が補完される。
    echo $(echo > ) の > の後で実行しても同様である。
    更に echo $(echo) の後でも空白が補完される。
    どうやら同じ点で nest-pop が 2 回起こっているとなっている気がする。

    % どうもこれは昔からあった振る舞いの気がする。後で対応する事にする。

    というか "echo @" でも空白が挿入される。
    この振る舞いは今までなかったはずだ。
    今までは、候補一覧が表示されたはず。
    つまり、これは最近埋め込んだバグである。

    調べてみると空文字列の候補が生成されている。
    どうも compgen で一つも候補が生成されなかった時に、
    ヒアストリングで <<< "$compgen" とした時に空候補が作られる様だ。

    - そもそも compgen が空の時には候補生成の処理はしなくても良いのだから先に抜ける様に変更した。
    - 更に、compgen に内容が含まれていたとしても空行がある場合には、それを除く様に変更した。
    - ble/util/assign-array も調整した。

  * highlight: failglob でエラーメッセージが出る (reported by cmplstofB) [#D0630]

    > コマンドラインで $ l* と入力すると bash: 一致しません: l* という
    > エラーメッセージらしい表示が入力位置の右隣に発生し，続く入力が妨げられます。

    直した。パス名展開を試みている箇所では同様のことが起こりうる。

    x fixed: あと、ble/string#split も火を吹いていた。諦めて set -f する事にした。

    x fixed: また、失敗するコマンドを一度実行するとそれ以降どのキーを入力してもエラーメッセージが出る様になる。
      しかも、C-c などの操作が効かなくなる? DEL も効かない。何故? decode の問題だろうか。
      先ず初めにどのタイミングでエラーが発生しているのかを確認しなければならない。
      これは getcount を実行する時に count=($(history 1)) に相当することを実行していたのが悪かった。

      調べてみると類似の物は広範囲に亘って存在する。全て修正しなければならない。
      grc '=\(\$' で検索して当たるものを全般に調べる必要がある。
      特に ble-syntax.sh における _ble_syntax_stat の類を ble/string#split で分割する必要がある。
      というのも、nparam にはヒアドキュメントの終端が入り * が含まれうるから。
      _ble_syntax_nest も同様である。

      大変なので ble/string#split-words 関数を追加した。

    - done: あと、パス名展開に失敗したらその単語をエラー着色するようにする。

  * keymap/vi (cmap): C-d で終了してしまうバグ (reported by cmplstofB) [#D0629]

    > たとえコマンドラインに文字があっても終了してしまいます。

    直した。

2017-11-24

  * complete: 更に key=key とした後に echo $key""@ も補完できない [#D0628]

    そのまま echo key@ だと勿論補完できる。
    調べてみると is-simple は true を返し、更に eval も期待した値 key になっている。
    一体何が問題で補完に失敗しているのだろうか。

    うーん。何と別のファイル名だと再現しない。
    しかも更に変数名を変えたら動く。
    $ var=key
    $ echo $var""@

    途中の様子を調べてみたら…何と $key"" が 67108969 という値に展開されていた。
    成る程、ローカル変数の変数名と被っているために変数の中身がすり変わっている。

    [cf memo/D0628.extract-global-values.sh]

    | x [困難] これに対処するのは困難である。外部文脈で評価するしかないが、
    |   評価の度に外部文脈にまで移動するのは難しい。
    |   処理を完全にファイバーにして処理しなければならないが、それは滅茶苦茶である。
    |
    | a [不可能] 或いは declare -g key などとすれば外部変数にアクセスする事ができるか?
    |   これは具体的に試してみないと分からない。試してみた所、
    |   declare -g key を用いるとグローバルでの変数の値を変更できるだけであって、
    |   グローバルでの変数の値を読み出すことができる訳ではないようだ。
    |
    | さて、グローバルでの変数の値を設定することができるのだから、
    | 何処かにその値を読み出す方法があるかもしれないと思って検索してみる。
    | しかし、サブシェルの概念を知らずに変数の値が設定できないと相談している人や、
    | 関数内で変数宣言のコマンド (local declare readonly typeset) を用いた時に、
    | 自動的に関数内の局所変数になるということを知らないで記事を書いている人が当たったりで、
    | "ローカル変数を定義している時にグローバルの値を読み出す方法" についての記事は簡単には見つけられそうにない。
    |
    | b [不可能] よく考えてみたら declare -p -g var とすれば見る事ができる筈だ。
    |   しかし $var でアクセスできる様になる訳ではないという事に注意する。
    |   declare -p -g var 等して得られた結果から、
    |   先頭の declare 云々の部分を消して local を付加し、
    |   それから eval すればローカルに値を丸っと持って来ることができる。
    |
    |   - 所で declare -p にはバグがあって改行について再現できない、
    |     と思ったがよく考えたらバグは bash-3.0 の話であり、
    |     一方で declare の -g オプションは bash-4.2 以降なので、
    |     これについては気にしなくても良い。
    |
    |   - この時にその文脈での変数名を上書きしない様に注意する必要がある。
    |     変数名は全て _ble_* という名前にすれば良い。
    |
    |   何と実際に試してみた所できないという事が判明した。
    |   declare -g に -p オプションを指定すると -g は無効になる。
    |   "declare -g" で現在定義されているグローバル変数を全て出力できるのではないかとも思ったが、
    |   実際に試してみるとローカル変数も含めて全変数について、現在での文脈の値が出力されるだけだった。
    |   結局グローバルでの値は分からない。
    |
    | c [不可能] 既に設定されているローカル変数を全て unset すれば
    |   グローバル変数に到達することができるはずだが、
    |   先ず、何回 unset したら良いかわからない。一番最後に定義されていた変数は分かるが、
    |   それが果たしてグローバル変数なのか、それともローカル変数なのか判別できない。
    |   declare -g var としても変数が "定義" される訳ではないので多分駄目だ。
    |   更に、unset した後でまた元の状態に復元する方法が存在しない。
    |
    | d [不可能] 或いはシグナルを用いてシグナルハンドラから出力させるという手もある。
    |   これは遅そうだが仕方がない。実際に試してみた所駄目だった。
    |   先ず呼び出しの順序はちゃんと保たれている。
    |   しかしながら、ローカル変数はそのままにして呼び出される様で、
    |   シグナルハンドラの中からでもローカル変数の値しか見えない。
    |
    | e 或いは bind の一番外側で毎回全てのグローバル変数を何処かに記録するという手もある。
    |   しかし、これは明らかに滅茶苦茶遅い。特に _ble_* の類を除外する方法がない。
    |
    | f もしくは、全てのローカル変数の名前を _ble_* に変えるという手もある。
    |   その様にすれば _ble_* という変数名を参照しない限りは
    |   グローバル変数の値を (何もせずに) 参照できるということが保証できる。
    |   更に、この方法は declare -g などと違ってどの bash の version でも使える。
    |
    |   然し、これはこれで変更コストが大きいし、またコードも読みにくく・書きにくくなる。
    |
    | g c の方法に於いてサブシェルに潜れば unset でグローバル変数を掘り出しても、
    |   外側では影響が出ない様にする事ができるのではないか。
    |   unset を繰り返し実施して一番最後に定義されていた変数の値を取れば良い。
    |   この方法でグローバル変数が定義されていればそれを取得できるという事が分かった。
    |
    |   v 実際に複数階層の場合でも各階層での値を逐次的に取得できることが分かった。
    |
    |   x ok: 途中にローカル変数があった場合は?
    |
    |     | 思ったのだが途中で -r のローカル変数があった時に unset できるのだろうか。
    |     | →試してみたところ駄目だった。できない。
    |     | これに関しては -r なローカル変数を設置しないという今までの方針を用いている限りは問題ない。
    |     | complete の処理の途中でユーザ関数を通過することはないので問題にはならない。
    |     | ただ、中で補完などを呼び出すような widget を書くときには readonly にしない様に注意するしかない。
    |
    |     グローバル変数にアクセスするには途中のローカル変数に readonly を指定してはならない。
    |
    |     というか試していて分かったことだが local -r 宣言してしまうと、
    |     更に呼び出した先の関数でその変数を local 宣言することができなくなってしまう。
    |     実際に検索してみるとそれをやっている箇所が ble-syntax.sh に二箇所見つかった。これは消す。
    |
    |   x solved: 問題点はグローバル変数が定義されていなかった時に、
    |     一番最初に定義されたローカル変数の値を拾ってきてしまうという事である。
    |
    |     a その変数がグローバル変数かどうかを判定するには、
    |       declare -g var=xxx を実行して値が変化するかどうかを見れば良いが、
    |       もしそれがグローバル変数ではなかった場合にグローバル変数の値を破壊してしまう。
    |       破壊が起こらない様にする為にはサブシェルの中で値が変化するかどうか見れば良いが fork が増える。
    |
    |       一応、以下の方法を用いれば余分な fork は一回に抑えることができる。
    |       先ず初めに unset を繰り返す事で何階層の変数が定義されているかを調べ、
    |       その後で改めて初めから unset を実行して一番最後の階層に移動し、
    |       そこで declare -g var=xxx に応答するかどうかでそれがグローバル変数かどうか判定する。
    |
    |     b 或いは declare -g var だけ実行すればそこに変数が存在することが保証されたりしないだろうか。
    |       或いは declare -g -r var などとすれば readonly な物をグローバル変数と解釈できる。
    |
    |     ここは b で実装してみた。動いている。
    |
    |     c 但し、declare -g は bash-4.2 以降でないと使えないので、
    |       bash-4.2 未満では [[ ${var+set} ]] による実装に切り替える。
    |       しかし、これだとやはりグローバル変数に到達できない場合があり問題だ。
    |
    |       或いは、__ble_MaxLoop=20 迄回してしまうというのも手である。
    |       fork に比べれば大した処理量ではない。また、別目的にこの関数を使うとしても、
    |       bash-4.2 未満の話なのでパフォーマンスは余り気にしない事にする。
    |       その様に修正した。動いている。
    |
    |       唯、bash-4.0 未満 ${!varname+set} が期待通りの動作をしていない気がする?
    |       しかし普通に bash-3.2 -c 'var=hello; [[ ${!var+set} ]]' とすると動いて見える。
    |       まあ、調べるのも面倒なので、少なくともグローバル変数がある場合には
    |       正しい値を取得できているので良しとする。
    |
    |   x ok: 途中に宣言だけの変数があった場合 (local var) は?
    |
    |     [[ ${var+set} ]] とすると変数が存在することになっている?
    |     と思ったが、それも2回だけで 2 回 unset すると変数は存在しないことになる。
    |     ところが、無視して unset を続けて行くと最終的にグローバル変数に到達することはできる。
    |
    |     まあ、取り敢えず動いているので気にしない事にする。
    |
    |   x ok: もう一つの面倒なことは、サブシェルで実行するので、
    |     実行結果を返すために標準入出力を用いなければならないという事である。
    |     といってもこれは面倒なだけで fork をするよりはコストも小さいし問題にはならない。

    結局 g の方法でテスト実装して動くようなものができたのでそれを使う事にする。
    ble/util/print-global-definitions という関数を定義した。

    次に simple-word から変数名を抽出する。テストした。
    それから変数名が一つ以上ある時に print-global-definitions を呼んで eval する。
    幾らか修正したら、問題なく動いている。

    些細な事のために大分実装が複雑になったが仕方がない。

  * complete: ファイル world があるとき var='w'o@ (@ はカーソル位置) で補完できない [#D0627]

    これは completion-context の CTX_VRHS において、
    CTX_VRHS が最後に設置された位置を補完開始点としているからである。
    上記の例で言えば o を起点に補完を実行しようとしてしまう。
    ここでは wbeg から変数名をスキップして補完を実行するべきである。

    この修正により以下の項目も解決した。

    | 2017-11-06
    |
    | * complete: リダイレクトのファイル名に @ が含まれているとき @ 以降で補完できない。

  * syntax: チルダ展開 [#D0626]

    チルダ展開が起こる文脈は?
    ctx-command ctx-values では起こる。
    ctx-conditions では %%起こらない%% と思ったら起こっている様だ。
    ctx-redirect CTX_RDRF/CTX_RDRS/CTX_RDRD では起こる。

    extglob や [...] の中では起こらない。
    最初のブレース展開の中では起こる。が、これは面倒なので認識しない。

  * highlight: リダイレクト先ファイル名が複数語に展開されたらエラー着色 [#D0625]

  * highlight: echo <<< {a,b} や echo <<< * ではグロブ展開が起きないのに、 [#D0624]
    着色はグロブ展開も含めてファイル名に一致するかどうかが確かめられている。

  * 2015-08-15 syntax: CTX_CMDXC, CTX_CMDXF 等に於いて redirect は許可するべきでないのでは? [#D0623]
    更に、CTX_CMDXC においては var=... も許可するべきではない。

    また CTX_CMDX1 についても直前のコマンドによっては redirect は許可するべきでない?
    (while, if, do, then, else, '(', time の直後では redirect も可能な様だ。)

    2017-11-24 改めて一通り動作を確認する事にする。

    | CTX_CMDX1 について調べた所、他に && などの直後が CTX_CMDX1 のようだが、これについても redirect は可能である。
    | 結局、現状のコードでは CTX_CMDX1 の場合はいつでも redirect は可能に思われる。
    |
    | CTX_CMDXF は CTX_FARGX1 に改名した。CTX_FARGX1 では redirect はできない。
    | CTX_FARGX2 でも redirect はできない。これらは大丈夫。
    | しかし、CTX_FARGX2 から CTX_ARGI に変換しているが、
    | bash は for a in aaa bbb > redirect; の形式を許していない。★これは修正が必要
    |
    | CTX_CMDXE は fi fi などの文脈であるが、
    | この直後に > redirect がある事はいつでも許される。
    | また redirect の後は CTX_ARGX0 になるという振る舞いも正しい。
    |
    | CTX_CMDXC は関数定義の始まる前の文脈であるが、ここでは redirect は使えない。
    | この振る舞いについても ble.sh で試したところ正しい。
    |
    | CTX_CMDXD は for ((;;)) 直後の文脈である。
    | これも現状の ble.sh の振る舞い通り redirect は使えない。

    結局 for a in の後の引数の列でリダイレクトを使えないという事に対応すれば良い。
    対応した。新しい文脈値 CTX_FARGX3, CTX_FARGI3 を追加した。

2017-11-23

  * 2017-11-21 syntax: ブレース展開? [#D0622]

    | 少し試してみたが、ブレース展開が起こる条件が謎。
    | echo ${aaaa:-{a,b}{c,d}} # 起こらない
    | echo ${aaaa:-{a,b}{c,d} # 起こらない
    | echo ${aaaa:-a,b}{c,d} # 起こる a,bc a,bd
    | echo ${aaaa:-{a,b}}{c,d} # 起こる {a,b}c {a,b}d
    | echo ${aaaa:-a,b}}{c,d} # 起こる a,b}c a,b}d
    |
    | bbbb=1234; echo ${bbbb:-{a,b}{c,d}} → 1234{c,d}} となるので、
    | ${} は特に {} の入れ子の回数を数えるという事はしていない。

    うーん。仮説は以下の通り。
    1 先ず初めにブレース展開を試行する為に {,} を抽出する。
      ${} が現れたら {} の入れ子を数えつつスキップする。
      ブレース展開が見つかったら展開する。
    2 展開後の単語について ${} 等の展開を行う。
      この時は ${} の中の {} の入れ子は数えず、
      "}" が現れた時点で即座にパラメータ展開が閉じるとする。

    この 1 と 2 の間の ${} の終端点の抽出の違いに依って
    変な振る舞いが生まれていると思われる。
    これは bash がおかしいので多少の着色の違いは無視する。
    基本的に ${} の抽出に従い (つまり {} の入れ子は考えない)、
    仮にブレース展開が {} の入れ子で無効化されていたとしても、
    気にせずに着色を実施する。

    ブレース展開の着色に対応するのであれば、
    {aa..bb} や {aa..bb..cc} や {aa,bb} 等の途中の区切りについても着色したい。
    CTX_BRAX と同様に delimiters が来たら抜ける。

    | a 初めは .. が来るか , が来るか分からない状態として解析し、
    |   何か複雑な構成が来たら , だけを受け付ける状態に移る?
    |
    | b と思ったが .. が許されるのは内部に構造がない時のみなので、
    |   "{" を nest-push する時点で .. の形式かどうかを判定する事ができる気がする。
    |   正規表現 (([0-9]+)\.\.([0-9]+)|[a-zA-Z]\.\.[a-zA-Z])(\.\.[0-9]+)?\} で読み取れる所まで読み取り、
    |   一番最後まで読み切れたら {aa..bb} の着色を行う。
    |   もし途中で一致しないと分かったら、その時点で , を受け付けるブレース展開の文脈に push する。
    |
    | c b の方法だと先読みのために何処まで読んだかを調べなければならないので、もっと単純化する。
    |   "{" が来たらそこから前方に [0-9a-zA-Z.]*\}? を読み取る。
    |   もし \} まで読み切ったら、中身が b の形式になっていれば {a..b} として着色し、
    |   そうでなければブレース展開ではなく通常の文字列として読み取る。
    |   途中までしか読み取れなかった場合には "{" で nest-push して
    |   {,} 形式のブレース展開の文脈に入る事にする。

    ここでは c の方法を用いることにする。

    ブレース展開の文脈でも角括弧式やグロブパターンは有効である。
    ブレース展開から角括弧式を呼び出した時には
    角括弧式は通常のコマンドの終端に加えて ,} でも終端する様に注意する。

    取り敢えずブレース展開に対応する事にする。

    [実装]

    1 done: 先ず初めに _ble_syntax_bashc[CTX_ARGI] を修正する。
      "{" を追加した。

    2 done: 影響範囲を確かめる。
      ${_ble_syntax_bashc[CTX_ARGI]} を参照しているのは、
      ctx-command, ctx-values, ctx-conditions, ctx-redirect である。
      更に ctx-bracket-expression でも使用している。

      - ctx-values ではブレース展開は有効である。
      - ctx-conditions ではブレース展開は無効である。
      - ctx-redirect ではどうだろうか。試してみると文脈によって振る舞いが異なる。
        - CTX_RDRF で使うと曖昧だと言われてエラーになる。
        - %%CTX_RDRH で使うとブレース展開は完全に不活性の様だ。%%
          →そもそも CTX_RDRH は ctx-redirect の対象ではなかった。
        - CTX_RDRS で使った場合も不活性の様だ。
        - CTX_RDRD これは fd を受け取る形式のリダイレクトである。
          曖昧なリダイレクトだと言われてエラーになる。

      つまり、少なくとも CTX_RDRF, CTX_RDRD ではブレースを認識し、
      そして、エラー着色を設置する必要がある。と思ったが、
      不完全なブレース展開の場合には入る時に確実なエラー着色を実行できない気がする。
      と思ったが、これは "}" が現れてブレース展開が閉じる時にエラー着色すれば良い。
      そして途中の "{" や "," は不活性という事にする。

    3 done: 取り敢えず ctx-command で使う為に check-brace-expansion を実装する
      実装した。動いている。

    4 done: 次に文脈毎に対応していく事にする。

      - ctx-values ではそのまま対応すれば良い。

      - ctx-conditions では着色しないし nest-push もしないという様にすれば良い。
        (或いは、そもそも ctx-conditions の通常文字集合から "{" を除けば良いのだが、
        新しい文字集合を定義するのも面倒なのでそのままにしておく。)

      - これは CTX_RDRS %%及び CTX_RDRH%% でも同様に取り扱えば良い。
        また CTX_RDRD 及び CTX_RDRF では一応読み取るがエラーにする。
        と思ったが > {1..1} 等の様に 1 個しか値が生成されない時はエラーにはならない様だ。
        うーん。これは展開の結果としてのエラーであって構文エラーではないので、
        余り気にせずそのまま解析してしまえば良い?
        唯、> {1..3} の様な場合はやはり明らかにエラーになることが分かっているので、
        この解析の時点でエラーにしてしまって良い気がする。エラーにする事にした。

        特に nest-push した時には最終的に , なしで終わってブレース展開として有効にならない事もある。
        その様なことを考えると nest-pop した場合にはわざわざエラーの着色はしなくても良い?
        →これは次の項目で対処する様に "," の前後で文脈値を変えることにしたので、
        実は "," なしで終わったかどうかは判定可能である。
        というか、"," より後でしか "}" で終わる事ができない。
        取り敢えず現状では "}" で抜ける時にエラーを設定する事にする。

    5 done: 実は echo {aaa},bbb} は {"aaa}","bbb"} と解釈される様だ。
      初めの "," が現れるまでは "}" は有効でない。対応した。

    6 done: ctx-brace-expansion の入れ子について。対応した。

    7 done: CTX_PATN や CTX_BRAX との入れ子の関係について考える必要がある。

      | CTX_PATN 及び CTX_BRAX の失効の関係についてまとめる。
      |
      | CTX_VRHS  -> CTX_BRAX 不活性, CTX_PATN 不活性, CTX_BRACE? 失効
      | CTX_RDRS  -> CTX_BRAX 不活性, CTX_PATN 不活性, CTX_BRACE? 失効
      | CTX_BRAX  -> CTX_BRAX 不活性, CTX_PATN 不活性, CTX_BRACE? 有効
      | CTX_CONDI -> CTX_BRAX 有効, CTX_PATN 有効, CTX_BRACE? 失効
      | CTX_RDRF  -> CTX_BRAX 有効, CTX_PATN 有効, CTX_BRACE? 不活性
      | CTX_RDRD  -> 同上
      |
      | 伝播は CTX_BRAX, CTX_PATN, CTX_BRACE の間で行えば良い。
      | と思ったが、そもそも CTX_BRAX 及び CTX_PATN の内部での
      | ブレース展開を許可するのかは謎である。
      |
      | | うーん。取り敢えず CTX_PATN の下からは好きに CTX_BRACE に入れる様にする?
      | | と思ったが、CTX_PATN の呼び出し元として何が考えられるか。。
      | | うーん。現状では glob pattern が有効な ctx-command 系統の文脈に限っている。
      | | 従って、CTX_PATN の呼び出し元が何であれ CTX_BRACE に入って問題はない。
      | |
      | | 一方で、今後 ${var#pattern} に対応したことを考えると事情は複雑になる。
      | | この場合はブレース展開は無効にしなければならない。
      | | 一つの方法は、${var#pattern} における extglob 及び 角括弧式
      | | は別の文脈値を使って解析するという物である。
      | | ${var#pattern} の場合には CTX_VRHS CTX_RDRS 等の不活性処理が不要である。
      | | 一方で CTX_BRAX による不活性処理は必要である。うーん。然し…。
      | |
      | | そもそも CTX_PATN を抜ける条件である "}" をどの様に伝播するつもりだったか。
      | | もし CTX_PATN を抜ける条件として "}" が有効かどうかを確かめる手段を与えるのだとしたら、
      | | この 「"}" で終わるかどうか」を以てブレース展開が有効かどうかを判定できるはず。
      | | その様に考えれば、将来的に ${var#pattern} に CTX_PATN が対応するかどうかに依らず、
      | | 現状として CTX_PATN から CTX_BRACE に入るのを有効にして良い気がする。
      |
      | 現状では CTX_PATN からブレース展開はいつでも呼び出せることにする。
      |
      | 1 先ずブレース展開に入るときを考える。
      |
      |   CTX_PATN/CTX_BRAX が不活性の時、その原因は CTX_VRHS/CTX_RDRS/CTX_BRAX のどれかである。
      |   原因が CTX_VRHS/CTX_RDRS のときブレース展開は不活性にする。
      |   原因が CTX_BRAX のときブレース展開は通常通りに処理する。
      |   CTX_PATN/CTX_BRAX が有効のときは、何も考えずにブレース展開を有効にすれば良い?
      |
      |   但し、CTX_BRAX の親 nctx が CTX_CONDI の時にはブレース展開はやはり無効にする。
      |   CTX_PATN の親 nctx についてもチェックできるが、CTX_PATN は幾らでも入れ子にできるので、
      |   入れ子の階層によってブレース展開が有効になったり無効になったりするのは分かりにくい。
      |   仕方がないので、[[ @() ]] の中ではブレース展開は有効になるように解析する。
      |
      | 2 次に CTX_PATN に入る時を考える。CTX_BRAX も同様にできそう。
      |
      |   特に CTX_BRACE(不活性) から CTX_PATN に入る時はどうするべきか。
      |   不活性要因は CTX_RDRF, CTX_RDRD だが、両者とも基本的には CTX_PATN, CTX_BRAX は有効である。
      |   従って、CTX_BRACE(不活性) から CTX_PATN に入る時はそのまま CTX_PATN に入れば良い。
      |   CTX_BRAX に入る時も同様である。一方で、CTX_VRHS, CTX_RDRS によって CTX_BRACE が無効化されている時は、
      |   そもそも CTX_BRACE? の文脈に突入しないので考慮しなくて良い。
      |
      |   問題は CTX_BRAX -> CTX_BRACE(有効) -> CTX_PATN/CTX_BRAX となる時だが…
      |   CTX_BRACE になっている時点で外側の CTX_BRAX は分断されるので、
      |   bracket expression として有効なのかも分からない。
      |   従って、内部で CTX_PATN や CTX_BRAX が有効でも良いのではないかという気がする。
      |
      |   つまり、これに関しては何も考慮しなくて良い。という事にする。
      |
      | 表にする。
      |
      |   CTX_VRHS  -> ... -> CTX_PATN(不活性) -> ブレース展開 x
      |   CTX_VRHS  -> ... -> CTX_BRAX(不活性) -> ブレース展開 x
      |   CTX_RDRS  -> ... -> CTX_PATN(不活性) -> ブレース展開 x
      |   CTX_RDRS  -> ... -> CTX_BRAX(不活性) -> ブレース展開 x
      |   CTX_CONDI -> CTX_BRAX(有効)          -> ブレース展開 x
      |   CTX_BRAX  -> ... -> CTX_PATN(不活性) -> ブレース展開 o
      |   CTX_BRAX(有効) -> ブレース展開 o
      |   CTX_PATN(有効) -> ブレース展開 o


    CTX_PATN/CTX_BRAX の入れ子に関して表にしてみたが分かりにくい。
    やはり日本語でまとめる事にする。

    以下のとき、ブレース展開は無効となり通常文字列として読み取られる。
    - CTX_CONDI/CTX_VRHS/CTX_RDRS からブレース展開を試みるとき
    - CTX_VRHS/CTX_RDRS によって不活性化した CTX_PATN/CTX_BRAX からブレース展開を試みるとき
    - CTX_CONDI の直下にある CTX_BRAX(有効) からブレース展開を試みるとき
    以下のとき、ブレース展開は不活性となりブレース展開として有効になったときエラーを設置する。
    - CTX_RDRF/CTX_RDRD からブレース展開を試みるとき
    - 不活性の CTX_BRACE1/CTX_BRACE2 から入れ子のブレース展開を試みるとき
    その他のとき、ブレース展開は有効になる。但し、bash と違い以下の場合を含む
    - CTX_BRAX によって不活性化した CTX_PATN からブレース展開を試みるとき
    CTX_BRACE1/CTX_BRACE2 から CTX_PATN/CTX_BRAX に入る時は特別な処理は何も必要ない。

  * syntax: "{fd}>" 形式のリダイレクトで先読みに問題が生じる可能性? [無問題] [#D0621]

    echo {f,d}> a.txt を echo {fd}> a.txt に書き換えるとどうなるのか。
    うーん。実はこれは問題にならない。何故なら、
    {f,d} の場合には {f,d} まで一気に読み取るので、
    "," が消えると必ず解析再開点は "{" になる。

    問題はリダイレクトとして有効な形になった瞬間に、
    解析再開点が "{" 以前になることが保証されるかである。
    もう少し落ち着いて考える。リダイレクトとして有効な形でないとき、
    ある点でそれがリダイレクトとして有効でないという事が判明する点がある。
    上記の例で言えば "," の位置である。これより前の位置ではリダイレクトとして有効である。
    この時、 "{" から "," の直前の位置までの解析が 1 回で済んでいれば問題ない。
    そして実際にその様になっているかどうかについては…。
    現状では /\{[0-9a-zA-Z]+|[0-9]+/ の連なりは一気に読み取るので途中に解析再開点が設置されることはない。

    ブレース展開に新しく対応する際にも \{[0-9a-zA-Z]+ については
    一気に読み取るという事を変更しない様にすれば大丈夫のはず。
    例えば、その文脈でブレース展開が有効でなかったとしても、
    "{" 単体で読み取るということはせずに後ろに続く alnum も一緒に読み取るようにする注意が必要である。

  * syntax: for ((i=0;i<10;i++)) { echo; } が構文エラーになってしまっている。 [#D0620]
    ble_debug=1 で見ると (()) の直後は ARGX0 になっている。
    うーん。is_command_form_for=1 の設定がうまく伝播していないのが原因だろうか。
    調べてみると is_command_form_for=1 は設定されているが、
    実際に ble-syntax:bash/ctx-command/.check-delimiter-or-redirect に到達する事には消えている。
    関数の呼び出しのされかたについて勘違いをしているだろうか。

    と思ったら ble-syntax:bash/ctx-command の先頭で
    local is_command_form_for= が実行されている。これが原因だ。これを削除する。
    しかし、そうすると野に is_command_form_for という変数があった時に誤動作する。
    変数名は _ble_syntax_bash_is_command_form_for 等に変えるのが良いだろう。

  * syntax: [[ ]] の中で <>();|& の文字を使った場合は構文エラーにするべき [棄却] [#D0619]

    但し、 "<" ">" "(" ")" "||" "&&" 等の特別な単語の時にだけエラーでなくなる。
    と思ったが、改めて調べてみると "<" ">" "(" ")" "&&" は何れも単語を構成していない。
    Bash でエラーが出ている様に見えたのは、
    各演算子の使い方が誤っていたからである。

    だとするとそもそもこの項目を立てた時に実装していた
    CTX_BRAX の方で不整合が生じているかもしれないので確認する必要がある。
    特に [aa&& でちゃんと && 演算子の手前で CTX_BRAX から抜けるだろうか。
    →これは特に対策もしていないので抜けるはずである。実際に確かめてもそうなっている。
      特に問題にはならなそうである。

  * 条件コマンドの比較の右辺で怪しいところが幾つかある [#D0618]

    $ grc '== \$[^'\'']'
    修正した。色々バグっていた気がする。

  * 2017-11-14 syntax: 後 !; は履歴展開ではないはずなのに履歴展開と解釈されている[保留] [#D0617]
    と思ったが、文脈によって履歴展開だったりそうでなかったりしている気がする。
    どうも履歴展開と解釈されてはいるが、必ず展開に失敗する?

    これは気にしなくても良いという事にする。

  * syntax: *? 等の文字は extglob の時にしか着色されない [#D0616]

    | また ble-syntax:bash/.update-_ble_syntax_bashc が extglob の変更に際して呼び出されていない。
    | →これは #D0615 で取り扱う。

    これは取り敢えず現在取り掛かっていることが終わってから対処する。

    多分、これは単に _ble_syntax_bashc で [ の他に * や ? も含める様にすれば良い。
    変更した。動いている。多分大丈夫だろう。

  * syntax: shopt -u extglob にしても _ble_syntax_bashc が更新されない [#D0615]

    これは _ble_syntax_bashc の変更条件は histc12 及び shopt -q extglob で決まるのに、
    ble-syntax:bash/cclass/update の呼び出し元で勝手に histc12 だけで呼び出しを判定している為である。
    無条件に ble-syntax:bash/cclass/update を呼び出す様にすれば良い。

    更に ble-syntax:bash/.update-rex_simple_word も、
    ble-syntax:bash/cclass/update の内部で更新が実行された時に限り呼び出す様にする。

  * syntax: hist1, hist2, hist12 等の変数は bash 固有である [#D0614]

    これはローカル変数として管理するのではなく、
    グローバル変数として _ble_syntax_bash_* にした方が良い。
    現在は bash 決め打ちで initialize-vars の前に、
    local "${_ble_syntax_bash_vars[@]}" しているが、
    別の言語を用いる際に動かない。

    もしくは、言語に依存したローカル変数を定義できる仕組みを提供する。
    本来はローカル変数を定義できる仕組みにするのが良い気がするが、
    設計がより複雑になる割にそんなに必要性があるか分からない。

    解析をしている途中に更に別の解析を開始する等の事をしない限りは
    グローバル変数にしていても特に問題にならない気がする。

    →取り敢えず直した。_ble_syntax_bash_hist12 というグローバル変数に入れる事にした。
    hist1, hist2 は実際に使うときに _ble_syntax_bash_hist12 の部分文字列として得る。
    また histstop についても _ble_syntax_bash_histstop という変数にした。
    ローカル変数は廃止した。

2017-11-22

  * syntax: 変数代入に於ける pattern で入れ子 @(@()) の内側が不活性になっていない [#D0613]

    これは var=@(aa|[bracket]) の [] も同様である。

    これは ble-syntax:bash/check-glob で
    ((ctx==CTX_PATN)) の分岐以下で attr を補正しているところを参考にすれば良い。
    というかこの部分をより前方に持ってくれば済む話なのでは?

    - ctx=$attr という ntype は検索しにくいので ctx:$attr などに変える。
    - また ctx:$attr ではなく ctx:$ctx にする。
    - CTX_PATN を nest-push している箇所で ntype を確定させる。

    これは #D0612 の対応に際して統合的に対応した。

  * 2017-09-06 ble-syntax: echo ${a#[!0-9]} は履歴展開ではない [#D0612]
    どうやら "echo [!1 " と入力しても展開されない。[ の中は (対応する ] がなくても) 履歴展開は無効ということ。

    実は、もう少し試してみた所、以下は何れも履歴展開となった。

    $ echo [a!a
    $ echo [a!a]
    $ echo [[!a

    1 つまり、[! の組み合わせで始まる range expression だけ特別扱いする。
    2 range expression の中で [! の組み合わせは特に特別な意味は持たない。

    ということ。しかし、それでも [! が特別な意味を持つかどうかの判定の為に、
    結局、現在 range-expression の中にいるかどうかの判定は必要になる。

    これに対応するには、やはり新しい文脈に対応するのが良い様な気がする。
    思うに $(()) と類似の文脈にするのが良いだろうか。
    というより $(()) と違って入れ子も考えなくて良いし、より簡単な気がする。
    或いは case のパターンの中と同様の文脈と考えても良いかも。
    但し空白・delimiterは来ない。これは丁度 ctx-command の check-word-end/is-delimiter で良い気がする。
    と思ったが、これは呼び出し元の文脈に依存する。例えば ${a#[a ]} などの場合には
    其処で bracket expression が終わったりはしない。これは ntype か何かで記録する事にする。

    うーん。然し、条件コマンドとの区別がややこしい。
    或いは条件コマンドをチェックして、それから [ をチェックする様にすれば良い気もする。
    例えば [[ の直後に文字列末端または delimiter が来る時には条件コマンドとし、
    それ以外の時には nest-push する。

    nest-pop が同じ点で起こっても良いのだったか。これは確かめる必要がある。
    nest-pop は tree-append により情報を登録している。
    tree-append は word の登録にも使う。つまり同じ位置で複数の tree-append が来ても良い様にできている筈だ。
    問題は tree-append を複数回出来るとしても nest-pop が同じ位置で
    一回しか呼び出されない的な仮定がないとは言い切れないことである。

    角括弧式の中で何が有効なのかについて調べる。

      $ echo [@(a|\*)]
      * @ a

    これを見ると角括弧式の中では extglob も含めて意味を失う様である。
    但し、quote は意味を失わない。

    [実装1] ctx-command での実装

    先に ctx-command から入った場合について実装することにする。
    取り敢えず nest-push について実装する。

    何が何だか分からなくなってきたので取り敢えず
    ntype は気にせずに ctx-command から入った時の終端方法で実装して動作確認する。
    その後で様々な場合に対応する事にする。

    x fixed: 空白や文字列末端で終端していない。
      check-word-end の is-delimiter が効いていないのではないか。
      実装仕掛けの ntype チェックで引っかかっていた。

    x fixed: stackdump が出る。
      これは check-word-end で nest-pop した時に、
      更に外側の check-word-end を呼び出さなければならないのを抜かしたのが行けない。
      nest-pop が二重に起こる場合も含めて動いているように見える。
      ただ、この方法が設計上良いのかどうかは分からないが、取り敢えず。

    x fixed: [!a*] などで * がエラーになっている。
      これは glob の入れ子を許可する様にすれば良い。
      直した。echo [a*] や echo [!a] は OK。
      取り敢えず echo [![!a] も期待通りに解析されている。
      echo [!a@(aaa|bbb)] は着色が変な事になっているが、
      これについてはまた後で実装しなおせば良い。

    [実装2] 呼び出し元文脈に依存した振る舞い

    次に角括弧式を抜ける位置をどの様に特定するかについて考える。
    現在の実装では常に ctx-command から呼び出されたと思って角括弧式を抜けている。
    しかし、実際には角括弧式に入った時の文脈によって色々である。

    % * ntype はどうするのが良いか。
    %
    %   nest-push "$CTX_BRAX" する時の ntype はどうしたら良いか。
    %
    %   - "]" が現れる前に中断される時にどのタイミングで中断するかを見るためには、
    %     やはり呼び出し元の ctx が必要になる。
    %   - また内部で CTX_PATN を実行する時には不活性にしなければならない。
    %
    %   従ってやはり ctx=$ctx を ntype にして伝播させるのが良いだろう。
    %   もう一つの方法は type=command だとか type=vrhs だとかであるが、
    %   これは CTX_PATN 等との兼ね合いを考えると面倒である。
    %
    %   よく考えてみると、CTX_PATN と混ざってくるとより面倒な事になる…。
    %   CTX_PATN の場合は不活性にするかどうかは一番最初の呼び出し元が CTX_VRHS かどうかで決まる。
    %   或いは、途中で CTX_BRAX になってその中で CTX_PATN を呼び出した時にも不活性になる。
    %   一方で、CTX_BRAX の読み取り方の制御はどの様に行われるかというと、
    %   一番最初の呼び出しにおける文脈に依存する。
    %   しかし、CTX_PATN と同様に不活性になった時の色にも注意しなければならない。
    %
    % 現在の実装では突入時の文脈を指定する事にしているが、
    % この方法で問題ないだろうか。
    %
    % - [] の中で更に [ や @(...) や * がある時にはどうするのか?
    %   [ は無視する。@(...) は着色せずに読み取りを実行する。
    %   * や ? は *() や ?() になっているかもしれないので、読み取る。
    %
    % うーん。実は一つ上の階層の ctx を考慮して CTX_BRAX の終端を判定すれば良いのではないだろうか。
    % そして、それとは独立に着色のために ctx= を用いるのが良いのではないだろうか。

    当初の考えでは入った時の文脈の種類に応じて ntype を設定して、
    ntype に応じて CTX_BRAX の中で処理を切り替えるという事を考えていた。
    しかし ntype は CTX_VRHS CTX_BRAX の下に入れ子になっている時に、
    着色を無効化する為に用いたいので、別の方法を考える。

    | 別の方法と言っても入った時の文脈を nest 情報から抽出するという事である。
    | ※実のところこの nest 情報は入った時の文脈というよりは、
    |   抜ける時の文脈といった方が正確である点には注意する。
    | 入った時の文脈を取得する関数として ble-syntax/parse/nest-ctx を作った。
    | 今までこれがなかったのは不思議であるが、便利そう。
    |
    | これを使って文脈を取得し、特別な文脈以外では ctx-command 由来として処理する。
    | さて、どのような文脈で CTX_BRAX が nest-push されるだろうか。列挙する。
    | 現在 CTX_BRAX を nest-push しているのは check-glob のみであり、
    | この check-glob を呼び出している箇所は以下の通り。
    |
    | - ble-syntax:bash/ctx-command (色々)
    | - ble-syntax:bash/ctx-values (CTX_VALI)
    | - ble-syntax:bash/ctx-redirect (CTX_RDR[FDS])
    | - ble-syntax:bash/ctx-conditions (CTX_CONDI)
    | - ble-syntax:bash/ctx-globpat (CTX_PATN)
    | - ble-syntax:bash/ctx-bracket-expression (CTX_BRAX)
    |
    | この内、ctx-command ctx-redirect は同様に扱って問題ない。
    | 残っているのは全て単一の文脈値なので直接比較して問題ない気がする。
    | 一つずつ見ていく事にする。
    |
    | - CTX_VALI の場合は、実は ctx-command と殆ど同じ扱いで良い気がする。
    |   但し、")" が来たら終わる。でも ")" が来たら終わるのは ctx-command でも同じ。
    | - CTX_CONDI の場合は、
    |
    |   % ctx-command と似ているが少し処理を変える必要がある。
    |   % 空白を除く delimiter つまり ()<>;|& が単語に含まれることが許されている。
    |   % これらは例えば "()<>;|&" を chars から除いて処理すれば良いのだろうか。
    |   % 念のため確認する。[...] の中に delimiter の文字が現れても良いのだろうか
    |   % →と思って試したら構文エラーになる。というか [...] の中でなくてもエラーになる。
    |
    |   改めて考え直す。先ず "()<>;|&" を含む単語で許されているのは、少数の物のみであり、
    |   更にそれらに "[" が含まれる事はない。従って、()<>;|& が現れた時点で [...] を抜けて良い。
    |   外側で自動的にエラーが設定されるだろう。また、空白類が来た時も [...] を抜ける。
    |   結局、CTX_VALI と同様に ctx-command と同じ処理をすれば良い。
    | - CTX_BRAX から check-glob を呼び出した時は nest-push が起こらない。
    |   つまり nctx が CTX_BRAX になる事はない。
    | - 結局特別な取り扱いをする必要があるのは CTX_PATN だけの様だ。
    |   CTX_PATN では < や > が単体で現れる事が許される。
    |   これは [] の中でも同様なのだろうか。どうも許される様だ。
    |
    |   さて、@([a|b]) はどの様に解釈されるのか?
    |   →調べてみると @(["a|b"]) と解釈されている様だ。
    |   @([a b]) は @(["a b"]) と解釈されている。
    |
    |   @([a()b]) は @(["a()b"]) と解釈されている。
    |   @(a|[) はどうも構文解析はうまくいくがパス名展開は失敗している。
    |   何れにしても ")" が現れた所で終わるという解釈で良さそうだ。
    |   うーん。つまり、[...] の中でも () の入れ子を追跡しなければならないという事。
    |   (後のパス名展開で失敗するかもしれないとしても、構文解析上はそうなっている気がする。)

    まとめる。CTX_BRAX による読み取りの判定は nctx を用いて行う。
    - nctx を取得するためのシェル関数 ble-syntax/parse/nest-ctx を追加した
    - nctx が CTX_PATN の時以外は、ctx-command から呼び出したと考えたと時と同様の処理で良い。
    - nctx が CTX_PATN の時は、) が来たら終わる。
      ( が来たら nest-push して入れ子を数える。
      その他の文字 (|<>*?@+!) は単に [...] に含まれる事が許される。

    x fixed: echo @([a|b]) で | の着色がエラーになっている。
      これは特別に追加する必要があった。
      他の文字 (*?!+@) は check-glob で着色される
      (extglob ならピンク、extglob でなければ黒) ので必要ない。

    [実装3] CTX_PATN と CTX_BRAX の入れ子について再確認

    | * CTX_BRAX の中で CTX_PATN になって更に "[" に出会った時にはどうするのか。
    |   調べてみると、"[" を bracket expression と認識している様子だ。
    |
    |   echo [@(aaa|[!a])] は履歴展開が無効だが、
    |   echo [@(aaa|[a!a])] は履歴展開が有効になる。
    |   つまり [! の組を認識している。
    |   と思ったが、実は echo [[!a]] も履歴展開は無効だし、
    |   echo [![!a]] も履歴展開は無効のようだ。
    |   一方で echo [[!a や echo [!a は履歴展開が有効になる。
    |   つまり bracket expression が閉じていれば [! の組の履歴展開は無効で、
    |   bracket expression が開いていれば [! の組でも履歴展開は有効になる。
    |
    |   従って、CTX_BRAX であっても [! は認識するべきである。
    |   但し、CTX_BRAX の時には nest-push はしないという事にする。
    |
    | * echo [![!a]] はどのように組まれるか?
    |   実際にファイル名に一致させて試すと
    |   echo [!"[!a"]"]" と解釈される様である。
    |   つまり、[!...] の入れ子は考慮に入れられないが、
    |   "[!" の組で履歴展開にならないということだけは処理される。
    |
    | * やはり [@(...)] の中で更に [...] があった時の解釈が分からない。
    |   ファイル名に一致させてみると echo [@([aaa])] は、
    |   echo ["@([aaa"]")]" というパターンになっている様である。
    |   これは実際の解析のまとまりとはばらばらの様に思われる。
    |   うーん。つまり最初の切り出しは ["@([aaa])"] となるが、
    |   実際の解釈では ["@([aaa"]")]" となるという事である。
    |   これは ble.sh の解析の枠組みでは直接取り扱えない。
    |   つまり着色は ["@([aaa"])] のまとまりで行いつつも
    |   残った ")]" の部分についてのエラーは
    |   ["@([aaa])"] の構造があるとして抑制しなければならない。

    - [...] の入れ子は考慮に入れられない。
      つまり "[" の登場に拘らず "]" の登場ですぐに閉じる。
    - [...] の中でも [! の組は履歴展開の ! とは認識されない。
      つまり、入れ子の勘定には入れないが、"[!" の組は認識している。
    - [...] の中でも extglob @(...) のまとまりは有効である。
      但し、元の意味は失う。つまり、解析にだけ考慮される。
    - [...] の中で @(...) があって、更に中に [...] があった時の解釈は厄介である。
      例えば [@([abc])] の場合には、
      構文構造としては [@([abc])] のまとまりで切り出されるが、
      最終的なパス名展開の適用に際しては [@([abc] のまとまりで切り出されてしまう。
      これについては構文構造を優先して着色する事にする。

    この辺りの振る舞いについては現在の実装で問題ないはずである。
    問題は @([(...)]) の場合に () の入れ子を処理する必要がある事である。
    check-glob を弄って ctx==CTX_BRAX の時も入れ子を数える様にする。
    取り敢えず色はさておき、構文構造は正しく解析できる様にする。
    取り敢えず対応した。

    [実装4] 入れ子になっている時の色の伝播に関して。

    % 改めて CTX_PATN が関わってくる場合を考える。
    % CTX_PATN の中で更に [...] がある場合には、
    % [... の不完全終端は CTX_PATN の終端と同じにする。
    % 一方で、着色に関しては CTX_PATN と同じ色にすれば良い。
    % 但し、CTX_PATN の nest の時には別の色にしなければならない。

    | 変数代入の右辺でどうなっているか。
    |
    | $ echo=[a] # → パス名展開は起こらない。
    | $ echo=[!a] # → 履歴展開されない。パス名展開も起こらない
    | $ echo=[a!a] # → 履歴展開される。パス名展開も起こらない
    |
    | つまり、解析としては [!...] を拾っているが、
    | パス名展開は起こらないと考えて良い。
    | 現状の @(...) と同様に nest-push して解釈はするが、
    | 着色はしないというように処理すれば良い。

    変数展開の下の glob パターンは、全て解析はするが着色は無効化する。

    うーん。特に色を無効化させるのであれば、
    色を外側から伝播させれば良い様な気がする。

    CTX_VRHS から下はどう頑張っても全て無効化
    同様に CTX_BRAX から下はどう頑張っても全て無効化。
    それ以外の時には nest の括弧は無色。それ以外は着色。

    さて、現在 ntype=nest は他の用途で使われているだろうか。
    どうも、ここで色を決定することにしか使われていない様だ。

    ntype の意味を次の様に定める。
    1 ntype='nest' の時はその括弧及び内側の | は特別な色をつけない事を意味する。
      更に内側の [...] や @(...) は有効になる。
    2 ntype='ctx=...' の時はその括弧及び内側の | はその ... で着色する事を意味する。
      更に内側の [...] や @(...) に対してもその塗り潰しは継承する。

    取り敢えず実装した。

    * supported: here string でも glob/bracket は無効化されるべき。

    [実装5] 後は新しく生じた不整合を解決する。

    x fixed: [[ が無効になっている。

      これはどの様に対応するべきか。
      先ず初めに [ の直後に [ がある場合はそれも一緒に読み取ってしまう?
      しかしそうすると今度は [[! の場合に其処まで読み取らなければならない。

      というかそもそも現状はどの様な状態なのだろうか。
      '[[' の部分を見ると i=$wbeg ble-syntax/parse/nest-push している。
      これはつまり単語の開始点が現在の解析 step の開始点以降である事を前提としている。
      現在の実装だとその仮定が崩れてしまっている。

      正しく実装し直す為には、nest-push の点をずらすか、
      或いは [[ の連なりは一度に解析できる様に修正するか。
      取り敢えず [[ の連なりは一度に解析する様に修正する。
      これは直した。

    x fixed: simple word で [] が許されなくなっている。
      これは _ble_syntax_bashc_simple に "[" が混入していたのがいけなかった。
      _ble_syntax_bashc_simple を _ble_syntax_bashc[CTX_ARGI] と独立に生成する様にした。

  * syntax: プロセス置換が @(<(echo)) で認識されていない。 [#D0611]
    角括弧式対応の途中で気付いた。
    これは元からあった問題である。修正した。

  * edit (command-help): quote されていると駄目 [#D0610]

  * edit (command-help): function, until が引っかからない。 [#D0609]

  * 2017-11-14 complete: コマンドの補完候補に出てくる functions とは何だろう [#D0608]
    実際には見つからないし実行できない

    →これはどうもディレクトリ functions が一致している様だ。
    所で、functions まで入力して TAB を押しても functions という候補が二重に出ている所為で補完できない。
    他のディレクトリ名についても同様の様である。

    重複を除く様にしてみたがそれでも 2 つ出て来る。
    異なる source から複数現れているのだろうか。
    と思って調べてみた所、ble-complete/source/command から 2 つ現れている。
    ble-complete/source-command では sort -u する様にしたはずなのにおかしい。
    と思ったら、ble-complete/source/dir が明示的に呼び出されている。

    しかし、そうだとしても不思議だ。shopt -s autocd は有効になっていないので、
    前者からは候補が出てこない筈である。

    うーん。と思ったら、どうも compgen -c -- foo で
    foo がディレクトリ名に厳密に一致している場合、
    foo も補完候補として表示されてしまうのだという事が分かった。
    これはどの様にしたら良いか。

    また、実際に補完候補が確定した時の振る舞いについても考える必要がある。
    例えば、確定された単語がディレクトリ名だったら / を後置する様にするなど…。
    しかし、コマンド名とディレクトリ名が被る場合はどうするのか謎である。
    mkdir grep として調べてみると、どうやら実行する時にはコマンド名の方が優先される様だ。

    a 一つの方法はディレクトリ名としての候補の場合には予め / を後置する様にする。
      確定した単語が / で終わりかつ実在するディレクトリ名だった時には、
      そのまま確定する。それ以外の時には空白を空ける。

      これだと / で終わる名前のシェル関数とディレクトリ名が同じ時に、
      本来はシェル関数の方が呼び出されるはずなのにディレクトリ名として解釈されて、
      空白が後ろに付加されない。しかし、まあ妥当な振る舞いの範疇だろう。

    - 同様に autocd によって列挙されるディレクトリ名の場合にも / を後置する。
      その様にしないと既存のコマンド名とディレクトリ名が被っていた時に、
      ディレクトリに移動しようとしてもコマンドを実行してしまうからである。

    適当に実装した。

    - 実は shopt -s autocd かどうかには依らずに、ディレクトリ名は foo*/ で生成すれば良い。
    - foo というディレクトリがある時に compgen -c -- foo で foo が列挙されてしまう問題については、
      workaround として "cand がディレクトリ名であって該当するコマンドが見つからないとき、
      その候補を除去する" という処置を取ることにした。

  * syntax: declare, local, の類が予約語の色になっている。 [#D0607]
    修正した。と思ったら、今度は declare の上での変数名の補完が効かなくなっている。
    ble_debug=1 で見てみると declare の直後の文脈が通常のものに戻っている。
    と思ったら、is_keyword でない時には後で ctx=ARGX に上書きされて、
    通常の引数のための処理が行われている。

  * complete: echo echo などのように二重に候補が出るのは何故か。 [#D0606]

    これは compgen -c -- echo の時点で再現する。
    どうも組み込みコマンドの echo と通常コマンドの echo が両方一致している?
    しかし、grep の場合も同様に二つ表示される。と思ったが、これの場合は alias だ。

    取り敢えず sort -u を呼び出すことにしたが、
    実は compgen に重複を発生させないオプションが合ったりするかもしれない。
    と思って man bash を見るがやはり complete と共通のオプション以外はない。
    そして complete には重複を除くなどのオプションはない。
    結局自前で sort -u を呼び出すようにしなければならない。

2017-11-21

  * 2017-11-11 complete: time の次に来るコマンド名で補完ができない。 [#D0605]
    これは恐らく文脈値を増やしたのにそれを追加していないのがいけない。

    これは調べてみた所、time -p command まで一度に解析する様にしているのが原因である。
    コマンド名の先頭に stat (ctx) が設置されていないのが原因である。
    現在の補完の枠組みでは ctx を使っているので、これでは補完候補を生成できない。

    或いは、コマンドの候補を生成する時には先頭が "time [-p]" になっていれば、
    その部分は削って候補生成を行うという様にも出来るが、
    それは実装として汚い気がする。やはり新しく文脈値を導入するほうが良さそうだ。

    →これは #D0604 の対応と共に実装した。

  * 2017-11-14 syntax: time -p -- echo hello (bash-4.2 以降) [#D0604]

    実は time -p -- echo hello とできる。
    time -- echo hello はできない。
    調べてみると、これは bash-4.2 以降の以降である。
    bash CHANGES にもちゃんと書かれていた (bash-4.2-alpha/3.r)。

    これに関しては途中に解析再開点を設置する様にしたいので、
    やはり文脈値を拡張して対応することにしたい。
    文脈値の拡張に関しては CTX_CARGX1 などを参考にするのが良い気がする。
    in 等の代わりに -p が特別な意味を持つようにする。

    取り敢えず CTX_CARG{X,I}{1,2} を複製する形で CTX_TARG* を作った。
    然し、実際の処理はもっと異なる形になるような気がする。
    一つずつ CTX_TARGX1 から順に対応していく事にする。

    少し対応した所で整理した。と思ったら完成していた。
    取り敢えず動いている。

  * 2017-09-05 syntax: function hello (()) は bash-3.0 では構文エラー。 [#D0603]
    →どうも調べてみた所 bash-4.1 まで使えなかった様だ。bash-4.2 以降で使える。

  * 2017-09-05 syntax: function hello (()) としておいて function hello () (()) にすると解析が誤っている。 [#D0602]
    これは新しく導入した set-lookahead 2 で簡単に直った。

  * 2017-11-14 syntax: echo $(echo > ) において $() が閉じていないとなっている。 [#D0601]

    元々 > の次に ) が来た時点で構文エラーなのだから、
    ")" がどう取り扱われようと勝手なのかもしれないが、

    - やはり直観としてはエラーは > の手前で止まってほしいし、

    - 例えば、長いコマンドの最初の方の $() の中にリダイレクトを追加する時、
      一瞬この様な状態になったことで部分更新が働かなくなるのも嫌である。

    従って、> において ) が現れたらその手前で nest-pop
    をするという訳には行かないだろうか。

    nest-pop/tree-append の都合で 1 文字以上進んでからしか pop できないと思ったが、
    よく考えてみれば、check-word-end 辺りで確認を行って、
    次に delimiter が来ていればエラーを設置すると共に、nest-pop すれば良い。

    と思ったが、調べてみると実際にその様な実装になっている。
    何故だろう…と思ったら、そもそも単語が始まっていない時には nest-pop は実行されない様だ。

    a それなら、単語を構成する文字が見つからない場合には初めから nest-push しなければ良い、
      と考えたが、駄目だ。先読みしてしまうと部分更新の時に破綻してしまう。
      先読みした分だけ呼び出し元で単語の設置などしてしまうと、
      結局新しい文脈を使って解析している意味がない…というか、
      プロセス置換などの構成を使っている時に対応がどんどん面倒になってくる。

    b 或いは、次の一文字だけなら読むことを許されているのだから、
      次の一文字が許される文字だったならば nest-push する。
      そして、CTX_RDRF 等の文脈において失敗したならば、

      と思ったが、次の一文字だけを見るのだと [<>] がいる時に、
      それがプロセス置換 [<>](...) の一部かもしれないので、
      受け入れざるを得ない。従って、[<>] の時は nest-push する。

    さて。nest-push するところを修正したらすぐに大丈夫になった。何故?
    よく見てみるとリダイレクトの後に続く空白類は既に
    redirection の始まりの記号の一部として読み取っていた。
    従って、直ぐに単語が始まる状態になっていたのだった。
    なので単語に突入しないという状態にはならない。

    [プロセス置換の先読み問題]

    例外はプロセス置換の時である。
    将来的にプロセス置換を構成するかもしれない < が単体で入力された状態の時、
    一体どのように解釈されるべきか。

    というか ble-syntax:bash/ctx-redirect/check-word-end で2文字以上先を参照しているが良いのだろうか。
    % うーん。どうやら > A<(B から A<B に化ける時には、直前の再開点は < であり…と思ったが、駄目だ。
    やはり問題になる気がする
    →現実に問題になることを確認した。
      先ず echo >A<(echo) の状態にしておいて ( と ) を削除すると、
      echo >A<echo において、"<" の位置でエラーという事になる。
      一方で、普通に echo >A<echo とすると構文エラーにはならない
      (但し、echo というファイルは見つからないというエラーにはなる)。

    これはどの様に処理するべきか。

    a 一つの方法は先読みの文字数を 2 文字にするということ。

      広範な変更が必要になりそう。
      また、解析再開が非効率になるのが気になる。
      実際どの程度非効率になるのだろうか。

      それに解決策としては余り綺麗でない気がする。
      例えば、今後 3 文字先読みが必要になったら、
      全体で 3 文字の先読みを許容するようにするのか? 際限がない。

    b 或いは、先読みをした時にはその文字数を記録する。

      % 因みに、読み取りの終端位置を決めるのに、
      % 例えば [[:alnum:]]+ 的なことをするので、
      % 実質必ず 1 文字以上先読みはしているような物である。
      % ただ、物によっては $(( など、それ以上一度に読み取らないというものもある。

      この方法が良い様な気がする。
      但し、stat に新しい要素を追加する事になる。
      stat に要素を追加する時の方法について確認する必要がある。

      また、今回の問題の解決に実際に使わないとしても、
      今までの実装を考えると先読みの文字数を指定できる様にすると大分楽になる気がする。
      実のところ、今までの方法では "先読みをした場合には、先読みされた部分まで一気に解析する"
      または "先読みした時にはそこには解析再開点は設置しない" という方法を取っていたので、
      実のところ解析の効率が落ちるということもない気がする。

    c もう一つの方法は "曖昧な状態" を表す文脈を用意するということ。

      しかし、これは <( の直前に現れる可能性のある文脈値全てについて、
      その種類が倍化するので始末が悪い気がする。
      或いは、別の変数を使って曖昧な状態を表現するとしても、
      それは結局 b と等価になるのではないだろうか。
      寧ろ、b よりも間接的なので分かりにくい。

    d 実のところ解析再開点を設置しないという対策だけで良いのではないかという気もしてきた。

      問題点は何かというと、現在の補完の枠組みでは解析再開点を用いて補完候補生成方法を決定しているので、
      解析再開点を省略するとそこから始まる単語について補完候補の生成を行うことができない事にある。

      現在の補完の枠組みは、解析再開点を用いるのではなく単語などの情報を用いるように変更するべきの気がする。
      と思ったが、結局単語の詳細な情報はその単語の読み取りを開始した時の文脈値に依存する。
      結局、解析再開点の情報も必要になるのではないか。

      或いは、"無効化した解析再開点" の様なものを用意して、
      そこにおける文脈値だけを記録するという手もある。

      やはり先読みの文字数を設定できるようにした方が柔軟な気がしてきた。
      また、解析再開点を設置しない方法だと、先読み位置以降・次の再開点以前の範囲で変更があった場合に、
      本来必要のない再解析をすることになる。更に先読みが続くと解析再開点が連続で設置されないという事になる。

    やはり先読みの文字数を記録する b の方針で考える。
    比較的大きな書き換えになるし、ちゃんとできるか分からないので取り敢えず commit を切る。

    [書き換え]

    1 解析変数の追加

      前回 nparam を書き換えた時と同様に行えば良い。
      注意点としては nparam は空文字列になりうるので、
      _ble_syntax_stat に格納する際には空文字列は none に置き換えるか、
      或いは nparam の前に新しい変数を挿入するかである。

      新しい変数を導入する度に nparam の位置が変わるのは始末が悪いので、
      空の nparam は none に置き換える事にする。
      これは _ble_syntax_stat に格納・から読み出すところで弄れば良い。
      と思ったら初めからそのような実装になっていたので問題ない。

      nparam の次の解析変数として lookahead を追加する。
      調べてみたが新しい解析変数の追加はそれほど大変ではないようだ。
      初期化と保存と ble_debug による出力に対応すれば良い。

    2 次に lookahead を見て解析再開点を決定する様にする必要がある。

      現在の実装では parse の以下の部分で決定している。

      | # 解析予定範囲の更新
      | local i1 i2 j2 flagSeekStat=0
      | ((i1=_ble_syntax_dbeg,i1>=end0&&(i1+=shift),
      |   i2=_ble_syntax_dend,i2>=end0&&(i2+=shift),
      |   (i1<0||beg<i1)&&(i1=beg,flagSeekStat=1),
      |   (i2<0||i2<end)&&(i2=end),
      |   (i2>iN)&&(i2=iN),
      |   j2=i2-shift))
      | if ((flagSeekStat)); then
      |   # beg より前の最後の stat の位置まで戻る
      |   while ((i1>0)) && ! [[ ${_ble_syntax_stat[--i1]} ]]; do :;done
      | fi

      先ず flagSeekStat とは何だろう。
      というか何故 i1 end0 _ble_syntax_dbeg, _ble_syntax_dend など色々あるのか。
      コメントに書かれていた。_ble_syntax_d* は前回の解析でやり残した部分を記録する。
      先ず初めに i1..i2 に前回の解析でやり残した範囲を読み込む。
      その後で今回の文字列の編集範囲を用いて i1..i2 を更新する。
      flagSeekStat は、今回の文字列の編集範囲によって解析を開始することを示す。
      flagSeekStat が立っていないとき、前回の解析中断位置から再開するが、
      必ず stat が設定されている位置で中断される (予定) なので、わざわざ解析再開点を探す必要がない。

      lookahead によるマージンを取るのは flagSeekStat の中で判定すれば良い。
      実装した。取り敢えず既存の解析再開の仕組みは動いている様に見える。

    3 後は、折に触れて lookadhead を更新すれば良い。

      lookahead の更新はただ代入するのではなくて、
      前の値よりも大きい時に更新するという様にする。

      そうすれば一回の解析の間に複数箇所で先読みをした時に対応できる。
      元々2文字以上の先読みを実行する箇所は少ないのだから、
      このぐらいのチェックで遅くなるということは考えにくい。
      従って、速度については気にしなくて良い。

    と思ったが、実のところ一回 lookahead を設定した後に、
    解析位置が進んだ場合にはどうするのだろう。
    その場合には lookahead を再び clear しなければならない。
    改めて lookahead の方法について考える。

    a 一つの方法は必ず解析の最後で lookahead を設定するという事である。
      その様にすれば lookahead の位置がずれる事はない。
      しかし、問題点は check-process-subst 等で一致するかどうか参照しているが
      引っかからなかったという時に lookahead をどう設定するのかということである。
      或いは、引っかからなかった時には lookahead は設定しなくても大丈夫だろうか。

      実のところ 2 文字ならば lookahead は設定しなくても大丈夫である。
      何故なら 1 回の解析で少なくとも 1 文字は進み、
      更に少なくとも 1 文字の先読みが存在するので、
      もし失敗して別の方法で進む場合には 2 文字まで先読みして大丈夫である。

      では任意の文字数先読みすることは可能なのだろうか。

      % もしかするとそもそも先読みがなかったことにできるという可能性もある。
      % 例えば <() について考える。今 <a 等の様になっていたとする。
      % この時一致は失敗して < 単体に後で引っかかる。
      % ここで先読みがなかったことにするとどうなるだろう。
      % "<(a" の様に "(" を挿入したとする。実際のところ a まで見て一致しないと判定したのに、
      % 解析再開の際には "<" の部分に変更がないからという理由で、
      % 前回の解析結果が採用されて、今回も一致しないという様になってしまう。
      % この例の時には、実際には > が読み取られてその次の文字まで先読みになるので問題にはなっていなかったが、
      % 3 文字以上に渡る先読みの場合にはやはり問題が発生する。

      一致に失敗したとしても先読みして動作を変更したのであれば、
      それを記録しておかないと後で不整合が起こってしまう。

      x 先読みの長さに関する制限もある。

        前回の解析ステップで先読みした長さを、
        次の解析ステップでは必ず全て取り尽くさなければならない。

        何故なら、解析再開点の決定では文字列変更範囲より前の再開点で、
        一番最初に見つかったものを採用するからである。
        もし前回の解析ステップの先読みを取り尽くさないと以下のような場合に問題になる。

          aaaaaaXa 文字列と編集位置
          +------- 解析再開点1 + 先読み
            +---   解析再開点2 + 先読み

        X の位置で編集が起こった時、本来であれば解析再開点1 から解析を再開しなければならないが、
        実際には最初に見つかった解析再開点2 から解析が再開されてしまうことになる。

    b もう一つの方法は、現在は lookahead を "何文字先か" で管理しているが、
      実際の解析の過程では "先読みした最後の位置の index" を管理する様にする。
      _ble_syntax_stat に記録する時に何文字先かの情報に書き換える。

      | すると shift の対象になるのではないかとも考えたが、shift はしなくてよい。
      | % というかむしろ shift するべきではないと思われる。
      | lookahead を設定するのは再開点と先読み点の間で変更があった場合に、
      | 解析再実行範囲を再開点まで拡張するために用いられる。
      | もし文字列変更範囲が再開点よりも前にある時には shift は必要ない。
      | 文字列変更範囲が先読み点よりも後にある時にはやはり shift は必要ない。
      | 文字列変更範囲が被っているとき、
      | 再開点が文字列変更範囲に含まれる場合にはそもそもその再開点は消滅するので気にしなくて良い。
      | 再開点と先読み点の間で文字列変更範囲が始まっている場合には shift してもしなくても、
      | その再開点は使えないということが計算して分かる。
      | なので、shift の機会があるとしても shift してもしなくても何も変わらない。

      [結論] shift の必要はない。

      % 或いは、寧ろ "何文字先まで見たか" を記録する為だけに "先読み点" を計算していたのであって、
      % 飽くまで "何文字先か" という情報なのだと思えば自然かもしれない。
      % と思ったがこの考え方はやはり安易な気がする。

      この方法を用いれば a の所に書いた先読みの長さに関する制限も自然に解消できる。
      こちらの方法を用いるべきである。

    2' 改めて b の方法に従って lookahead を書き換えることにする。
      変数名はどの様にするべきか。lookahead を文字数として、
      ilook を lookahead の位置ということにしようか。
      書き換えた。まあ問題なく動いている。

    3' 取り敢えず問題になっていた部分について設定を行う。

      % と思ったら…再現しない。現在は問題なく解析できている。
      再現した。スペースがあるかないかで変わる様だ。
      "echo > A<(echo)" から "echo > A<echo" に書き換えるとなる。

      これの原因は何だったかというと "> A<(echo)" となっている時に、
      解析再開点が < の位置に設置されリダイレクト先の続きを読む設定になっている。
      ここで、<( となっている時には問題がないが < に書き換わると、
      ここはリダイレクト先の続きを読むのではなくて、
      新しい別のリダイレクトとして読まなければならない。
      つまり、この解析再開点が誤っている。
      何故このような事になったかというと、そもそもこの解析再開点を設置した時に先読みして
      "<(" まで見てリダイレクト先の続きを読むとした為である。
      つまり "(" が消滅する様な場合には、この解析再開点は無効化されなければならない。

      さて set-lookahead で先読みしたことを設定してみる。
      正しく先読み情報が記録されている。
      そして上記の編集の後でも正しく文法が解析されていることを確認した。取り敢えず OK

    4' その他のプロセス置換の部分についても確かめる。

      % と思ったが、よく考えたらプロセス置換に限らず
      % $(( や $( でも問題になるのではないだろうか…。
      % しかし、これらについて問題になるのではないかという事は今まで意識したことがない。何故か。
      %
      % 例えば $(( について考える。一致した時には $(( の末端まで移動するので問題は起こらない。
      % 一致しなかった場合には、3 文字目まで見たときは代わりに $( の方に一致するはずである。
      % この時、3 文字目も先読みしたことになるので問題ない。
      % 2文字目まで見て一致しないという事が分かったとき、必ず後で 1 文字は解析が進むので、
      % やはり 2 文字目の先読みの範囲に自動的になるので問題ない。

      $( や $(( で問題にならなかったのには、ちゃんと理由がある。
      $(( は 3 文字目まで見て失敗した時は必ず $( に一致するので OK。
      先読み2文字以下の構造については、そこで採用されなかったとしても必ず1文字進んで、
      その先読みで2文字は必ず進むので、気にしなくても良い。

      - その他、同様に check-word-end で参照している部分については、
        共通の関数 check-word-end/is-delimiter を用意してそれを使う事にした。

      - また、starts-with-delimter という関数も用意する事にした。
        これは実際に読み取りを行うよりも前の位置で呼び出すので、
        恐らく先読みの設定はしなくても大丈夫。
        先読みが当たればそれに対応する分だけ解析が進むし、
        先読みが外れるとしても1文字少ない部分列で解析が進むので、
        先読みの文字数に問題は起こらない。

      - 最後に starts-with-delimiter-or-redirect については、
        'time' 予約語に対して使っている箇所と、
        ctx-command の冒頭で使っている箇所がある。

        ctx-command の冒頭で使っているところでは、
        最終的に対応する redirect または delimiter を読み取るので問題ない。
        'time' 予約語に関してはまた実装を見直す予定なので、
        ここでは未だ余り真面目に考えなくても良い。
        実のところ、駄目な気がする…というか check-word-end/is-delimiter を使うべきでは?
        →starts-with-delimiter-or-redirect ではなく check-word-end/is-delimiter を使う事にした。

    取り敢えずよしとする。

  * memo.txt: D0535 が重複している。D0587 も重複している。 [#D0600]

    以下を使って調べたところ重複は他にはない。
    $ grep -ao '\[#D....\]' memo.txt | sort | uniq -cd

    跳びもない
    $ grep -ao '\[#D....\]' memo.txt | wc
    599

    番号が付いていない項目もない
    $ grep -Ea '^  \* (.*\[#D....\]$)?' memo.txt


    どの様にしたら自動的にずらす事ができるだろうか。
    D05\(3[5-9]|[4-9].\) → D05\,(1+ \1)

    うーん。
    D05\(3[5-9]|[4-9].\) → D05\,(+ \1 (if (<= \1 87) 1 2))
    D05\(3[5-9]|[4-9].\) → D05\,(let ((num (string-to-number \1))) (+ num (if (<= num 87) 1 2)))

    修正した。多分、大丈夫。

  * syntax: $(()) が常にエラーの着色になってしまっている。何故か。 [#D0599]

    [状況]

    調べてみると nest-push した時に中で ARGX になっている。
    $() も赤くなってしまっている。"$(echo)" も最初の " が赤くなっている。

    これは明らかに、#D0597 の書き換えによって単語内部を解析する時の
    wtype を変更したのが原因である。しかしどの部分でエラーになっているのだろう。
    調べてみるとエラー着色は構文解析の時点で設定されている。
    特に nest-push が発生した時に限り起こっている様に思われる。

    [原因]

    もう少し調べてみる。先ず初めに $(( が来ると check-dollar に入る。
    ここで attr には CTX_PARAM が設定される。そして nest-push をしてそのまま抜ける。
    抜けると ble-syntax:bash/ctx-command に戻る。
    flagComsume=1 が設定されるので、後でその分岐に入る。
    エラーが設定される条件は2パターンある。

    - 1つは _ble_syntax_bash_command_expect[wtype] に設定されている wtype であること。
      これは違う。この配列に登録されているのは CMDXE などだけである。

    - もう一つは unexpectedWbegin が設定されていること。
      しかし、こちらだと考えると変だ。

      例えば " の場合は "a" の様に単純な場合にはエラーにはならない。
      一方で "$(echo)" だとエラーになる。unexpectedWbegin は其処にある文字で判定するので、
      " の後に何が来るかに依存しないはずである。

      エラーになるかならないかを分けているのはやはり nest-push したかしないかである。
      nest-push では unexpectedWbegin は書き換えない。wtype は書き換える。
      という事を考えると、やはり wtype が書き換わる nest-push が怪しい。
      nest-push で wtype は -1 になる。しかし _ble_syntax_bash_command_expect に -1 はない。
      配列に -1 を指定すればエラーになる。と思ったが、よく考えたら負の添字を渡すと、
      一番最後の要素の値が取れるのではなかったか。実際に試してみるとそうだった。

    [修正1]

    ${_ble_syntax_bash_command_expect[wtype]} の確認をする前に
    wtype が 0 以上である事を確認する様にした。直った。

    test/benchmark/benchmark-201711-arithmetic.sh
    所で、0 以上である事を調べてから条件コマンドで中身を確認する時に、
    算術式コマンドと条件コマンドに分割した方が速いのか、
    或いは、単一の条件コマンドのした方が速いのかについて調べた。
    このケースの場合にはどちらが速いとも言えないが
    基本的に算術式で評価できるものは算術式で評価した方が速い様だ。

    [修正2]

    直ったと思ったら、今度は本来の目的の fi $(echo) をエラーにするという機能が駄目になった。
    nest-push しているので wtype が変わってしまい、エラーを設置する機会が失われている。
    また、今まで動いていた様に見えたのも nest-push して wtype=-1 になった事で、
    誤った条件判定によりエラーが設定されていただけの事であった。

    nest-push があった場合には nest-push する前の wtype が必要になる。
    これは実は初めの wtype を覚えて置くだけで良いのかもしれない。

2017-11-15

  * edit: echo !( !a ) で !a の直後で magic-space しても展開されない。 [保留] [#D0598]

    現在の実装ではカーソル位置よりも前の部分に対して展開を試みる。
    しかし、どうやら "echo !( !a" だと構文エラーか何かで失敗する様だ。
    最後の位置までカーソルを持っていかないと展開されない。

    元々の bash の実装ではどうなっていただろうか。
    echo !( !a の状態で SP をすると event not found のエラーになる。
    そして space も入力できない。これは不便だ。

    また、!( !a ) の状態ならば magic-space すれば展開される。
    カーソル位置もちゃんとなっている。

    echo !( !a) !a の状態で初めの !a の直後に magic-space を入れようとすると、
    履歴展開は両方共実行される。実行後のカーソルの位置は最後から四文字目。
    これは展開で挿入された文字列の中途なところである。
    つまり、実際に展開で挿入された文字列の位置ではなくて、
    展開前の最後尾からの位置を覚えておいて、展開後に覚えておいた最後尾からの位置に移動するだけの様だ。
    しかも、展開した後に空白を挿入するせいで、変なところに空白が挿入されている。
    Bash の magic-space の実装は微妙である。

    その様に考えると現在の実装の方が妥当に思われる。
    因みに、全体に対して展開を実行して、
    それでいて、展開後の現在位置に対応する箇所を特定する方法はあるだろうか。
    うーん。難しい気がする。ならばわざわざ実装する必要もないのではないだろうか。

2017-11-15

  * syntax: 以下はエラーにするべき。 [#D0597]
    if true; then true; fi <(echo)

    おかしい。fi echo はちゃんと赤く着色されているが、どの時点で着色されているのか謎だ。
    調べてみると単語を読み取る時には赤くなっていない。
    これは考えてみれば単語が終わるまでは、fi の後に fi done などが来るかもしれないので、
    この時点では未だ構文エラーかどうか分からないので、妥当な処理である。
    しかし、実際に赤くなっているのは誰が管理しているのだろうか。

    更に気付くことは fi echo$(echo) とすると赤くならないという事である。
    fi $(echo) も赤くならない。これは問題である。

    これはプロセス置換に限った話ではなくて全般的な問題の様に思われる。
    さて、そもそも現在の着色は何処で行われているのかを特定する必要がある。
    どうも、文法的に着色されている訳ではなくて、後付で着色されている様だ。

    うーん。実は CTX_CMDXE 及び CTX_CMDXD では取り敢えずエラーを設定して、
    word が終わる箇所でもし許容できるコマンド名になっていたら attr を設定する
    という方式で良いのではないだろうか。許容できるコマンド名は単純なので必ず同じステップ内のはずである。
    CTX_CMDXE CTX_CMDXD 以外にもあるかもしれない。
    これについては、後付で着色しているコードを観察すれば良い。
    所で、未だ後付で着色している部分の特定には至っていない。

    →多分分かった。ble-highlight-layer:syntax/word/.update-attributes/.proc
      CTX_CMDXE 及び CTX_CMDXD では wtype に ATTR_ERR を設定しているのだ。
      そして wtype が ATTR_ERR ならば赤く色を付けるという様にしている。
      然しながら、この判定をしているのは $wtxt =~ $_ble_syntax_rex_simple_word の中なので、
      $(echo) などを含む単語についてはエラーの着色が起こらないのである。
    →では wtype に ATTR_ERR を設定しているのは何処だろう。
      ble-syntax:bash/ctx-command/check-word-end の中で
      _ble_syntax_bash_command_expect を参照している。
      この配列に正規表現が登録されている問、この正規表現に一致しない物について
      wtype=ATTR_ERR を設定している。

      逆に言えば、この配列に登録されている様な文脈の場合には属性値を取り敢えず ATTR_ERR にしておいて、
      正しいと分かった時に改めて、期待される属性値を代入するという具合にするのが良い気がする。
      更によく見ると CTX_CMDXE CTX_CMDXC CTX_CMDXD で許容されるコマンドは何れもキーワードなので、
      改めて期待される属性値を代入しなくても正しい値で上書きされる様に見える。つまり、気にしなくて良い。

      % と思ったが、属性値を ATTR_ERR にしようと思っても、
      % 実は属性値は ctx の値をコピーして設定する事になっているので、
      % 自由に設定できるようなものではない。
      % 特に単語の開始境界の位置で設定できる物という訳ではない。
      と思ったが、ctx の値をコピーして設定する所で wtype も参照して設定する事にした。動いている。

      ところで、わざわざ wtype を設定して highlight で色を付けて貰うこともないのではないかとも思ったが、
      'echo' 等の様にして囲んだ場合には現状の方法だと対応しきれないので、
      やはり wtype によるエラー着色は必要である。そのままにする。

    しかし、それでも未だ if true; then true; fi <(echo) はエラー着色が見えない。
    やはり全体をエラーの色で塗り潰したい物である。
    →単語を構成する要素は全て先頭にエラー色を上書きする事にした。動いている。
    多分問題も生じないであろう。

    さて、改めて今まで調べて問題だったものについて確認する。何れも着色されている。OK
    正しい場合にはエラーの色は残っていない。OK

    * resolved: 因みに、[[ echo ]] echo や (( echo )) echo に関しては
      構文的に誤っているということがすぐに分かるのにも拘らず、
      エラーの着色が為されていない。これも何故だろう…。
      _ble_syntax_attr にはちゃんと CTX_ARGI が設定されている。
      CTX_ARGX0 なのに ble-syntax:bash/ctx-command/.check-word-begin がちゃんと返していないのが悪い。
      しかしちゃんと返しているとしか思えない。と思って、呼び出し元を見たら、
      何故か unexpectedWbegin に値を設定するはずの所が壊れていた。
      どうやら色々試している内にここを壊してしまっていた様だ。
      これについては直った。

    * fixed: 後、echo とした時、普通は後付の色で上書きされるために見えないが、
      その下にはコマンドの色がついているはずなのに黒である。これはどういう事か。
      _ble_syntax_attr[i]=ctx によって現在の ctx を代入している様にみえる。
      というか ble_debug の一番左の列に表示しているのが attr だった。
      これによるとちゃんと CTX_CMDI が設定されている。
      だとすれば、attr から色に変換する所で誤っているのか。
      別に bashrc で syntax_command の色設定を上書きしている訳でもない。
      何と色指定を誤っていた。元々 red となっていたのを brown に書き換えたのだったが、
      正しくは fg=red であるべきで、それを fg=brown に書き換えるべきだった。直した。

2017-11-14

  * syntax: [[ a == b ]] などが誤って構文エラーになっている。 [#D0596]
    これはごくごく最近発生した問題のはずである。

    直した。序に、[[ と ]] は今まで予約語色にしていたが、
    構文レベルで ATTR_DEL にする事にした。
    (今までは構文レベルで [[ を ATTR_DEL にしていたが、
    その後の単語の着色で予約語色になっていた。
    ]] はそれを見越して構文解析の時点で予約語色にしていた)

  * syntax: - で始まる名前のコマンド・関数だと正しく着色されない。 [#D0595]
    これは type がコマンド名をオプションと勘違いしている為である。
    type を呼び出す時に -- を前置すれば良い。

  * syntax: time の後に何もなくても文法的には正しい。 [#D0594]
    time -p の後に何もなくても文法的には正しい。

    実は ! / time の直後は特殊な文脈になっている様だ。

    以下はリダイレクトの文法の詳細について調べている時 (#D0591) に分かったこと。

    | 実は ! 単体でも OK
    | while !; do break; done
    | これは直したのに直っていないと思ったら、
    | そもそもリダイレクトに関係ないので修正とは関係なかった。
    | 独立に修正する必要がある。
    |
    | 所が調べてみると ! ; echo これは文法エラーになる。不思議だ。

    調べてみるとまたよく分からない規則がある様だ。

    $ ! ;                          # OK
    $ time ;                       # OK
    $ ! ; echo                     # Error 何故?
    $ time ; echo                  # Error 何故?
    $ while ! ; do break; done     # OK
    $ while time; do break; done   # OK
    $ while false; do ! ; done     # OK
    $ while false; do time ; done  # OK

    どうやら !, time 直後の ; の後は CTX_CMDXE になっている様だ。

    2021-02-18 Note (#D1477): bash 4.4 で振る舞いが変更された。
      4.4 以降では time ; や ! ; の後は通常のコマンドも来る事ができる。

    もう少し調べる。

    $ time &        # Error
    $ time && echo  # Error (&& が来た時点で既にエラー)
    $ time || echo  # Error
    $ time | echo   # Error
    $ time |& echo  # Error
    $ case a in (a) time ;; esac  # Error
    $ case a in (a) time ;& esac  # Error
    $ case a in (a) time ;;& esac # Error

    つまり ; 以外が来るともう駄目ということである。
    さて、; 以外については現状の振る舞いと一致しているので、
    ; が来た時だけ特別扱いをすれば良い。

    ! と time の後は、現在の枠組みでは文脈値として CTX_CMDX1 になっている。
    これは例えば else の時も同じである。試してみる。

    $ if true; then true; else ; fi # Error
    $ if true; then true; time ; fi # OK
    $ if true; then true; ! ; fi    # OK

    やはり明確に !, time の直後だけ文脈が異なる。
    そして、! と time の直後はやはり類似の文脈の様だ。

    % と思ったが、! に関しては寧ろ else と同じ?
    % 勘違いだった。構文エラーではなくて単に ! が実行されて終了ステータスが 1 になっただけだった。

    取り敢えず CMD_CMDX1 を複製することにする。複製した。
    time ; 及び ! ; に対応した。
    次に行末での処理に対応する。改行のある時と、最後(文字列末端)のチェックを直す。
    多分、これで対応できた。

  * syntax: 以下で ")" の位置で誤って構文エラーが報告されている。 [#D0593]

    echo $({ time echo helo; })
    echo $(while true; do break; done)

    CTX_CMDXD の後にコマンドがなくて終了しても OK にする。

  * syntax: 予約語と変数代入・リダイレクトの順番に関する修正 [#D0592]

    というか time や ! 周りの文法が分からなくなってきた。試してみる。

    * ok: 何と、以下の何れも文法的に正しい。
      今まで深く考えていなかった実装でそんなに間違っていはいなかった様だ。

      $ time ! echo hello
      $ ! time echo hello
      $ ! time ! echo hello
      $ time time echo # 一個しか time を指定しなかったときと同じ
      $ ! ! echo
      $ ! ! ! echo # ちゃんと数に意味があって奇数個・偶数個で振る舞いが変わる

    * fixed: 以下は time はコマンドとして実行される。! はコマンドが見つかりませんと出る。

      $ > a.txt time echo
      $ > a.txt time -p echo
      $ a=b time echo
      $ > a.txt ! echo
      $ a=b ! echo

      % これについては !, time は CTX_CMDXV 以外で有効ということにすれば良い。
      %
      % そう言えば他の特殊文脈での振る舞いはどうなのだろう。確かめる。
      % CTX_CMDXC の場合は time があると駄目である。! も駄目である。
      % CTX_CMDXE の場合は如何にもだめそうだが…一応試すと time も ! も駄目だった。
      % CTX_CMDXD の場合も試すと time も ! も駄目だった。
      % これらは元々エラーなので特別の対策はいらないだろう。
      % 特に ! や time を下手にコマンドとして取り扱うと、
      % それ以降に復号コマンドなどがある時に振る舞いがおかしくなるので、
      % これはそのまま通過するということで良い気がする。
      %
      % さて、どの様に対応したら良いだろうか。
      % 実際に '!', 'time' 等の判定をしているところを見ると、
      % ctx は既に CTX_CMDI になっているので元々の文脈値が分からない。
      % ここで、元々の文脈値を過去に遡って確認することは許されていただろうか。
      % 少なくとも直接に stat/attr 配列を参照して確認することは許されていない。
      % 部分更新の際にこれらの情報は書き換わってしまうからである。
      % | 或いは、必ず1回の step で '!' や 'time' の終端に達すると考えれば、
      % | 実は '!' や 'time' 以降の状態を参照しても良い気もするが、
      % | 原則を破ると汚くなってなんだかよく分からないので、できるだけこれはしない。
      %
      % では word の情報としてこれらは記録されていただろうか。うーん。
      % どうも wtype として記録されている気がする。
      % 調べてみると CTX_CMDX[CDE] に関しては実は既に wtype にそれが設定されていた。
      % しかし、それ以外の場合については wtype は word の中を解析する ctx (つまり CTX_CMDI) に統一されている。
      % これには意味はあっただろうか。取り敢えず一旦 wtype になったものが ctx になることはないだろう。
      % なので wtype で CTX_CMDI に特別な意味を持たせているものについてチェックすれば良い。
      % ble-syntax.sh で登場する CTX_CMDI について wtype に関係するものは以下の二箇所で出て来る。
      %
      %   ble-syntax:bash/extract-command/.construct-proc
      %   ble-highlight-layer:syntax/word/.update-attributes/.proc
      %
      % これらは何れも tree-enumerate の過程で呼び出される proc である。
      % という事は最終的に登録される wtype だけしか効かない筈である。
      % 途中で CTX_CMDXV などになっていても大丈夫のはず。

      というか、今気づいたのだが、そもそも

      $ a=b function hello [[ a ]]
      $ > a.txt function hello [[ a ]]

      等は何れも function をコマンド名扱いしている。
      他のキーワードのチェックに現れるコマンドを全て確認したが、
      何れもコマンド扱いされるようになる様だ。

      a うーん。新しい文脈値 CTX_CMDIV 的なものを導入する可能性も考えたが、
        其処まですることもない様な気がする。何より違いというのはここにしかない。

      b したがって、CTX_CMDXC 等と同様に wtype に記録するのが良い気がする。

      c というかそもそも解析中の wtype を参照する箇所は他にあるのだろうか。
        探してみた所見つからない。という事は、実は開始時の wtype をそのまま指定して、
        それから word-pop する直前で調整すれば良いだけなのではないだろうか。

        word-push では単に wtype 変数に値を指定するだけなので気にしなくて良い。
        実際に tree に登録されるのは word-pop の時である。
        そして、既にそのことを意識して途中で wtype を書き換えるという事は行っている。
        但し、その wtype の書き換えの際には実際には元の wtype は参照していなくて、
        ctx に基いて新しい wtype を設定しているだけである。つまり、wtype は使われていない

        うーん。念のため、以前実装した時にどうしてこの様にしたかを確認する。
        関係がありそうなのは #D0393 #D0382 #D0378 #D0372 #D0371 だが、
        何れにおいても現在の実装については議論されていない。
        _ble_syntax_bash_command_bwtype を弄っている commit を見てみると、以下の通り。

          70e1e49d     2017-03-05 19:07:58 → これは #D0382 だろう。
          fdbfb399     2017-03-01 11:40:26 → これは #D0372 なのだろう。

        結局そんなに分からない。恐らく元々 wtype=ctx としていたのを破壊しない様に修正した結果、
        現在のような形になったというだけで、これに対した意味は無いだろうと思われる。

      [実装]

      wtype には octx を設定する様にする事にした。
      check-word-end で _ble_syntax_bash_command_ewtype を使って変換してから word-pop する。
      取り敢えず分かっている範囲での動作に破壊が生じないことは確認する。

      wtype が CTX_CMDXV だった時には予約語は解釈しない様にする。
      直してみたらエラーになった。うーん → 修正した。

    * 変数代入とリダイレクトの後は予約語を解釈しないように変更したが、
      相変わらず予約語の色で着色されている。
      これはコマンドとしてマークされた予約語には現在予約語の色をつけている為である。
      しかし、思うに予約語はそもそもコマンドとしてマークする必要はないのではないか。

      (ところで初めは以下のように書いていたが、実は予約語全般に当て嵌る話だった)

      | 所で、現在の実装では '!' は何も着色していないが、
      | type -t '!' とすると keyword と出るので keyword 色にするべきでは。
      | もしくは、[[ 等と同様に太字にするか。性質を考えると time と同じにしたい。つまり青字。

      コマンドとしてのマークをしないという事にした時にどの様な影響が出るかについて考える。
      先ず初めに extract-command が正しく働かなくなる。予約語の為の word type を用意するべきだろうか。

      或いは、別の方法でコマンド着色の際に判定を行う。
      例えば、初めから attr に予約語の色が設定されている時には改めて着色は行わないなど。
      こちらの方が現実的な気がする。

      さて、では予約語に対応する語がコマンドとして呼び出される時は、
      実際にはどのようにして色を決めれば良いのだろう。
      例えば type -tP time などとすればコマンドがあるかどうか分かる様だ。
      しかし、a=b time は関数でも良いようだ。なので、関数があるかどうかも調べなければならない。

      そう言えば 'time' 等として呼び出す場合にも同じことが当てはまる。
      現在の実装では 'time' なども予約語として取り扱われて青くなったのだったろうか…
      と思ったら、'time' とした場合には正しく解決できている。これを参考にする必要がある。
      →これは ble-syntax/highlight/cmdtype2 の $type == $ATTR_CMD_KEYWORD 分岐で処理されていた。

      [実装]

      a 予約語の時は語の先頭の attr を書き換えれば良い…と思ったが、
        よく考えたら check-word-end に至った時点で既に先頭の attr は設定されている。
        この値を書き換える為には [[ で行っている様に、

          ble-syntax/parse/touch-updated-attr "$wbeg"
          ((_ble_syntax_attr[wbeg]=ATTR_DEL))

        という様な事を明示する必要がある。

        これだと解析の効率が下がるのではないかとも思ったが、
        よくよく考えてみるとそもそも予約語の様な単純な単語の場合には、
        必ず 1 回で解析が終了するので、これで効率が下がることはない。
        寧ろ、ble-syntax/parse/touch-updated-attr "$wbeg" をわざわざ呼び出す必要も、
        本当は無いのかもしれない。ただ、これはルールとして呼び出すようにしておく。

      b wtype に記録された情報を用いる。

        そう考えると寧ろ check-word-end の支配下にある
        word-pop で登録される情報を弄る方が良い気もしてくる。
        然し、改めて実装を見てみると word-pop を使うとしても
        現在のコードの流れでは word-cancel を実行してから、
        再度 word-pop をしなければならないという面倒なことになっている。

        word-cancel はそれなりに面倒なことをしている。
        もしこの wtype を用いる方法を採用するとすれば、
        処理の流れを変えて word-cancel をしなくて済む様にしたい。

      どちらの方が良いだろうか。

      | extract-command の観点から考えてみる。
      |
      | | しかし、そうするとこれは extract-command に影響が出てくる。
      | | (所で、extract-command を使っている command-help の方はどうなのだろう。
      | | 例えば a=b function となっていた時、command-help の中からは
      | | それが予約語の function なのか、コマンドの function なのか判定ができない。
      | | command-help にも配慮した設計にするべきなのではないだろうか。
      | | と思ったが、(attr を用いる方法か wtype を用いる方法か) 何れの方法を用いたとしても、
      | | 現状の枠組みでは command-help に情報を伝えるのは難しい。
      | | 或いは、extract-command において単語開始位置の情報まで全て返すようにすれば、
      | | 後は attr/wtype に拘らず command-help 側で好きに調べることができる。
      | | もし wtype になっていれば extract-command を返す時に、
      | | 先頭の単語の種類も一緒に別の変数かなにかで返すことができる。
      | | しかし、現状の実装ではそれが予約語かそれ以外かの二択なので、
      | | わざわざ変数にして返す意味があるのかという疑問も生じる。
      | |
      | | 更に、よく考えてみると command-help だけでなく、
      | | complete を行う時にもそれがコマンドかどうかによって振る舞いは変えるべきなのではないか。
      | | と思ったが、complete の場合にはそもそも予約語に対して引数はないので、
      | | complete が呼ばれることもない気がする…いや、for 等の場合には complete が呼ばれる。
      | | もし complete で関数が登録されていればやはり extract-command を呼び出すのが良いだろう。
      | | しかし、この時には bash の補完関数の仕組みではそれが予約語かコマンドか判定する仕組みがないので、
      | | 結局、そのような情報を提供する意味がない。
      |
      | - command-help で表示するヘルプを選択するときには、何らかの方法で予約語かそうでないかを区別したい。
      | - Bash の補完関数の枠組みを模倣するときは予約語かそうでないかの区別はない。
      |
      | highlight の観点から改めて見てみる。
      |
      | wtype 及び attr は何れも簡単にアクセスできる物だろうか。
      | そもそも highlight は wtype を参照して着色する方法を選択している。
      | その場所は ble-highlight-layer:syntax/word/.update-attributes/.proc である。
      | 一応、この箇所で _ble_syntax_attr[wbeg] を参照すれば良いが、
      | やはり綺麗なのは別の wtype にする事の気がする。
      |
      | 改めて wtype CTX_CMDI を明示的に調べている部分を探す。
      | これは先程調べたものである。extract-command と highlight 以外では使っていない。
      | extract-command の wtype == CTX_CMDI を新しく追加した wtype にも対応するという風にするだけで良い。
      |
      | さて、wtype を追加するとしたらどの様な値にするべきだろうか。
      | a 一つの方法は新しい文脈値を作るというものだが、
      |   実のところ解析に関与していない文脈地は作りたくない。
      | b 或いは、既存の文脈値を流用する。しかし予約語に向きそうなものはない。
      |   一応 CTX_CMDXE や CTX_CMDXD は予約語しか次に受け付けないが、
      |   これらは既に来る予約語名までの空白の色に同時になっている気がする。駄目。
      | c 或いは、ATTR_CMD_KEYWORD を用いる。
      |   現在の実装では ATTR_CMD_KEYWORD は CTX_* と重複しないようになっているので問題はないはず。
      | もし wtype の方法にするとしたら ATTR_CMD_KEYWORD を用いる。
      |
      | function の最後の文字のエラーの着色が透過するためには、
      | 予約語の時には敢えて単語の種類による着色を行わないという様にすれば良い気がするが、
      | その為には結局最初から _ble_syntax_attr を書き換えて置かなければならない。
      |
      | 或いは、function のエラー着色を今まで通りに上書きしても良いとしても、
      | 予約語について上から予約語色で塗るというのは、
      | わざわざ highlight の phase で実行しなくて良い気がする。
      | 色の管理が面倒になるので、寧ろ文法解釈の時点で分かる色・属性はそこで設定した方が良い。

      [結論] _ble_syntax_attr[wbeg] を書き換える。

      - wtype を用いて判定すると予約語の時に改めて着色する必要がある。
        予約語の色は構文解析の時点で分かっているので、改めて着色の判定をするのは無駄である。
        また孤立 function のエラーなど構文解析でのエラー着色が上書きされてしまう問題があった。
        これを解決する良い機会でもある。

      - _ble_syntax_attr[wbeg] を書き換えると、一見、解析の効率が悪くなる様にも思われるが、
        実際には予約語は単純なので wbeg の位置は同じ解析ステップの範囲のはずなので気にしなくて良い。

    この修正により以下の古い項目は解消した。

    | 2015-08-15
    |
    | * ble-syntax.sh: `function' と入力した時に最後の n の部分にエラーを設定するが、
    |   command 名としての着色の際に上書きされてしまっている。

  * 2017-11-10 syntax: > a.txt ; echo が文法エラーとされているが、これは文法エラーではない。 [#D0591]

    * fixed: 以下は本来文法的に正しい
      > a.txt; echo

    他にも試してみると色々新しいことが分かった。
    以下は何れも文法的に正しい。

    * fixed: 以下は本来文法的に正しい
      while > a.txt; do break; done
      →これは色々試してみた所、
        リダイレクトを挟むと CTX_CMDXV になるとすれば良さそうだ。
        リダイレクトの後に変数代入があってもいいし、
        変数代入と変数代入の間にリダイレクトがあっても良い。

    以下は本来文法的に正しくない。

    * fixed: 関数の本体の直前
      function hello () > a.txt ((a+=b)) # 駄目
      function hello () ((a+=b)) > a.txt # 備考: これは正しい
      →これは CTX_CMDXC ではリダイレクトは駄目ということにすれば良い

    * fixed: fi などの直後にリダイレクトを挟んで fi などが来るとき
      if true; then if true; then echo hello; fi > a.txt fi # 駄目
      if true; then if true; then echo hello; fi fi # 備考: これは正しい
      →これは CTX_CMDXE でリダイレクトを挟むと CTX_ARGX0 になるとすれば良い。

2017-11-12

  * encoding: input_encoding を切り替えた時ごみが残るのでは。 [#D0590]
    detach の時にもこれは処理するべき。
    ごみは flush するのかそれともそのまま消去するのか。
    ble-decode/unbind で消去してしまうのが良い気がする。

  * encoding: この辺りで __ENCODING__ という部分を整理する。 [#D0589]

    調べてみるともう2箇所しか残っていない。
    一箇所は ble-color.sh の ble-highlight-layer:plain/update/.getch で、
    これは C1 文字を M-^? の形の表示に変える為のものである。
    これは ble/util/s2c でコードに変換してから判定することにした。
    多少重くなるかもしれないが仕方がない。

    ble/util/s2c は必ず Unicode の値になるのだろうか。
    現在の実装を調べてみると結局 builtin printf %d "'あ" を使っている。
    これは実際に試してみた所、eucJP でも 12354 という値を出力したので、
    最終的に Unicode に変換してから出力するようである。

    | 疑問: ble/util/s2c の実装は本当に Unicode 値を得られているのだろうか?
    | [cf memo/D0589/D0589.test-printf-s2c.sh]
    |
    | eucJP で試す。_ble_bash>=40100 の実装は OK
    | builtin printf %d "'あ" はちゃんと unicode の値を返す。
    | 他の実装も結局同様に builtin printf を使っているので大丈夫のはずだ。

    もう一つの __ENCODING__ は ble-edit/draw/trace に残っている。
    現在では LC_ALL=C ではなく LC_COLLATE=C にしているので、
    問題は起こりそうにないが念のため実験する。
    試してみた所 glob でも正規表現でも、
    ちゃんと LC_CTYPE に従った文字の単位で切って、
    その後で LC_COLLATE=C に従った比較になっている様だ。
    問題になることは無さそうに思う。
    [cf memo/D0589/D0589.test-lc_collate.sh]

    ただ、比較をする上で直接 ST を正規表現に埋め込んでいた。
    これはソースコード上 UTF-8 で符号化されて埋め込まれている。
    UTF-8 でない環境で source ble.sh した時に問題になると思われるので、
    ble/util/c2s 156 で文字を取得するように変更する。

    | 唯、気になるのは ST に対応する文字が存在しない環境で、
    | ble/util/c2s (もしくは printf -v var '\uXXXX') がどの様な結果を齎すかである。
    | [cf memo/D0589/D0589.test-printf-uXXXX.sh]
    |
    | 例えば空欄になるのか、或いは変な文字がそこに入るのか、変数に代入が行われないのか。
    | 手許の環境では ST のある文字コードしかないので取り敢えず別の文字を使う。
    | ここは周回積分記号 ∮ を用いることにする。U+222E である。
    | iconv -f UTF-8 -t EUC-JP <<< ∮dx とすると以下のエラーになる。
    |
    |   iconv: illegal input sequence at position 0
    |
    | 従って、これは EUC-JP に対応するもののない文字である。
    | さて、実際に printf '\u222E' を試してみると
    | 何と '\u222E' という文字列がそのまま出てきた。
    | \u3042 (あ) はちゃんと ja_JP.eucJP でも変換されている。
    | と思ったら、実際に使っているのは $'\uXXXX' だった。
    | 改めて調べなおすと同じ振る舞いだった。'\u222E' という文字列になる。
    |
    | 所で、もう一つ気付いたことは $'\uXXXX' は、Bash が parse した時の文字コードで先に文字に変換されている。
    | 従って、eval で評価を遅延させる必要がある (これは実際に c2s でやっていることとも一致する)。

    →対応する文字が存在しないときは '\uXXXX' の形になるので文字数が 2 文字以上なら失敗と見做せば良い。

    % ところで周回積分記号の幅の計算が誤っているがこれはどうしてか。
    % どうも幅 1 と思っている様だ。手許の emacs では変なことは起こっていない。
    % そして現在の ble.sh は emacs のテーブルを元にしているはずなのだが。
    % →と思ったらこれは直したのだった。最新の ble.sh では変なことは起こらない。
    % ble.sh を編集しているシェルセッションが古いのがいけなかった。

    他に動作に深く関わるもので Unicode の文字 (C0 GL でない文字) が直接埋め込まている箇所はあるだろうか。
    実のところ意味を持つのは C1 程度なので、C1 以外を埋め込む意味がないように思われる。
    あるとすれば(エラー)メッセージに日本語が含まれる場合だが、
    日本語のメッセージを出力する箇所はないはずだし、
    もし日本語メッセージが UTF-8 で出力されたとしても大きな問題には至らない筈である。
    ST (\u009C) と CSI (\u009B) は検索したが、今回対処したところ以外にはない。
    多分、他の文字も存在しない。OK

  * ble_debug=1 で表示していた内容が :q で消去されない。 [#D0588]
    これは info の仕組みを用いて表示していたので、
    :q をする時に消去されるはずなのではないか。

    というか、普通どおりに exit しても消去されない。
    と思ったが補完候補達は初期されている気がする。うーん。
    もしかして高さの計算を誤っている?

    と思ったが mode 変更の際に info が変わる時には
    ちゃんと正しい高さだけ削除されている。

    実装の方を観察してみる。
    ble/widget/vi-command:q は ble/widget/exit を呼び出している。
    ble/widget/exit は ble-edit/info/hide を呼び出している。
    もしかして hide した物が再度描画されてしまっている可能性?

    と思ったが、再描画されるようなタイミングはなく exit している気がする。
    うーん。途中の出力の様子を見てみると何も出力されていない?
    直前の高さを確認してみたが _ble_form_window_height にはちゃんと高さが設定されている。
    そして hide の直後には高さが潰れている。

    うーん。どうも調べてみると ^O しか出力されていない様だ。
    と思ったが、どうやら alias less で確認していたために
    エスケープシーケンスが表示されていなかったようだ。
    ちゃんと確認したら消去のシーケンスは _ble_util_buffer に入っていることは分かった。
    ESC[m^OESC[1B^MESC[8M となっている。SGR() ^O CUD(1) DL(8) である。
    では、何故実際に消去されていないのだろうか。
    flush を挟んで見る。しかしながら消去できていない…。どういうことだろうか。
    あれ、もしかして高さの計算を間違えている? と思ったがそんな事もない。

    うーん。おかしい。もしかして render の中で再描画されている?
    →そのようだ…。高さが復元している…。
    あ…分かった。textarea#render が中で syntax を呼び出して、
    syntax は ble_debug=1 の時中で info を呼び出すのだった。

    ble/util/hide の方を後にしたら収まった。

  * ble_debug=1 で表示される内容の _ble_highlight_layer_disabled_buff [#D0587]
    の行が前の行にくっついている。
    これは ble/util/assign の実装を変更して行末の改行を除くようにしたのが原因だった。直した。

    改めて ble/util/assign の様子を観察してみるとどうも最後の改行が除かれている
    前提のコードが多いような気がする。今まで動いていたのはなんだったのか不思議である。
    一応動作を統一するために bash-4.0 未満でも最後の改行は除くようにした。

  * bind: bleopt input_encoding=C は動かない気がする。 [#D0586]

    素直な bind ではちゃんと入力を読み取れないので UTF-8
    では文字を 2 byte 表現に一旦変換してから読み取るなどの工夫をしている。

    これに正しく対応するためには、C であっても特定のシーケンスについて特別な意味を持たせる必要があるのではないか。
    そうすると、例え C であっても C1 の領域の何れかの文字を生贄にするしかない。
    因みに vim では right を <80>kr という表現でキーボードマクロに記録する。
    これを考えると <80>? を特別な表現に割り当てれば良い気がする。

    % とここまで書いて思ったが、実は現在の設計は文字符号化方式の部分と、
    % bind の部分が癒着しているのがいけないのではないか。
    % つまり、ble-decode/.hook から直接 ble-decode-byte を呼び出しているが
    % その手前で特別表現からバイト値に変換する段があっても良いのではないかという事である。
    %
    % そうすれば bind の文字符号化方式依存の部分は解消するし、
    % 場合によっては孤立 ESC を受け取るために使った
    % <wait> などの仕組みについてももっと綺麗に解決できるかもしれない。
    %
    % 取り敢えず、孤立 ESC の細かい取り扱いは抜きにしても、
    % 文字符号化部分とバイト受信部分を明確に分離する。
    % 特別なバイトを受け取る時に使用するシーケンスとして何を使うか考える必要がある。
    % これには UTF-8 で決して使われないバイトを使うのが良い気がする。
    % 勿論、完全に文字符号化部分と分離するのであるから、UTF-8 で使われるバイトを用いても良い。
    % 然し、多くの場合 UTF-8 で使われることを考えると効率の観点などから考えて、
    % やはり UTF-8 では来ない様なバイト値で処理をするのが良い様に思われる。
    %
    % 先ず初めにどのバイトを用いるのかを決定する。
    % UTF-8 で使われないバイトは \xFF \xFE と、
    % 更に不正な表現の先頭バイトになる \xC0 と \xC1 である。
    % 実は現在の実装では \xC0? (不正な 2 バイト表現) に置き換えているので、
    % \xC0 を特別なバイトとして扱う事にすれば bind.sh の変更を最小限にできる。
    % 0xC0 を特別なバイトとして採用する事にした。
    %
    % 後は、0xC0 自身をどう表現するかである。
    % 一つの方法は \xC0\xC0 とするものである。或いは \xC0\xC1 とする。
    % 混乱を防ぐ為には \xC0\xC0 は避けた方が良い。\xC0\xC1 とすると、
    % 仮に \xC1 を受け取りたい時との混乱を避けられないのではないかという懸念があるが、
    % 実の所それは例えば C-@ を受け取るのに \xC0\x80 を使う時に \x80 で混乱が置きないかと心配するのと同じである。
    % 寧ろ、\xC1 は UTF-8 として不正な値であるので、寧ろ受信される頻度は殆どないと考えて良い。
    % ここでは \xC0 は \xC0\xC1 として受け取る事にする。
    % \xC0 については特に問題も起きそうにないので一旦 bind '"\xC0": "\xC0\xC1"' と置き直す必要もない。
    % というか、その様な置き換えをしてしまうと無限ループになってしまうので駄目だ。
    % 所で…現在 "\C-@": "\xC0\x80" 及び "\C-[": "\xC0\x9B" で置き換えているが、
    % これらは最終的に \xC0 \x80 として受信される。だとすれば、
    % この \xC0 と本来の \xC0 はどの様にして区別するのだろうか。
    %
    % ここで何故現在のような実装になっているかを思い出す。
    % その文字符号化方式で送られてこないような符号に変換する必要があったのだ。
    % そして UTF-8 の場合にはたまたまそれぞれのバイトに対する
    % 多バイト表現があったので、それを使うことができたのである。
    %
    % しかし、本当にそうしなければならないのかについて考える。
    % 先ず、\xC0 を使って表現すると決めた時点で、
    % \xC0 自身を区別して受信する方法が必要になる。
    % しかし "\xC0": "\xC0\xC1" などのようにすると無限ループになるし、
    % 更に、これだと "\x1B": "\xC0\x9B" なども "\xC0" に突入してしまう。
    % "\xC0\xC1" にも同時に bind -x する事にすると単体の
    % \xC0 が来た時に timeout を待つことになる。
    %
    % やはり符号化の "穴" を突くしか無いのだろうか。
    % そうすると結局また符号化方式依存になってしまう。
    %
    % 或いは制御文字は恐らくどの (現実的な) 文字符号化方式でもあるだろうと考えれば
    % (そうでなければ C-@ ～ C-_ の表現が普通と異なってしまい大変だ)、
    % 制御文字のどれかを特別な文字として組み合わせで受信することができる。
    % しかし、これもその制御文字に対する timeout が発生することになる。
    %
    % 勝手に keymap-timeout を変更すると、それはそれでキーシーケンスが
    % 認識されなかったり、途中の timeout によって文字が連なって来た時に混乱が生じたりする。
    % なので keymap-timeout はそのままにしておく。すると 300ms の遅延が生じる。
    % 結局、既存の文字に割り当てる時と同様に問題になる。
    % 特に制御文字は ASCII にないような変な文字に比べて入力する機会が多いし、
    % 結果として大きな変化を齎す物もあるから遅延があるのは通常文字に増して問題がある気がする。

    結局、Bash のキーボードマクロが反復して適用されることにより、
    1対1の対応付を作ることが難しい。従って、遅延などが起きない様にしようと思うと、
    文字符号化方式に依存して使われていないコードポイントを使用するしかない。

    * しかし、やはりできそうな気がしてくる。本当に不可能なのだろうか。

      | 先ず前提として、或る文字を直接受信できないときに、
      | bind '"\x1B": "\xC0\x9B"' などの様にして別のシーケンスにして受信できる。
      | この時、受信できないバイト "\x1B" は当然代替シーケンスには含まれない。
      |
      | 問題は以下の様に要約できる。
      |
      | 1 256 種類のバイトを 254 種類のバイトで符号化する方法を作る。
      | 2 この符号に対して再び符号化を適用しても不変である。
      |
      | 254 種類というのは、直接受信できないバイトが 2 種類存在するという前提である。
      | この時 bind -x で受信するためには残りの 254 種類のバイトで行わなければならない。
      | 要求 2 は、bind '"\xC0": "\xC0\x9B"' に対して反復して変換が試みられる実情を反映する。
      | この条件が満たされないと無限ループに陥る。
      |
      | この様な符号化は不可能な気がする。
      | もう少し真面目に考える。とにかく鍵となるのは直接受信できないバイト
      | B1, B2 を表現するために使われるシーケンスを構成するバイトである。
      | 特に Encode(B1) の先頭文字を B3 ということにする。
      | この時、曖昧でないためには B3 自体も符号化しなければならない。
      | 無限ループに陥らない為には B3 は B1-B3 以外の文字で表さなければならない。
      | これを繰り返すと最終的に文字がなくなる。よって不可能だ。
      |
      | これを克服するには少なくとも条件を緩くしなければならない。
      | 例えば bind -x '"\xC0\xC0": hoge' 等のようにする。
      | \xC0 は単体で受信されることはなくて必ず二文字に増やしてから受信するのだとすれば、
      | これで遅延が生じることはないように思われると思ったが…
      |
      | 1 \xC0 単体で受信した時に次の文字が来ないか待つのでここで timeout 分遅延する
      | 2 更に、たまたま本当の入力に \xC0\xC0 の様な並びがあるときに
      |   それが別のバイトに化けてしまう。

      やはり文字符号化方式の穴を使わずに
      完全な読み取りを実現することは不可能であると判断する。

      (全て Bash の bind で直接受信できないバイトが存在するのが悪いのだが)

    * さて、この時 input_encoding=C については全ての文字が意味を持つので、
      穴など存在しない様に思われる。何れかのバイトを犠牲にするしかない。
      例えば C1 制御文字の何れかを犠牲にするのが一番影響が小さいだろう。
      C1 制御文字をコマンドの文字列を構成する文字の一つとして使いたい時は問題だが、
      その様なケースは限られているので仕方がない。

      一番影響が少ないと思われるのは、元からシーケンスの一部として使われる様な文字である。
      例えば ESC がそれだが、これが丁度 Bash では直接受信できない文字である。
      次に CSI などがある。他に DCS SOS OSC PM APC 等がある。
      DLE (C-p) は実際に使われるので駄目。まあ CSI を使って置くのが妥当であろう。

      さて CSI を犠牲にすると言えば、どの様にするのが良いだろう。
      実際に 8 bit CSI シーケンスが送られてきた時と干渉しないためには、
      これ自身も CSI シーケンスになる様に構成するのが良い。

      | a 2文字で表現する案
      |
      |   また CSI は、もし CSI シーケンスを処理するのだとしたら、
      |   結局何れにしても 2 文字目以降を待つ必要があるので都合が良い。
      |   private CSI を使うことにする。特に、端末制御用のシーケンスは
      |   逆に端末から送られてくることは無さそうなので、それが良い。
      |   下手に使われていない private CSI は端末によっては拡張で対応している可能性がある。
      |
      |   然し、そのように考えてみると実は private CSI ではなくて ANSI CSI seq の方が良いかもしれない。
      |   と思ったが CUU, CUD, CUF, CUB などはカーソルキーで使われているし、際どい。
      |   もしかすると端末によってはその他のキーについても ANSI CSI seq と同じものを使ってくるかもしれない。
      |   しかしその危険性は private CSI の方が高いような気もする。結局 private/ansi は当てにならないので
      |   実際の実装を確認するしか無い様に思われる。vt100 の function key f1-f10 で ESC O ? が使われている。
      |   ? には P Q R S t u v l w x が使われている。これらは避ける。
      |
      |   しかし、現在では CSI による制御シーケンスは使われず、
      |   専ら ESC [ による 7 bit の制御シーケンスが使われる。
      |   従って、そんなに気にする必要もないのかもしれない。
      |
      | b 或いは 2 文字でなくても良い。
      |   <csi>27;1;2047~ などとしてこれに対して bind -x しまう手もある。
      |   しかしこの方法で問題が生じないかは疑問である。
      |
      |   と思ったが、bind -x で 2 文字以上に bind できるのは
      |   bash-4.3 以降なのでこれは駄目である。
      |
      | c うーん。或いはそもそも CSI シーケンスの形をしていなくても良いのでは。
      |   CSI シーケンスとして不正なものに割り当てるのが良い。

      ここは c を採用する事にした。

    * 次に bind を符号化方式依存にするのであるから、
      bind.sh の方も符号化方式に依存して切り替える様にするべきなのではないだろうか。

      一つの方法は符号化方式毎に generate-binder を設計するというものである。
      もう一つの方法は、現在の UTF-8 の generate-binder を元にして、
      各符号化方式毎に後付の補正を行うという方法である。
      各符号化方式毎の後付の補正にする方が管理が楽であるように思う。
      何より新しい符号化方式に対応する時のコストが小さくて済む。

      取り敢えず現在の UTF-8 用の bind の整理を行う。
      #D0583 で C-x について単純化できないか考えたができなそうだ。
      #D0584 で ESC ESC について単純化を考える。これは現在の枠組みでは不要だった。

      現在の UTF-8 用の bind で UTF-8 依存なのは以下の物である。
      bind の設定に依っては変わるかもしれないが気にしないことにする。

        ble-decode/generate-binder/bind-s '"\C-@":"\xC0\x80"'
        ble-decode/generate-binder/bind-s '"\e":"\xDF\xBF"'
        ble-decode/generate-binder/bind-s '"\e'"$ret"'":"\xC0\x9B'"$ret"'"'

    [実装1] ble-decode-attach/ble-decode-detach で符号化方式依存の物にする。

    % bind 修正用の関数を定義した。
    % ble/encoding:C/rebind 及び ble/encoding:C/unbind である。
    % 更にそれに応じて ble-decode-char+C も修正した。
    % isolated ESC にも対応している。しかしその前に isolated ESC が UTF-8 でも動作することを確かめたい。
    %
    % 同時に ble/encoding:UTF-8/rebind 及び ble/encoding:UTF-8/unbind も用意する。
    %
    % 更にこの rebind, unbind を適切なタイミングで呼び出す様にする必要がある。

    と思ったがこの ble/encoding:UTF-8/rebind の時間計測を行うと存外に遅い。
    42ms かかっている。bind のキャシュを source するのにかかる時間が 19ms である事を考えると遅い。
    やはり encoding 毎の bind キャッシュを考えるべきだろうか。やはりそうする。

    取り敢えず対応した。動いている。意外と変なことも起こらず普通に動いている。
    所で、やはり UTF-8 の binder を上書きするようにしている為に、source には多少時間がかかる。
    元々 18ms だったのが 26ms に増えている。8ms の増加である。
    まあ、UTF-8 でない変な文字コードを用いることの代償としてはそんなに大きくないので気にしない。

    ところで思ったのだけれど bind のキャッシュを生成するときに
    bind.sh のタイムスタンプは見ているが、ble/encoding:C/generate-binder のタイムスタンプは分からない。
    新しい符号化方式に対応する時には、このタイムスタンプも確認する必要がある。
    これについてはメモに記録することにする。

    [実装2] 動的に符号化方式を切り替えるときについて対応する。

    新しく ble-decode/bind 及び ble-decode/unbind を作成した。

    今回の改修で memo.txt の冒頭にある文字コード対応についての以下の記述は古くなったので更新した。

    | ble-decode.sh (function .ble-decode-bind):
    | bash-3 で "ESC [" を bind する為に ESC [ を
    | utf-8 の非正規な符号 "\xC0\x9B[" に変換している。
    | bash-4.3 で "C-@" を bind する為に \C-@ を
    | utf-8 の非正規な符号 "\xC0\x80" に変換している。
    |
    | UTF-8 以外の文字コードを使う場合には
    | これらのバイト列を特別に認識する様にするか、
    | 別のバイト列を指定する必要がある。
    | (これらは bind にハードコードされているが、
    | 外部から指定できる様に変更する必要がある。)

  * decode: <C-q><C-[> とすると ^[[27;5;91~ が入力される。 [#D0585]

    これは単体の ESC を ESC[27;5;91~ に翻訳し、
    何かに前置されてやってくる ESC を ESC で受信しているのが原因。

    <C-q> の引数として一文字読み取るのに使うためには、
    寧ろ単体の ESC を ESC として読み取って、
    Meta と解釈されるものを別の文字として受信するべきなのではないか?

    しかし、そうすると今度は <C-q><left> の方がより変な入力になってしまう。
    現状では ^[[C が入力されるがこれが ^[[27;5;91~[C などになる。
    どちらでも期待通りに入力するためには bind/decode の側で工夫しなければならない。

    | a 例えば同一の文字として解釈されるが内部的な表現の異なる UTF-8
    |   (要するに不正な UTF-8 表現) を使って両者を区別する方法。
    |   しかし、この違いは ble-decode-char まで来た時に吸収されているので、
    |   区別することはできない。
    |
    |   区別しようと思ったら ble-decode-byte:UTF-8 の中を弄るか、
    |   或いは、不正な UTF-8 表現に対して ble_decode_Erro フラグを立てて、
    |   それの有無で ESC の種類を特定するという方法がある。
    |   しかし、現状では ESC の受信には常に不正表現を使っているので、
    |   ble_decode_Erro フラグをつけるとすれば常につける事になるので良くない。
    |
    | b もう一つの方法は、ble/util/is-stdin-ready を修正して、
    |   ble-decode-byte 及び ble-decode-char で処理中の文字が残っているかどうかで、
    |   それが孤立 ESC か続きのある ESC かを判定するという方法がある。
    |
    |   こちらの方が良さそうだ。問題点としては何があるだろうか。
    |   例えば、キーボードマクロに登録されたものを再生する時は、
    |   元々孤立 ESC だったものも Meta になってしまうという問題がある。
    |   と思ったが、これについては記録する時に ^[[27;5;91~ に変換すれば良い。
    |   と持ったが、<C-q><C-[> として記録する時にはどうするのだろう…。
    |
    | c 或いは、孤立 ESC の時には、ESC に続いて
    |   無視される文字 <wait> を読ませるという手もある。
    |   つまり、ESC は取り敢えずは Meta として読ませて置いて、
    |   Meta が設定されている時に <wait> 文字が来たら、
    |   それを C-[ として ble-decode-key に伝達する。
    |
    |   何もない時に <wait> が来たら無視する。
    |   (これは <C-q><C-[> によって先頭の ESC が横取りされた時などに発生しうる。)
    |
    |   キーボードマクロに登録する時には、<wait> 文字も含めるようにすれば良い。
    |   p 等でレジスタの中身を表示するとそこに文字があることが見えてしまうが、仕方がない。
    |
    |   さて。問題はどの文字を <wait> として採用するかである。
    |   a C0 の文字でそういう意味を持ちそうな文字はありそうだが、
    |     実のところこれらは C-? としての意味を持つので、他の意味には使えない。
    |     例えば C-@ や DEL は元々は通信では無視されるものだったが、今では意味を持つ。
    |   b C1 の文字についてはどうだろうか。これはキーボードから直接入力することはない。
    |     (M-C-? で入力できる端末もあるかもしれないが、まあ ESC C-? で送ってもらうべきである)
    |     しかし、現在の実装ではコピーペーストなどによって、
    |     実際に self-insert で編集文字列の一部として入力可能である。
    |     この動作を破壊するのも難がある。編集文字列の一部になりえないのは C-@ のみであるが、
    |     これは文字列として入力されることはなく特別な操作に使われる。
    |   c Unicode の定義されていない文字を用いるというのが無難そうである。
    |     Unicode の文字を使用すると他の符号化方式に対応した時に問題になるが、
    |     他の符号化方式を使うときはその符号化方式で使われていない code point を使うことにすれば良い。
    |
    |     現状で C0 も GL も <wait> には使えないとなれば
    |     結局文字符号化方式によって大きく意味が異なる C1 か GR の領域を使わざるを得ないので、
    |     このように文字コード毎に特別な文字を確保するということは不可避である。
    |
    |     ただ文字符号化方式が C の時に限れば何処にも特殊な文字を置く場所がないので、
    |     この問題は不可避である。というかよく考えたら、現状で既に文字符号化方式 C は壊れているのではないか。
    |     →これは別項目で議論することにする #D0586
    |
    |     https://ja.wikipedia.org/wiki/Unicode%E4%B8%80%E8%A6%A7_0000-0FFF を見ると、
    |     未使用は結構あるようだが不使用ではない。つまり、将来的に何か文字が割り当てられるかもしれない。
    |     不使用の文字はずっと後ろの方にありそうである。
    |     一方で、特別な文字については余り沢山の文字を消費したくない。
    |     UTF-8 で 2 byte に収まるのは 0-800 の範囲である。7FF が良さそうだ。
    |
    |   d 或いは Unicode の場合には UTF-8 不正表現の内のどれかを特別に wait に割り当てても良い。
    |     例えば 0 (NUL) の 2 byte 表現はどうだろうか…と思ったら既に NUL を受信するのにその対処が必要だった。
    |
    | d 逆も考えうるかもしれない。つまり、孤立でない ESC の時は、その直後に <meta> の文字を挟む様にする。
    |   (vi-mode の) キーボードマクロで記録する時には常に CSI 27 ~ に M-* も含めてしまう様にする。
    |
    | e うーん。孤立 ESC かどうかを判定してキーの組み立てに影響を与えるのは ble-decode-char の中である。
    |   これは文字符号化の復号を行う ble-decode-byte よりも後段になる。
    |   という事は、ble-decode-byte を貫通して Meta の情報を伝達する仕組みは何れにしても必要である。
    |   或いは、実は Meta の時には ble-decode-byte をスキップして直接 ble-decode-char に対して、
    |   特殊な文字を送り込むという手管も考えられる。そうすれば、文字符号化方式と直交させることができる。
    |   その折にはそもそも ESC <meta> などという 2 バイトの組み合わせにする必要はなくて、
    |   単に <meta> を ble-decode-char に送りつければ良い。
    |   更に、ble-decode-char に渡される文字は既に Unicode になっている筈なので、
    |   文字符号化方式毎に <meta> のために使う特別な文字を割り当てなくてもよい。

    #D0586 で議論されている方法を用いて、上記の e の方式で行くことにする。

    % - 孤立 ESC はそのまま ble-decode-byte に入っていく。
    %   文字符号化方式が ESC を特別扱いしなければ、
    %   これはそのまま ble-decode-char に入っていく。
    %   ble-decode-char では ESC は即座に key C-[ に変換し、
    %   キーシーケンスの一部になることは防ぐ。
    %   但し _ble_decode_char__hook が設定されている時は ESC として処理する。
    %
    % - ESC ? として受信した場合は <meta> を ble-decode-char に流し込む。
    %   或いは、そもそも meta という文字を定義しなくて
    %   単に ble-decode-char/set-meta 的な関数で良い。
    %   但し _ble_decode_char__hook が設定されている時は ESC として処理する。
    %
    % 問題となるのは文字を構成するバイトの途中で ESC が現れた時である。
    % その様な文字符号化方式は (少なくとも現実的なものでは) 存在しなそうだが…。
    %
    % と思ったが、そもそも iso-2022-jp などでは文字コードの制御に ESC を用いるので、
    % 孤立 ESC でなかったからと言って処理をスキップすることは不可能である。
    % 寧ろ孤立 ESC の時こそ ble-decode-byte をスキップするべきである。

    という訳で以下のように手順を修正する。

    - 孤立 ESC は文字復号には参加せず ble-decode-char に
      <isolated-esc> として入っていく。
      _ble_decode_char__hook が設定されているとき、
      <isolated-esc> は ESC (^[) に変換してから呼び出す。
      それ以外の時はそのまま C-[ になって出ていく。
    - 先行 ESC は文字復号に参加する。例えば UTF-8 などの場合には、
      そのまま貫通して ble-decode-char に渡る。

    vi-mode のキーボードマクロに記録する時は、
    isolated-esc をどうにかしなければならない。

    | a 或いは再生時に esc を isolated-esc に変換するか。
    |
    |   % と思ったが、それだと通常のキーシーケンスも isolated-esc になってしまう。
    |   % 通常のキーシーケンスは ESC [ ではなくて CSI で始まる様にするという手もあるが、
    |   % そうすると今度は ble-bind -c で ESC 云々 として登録された物が処理されない。
    |   % と思ったが、よく考えたらそれは気にしなくても良い。
    |   % 結局キーボードマクロに記録されるのは文字ではなくてキーであり、
    |   % キーは必ず CSI 27 ~ で記録されるので ble-bind -c の設定には関係ない。
    |
    |   キーは CSI 27 ~ で記録するようにすれば問題ない。
    |   後、これに対応するためには decode で CSI に対応しなければならない。
    |
    | b 或いは、全て先行 ESC と解釈して実行してしまっても良い?
    |   と思ったがやはり不便である。<wait> 的な文字をやはり実装するべきか。
    |   しかし、その様な物を実装するくらいであれば、
    |   初めから <isolated-esc> としてレジスタに記録すれば良いのである。

    上記 a の方法を採用する。
    vi のキーボードマクロでは全て isolated-esc として ble-decode-char に送る。
    また decode は CSI 27 ~ に対応する。

    % [孤立 ESC を ESC とし、先行 ESC を <meta> として ble-decode-char に入れる案]
    %
    % ここまでの案では孤立 ESC は <isolated-esc> として ble-decode-char に入り、
    % 先行 ESC についてはそのまま ble-decode-char に入るという話だった。
    % しかし逆にするという手もあるのではないか。
    % そうすれば vi のキーボードマクロでの実装も自然になる。
    %
    % この時孤立 ESC はそのまま ESC として ble-decode-char に入り、
    % キーシーケンスの一部とはなりえない。
    % 一方で、先行 ESC は <meta> として ble-decode-char に入り、
    % キーシーケンスの一部になりえる。
    % キーシーケンスの一部ではないときは単に C-[ になる。
    %
    % と思ったが、ユーザが ble-decode-char 27 を呼び出した時に、
    % それが孤立 ESC として取り扱われ決して先行 ESC として取り扱われないのは変だ。
    % やはり先行 ESC として取り扱う方が自然なのではないのか。
    % 或いは、ble-decode-char に同時に複数の引数を指定することがあれば、
    % 一番最後の引数の 27 でなければ先行 ESC として取り扱うという手もある。
    % x しかしそれだと結局キーボードマクロの孤立 ESC を孤立 ESC として取り扱わせるために特別の処理が必要なので、
    %   孤立 ESC の方を <isolated-esc> として取り扱う手法に対する利点がなくなる。
    % x また、ble-decode-char を連ねて書く場合とそうでない場合で振る舞いが異なるのも混乱の元である。

    →やはり孤立 ESC を <isolated-esc> として取り扱う方が自然である。

    [実装1] 孤立 ESC を 0x7FF にする

    取り敢えずキーボードマクロの事はさておき、
    孤立 ESC の受信方法を変更することにした。
    孤立 ESC は U+07FF で表すことにする。ble-decode-char で適切に対応する。

    % と思ったら全く入力できなくなっている…。
    % bind -s を見てみると登録されているべきものが登録されていない。
    % と思ったらテスト用の設定がそのままになっていた。戻した。

    今度は C-[ は動くが、M-a や M-i を押した時の動きが変だ。
    うーん。今までは動いたはずである。例えば M-c は動いていた。
    bind -s の違いは \e を何に翻訳するかが異なるだけである。
    bind -X の違いはなかった。だとすると ble-decode の方の問題だろうか。
    → keylog で確認してみた所、何と ESC c a が M-a ESC a に翻訳されている。
    これは一体どういうことだろう。最後の ESC a は vi_imap/__default__ による物だろう。
    だとすると ESC c を処理する時に c が消えてしまっているのが問題だ。
    連続してきた文字の処理ができていない? と思ったが矢印などは処理できている。

    と思ったら while (($#)) を for char に書き換えたのが駄目だった。
    ループの途中で set -- "${rest[@]}" "$@" などとしている為である。
    取り敢えず動くということを確認した。

    また <C-q><C-[> がちゃんと ^[ の入力になるということを確かめた。

    [実装2] 次にキーボードマクロの為 CSI シーケンスを解釈する様にする。

    対応した。簡単だった。多分、これで大丈夫。

    今まで CSI に対応していなかった理由を探したが特に書かれていなかった。
    現在の CSI シーケンス抽出の仕組みを整える前は、
    CSI まで全て cmap に登録すると大変になるという理由で対応していなかった。
    現在では CSI シーケンスに対応しないという理由はない。
    ble-decode-char の中での処理なので UTF-8 を構成するバイトの CSI と干渉するという事もない。
    多分、大丈夫である。

    [実装3] vi のキーボードマクロに登録する時は CSI を用いるの事。

    対応した。同時に C-[ は ESC として記録する。
    再生時には ESC は ble_decode_IsolatedESC に変換する。

  * bind: ESC ESC for bash-4.1/4.2 は不要なのでは? [#D0584]

    これは #D0586 の整理の一環である。

    過去に bash-4.1, 4.2 の ESC ESC で問題が生じていた。
    これは元々 #D0055 で議論されている。

    然し、その後で ESC の方式を切り替えた。
    もしかすると、今となってはこの対策も不要になっているのでは?
    うーん。これも今は再現しない。

    再現することはできなかったが、実際の実装を見てみると、
    bind '"\e\e": "..."' に移しているのだから、
    現状の ESC の読み取りの方法と同様である。
    従って、特別にこの方法を取る必要性はない。
    現在の方法を利用している際には有効にならないように修正した。

  * bind: C-x の workaround を別の方式に切り替える [却下] [#D0583]

    これは #D0586 の整理の一環である。

    この辺りで既存の UTF-8 用の binder について整理が必要に思われる。
    観察していて気付いたのは、C-x を捕まえる為に使っている方法である。
    二文字の組み合わせで捕まえることにしている。しかし、これは本当に必要だろうか。
    実は C-@ と同様に別の文字に振り替えれば問題なく捕まえることができたりしないのか。

    % 取り敢えず、work around の原因となった問題の再現を試みる。
    % bash-4.2 と bash-4.4 と bash-3.1 で確かめる。
    % おかしい。何れを用いても再現しない。
    % この問題は例えば #D0391 などに記録が残っているがヒントはない。
    % もっと遡ると #D0148 #D0122 #D0057 #D0018 #D0017 にある。
    % C-x C-b C-b 等と入力してみてもやはり再現しない。

    →分かった。vi-mode だと発生しない。emacs mode だと発生する。
    bash-4.2 で再現した。bash-3.1 で再現する。bash-3.2 は無限ループになる。
    bash-4.0 もクラッシュする。bash-4.1 もクラッシュする。
    bash-4.3 は大丈夫。bash-4.4 はコマンドのキーマップがありませんと出る。
    まとめると以下のようになる。

    version | 症状
    --------+--------------------------------------------------
    3.0-3.1 | segfault
    3.2     | 無限ループ
    4.0-4.2 | segfault
    4.3     | 大丈夫
    4.4     | "コマンドのキーマップがありません" のエラー

    ここで別の方式に切り替える。bind -s '"\C-x": "\xC0\x98"' に変更する。
    すると C-x C-x と押しても即座に反映されなくなってしまった。何故だろう。
    以前に似た症状があった #D0395 これを確認してみたが、
    この時の原因は今回とは関係ないはずである。

    以下を実行してみてもやはり遅延は残る。
    for ((i=0;i<256;i++)); do ble-decode-bind/c2dqs "$i"; bind -r '\C-x'"$ret"; done

    結局遅延を抑える為には C-x? に bind するしかない様だ。
    そうするとクラッシュの問題は生じなくなるので気にしなくて良い。

  * vi-mode: bug, キーボードマクロで Meta が正しく記録されていない [#D0582]
    #D0586 周りの考察をしている時に見つけた。直した。

2017-11-10

  * 2017-11-08: vi-mode (nmap K): ページャの表示の問題 (reported by cmplstofB) [#D0581]

    * 再描画の実施

      | - 再描画を実施するように変更する。
      |   どのページャも常に altscreen を使用するとは限らないということ。
      |
      |   但しヘルプを表示する度に新しい行に移動するのは嫌なので、
      |   一旦現在表示している内容を消去してからヘルプを呼び出し、
      |   その後でまた再描画するようにする。
      |
      | - cmplstofB さんの報告によると:
      |
      |   > 私は Xfce4 Terminal [1] を使っているのですが，この仮想端末は xterm-256color
      |   > を terminfo として用いており，xterm-256color の terminfo ではきちんと
      |   > alternate screen は有効になっておりました。
      |
      |   だとすると、複数画面に亘る時に空行になってしまう問題の原因は altscreen off ではない?
      |   何故なのかよく分からないが、取り敢えず毎回再描画することにすれば何れにしても解決する気がする。
      |
      | leave/enter と編集文字列の消去と再描画を実施するようにした。
      | しかし、現状の実装だと man に失敗する場合でも
      | 編集文字列の消去と再描画を実施するようになっていて気になる。
      | 本来であれば man が成功して何か表示できると分かった時点で再描画を実施したいものである。

      PAGER を設定できるようにするのであれば、何れにしても完全に対応しなければならない。
      従って、ヘルプを表示する前に消去して、ヘルプを表示した後に再描画する。

    * stty で leave/enter をちゃんと実施する。
      man はキーボード入力を求めるが、これが操作不可能になってしまう。

      > これも私の設定の問題ですが，$MANOPT に --all 等の値を設定していると，
      > ble.sh と man ページが競合するか何かしてキー入力が受け付けられなくなります。

      多分、これはこの leave, enter が原因なのである。
      もしかすると違うかもしれない。実装後に確認が必要である。
      →実際に leave/enter を呼び出すようにした所直った。

    * 日本語 man の内容を正しく取得する方法?

      | 問題点は何処にあるかというと $(man ...) もしくは、man > ... として実行すると、
      | man の日本語見出しが壊れてしまうということと man の太字などの修飾が消滅してしまうということである。
      | なので、現在は成功するかどうかわからない man をいきなり実行する様にしている。
      |
      | a 一つの方法は、一回 man ... &>/dev/null を実行して成功するかどうか確かめて、
      |   その上で man を再度実行するというものである。これは二回 man を呼び出すので遅い。
      |
      | b 或いは PAGER='...' もしくは man -P '...' に cat などを指定して
      |   何処かにデータを書き出してしまえば良い。
      |   しかし POSIX man ではその様な規定はないので、
      |   これが実際に使えるかどうか分からない。
      |
      |   PAGER 指定が無効な man の為に PAGER=... man > file などとすると、
      |   また日本語見出しが壊れたり太字などの情報が消えたりする。
      |
      | c 別の方法として仮想端末を新しく作るという方法はあるかもしれない。
      |
      |   exec 9<>/dev/ptmx で 9 に開く。
      |   pty=$(tty <&9) でスレーブのファイル名が分かる
      |   grantpt は chown $UID $pty; chmod 620 $pty とすれば良い。
      |   unlockpt は分からない。
      |
      |   と思ったが tty <&9 では /dev/ptmx が得られるだけだった。
      |   slave のファイル名が分からないので開けない。
      |   検索してみても shell で同じことを実現しようとしている人は見つからないし、
      |   また Python でも似たことを挑戦しようとしている質問では、
      |   ptsname, grantpt, unlockpt の手段がないということで、
      |   専用のライブラリ pty を import して使うことを薦められている。
      |
      | しかし改めて考えてみると run-help 的な枠組みに対応するのだとしたら、
      | 何れにしても成功するのか失敗するのかは外側からは分からない。
      | 結局、毎回消去してヘルプの表示を試行して再描画するということになる。
      | 一応 run-help 的関数が定義されていない場合には、
      | 無駄な消去・再描画がないように頑張れるが、構造的に面倒だ。
      | 毎回消去・再描画がある方が自然な実装になる。

      結局日本語 man の中身を正しく抽出する方法は不明である。
      しかし (遅いが) 一応動いているので取り敢えずよしとする。

    * run-help 的関数は complete の枠組みと統合するべきか。

      | そもそも未だ実装していないが complete の枠組みとして以下のようなものが構想にある。
      | 現状では補完関数は専ら組み込みの complete によって設定されるものだけであるが、
      | より分かりやすい枠組みとして ble/complete/コマンド名 という関数を通して定義できる様にする。
      | 或るコマンドの引数を補完する時は、その関数が定義されていればそれを使う。
      | また、"${BLEPATH:-$_ble_base}/complete/コマンド名" が存在すればそれを
      | source して定義された関数を使う。
      | それでも見つからないときは従来の complete による枠組みを使用する。
      |
      | 同様に、引数の色つけ関数も考えうる。
      | 例えば ble/color/コマンド名 というシェル関数で定義できる様にして、
      | "$BLEPATH/color/コマンド名" というファイルも探索する様にするとできる。
      |
      | しかし、機能毎にファイルを配置するのは大変だし、
      | 恐らく実際の設計上はやはり同じファイルで補完も色つけも定義したい。
      | その様に考えれば "$BLEPATH/command/コマンド名" 的なファイル名にして、
      | 更に、ble/command/complete:mycmd, ble/command/color:mycmd などという関数名にする。
      |
      | % また、引数の補完ではなくて標準入力 (ヒアドキュメント) の補完といった物も考えうる。
      | % →これは新しい関数として定義するというよりは ble/command/complete:mycmd に、
      | %   特別な引数を指定して呼び出すというのの方が良いような気もする。
      | と思ったが、恐らく complete:mycmd を実装する時には
      | そのような滅多に実装しない様なものの為に毎回条件分岐するのも面倒なので、
      | ここはやはり独立した関数として提供するべきである。例えば、
      | ble/command/complete-stdin:mycmd
      |
      | 更にリダイレクト先のファイルの補完も同様に処理できる。
      | ble/command/complete-redirect:mycmd
      |
      | この延長で ble/command/help:mycmd というのを入れるのは妥当である。
      |
      | 所で名前空間 ble/command に関してはもう少し考察の余地がある。
      | この名前空間は実際に補助のファイルを配置するディレクトリの名前と合わせたい。
      | $BLEPATH/command/mycmd というファイル名があると、
      | 其処に実際のコマンドを格納するみたいである。なので、command ではないより良いものが欲しい。
      | 例えば terminfo の様に commandinfo もしくは cmdinfo とするのはどうだろうか。
      | cmdinfo は省略形なので余り好まれないかもしれないと思ったが、
      | 実のところ commandinfo の時点で command-information の略である。

      従って cmdinfo で良いような気がしてきた。以下のような感じにする。

      ble/cmdinfo/complete:mycmd
      ble/cmdinfo/complete-stdin:mycmd
      ble/cmdinfo/complete-redirect:mycmd
      ble/cmdinfo/color:mycmd
      ble/cmdinfo/color-stdin:mycmd
      ble/cmdinfo/help:mycmd
      ble/cmdinfo/help-stdin:mycmd

      結論としては即座には統合しないが、将来的に統合するときのために関数名だけは決めておく。
      ble/cmdinfo/help:mycmd という事にする。

    * ble/cmdinfo/help:"$cmd" と ble/cmdinfo/help に対応する。
      対応した。動作テストはしていない。

    * テスト項目

      - done: bash builtin
      - done: bash keyword
      - done: bash [[
      - done: alias resolve
      - done: function

  * 2017-11-08 command-help: bash 組み込みコマンドの man (suggested by cmplstofB) [#D0580]

    > $ # K --> function-for-help test --> man -P 'less $LESS -p ^test' bash

    そのままだと動かない。少し工夫が必要である。

    man bash | \grep -n '^[[:space:]]*test' | awk '/^([0-9]+)/ {sub(/[^0-9].*/, "");print;exit}'

    結局色々試した挙句複雑な実装になった。
    ble/widget/command-help/.locate-in-man-bash に実装した。

  * vi-mode (cmap): isearch している途中に決定を押すとその内容が実行されてしまう。 [#D0579]
    調べると ble/widget/isearch/accept の中で ble/widget/accept-line を呼び出している。
    これは駄目。仕方がないので、ble-decode-key "${KEYS[@]}" を呼び出すことにした。
    isearch では C-m で確定である。同様に呼び出し元でも C-m が確定であると想定して良い。
    だとすれば、そのまま "${KEYS[@]}" を呼び出しておけば問題ないだろう。

  * decode: bug 'unset var[index]' が failglob/nullglob で全滅する (reported by cmplstofB) [#D0578]

    > あと，もう一つ細かいのですが，failglob を有効にしていると，l* のようなコマンドを入力した場合，
    > (決定キーを押下する前に) 「-bash: 一致しません: _ble_decode_keymap_stack[last]」というエラーメッセージが出ます。

    failglob は厳しい。浮いている [] があるともう駄目だ。
    というか nullglob の時は何もメッセージを出さないので、なおたちが悪い。

    unset _ble_decode_keymap_stack[last] が駄目になっていた。

    類似のものがないか検索する。

    grc 'unset [[:alnum:]_]+\[|^[^][#"'\''`{}()]+\[[^[]'

    どうも unset は全て確認したほうが良さそうな感じがしている。
    他に ble-bind -f C-[ となっている物が vi.sh の中にある。
    これは大丈夫かもしれないが念のため囲むことにする。

    更に、この問題は過去の version にも波及する。修正が必要である。
    これは一応探してすぐ分かるところは直した。

2017-11-09

  * vi-mode (cmap): 履歴に対応 (requested by cmplstofB) [#D0577]

    現状の履歴の仕組みはシェルのコマンド履歴 history とくっついている。
    これを分離しなければならない。実際の変更はそんなに大変ではないだろう。
    ただ、それぞれの変数の役割を特定するのは面倒である。

    | 何れにしても一つずつ調べていくしかない。
    | 恐らく履歴に関係しているのは _ble_edit_history* という変数のみである。
    | この名前の変数は幸いなことに ble-edit.sh において、
    | ./ble-edit.sh:4248-4982 に固まって存在している。
    |
    | 以下の変数はコマンド履歴と関係なく必要な変数である。
    | 使われ方も共通で良さそうに思われる。
    |
    | _ble_edit_history=()
    | _ble_edit_history_edit=()
    | _ble_edit_history_dirt=()
    | _ble_edit_history_ind=0
    |
    | * 以下の変数と関数もコマンド履歴とは独立に対応するべき気がする。
    |   従って、そのまま利用できるようにする。
    |   但し、onleave.fire で呼び出された関数で変なことにならない様に注意する。
    |   これは keymap を見て vi_cmap だったら何もしないという事で対処できそう。
    |
    |   _ble_edit_history_onleave=()
    |   ble-edit/history/onleave.fire
    |
    |
    | * 以下の変数は危険である。これが空欄の時にはコマンド履歴を呼び出してしまう。
    |   コマンド履歴ではない時には、これらの変数は空白であってはならない。
    |   これらが非空白であればコマンド履歴は呼び出されない。
    |   というか _ble_edit_history_loaded だけ注意していれば良さそうだ。
    |
    |   _ble_edit_history_loaded=
    |   _ble_edit_history_count=
    |   ble-edit/history/getindex
    |   ble-edit/history/getcount
    |   ble-edit/history/load
    |
    | * 以下の関数はコマンド履歴に追加を行うので、
    |   コマンド履歴以外では呼び出してはならない。
    |   現在は accept-line の一箇所でしか呼び出していないので
    |   それ程気にしなくても良いが、名前を変えるなどする必要がある。
    |
    |   ble-edit/history/add
    |
    |   これは ble-edit/history/add-command-history に改名した。
    |   単に追加を行う関数として ble-edit/history/add を追加した。
    |
    | * isearch 関係の関数は殆どコマンド履歴と直交している。
    |   isearch keymap に入る瞬間の以下の widget で
    |   ble-edit-/history/load を呼び出しているが、
    |   これは _ble_edit_history_loaded だけ注意していれば良い。
    |
    |   ble/widget/history-isearch-backward
    |   ble/widget/history-isearch-forward
    |
    | うーん。状態変更にどのように対応すれば良いだろうか。
    |
    | a 初めに考えたのは history に関連する widget それぞれについて、
    |   cmap/history-* のような新しい widget を作って、
    |   その中でローカル変数を設定して _ble_edit_history_* をすり変えて、
    |   その上で各関数を呼び出すという物である。
    |   呼び出した後は、変更のあったものについては
    |   自前の履歴変数に書き戻すなどする。
    |
    |   しかし widget 毎に一つ一つ用意するのは非効率的である。
    |
    | b なので @vi_cmap-history などの修飾 widget を作成しても良い。
    |
    |   それでも色々と面倒はある。
    |   例えば、isearch は特別の keymap を用いるので、
    |   cmap で isearch を利用しようと思ったら、
    |   isearch keymap の clone を作成しなければならない。
    |
    |   - これは色々問題が残る。先ず、似たような履歴を持つ編集モードの
    |     それぞれについて isearch の clone を作らなければならない。
    |   - 更に、isearch キーマップを変更しても、それは clone には適用されない。
    |     全ての isearch clone たちに対して同様の変更を適用する必要がある。
    |     これは場合によっては有用かもしれないが、非直感的であるということの方が勝る。
    |
    |   また、一様に状態を復元し・保存しということをすると、
    |   毎回全項目について状態を保存しなければならず非効率的である。
    |   大体の場合は履歴移動しかしないのだから、履歴番号だけ書き戻せば十分のはずである。
    |   % と思ったが、history 云々のコマンドからは、元から履歴番号だけしか書き戻さないかも。
    |   履歴番号だけしか書き戻さなくて良いかどうかは
    |   history, isearch の実装の方が知っているはずなのでそちらに任せたい。
    |
    | c やはり history, isearch 側で代替履歴の存在を
    |   認識する様に実装するほうが自然に思われる。
    |
    | ここは c で行く事にする。先ず初めに _ble_edit_history_prefix という変数を定義する。
    | 幾らか実装したが、すり替えによる実装は混乱が大きい。
    | 先ず、どの関数がすり変えたことが前提になっていて、
    | どの関数が何も考えずに呼び出せるのかが分かりにくい。
    |
    | 更に、或る関数が、すりかえを実行している関数とすり替えを
    | 実行していない関数の両方から呼び出されているとき、
    | どの様に処理をするのかが謎である。
    |
    | a 関数がすり替えを実行する時に local _ble_edit_history_prefix= とする?
    |   その様にすれば呼び出された関数が重複して復元・記録を行うことはなくなる。
    |
    |   しかし、これは何を意味するかというと使用しない変数も含めて
    |   全ての変数を復元・記録するということになる。
    |   或いは、どの変数がすり替えられていてどの変数がすり替えられていないかについて
    |   一つ一つの関数について決定して、それに基いて注意深く実装するということも
    |   原理的には可能だが、これは言語道断の実装である。
    |
    | b 或いは、二重にすり替えが起こっても大丈夫な様に設計を行う。
    |
    |   すり替えが実際に実施されていたとしても、
    |   変数の内容を書き換えたりしていない限りは、
    |   元の変数の方にアクセスしている限りにおいては問題はない。
    |
    |   従って、search-history などの関数において、
    |   内部で変数を _ble_edit_history_edit にロードしていても、
    |   何も考えずに他の対策済み関数を呼び出して良い。
    |
    |   関数に対する要請は以下の通りになる。
    |
    |   1. prefix が設定されている時には本来の変数 (コマンド履歴) にはアクセスしない。
    |   2. ローカル変数にロードしてすり替えを行う時には、変数の中身に対する変更はしない。
    |
    | c 或いは、外部から直接呼び出せる関数に制限をかける。
    |   その関数を呼び出した時に、全変数をすり変える。
    |   外部からも内部からも呼び出す関数については、
    |   外部から呼び出すための物と内部から呼び出すものの二つを用意する。
    |
    |   x この方法は重そうだ。
    |     調べてみた所、変数のすり替えが必要になりそうな関数は、
    |     内部に履歴のループを含む {for,back}ward-search-history 系の関数のみである。
    |     そして、この関数は 1 回の呼び出しで何度も呼び出されるものではない。
    |     寧ろ、恐らく1回しか呼び出されない。
    |     従って、全変数を毎回すり替えるとういことをしても速くはならない。寧ろ遅くなる。
    |
    |
    | ここは b の方向で実装することにする。
    |
    | - すべての関数は prefix の値に応じて適切な変数を参照・設定して動作するようにする。
    | - すり替えによる実装はできるだけ避ける。
    | - すり替えを実行して効率化を測る関数の場合には、
    |   その関数自体は履歴情報に対して副作用を持たない。
    |   また、そこから呼び出す関数も履歴情報に対して副作用を持たない。
    |
    |   この時、実はすり替えをしていたとしても、
    |   その他の関数を安全に呼び出すことができる。
    |   また、その関数で直接使う変数のみすり替えれば十分である。

    取り敢えず修正した。これで _ble_edit_history_prefix の値に応じて対象の履歴を切り替えられる様になった。
    実は未だ vi.sh にも _ble_edit_history* を触るコードがあるが、
    これらは全て本体のコマンド履歴を操作するための関数であり、
    再利用する予定も (今のところ) ないので、このままで良い。

    次に cmap に入る時と出る時に _ble_edit_history_prefix を設定・解除する。
    また出る時に履歴項目を追加して最後の位置に移動する。
    その様に設定した。動いている様に見える。
    但し、未だ keymap に登録を行っていなかった。

  * edit: C-r で即座に履歴をロードしようとするが、 [#D0576]
    実は、現在の履歴項目に一致が見つからないということが分かってからでも遅くないのでは。

    →これの対応は実は簡単だった。既に _ble_edit_history* に直接触るのは
    backward-search-history-blockwise, forward-search-history.impl 関数に限られていた。
    ここで ble-edit/history/load を呼び出す様にすれば、
    isearch に入る時の ble-edit/history/load は必要なくなる。
    多分、これで動いているような気がする。

  * vi-mode (cmap): bug C-[ でキャンセルできない (reported by cmplstofB) [#D0575]

    vi_cmap/define を見てみると登録されている。しかし、実際に実行してみると動かない。不思議だ。
    と思って ble-bind -d で見ると bell になっている。
    実は、vi_cmap/define の下の方で上書きされていた。修正した。

2017-11-08

  * 2017-11-01 vi-mode: キーボードマクロ対応 [#D0574]

    | 挿入モード繰り返しの quoted-insert 対応に関連して、
    | 繰り返し機能とキーボードマクロの整合性について考察した。
    | 結論は両者 (キーボードマクロ vs 挿入モード繰り返し) は独立に実装するべきとなった。
    | その時に調べたキーボードマクロの振る舞いと対応方法の可能性に関する議論をここに残す。

    さて、矢印キーなどの操作をした時にレジスタにどの様に記録されているのかを調べる。
    →どうやら右矢印は <80>kr という文字列に変換される様だ。実際に正しく再生することもできる。
      これは端末から渡される文字列とは異なることに注意する。
    - つまり、一旦 key から文字の列に逆に戻すという過程が入っている様に思われる。
      特に2文字目と3文字目が通常の文字であることから矢印キーを UTF-8 の特別な文字に割り当てていることによって
      そのまま文字列にしたら文字化けしているということではなくて、
      むしろ明示的に key を文字の列に符号化していると思われる。
    - 因みに "xp とすればその中身を直接挿入することができる。
      <80>kr という部分を選択して "by して、@b として再生するとちゃんと右矢印として解釈される。

    うーん。面倒なので ble.sh では矢印キーはそのまま kcode に対応する UTF-8 で文字列に埋め込んで良い気がする。
    但し、その為には c2s で矢印キーに対応する文字を生成できる必要がある。
    これは UTF-8 環境ではできることが明らかであるが C などの環境ではできない。
    また将来的に別の文字コードに対応するときにも毎回問題になる。
    その様に考えると特別なキーシーケンスを与える必要があるのかもしれない。

    取り敢えず対応した。

    - 通常の文字はそのまま記録
    - C-@ C-[ を除く制御文字が対応するキーは制御文字で記録
    - その他は "ESC [ 2 7 ; * ; * ~" シーケンスで記録
    - @: には対応していない。これは bind -f '@ :' で登録することにする。
    - 無限ループを防ぐためにマクロの中でマクロは呼び出せない

    * 無限ループの問題について。
      実際の vim でやると本当に無限ループになる。
      C-c をすると中断することができる。

      ble.sh ではどのように実装するか。
      stdin を確認してもし何かあればその時点で
      マクロの中でマクロ呼出しができなくすれば良い。
      stdin を確認できない bash-3.0 未満では、
      常にマクロの入れ子呼び出しはできないことにする。

      或いは最大の再帰の深さを設定すれば良いのではないか。
      →再帰の深さを設定できるようにした。

      これで正しく動作するだろうか。

    ? checked: 現在は accept-line の直前に記録を完了する様にしている。
      他にそのような対策が必要な箇所はあるだろうか。
      これは keymap を観察して見れば良い。
      簡単に確認したところその様な箇所はない様に思われる。

      一つ気になるのは :commandline を実行している間の操作だが、
      vim で試してみると、その間の操作も全て記録されている様なので問題ない。

    x fixed: 実際のキーボード入力と、再生または再度のやり直しによるキーボード入力が
      重複して実行されないように後者が登録されないようにする必要がある。

      % vi.sh については ble-decode-* の呼び出しの前に、
      % ローカルに _ble_decode_keylog_enabled= を設定する様にした。
      %
      % 実は他の場所で定義されている widget についても同様に対策する必要があるのではないか。
      % 調べてみると ble-edit.sh に同様に ble-decode-key を呼び出している箇所があった。
      % この場所でも _ble_decode_keylog_enabled= を設定するようにした。
      %
      % しかし考えて見るにもっと根本的な対策が必要なのではないか。
      % つまり keylog を記録する側で、それがキーボードからの入力なのか、
      % 或いは、更なる呼び出しによるものなのかを判定する様にしても良いのではないか。
      %
      % もう一つ気になるのは、ローカルに _ble_decode_keylog_enabled= を設定した状態で、
      % 更に qa でマクロの記録を開始した場合にどうなるのかという事である。
      % 結果として、書き込み先のレジスタがすりかわるという事が起こる。
      % また、もっと悪いことに q で記録を停止することができなくなってしまう。
      % (M-q をもってノーマルモードに戻ると共に記録を停止するなどのことができない。)
      %
      % % これについては、現在マクロを記録中かどうかは、
      % % _ble_decode_keylog_enabled 変数ではなくて、別の変数を用いるというようにすれば良い。
      % % それでも未だ問題は残る。例えば end-logging が中で呼び出された場合に、
      % % ローカルの _ble_decode_keylog_enabled のみが解除される。
      % % 関数を抜けると再び logging が開始してしまう。

      ローカルに設定した _ble_decode_keylog_enabled= ではなくて、
      もっと別の仕組みによって重複して実行されるコマンドを防ぐ必要がある。
      それも ble-decode の内部で完結した方法が良い。
      例えば、widget を呼び出す時に、何らかの特別な変数を設定すれば良い。
      _ble_decode_keylog_suppress という変数を導入することにした。
      また、外部で手で _ble_decode_keylog_enabled= を指定している部分は削除する。

      今度の仕組みを使えば上記で述べたような問題点は発生しないだろう。

      o 5i12<C-[> としても 12 がたくさん登録されるなどのことはない。
      x M-q が C-[ q に分解されてから改めて実行された場合でも、
        C-[ q が二重に実行されるということはない…。

        % と思ったが、確認してみると <C-[> が登録されている? と思ったら、
        % そうではなくて単に M-q がその 27 表現として記録されているだけだった。
        % いや。改めて 27 表現を調べてみると <M-q> としてではなくやはり <C-[>q として記録されている。
        % 変だ。と思って再度試してみると、ちゃんと期待通りの振る舞いになっている。大丈夫。
        % しかし別の問題があることが分かった。これは別項目を立てる。

    x fixed: 現在、KEYS に入っているキーの数だけ pop して内容を記録しているがこれは正しくない。
      _ble_decode_keylog_suppress が設定されて呼び出された時 KEYS は本来と異なる値になっている。
      →これは次の項目と一緒に解決した。

    x fixed: M-q などを用いてロギングを中断した場合に <M-q> が全て記録されない。
      <M-q> が <C-[>q に分解されて <C-q> の部分だけは記録されてほしいのにも拘らず、である。
      その様な場合にはどの様に処理したら良いのだろうか。
      これは _ble_decode_keylog_enabled とはまた別の問題である。

      % むしろこの場合こそ KEYS を pop するべきなのではないか。
      % そして _ble_decode_keylog_suppress=1 の時には pop を行わない様にする。
      %
      % また、_ble_decode_keylog_suppress= にして記録が行われるようにする…
      % と思ったがこの対処は本当に正しいのだろうか。
      % 例えば直接ユーザの入力から decompose-meta が呼び出された場合には、
      % _ble_decode_keylog_suppress= により記録が実施されるようにすれば良い。
      % ところが widget A から ble-decode-key を通して decompose-meta が呼び出された場合には、
      % 先ず初めに pop が起こらないというのは良い。
      % しかし、次に _ble_decode_keylog_suppress= を解除してしまうと、
      % widget A によって生成された仮想的なキー操作が記録されてしまう。駄目だ。

      思ったが上記の方法には色々問題がある。
      先ず初めに _ble_decode_keylog_suppress=1 の時には pop を行わないと書いたが、
      widget の呼び出し中は常に _ble_decode_keylog_suppress=1 なのだから、
      _ble_decode_keylog_suppress の値は当てにならない。
      思うに _ble_decode_keylog_suppress の値は整数値にして入れ子のレベルを表す様にするべきなのだ。

      →_ble_decode_keylog_suppress は _ble_decode_keylog_depth に改名して、
      入れ子のレベルを保持することにした。
      そして _ble_decode_keylog_suppress == 1 の時にのみ pop を行うことにして、
      更に decompose-meta では _ble_decode_keylog_suppress を 1 だけ減ずることにした。
      また記録は _ble_decode_keylog_suppress == 0 の時にのみ行う。

    ? fixed: レジスタの中に qa...q が含まれている場合にそのレジスタを再生するとどうなるのか。
      ... がレジスタ a に記録されるのか、
      それとも実際のキーボード入力がユーザからされる訳ではないので a は空文字列になるのか。
      更に qb などとして別のレジスタへの記録を実行している途中に @c (中身 qa...q) などとして、
      別の記録を開始した時の振る舞いもどうなるのか気になる。a. 前の記録が中断されるのか、
      b. その時点で終了するのか、c. 記録が入れ子になるのか。記録が入れ子になるのだとしたら、
      内側の記録の内容は c1. 外側の記録にも反映されるのか c2. 外側の記録からは抜けるのか。

      →実際に試してみると再生中には q は全て失効しているようだ。
      特に qa...q という組があったとしても a... が実行されたのと同じ結果になる。

      さて 12qa...q とした時には引数 12 は捨てられるのか、それとも a に渡されるのか。
      →試してみると a には引数は渡らない。つまり、q を押しても全く何も起こらないのではなくて、
      引数などの消費は行われるという事である。

    x fixed: 何故か既定のレジスタにも値がコピーされている。
      これは register#set を用いているのが行けない。

      そもそも register#set を使う必要はないのではないか。
      と思ったが追記の時に何が起こるのかは非自明である。
      もしかすると通常の "Ay 等による追記と異なる振る舞いをするかもしれない。
      ("Ay の時には既にレジスタに登録されている内容の種類 char, line, block かによって
      追記のされ方が異なっていた事に注意する必要がある。)
      →確かめる。うーん。何か不思議なことになった。動作を詳細に調べる。

      | | - 先ず行指向で A^JB^J という内容にしておく。
      | |   ここで v{motion}"Ay で文字列を追加すると A^JB^JC^J という内容になる。
      | |   更に、qAihello^Cq としてキー操作を追記すると A^JB^JCihello^C^C^J という内容になる。
      | |   どうやら最後の改行の直前に追記されるようだ。
      | | - この後に v{motion}"Ay で追記するとちゃんと ^J の後に追記される。
      | | - <C-c> 単体でも ^C^C と記録される様だ。^V は重複しない。
      | |   ^V 中の ^C も重複する。というか別に追記でない時でも ^C は重複する。
      | |   これについては別項目で調べることにする。
      | | - 行指向でそのまま qAihello^[q としたらどうなるか。
      | |   →やはり改行直前に挿入される。
      | | - 挿入した後のレジスタの性質は変わるか。つまり p が行指向挿入になるか。
      | |   →なる。行指向のままである。
      |
      | つまり行指向レジスタに追記する時は改行の直前に挿入される。
      |
      | | - 矩形の場合には最後の行に追記される。新しい行ではない。
      | | - また q で追記した後も矩形挿入のままである。
      |
      | | - 文字指向の場合はそのまま追記される。文字指向のまま。
      | | - 文字指向の時に末端に改行がある時でも、そのまま追記される。文字指向のまま。
      |
      | - 実は追記の場合には同時に既定のレジスタにも変更後の値が設定される。

      まとめると、

      - マクロの登録の場合には記録先レジスタの他に "" にも登録されるということはない
        但し、例外として、追記の場合には "" にも登録される。
      - 行指向のレジスタに追記するとき、最後の改行の直前に挿入される
      - 矩形指向のレジスタに追記するとき、最後の行に追記される。
        文字範囲を追記したときの様に新しい行に追加される訳ではない。
      - 文字指向のレジスタに追記する時は通常と同様に、ただ追記する。
      - 何れの場合でも追記先のレジスタの指向を変えることはない。

    ? ok: vim では記録中に押された ^C は重複して記録される。何故か?
      ble.sh では当然その様にはなっていない。もう少し詳しく調べる。

      例えば、i<C-q><C-c><C-[> と操作した時にはどうなるのだろうか。
      試してみるとこの場合には ^C は単体で記録されるようである。
      ということは無条件に ^C が二重化される訳ではない。

      うーん。これはどういう事だろうか。キャンセルとしての C-c
      が内部で呼び出さされるともう一度 C-c を実行する等のことが
      内部的に実行されているのだろうか。謎である。

      これについてはよく分からないので、ble.sh では取り敢えずは ^C は
      実際に入力されたとおりに 1 個だけしか記録しない様にする。

  * vi-mode: 実は以下で ggvj"ay とすると echo^J^J がレジスタに登録される。 [#D0573]

    % | echo$
    % | $
    % | $
    %
    % これはどういう事だろうか。一番最後の行で同様に試してみた所、echo^J だった。
    % つまり、空行の末端で実行するとそこにある改行まで含むという事になる。
    % 最後の行にいる時にはそこに改行がないので含まれない。
    %
    % | echo$
    % | $
    % | ~
    %
    % というかそもそも以下で vjd とすると二行消える。
    % つまり、ビジュアルモードに置ける範囲というのは行末の改行も含むという事。
    % しかも、今調べると現在の ble.sh 実装でもちゃんとその様になっている。
    %
    % | echo$
    % | $
    % | hello$

    これは現在の ble.sh の実装でもそうなっているので気にしなくて良い。

2017-11-05

  * 2017-11-03 edit: command-help [#D0572]

    現在の文脈に従ってコマンド名を抽出して調べる。
    実のところ、complete 辺りで似たようなことをしているはずだから、
    簡単に実装できるはずである。

    ble-syntax.sh の syntax-complete の辺りを見ると
    先ず初めにただ単に文脈によって argument だとかを返しているだけである。
    complete.sh の方を覗いてみると、
    ble-complete/source/argument/.compgen で
    ble-syntax:bash/extract-command "$index" を呼び出している。
    この関数は変数 comp_cword comp_words comp_line comp_point を設定する。

    対応した。--help よりも man の方を優先する様に変更した。
    また man の出力をパイプに流すと日本語の見出しが変なことになるので、
    man を直接起動することにした。man の標準エラー出力は /dev/null に捨てる。

  * vi-mode (nmape * #): 単語の検索に対応するということ [#D0571]

    * をおした時カーソルの下に単語 (WORD) があればそれを検索する。
    行内の forward に単語があればそれを検索する。
    http://vim-jp.org/vimdoc-ja/pattern.html#star には keyword か WORD と書かれているが、
    実際にテキストファイルで試してみると word である。WORD ではない。
    として、ソースコードのなどの編集を考えると WORD は不便である。
    word でなければならない。従って ble.sh では word で対応する。
    :help star で確認してみると WORD とは書いていなくて non-blank word と書いている。誤訳か?

    | 実のところ bash の正規表現では \<\>\b しか使えず、
    | これらの振る舞いを自由に変更することは敵わない。
    | 従って、bash の定義する単語にするしかない。
    |
    | 先ず初めにどの様にして単語を抽出すれば良いか。
    | 例えば \<(.\B)*.\> などとすれば内部に単語区切りを含まない単語を抽出できる。
    | 現在のカーソルの下にある文字が単語を構成する文字かどうかを判定するにはどうすれば良いか。
    | 実は (.\B)*. の様な面倒なことをしなくても判定する方法があるのではないか。
    | これには POSIX ERE を調べる必要がある。というか調べたら BRE/ERE には \b, \B, \<, \> はなかった。
    | 然し bash の正規表現では確かにこれらの演算子を使うことができる。
    | ということは bash の正規表現はどの正規表現なのか? Bash のマニュアルには何も書かれていなかった気がする。
    |
    | 昔作った表によると \b\B\<\> に対応しているのは GNU grep -G/-E および GNU Emacs, それから Perl 5 である。
    | 大分限られている。という事は bash の実装は GNU Regexp もしくは独自エンジンと考えられる。
    | 調べてみると lib/sh/shmatch.c から regex を呼び出している。
    | 実は POSIX の header regcomp/regexec を呼び出しているだけだった。
    | という事は \b\B\<\> に対応しているかどうかは非自明である。環境依存という事になる。

    [結論] つまり Bash の正規表現は <regex.h> regcomp/regexec による物で ERE にないものは環境依存。
      また [[:alpha:]] などの文字クラスも環境依存・ロケール依存である。

    - ok: 因みに今までの実装で \b\B\<\> を使っているとそれは対策を考える必要がある。
      と思ったが実際に検索してみると今までは \b\B\<\> は使ってこなかった様だ。問題ない。

    | さて、もう少し vim で試してみると /// などには一致しない。
    | 確かにこれは \<\> で囲んでも一致しないので除外するべきである。
    | その様に考えると vim でも既に w や W で定義される word や WORD
    | とは異なる種類の "単語" である (それでも word に近いが)。
    | という事は ble.sh でも厳密に対応する必要はない気がする。
    |
    | 取り敢えず \<[[:alnum:]_]+\> で捕まえるというのはどうだろうか。
    | 更にいうと手許の環境で試してみた所 [:alnum:] で平仮名などに一致する一方で、
    | \b\B の方も平仮名と英数字の間を単語の内部と判定している。
    | \b\B\<\> が一体どのようなものかについて定義はあっただろうか。
    | 例えば POSIX awk での定義はどうなっているだろうか。
    | 調べてみたら実は POSIX awk でも単語境界演算子は定義されていなかった。駄目だ。
    |
    | 仕方がないので \b\B\<\> が定義されている別の環境ではどのように実装するのが普通なのか調べる。
    | 取り敢えず GNU/Linux の <regex.h> の振る舞いは全て共通と仮定して良い。
    | だとすれば恐らく [[:alnum:]_] とそれ以外の境界が単語境界である。
    | perlre では \w とそれ以外の境界が単語境界ということになっているが、
    | \w の意味については明記されていない。ロケールや設定に依存すると書かれている。
    | 例えば /.../a というオプションを指定すると ASCII の [:alnum:]_ に制限されるとも書かれている。
    | 因みに ES8 だと 21.2.2.12 で \w は WordCharacters() と書かれている。22.2.2.6.1 を読むと、
    |
    |   WordCharacters() = {c | Canonicalize(c) in [a-zA-Z0-9_]},
    |   (Note: 但し Unicode && IgnoreCase のとき以外は [a-zA-Z0-9_] になる)
    |
    | である様に思われる。Canonicalize は 21.2.2.8.2 で定義されている。
    | Unicode && IgnoreCase のときは Unicode データベース CaseFolding.txt に従って変換されるそうだ。
    | しかし、これは大文字小文字の変換であるような気がするので、実のところ [a-zA-Z0-9_] なのか?
    |
    | まとめ
    |
    | vim の実装は \<\> を使って定義される "単語" である。
    | Bash 正規表現について \b\B\<\> に対応していない環境もある。
    | 対応している環境の場合には、これらの演算子は
    | "単語を構成する文字とそれ以外の文字の境界" として実装されると見て良い。
    | 単語を構成する文字は環境依存であるが、
    | a [a-zA-Z0-9_] のときと
    | b [[:alnum:]_] のときと
    | c 更にこれを Unicode に拡張したもののときと、
    | d perlre の様に名言を避けているとき
    | の4種類がある。GNU/Linux <regex.h> では \<\> は b で対応しているようだ。に対応しているとき、
    | 基本的に [[:alnum:]_] で判定できるとしてしまって問題ない気がする。
    | 因みに [:alnum:] は POSIX ERE で存在することが保証されている。

    [結論] ble.sh では [[:alnum:]_]+ を単語として取り扱うことにする。
      これが \<\> の境界の判定条件と合致すると仮定する。
      合致しなくて起こる不整合については仕方がないので諦める。

    何れにしてもどの様にして対応を行うかを考える必要がある。

    | 1 先ず \b\B\<\> が使えない環境から考える。
    |
    |   先ず初めにカーソルの下の単語の抽出から考える。
    |   これは実のところ可能である。
    |   単に、現在位置の文字が [[:alnum:]_] であれば前後に拡張し、
    |   それ以外ならば \G[^[:alnum:]_\n]*([[:alnum:]_]+) を捕まえれば良い。
    |   但し \G は現在のカーソルの位置。
    |
    |   検索については厳しい。一応 (^|[^[[:alnum:]_]])my_word([^[[:alnum:]_]]|$) で検索してから、
    |   前後の余白を除去すれば一致させることは可能ではあるが、
    |   これは search の仕組みに手をいれなければならない。しかも汚い。
    |   なので境界に一致させることには対応しないことにする。
    |
    | 2 次に \b\B\<\> が使える環境について考える。
    |
    |   先ず初めにカーソルの下の単語の抽出を行う。これは同様である。
    |
    |   次に検索について。原理的には単に \<\> で囲めば良い。
    |   しかし、もし \<\> と [[:alnum:]_] の間に不整合がある場合には、
    |   これによって全く一致しなくなってしまう可能性もあるので、
    |   念のため my_word =~ \<my_word 及び my_word =~ my_word\> を試して、
    |   それぞれ一致したら付加することにする。
    |   実のところ、この様に実装すれば \<\> が使えるかどうかに
    |   依存しない実装に出来る気がする。

    1. [[:alnum:]_] の連続として単語を抽出する。抽出した単語を my_word とする。
    2. my_word =~ ^.{len}\>$ ならば \> を付加する。
    3. my_word =~ ^\<.{len}$ ならば \< を付加する。

    対応した。動いている。

  * vi-mode (nmap :q): 残っている文字列を灰色にする? [#D0570]

  * vi-mode (omap): C-c 及び C-[ 等でキャンセルするべきなのでは。 [#D0569]

    マニュアルを少し探してみたが該当する記述は見つからない。
    vimindex によるとC-c は現在のコマンドをキャンセルと書かれている。
    恐らくコレが該当するのだろう。
    C-[ 及び <esc> は未使用と書かれている。

  * vi-mode: cw cW の特殊な動き (reported by cmplstofB) [#D0568]

    | echo   hello   vim   world # 元の文字列
    |
    | echo   hello@  vim   world # カーソル位置
    | echo   hellovim   world # cw
    | echo   hellovim   world # 1cw
    | echo   helloworld #2cw
    |
    | echo   hell@   vim   world # カーソル位置
    | echo   hell   vim   world # cw
    | echo   hell   vim   world # 1cw
    | echo   hell   world # 2cw
    |
    | echo   @ello   vim   world # カーソル位置
    | echo      vim   world # cw
    | echo      vim   world # 1cw
    | echo      world # 2cw
    |
    | echo nihongo日本語にほんご # 元の文字列
    |
    | echo nihong@日本語にほんご # カーソル位置
    | echo nihong日本語にほんご # cw
    | echo nihong日本語にほんご # 1cw
    | echo nihongにほんご # 2cw
    |
    | echo @ihongo日本語にほんご # カーソル位置
    | echo 日本語にほんご # cw
    | echo 日本語にほんご # 1cw
    | echo にほんご # 2cw

    - 先ず初めに cw と 1cw に違いはない。
    - 空白の上にいる時には {N} 個先の w の手前まで。
      これは cmplstofB さんの報告通り {N}dw と同じ範囲で良い。
    - 単語の文字の上にいるときは {N} 個先の単語終端まで。現在位置を含む。

    うーん。もしかして caw の終端点? と一瞬思ったが全然違った。

    空行を挟む場合にはどうなるか。
    先ず空行または行の最後の空白文字で実行すると、その文字以降を消すだけ。
    行の最後の単語の上で cw を実行しても同様に、その文字以降を消すだけ。
    行の最後の単語の上で 2cw を実行すると、空行を飛び越えて最初の非空行の最初の単語の末端まで消える。
    行の最後の空白の上で 2cw を実行すると、空行が1つ消えるのみである。

    x fixed: というか 2dw の時点で vim と ble.sh で振る舞いが異なっている。
      →これについては #D0567 で修正した。

    x fixed: あと、最終行で最後に空白しか無いときに e を押すと最後の文字に移動して bell がなるが、
      vim ではオペレータ付きでこれを実行すると bell はならない。
      ble.sh ではオペレータがついていても bell を鳴らしていたので、修正する。

    取り敢えず対応した。これから動作確認をする。
    取り敢えず提示された編集を実行してみることにする。

  * vi-mode: w, dw の動作の違いに関して。 [#D0567]

    これは既に Issues #2 にも書いたが、
    以下の内容に対して H5|w だと 9 位置に行くが、
    H5|dw だと 5678 を削除するという振る舞いについてである。

    | 12345678
    |     90ab

    - 実は :help word-motions に記述があった。
      {op}w の時には最後に通過した単語が行末にあった時、
      その後の空白は含まれないというものである。

    - {op}W に関しては記述がないが、
      実際に試してみると {op}w の時と同様に働く。

    - "最後の単語" の後に空白があってから改行でも良い。
      更にいうと、word-motions には単語の終わりがオペレータの対象の終わりと書いてあるが、
      これは間違いで実際には行末までがオペレータの対象の終わりになる。

    - "最後の単語" が改行の場合でも成立する。
      この時には改行の直後がオペレータの対象の終わりになる。
      (但し、その後で exclusive-linewise の規則が適用される。)

  * vi-mode: SP DEL は vi_xmap 及びオペレータが設定されている時は改行も数える。 [#D0566]

  * dw に引数を与えて試していて気付いたが、 [#D0565]
    exclusive-linewise の辺りに書かれている記述の意味が分かった気がする。
    これらの記述は移動先自体が変わるという訳ではなくて、
    オペレータで処理するときの範囲が変わるという話だったのではないか。

    幾つか試してみる。以下 ★◆ を付記したものが
    特別な範囲補正が必要になり、ble.sh で再現しないものである。

    - 以下で H3|2w とすると cc の 1 文字目に行くが、
      H3|2dw とすると " bb" だけが削除され行が連結されるということはない★

      aa bb
      cc

    - Hdgj とすると1行目が消える。行指向になる◆

      % exclusive-linewise に記述されている結果になっているが、
      % 条件を満たしていない気がする。
      % これは読み間違えであったということが分かった。日本語訳が悪い。

      →"その行" とは移動後の位置の行のことではなくて、
      移動初めの位置の行のことである。日本語ではわざわざ "その" とは付けない。
      わざわざ付けると "別のものに属する行" の意味になる。

      | aa
      | bb

    - Hldgj とすると1行目の最後の "a" だけが消える★
      これは :help exclusive-linewise の上の段落の記述に合致する動作である。

      | aa
      | あ

    - 3Hdgk とすると2行目が消える。行指向になる◆

      | xxxx
      | 1234
      | 5678

    - 3Hldgk とすると2行目と "5" が消える。1行目に連結はされない。
      :help exclusive-linewise の上の段落の記述と一致せず、
      特別な動作は何もしていないように見える。

      | xxxx
      | あ34
      | 5678

      日本語訳がおかしいのかと思って改めて英語の説明を見る。
      しかし英語でもこの動作を正しく言い表しているようには見えない。
      むしろ "}" と "d}" が何故異なるのかについて、
      より矛盾を孕む動作になっているような気がする。

      > If the motion is exclusive and the end of the motion is in column 1, the
      > end of the motion is moved to the end of the previous line and the motion
      > becomes inclusive.  Example: "}" moves to the first line after a paragraph,
      > but "d}" will not include that line.

      ここまでの振る舞いから実際には以下の様になっていると思われる。

        移動コマンドが排他的で、現在の位置より後の列1に移動し、omap のとき、
        範囲は移動先の前の行の最後の文字になり inclusive になる。

    - 前の行が空行の時にはどうなるのだろうか?
      以下で H5d<SP> とすると 1234<LF> が削除される。★
      つまり、前の行の行末までになる。

      | 1234
      |
      | 5678

      更に行指向になる。◆
      これはつまり ★の修正と exclusive-linewise★
      の修正が同時に起こりうるということである。

    - 2Hdh としても何も起こらない。1 行目に連結はされない。
      つまり移動前と移動後の位置が同じときには★は作動しない。

      1234
      5678

    - ◆の動作の説明には非空白行頭と書かれているが、
      空白行頭にいた場合には有効ではないのだろうか。

      % 以下で Hdgj とすると行指向になる。
      % H dgj, H3 dgj, H4 dgj の場合は行指向にならない。
      % 2Hdgk は行指向になる。
      % 2H dgk, 2H3 dgk, 2H4 dgk は行指向にならない。
      %
      % | 12341234
      % |     5678
      %
      % 以下で試しても全く同様であった。
      %
      % |     1234
      % |     5678
      %
      % うーん。不思議だ…と思ったらよく考えると移動先が列1でないと駄目なのだった。

      % うーん。"d}" と "d12 " で振る舞いが異なる気がする。
      % "d`a" は "d}" と同じ振る舞いである。
      % "d}" の場合には移動元が行頭以降・非空白行頭以前のときに行指向になる。
      % 別に非空白行頭の直前でなくても良い。(これも日本語訳が悪い。
      % "その手前の位置" と書いたら非空白行頭の直前の位置一点を指すのかと思うが、
      % 実際にやってみると別に直前でなければならない訳ではない。)
      %
      % "d12 " の振る舞いは不可解である。
      %
      % |     1234
      % | 567890ab
      % |
      %
      % において "d4 " は "1234" を削除するが、
      % "d12 " は "12..0a" までを削除する。b を削除しない。
      % 更に言うと :help exclusive-linewise の上下の 1./2.
      % のどちらが適用されるかはどう決まるのか…。

      これは分かった。<space> はオペレータがある時は文字の数え方が異なる。
      :help whichwrap に書かれている。

      上記の例で "d}" "d`a" (3Hma してある) "d2gj" は全て同じ振る舞いである。
      bol <= src <= nol の時は◆になり nol < src の時は★になる。
      と思ったが振る舞いを見ると bol <= src <= nol の時は◆と★の両方が適用されている。

    これの修正は何処で行われるべきか。
    テキストオブジェクトや inclusive も exclusive-range.impl を呼び出す。
    従って、exclusive-goto.impl の中で修正を行うべきの気がする。

2017-11-04

  * 2017-08-19 ble-edit: C-x C-x で微妙な遅延が見える。これは stty の問題だろうか? [#D0564]

    これは現在大きな問題にはなっていないので優先度は低い。

    | ちょっと stty -a の結果を見たり ble-stty/* の実装を見ても分からない。
    | そもそも ^X は stty で特別な文字としては扱われていない様に見える。
    | もしかすると stty raw などとすると遅延は起こらないのかもしれないが、
    | これは時間のある時に試すことにすれば良い。
    |
    | →screen の maptimeout や readline の
    |   keyseq-timeout を変更してみたが変わらない。
    |   screen を抜けても変わらない。ローカルでやると遅延はない。
    |
    | - どうやら ssh ごしだと遅延があるようだ。
    |   ssh で timeout で検索すると別の timeout が当たる。C-x や Ctrl-x で検索しても何も出ない。
    |
    | - よく考えたら実は ssh は関係なくて端末の設定なのではないだろうか。というのも Emacs では遅延はない。
    |   stty の設定を動いている時と動いていない時で比較したが良くわからない。
    |   できるだけ似るようにして見たが遅延はそのままである。
    |   padparadscha ではなく tkynt2 でやってみても同じである。
    |   ローカルでは screen の中でやっても同じである。
    |   $ ssh pad bash -i として端末を割り当てずにやってみた所、それでも遅延はある。
    |   つまりやはり端末の設定ではなくて ssh が怪しいのではないだろうか。
    |
    |   と思ったがそれもおかしい。Emacs はやはり遅延がない。bash が悪いのだろうか?
    |   ローカルでは bash-4.4 でリモートでは bash-4.3 である。
    |
    | - リモートで bash-4.4 を動かしてみたら遅延がなくなった。
    |   つまり bash-4.3 に何らかのバグがあって C-x に遅延が生じているということなのだろう。

    bash-4.0, 4.1, 4.2, 4.4 では遅延はない。
    bash-4.3 のみで遅延がある。これの対策はしない。

2017-11-03

  * vi-mode: refactor [#D0563]

    - done: ble/keymap:vi/mark/set-local-mark 96 "$_ble_edit_ind" を実行するコマンドを提供するべき。
      例えば ble/keymap:vi/mark/set-jump など。

    - done: また、linewise-goto.impl 及び linewise-range.impl は
      bolx nolx を用意しなければならないのが分かりにくい。これも修正するべき。

    - done: ビジュアルモードの種類 char line block を格納する変数名は type ではなく context に統一する。

  * 2017-09-16 vi-mode merge 直前に一括して行うテスト・仕様変更など [#D0562]

    * 各コマンドについて再度動作するかどうかについてテストする必要がある。
      Wiki に各コマンドの説明を書きつつテストして行くのが良いだろう。

      x fixed: ihello world<C-[>. で world 以降しか挿入されない。
        これは vi_imap/magic-space によって記録が reset されていた為に起こった物である。
        現在は irepeat は実際に行われたコマンドの列で記録されているし、
        また xmap I, A なども dirty-range による追跡を行っている。
        imap での様々な編集が起こっても問題ないようになっているので、
        単に magic-space を登録してそれを white としても問題ないだろう。

        vi_imap/magic-space は廃止した。今後は magic-space を直接使ってもらう。

      x fixed: a123<C-[>.. において1つ目の . ではちゃんと a で実行されているが、
        2つ目の . においては i で実行されている。これは何故か。
        record-insert で (vi_nmap/repeat で呼び出されたかどうかに拘らず)
        毎回記録しているのが原因である。→修正した。

      x fixed: nmap w b e ge において単語の定義が異なる。
        これは imap <C-w> や text object iw aw と同様にすれば良さそうだ。
        というか、imap <C-w> や text object iw aw についても数字が考慮されていなかった。

      x resolved: imap <C-w> でスペースの削除の仕方が異なる気がする。
        と思ったら、これは bashrc で設定している関数が問題だった。

      x fixed: {N}% がいつも同じ位置に移動する気がする。
        →これはどうやら local bolx= nolx= を定義せずに linewise-goto を呼び出したのが行けなかったようだ。
        類似の修正を text objects ip ap に対しても行った。

      x fixed: `a 'a でオペレータが全く動いていない。
        goto-local-mark.impl, goto-global-mark.impl を呼び出す前に clear-arg を実行していたのがいけなかった。
        他にも operator の効かない移動コマンドが存在したりするかもしれないので確認する。

      x fixed: d_ 及び d1_ が charwise になっている。正しくは linewise である。

      ここまでで取り敢えず setup-map で登録されているコマンドについては一通り動作することを確認した。
      次に omap nmap xmap に登録されているコマンドについてテストを行う。

      x fixed: lib/vim-surround (xmap S): vS が linewise になっているが、
        元々の surround.vim ではそうではない。
        vS は charwise で vgS の時に linewise になっている。
        また VS および VgS の時も linewise だがインデントは行わない?
        surround.vim の振る舞いは謎だが、取り敢えず修正した。

      x resolved: command-help が常に一番最初のコマンドの help しか出さない?
        →調べてみた所、これは元からそういう仕様だったようだ。
        これの改良については別項目を立てて処理することにする。 #D0572

      x implemented: 実は xmap c, xmap s, xmap C では InsertLeave を設定する様だ。
        これの対応は面倒である。

        先ず初めに operator:c の中で、
        現在の operator の実行が xmap 経由であることを認識しなければならない。
        と思ったが、よく考えたら context == block となるのはビジュアルモードだけなので、
        この時は常に block-insert-mode.impl を呼び出すようにしてしまえば良い。

        block-insert-mode.impl は今まで自身で extract-block を呼び出していたが、
        operator:c context=block の時は既に sub_ranges があるので、これを利用したい。
        block-insert-mode.impl の呼び出し元で sub_ranges を計算することにした。

        operator:c で .insert-mode を呼び出す代わりに block-insert-mode.impl を呼び出す様にする。
        vi_xmap/exit が重複して呼び出されることの対策を vi_xmap/exit に追加した。

        実装した。動いている。と思ったが、挿入される文字の数が少ない。

        operator:c の中で、block-insert-mode は行の長さの変化を見るから、
        これを呼び出した後で領域を削除する訳にはいかない。
        従って block-insert-mode.impl を呼び出す前に領域を削除しなければならない。
        すると、それに応じて sub_ranges の修正が必要になる。
        block-insert-mode は sub_ranges[0] しか参照しないので、これを修正すれば十分である。
        →修正した。OK

      取り敢えず各 keymap で定義されているコマンドは確認した
      (imap cmap は面倒だし殆ど emacs-mode と同じなので良いだろう)。

      後は各 mark, 各 registers の特殊な振る舞いについて確認すれば良い。

      o 先ず registers については、そもそも特殊レジスタには対応していない。
        なので確認することは現時点ではない。

      o mark `^ (挿入モードを抜けた位置)
      o mark `" (最後にその履歴項目から抜けた時の位置)
      o mark `. 最後に編集の起こった位置。これは vim のそれと
        厳密には振る舞いが異なる可能性もあるが、気にしない。
      o mark `[`] これはよく使っているので問題はないはず。
      o mark `` これについても既に試したので問題はないはず。
      o mark `<`> これも gv で使われているので問題ないはず。

      x fixed: xmap ? を押したら rot13 が呼び出される。
        xmap: / ? n N これは motion として働くべき。
        確認してみると元から登録されている。
        単に operator rot13 が上書きされていた。削除した。

      x fixed: xmap で / ? n N を実行すると選択範囲がずれるのでは?
        →ずれた。これは修正する必要がある。
        単に xmap にいる時には選択範囲のハイライトをしないという様にすれば良さそう。

        と思ったら、_ble_edit_mark を用いて現在位置が
        既に一致したものなのかどうか判定している様だ。
        そうすると _ble_edit_mark を設定しておかないと n N で移動ができなくなる。
        と思ったが、既に一致したかどうかの判定は ble/keymap:vi/search/invoke-search の中で行っていて、
        _ble_edit_mark_active または _ble_keymap_vi_search_activate が search になっているかで判定している。

        うーん。invoke-search の中を vi_xmap の時に合わせて書き直そうとしたが難しい。
        やはり既に一致したかどうかの情報は必要である。
        そしてそれは _ble_edit_mark_active の clone の様な変数を用意すれば良い。
        (或いは _ble_edit_mark_active=line+! などのようにどんどん構造を複雑にすることも可能ではあるが、
        全体に汚くなるのでやはりそのような方法は駄目だ。)

        うーん。取り敢えず _ble_keymap_vi_search_matched という変数を導入してみた。
        しかし、この変数が正しくクリアされるかどうかについては自信がない。

        - _ble_edit_mark_active は異なるタイミングでもクリアされる。
          特に xmap から抜けるときと xmap に入る時。
          xmap から抜ける時は実のところ一致状態が残っていても良い。
          xmap に入るときも一致状態が残っていても良い。
          問題は motion によって解除されるはずのところ解除されないということが起こる場合だが、
          恐らく問題はないはずである。

        - 他に imap や cmap に移るときに問題になることはあるだろうか。
          cmap に移る時には _ble_edit_mark_active はクリアされるが、
          _ble_keymap_vi_search_matched はクリアされない。
          しかしながら cmap から _ble_keymap_vi_search_matched を参照することはないから問題ない。
          更に、また元の nmap に戻ってきたときには _ble_edit_mark_active が復元されて元の状態に戻る。
          : を実行している場合には更に adjust-command-mode が呼ばれるので、無事に両方共解除される。

        - imap に移る時にはどうだろうか。_ble_edit_mark_active は解除される。
          _ble_keymap_vi_search_matched は解除されない。
          そのまま挿入の操作をしても _ble_keymap_vi_search_matched は解除されないまま残る。
          次に normal-mode に突入するときにも残る。ここで初回から n などを実行すると、
          本当は一致していないのに一致しているという様に勘違いして検索が始まる。

          この微妙な違いにユーザは気づかないかもしれないが、確かに変な振る舞いになる。
          取り敢えず .insert-mode の _ble_edit_mark_active をクリアしているところで、
          _ble_keymap_vi_search_matched もクリアすることにする。
          取り敢えずこれでよしとする。

        さて実際に試してみると駄目だ。動いていない。うーん。

        x fixed: これは invoke-search の中で _ble_edit_mark を用いて開始位置を探索していたのが駄目だった。
          単に 1 文字進めるというようにすれば良いだろうか。。
          或いは再度一致させてしまえば良い→再度一致させる方針で実装した。

        x fixed: それでも動かないと思ったら、そもそも _ble_keymap_vi_search_activate を
          vi_xmap の時に設定していなかった。従って、_ble_keymap_vi_search_matched も設定されなかったということだった。
          _ble_keymap_vi_search_activate を設定するようにした。

        x fixed: 所が今度は _ble_keymap_vi_search_activate を設定したら _ble_edit_mark_active が上書きされてしまった。
          これは _ble_keymap_vi_search_activate から _ble_edit_mark_active に移す時の keymap の判定が誤っていた。修正した。

        x fixed: また詳しく見てみると範囲がずれている。
          元々は _ble_edit_mark から読み取って _ble_edit_ind++ していたが、
          具体的に再一致させて end を読み取っているときには _ble_edit_ind++ は要らないのだった。直した。

      x fixed: / ? n N xmap の時に履歴項目を移動するのはまずいのではないか。
        →xmap にいる時には履歴項目の移動はしない様にした。動いている。

      取り敢えずはこんなところだろう。

    * vi-mode を bash-3.0 でもテストする。

      そんなに詳しくテストするつもりはない。
      簡単に動かしてみているが、問題はないようだ。
      少なくとも全く動かないということはないことは確かだ。

      x fixed: ところで矩形挿入の時の `[`] が変だということに気付いた。
        修正した。commit-edit-area を追加すれば良いだけだった。

2017-11-02

  * vi-mode (operator): ble/keymap:vi/call-operator [#D0561]

    オペレータの中で更に編集コマンドを実装する場合に備えて
    _ble_keymap_vi_mark_suppress_edit を設定してオペレータを呼び出す。

  * vi-mode: ble/widget 実装の注意点 [#D0560]

    これらは Wiki に記述することにした。

    | vi-mode 用の ble/widget を実装する上での注意点についてまとめる必要がある。
    |
    | - 先ず __before_command__ の内部で set-previous-edit が発生してはならない。
    |   set-previous-edit 内部では . で繰り返すために、その編集が起こった原因となる
    |   コマンドを WIDGET によって特定する。__before_command__ は
    |   WIDGET 経由で呼び出されないので、誤った復元をしてしまうことになる。
    |
    | - WIDGET を widget 本体の中で変更してはならない。
    |   これは同様に . で繰り返すための情報を破壊してしまうことになるからである。
    |   __before_command__ 内部でコマンドを変更する目的で書き換えることは可能。
    |
    | - operator の定義方法について
    |
    |   もし . による繰り返しに登録しないときには
    |   空の関数 ble/keymap:vi/operator:foo/norepeat を定義する。
    |
    |
    | - `[`] が正しく設定されるために
    |
    |   編集を伴うコマンドについては、編集後に編集範囲を設定するために
    |   ble/keymap:vi/mark/set-previous-edit-area 編集開始位置 編集終了位置 を呼び出す。
    |
    |   複雑な編集について編集範囲が容易に決定できない場合には、
    |   ble/keymap:vi/mark/set-previous-edit-area を自分で呼び出す代わりに、
    |   編集が行われるコード全体を ble/keymap:vi/mark/start-edit-area と
    |   ble/keymap:vi/mark/end-edit-area で囲めば良い。
    |
    |   | ble/keymap:vi/mark/start-edit-area
    |   | local _ble_keymap_vi_mark_suppress_edit=1
    |   |
    |   | ... # 編集操作
    |   |
    |   | unset _ble_keymap_vi_mark_suppress_edit
    |   | ble/keymap:vi/mark/end-edit-area
    |
    |   mark/{start,end}-edit-area の内側で更に別の編集コマンド (内部で `[`] が設定される)
    |   を呼び出す場合には、更に _ble_keymap_vi_mark_suppress_edit を設定する必要がある。
    |
    |   | ble/keymap:vi/mark/start-edit-area
    |   | local _ble_keymap_vi_mark_suppress_edit=1
    |   |
    |   | ... # 編集操作 (`[`] の設定を行う widget の呼び出しを含みうる)
    |   |
    |   | unset _ble_keymap_vi_mark_suppress_edit
    |   | ble/keymap:vi/mark/end-edit-area
    |
    |   オペレータについては外側で自動的に編集範囲が検知されるので、
    |   自身で {set-previous,end}-edit-area を呼び出す必要はない。
    |   但し、編集は起こらないが範囲を設定したい場合 (operator y など) には、
    |   commit-edit-area 関数を明示的に呼び出す。
    |
    | - . による繰り返し操作が正しく設定されるようにするために
    |
    |   基本的には繰り返しの対象になる widget で ble/keymap:vi/repeat/record を呼び出せば良い。
    |   繰り返しの対象となるコマンドは2種類ある。
    |   一つは編集を伴うコマンドで、もう一つは挿入モードに入るコマンドである。
    |
    |   1 ble/keymap:vi/mark/{set-previous-edit-area,end-edit-area} を呼び出すときは、
    |     そこで1単位の編集が完了するということを表すので、
    |     大抵、対応して ble/keymap:vi/repeat/record も呼び出すと考えると良い。
    |
    |   2 ble/widget/vi_nmap/.insert-mode を呼び出した後も、
    |     場合に応じて、ble/keymap:vi/repeat/record または ble/keymap:vi/repeat/clear-insert を呼び出す。
    |     repeat/record はその挿入モード突入に至るコマンドを . で再現したい時に使う。
    |     repeat/clear-insert は、挿入モードの途中で挿入操作をクリアする時などに使う。
    |     repeat/clear-insert は実例として imap の <C-o>, 移動操作, コマンド実行などで使われている。
    |     - 但し operator の中では、外側で自動的に repeat/record が呼び出されるので、これらは自分で呼び出さない。
    |       例えば operator:c では .insert-mode を呼び出すが、自身で repeat/record を呼び出すことはしていない。
    |       operator による非同期読み取りによる継続の場合は、mark/set-previous-edit の時と同様に自分で呼び出す必要がある。
    |     - repeat/record はその時の keymap を参照するので、vi_nmap/.insert-mode よりも後で呼び出す必要がある。
    |
    |     また、編集を行って更に挿入モードに入るコマンドの場合であっても、
    |     1回だけ repeat/record を呼び出せば問題ない。
    |     その時でもやはり .insert-mode よりも後で repeat/record を呼び出すようにすること。
    |
    |   KEYMAP, KEYS, WIDGET, ARG, FLAG, REG の値は記録され
    |   繰り返しの対象となる widget を呼び出すときに再現される。
    |   繰り返しの対象となる widget が、それ以外の "状態" に依存して振る舞いが変化し、
    |   その時選択された振る舞いを繰り返しの際にも再現したい場合には、
    |   それを明示的に記録・再生する必要がある。

  * vi-mode: xmap I A が動かなくなっている…。 [#D0559]

    これは修正した。InsertLeave オプションが指定されているかどうかの判定が誤っていた。直した。

    という事は、いつからなのか分からないが、ずっと誤っていたのではないかと思われる。
    blame で見ると最後の書き換えは 453da8a2 (2017-10-12) である。
    調べるとこの時に複数に分かれていた insert-mode を統合したのだった。

    さて、更に振る舞いで気になることがある。
    挿入を終わった後のカーソルの位置が一つ戻っている。
    これは何か? nmap に戻る時にカーソル位置が一つ戻ることに関係するだろうか?
    そうだった。その様になっている。これは前からそうだった筈なのだが何故気が付かなかったのか。
    何れにしても修正する。どの様に修正するのが良いだろうか。

    a 例えば InsertLeave が設定されている時には一つ戻るという操作を行わない?
      これは駄目。例えば InsertLeave にカーソル移動を伴わない・編集を伴わない操作が設定されることも考えうる。
      その時に、(カーソル移動も編集もないのに) 位置が1つ戻るという操作がキャンセルされるのは変だ。

    b InsertLeave の内部でカーソル移動が起こった場合には 1つ戻るという操作を行わない?
      これは魅力的だが微妙。もしかすると InsertLeave の中で
      明示的に現在位置と同じ位置に移動するという事があるかもしれない。
      その様な場合には結局 1 つ戻るという操作が無駄に発生してしまうことになる。

      更に言うと InsertLeave の中でのカーソルの移動が、
      normal mode に移行する時に 1 つ戻ることを前提としている or それが自然という場合も考えうる。

    c 或いは、InsertLeave の中でカーソル移動を行う時は、
      normal mode に復帰する際にカーソル位置が 1 つ戻るという事を前提として、
      1つ次の文字に設定するということも考えうる。

    実のところ c の実装が最も自然に思われる。

  * 所で挿入モードに a で入った時と i で入った時で <C-o> 後のカーソル位置が異なる? [#D0558]
    と思ったけれど改めて試してみるとそうでもなかった。

  * vi-mode: . 実装 (6) 取り敢えず完了 [#D0557]

    #D0543 各 widget の戻り値の確定
    #D0550 WIDGET/KEYMAP/ARG/FLAG/REG ローカル変数の導入
    #D0551 nmap/omap における operator 操作の記録と復元
    #D0555 xmap における operator 操作の記録と復元
    #D0556 挿入モードの操作の記録 (これの為に imap-repeat も整理した #D0554)

    - 3l. とするとそれより前に行われた編集コマンドが実行される。
      つまり編集コマンドしか繰り返しの対象とはならない。

      どのコマンドが繰り返しの対象になるかについては help を見るのが良いだろう。
      help には repeat last change, also yank is repeated
      commandline command is not repeated としか書かれていない。

      % しかも実際に試してみると yiw は repeat されない様である。
      % also yank is repeated とはどういう意味だろう?

    * $widget.record 的な関数を定義して、それが使われていたらという話があったが、
      operator などの内部で記録を行いたい場合には難しいのでは?

      % と思ったが operator の内部では基本的に記録は行わず記録を行うとすれば非同期な読み取りが関わるときだが、
      % その場合には改めて hook 関数が呼び出されるのだから、"(hook 関数).widget" という形の関数名にすれば良いのでは?

      とも思ったが、直接 hook 関数が _ble_decode_key__kmap に登録されているとは限らない。
      例えば、vim-surround.sh の async-inputtarget では async-inputtarget 用の関数が WIDGET の本体になってしまう。
      従って、"(WIDGETの本体).record" をそれぞれ定義して動作を制御するというのは難しい。

      従って、やはり $widget.record の様な仕組みは余り意味がない。
      各自で ble/keymap:vi/repeat/record の代わりに独自の記録関数を定義するのが良い。
      その場合には _ble_keymap_vi_repeat{,_irepeat} 配列を必ず設定させるようにする。

    [実装]

    * 後は一つ一つのコマンドについて確認を行って行くことにする。

      - nmap ~ OK
      - nmap p P OK
      - nmap rx Rx OK
      - nmap J gJ OK
      - xmap rx Rx OK
      - xmap p P OK
      - xmap I A OK
      - lib/vim-surround: ysiw" OK (surround.vim とは異なるが想定した動き)
      - lib/vim-surround: cs"b OK (同上)

      どうも実装した後で気付いた事だが、lib/vim-surround.sh の ysiw" に対して
      . を実行すると、最後の " の部分に関しては前回のものが使われるのではなくて、
      改めて入力を求められる様である。

      更に、cs"b などについても入力が求められるが
      cs<空><入力したもの> という解釈になる様だ。
      これはバグなのではないかと思っている。

    * 一段落したら set-previous-edit / end-edit-area と統合できないか考察する。
      実装してみた結果、考察するまでもなく、これは全然統合できない。

2017-11-01

  * vi-mode: . 実装 (5) 挿入モードの操作の記録 [#D0556]

    | - ihello<C-c>. とすると o の前に再度 hello が挿入される
    | - ahello<C-c>. とすると末尾に hello が挿入される
    |   つまりどのような挿入モードによって挿入が起こったかを覚えている。
    | - 更に c$123<C-[>. を実行してみるとちゃんと削除してから挿入するまでを一通りの編集として記録している。
    | - 挿入モードの途中でカーソルを動かして更に編集を行うと、
    |   最後にカーソルを動かしてからの編集が繰り返される。
    |   最初に指定した繰り返し回数の引数は忘れられるようだ。
    |   またこの場合には a で始めたとしても、i と同様の状態になる。

    動作を調べる

      a<C-w><C-[>... とするとちゃんと単語毎に削除される。
      つまり削除された文字数ではなくてちゃんとキーの列で記録されている。

      という訳で {count}i の為の記録と同じ枠組みで記録した物を用いる。
      と思ったがよく考えると quoted-insert が正しく再生されないのではないか?
      試してみた所やはりうまく再生できていない → #D0554 で修正した。
      この修正によりキーの列として記録するのではなくて、
      実行したコマンドの列として記録することになった。

    - done: さて . による繰り返しに対応する為には
      先ず初めに imap-repeat を _ble_keymap_vi_irepeat_count の有無に拘らず
      常に記録する様に修正する必要がある。
      そして white list にないコマンドが来た場合には中身をクリアする。

    - done: どうやら ihello<C-o>. とやると hello の挿入が繰り返される訳ではなく、
      それより前の操作が繰り返される様だ。試してみると、<C-o> では繰り返しは登録されない。
      更に現在の挿入モードが ciw などによって導入されたものの場合にはどうだろうか。
      この場合も ciwhello<C-o> とやった時点では ciw は繰り返しに登録されていない。
      つまりオペレータが呼び出されたと言ってもその時点では記録されていないのだ。

      これを記録する為には、オペレータを呼び出した後に記録を行う時、
      _ble_decode_key__kmap == vi_imap の時には、repeat に直接記録するのではなく、
      一旦 _ble_keymap_vi_repeat_insert などに記録を行う様にし、
      最終的に <C-[> または <C-c> を行う時に実際に記録する様に修正する必要がある。

    - done: また <C-o> や途中の non-white な操作の際には、
      この内容を ble/widget/insert-mode か何かに書き換えてしまえば良い。
      →これは ble/keymap:vi/repeat/clear-insert の中で処理することにする。

    - done: 更に .insert-mode を呼び出す各 widget で ble/keymap:vi/repeat/clear-insert を呼び出すようにする。

    - ok: また、最終的に <C-[> または <C-c> で抜ける時に、最後の <C-o> 以降の内容が記録される。
      これは <C-o> を行う時に reset すれば良い。実の所 <C-o> から insert mode に戻る時に
      何れにしても reset されるのでこの点に関しては気にしなくても良い。

    | 挿入モードの途中でカーソルを動かしてもOK
    | (注意: これは i の引数による繰り返しがキャンセルになる状況である)

    これについても対応する。

      というか、実際に試してみると、カーソルを動かした瞬間に記録される様だ。
      例: iA<C-c>ihello<left><C-o>. とすると . で ihello<C-[> が実行される。
      また、その後でカーソルを動かしただけで (挿入を伴わずに) <C-c> or <C-[> を押した場合には、
      改めて記録されるということはない様だ。つまり clear-insert では単に repeat_insert を空にして、
      record-insert において repeat_insert が空の時には repeat_irepeat 操作が
      1 つ以上記録されているときに限って記録を行う様にすれば良い。

      実際に <C-o> における clear-insert でも同様に動作するようだ。
      つまりそれ以降に操作がなければ最終的には記録されない。
      例: iA<C-c>ihello<C-o>.<C-[>. とすると最後の . でも A が入力される。
        つまり最後の <C-o>. 以降に何も挿入操作が行われないので、
        <C-[> においては何も新しく登録されない。

    取り敢えず実装したので今度は動作確認が必要である。

    x resolved: ahello<C-c>. で動かしてみた所 . で挿入モードには入るが実際の挿入操作は行われない様だ。
      というかノーマルモードに戻るという動作すらしていない。
      →これは widget 実行後に vi_imap かどうかの確認をするのに KEYMAP を使っていたのが駄目だった。
      現在の keymap は _ble_decode_key__kmap で確認するべき。修正した。

    x resolved: ahello<C-c> の後に、何故か . を実行する度に挿入操作が一つずつ減っていき、
      最後には誤った添字のエラーメッセージが発生する。
      このエラーメッセージは ble/keymap:vi/imap-repeat/pop で出ている。

      これは imap-repeat/pop が normal-mode で呼ばれているのが原因?
      取り敢えず /normal-mode を手で呼び出している箇所で
      imap-repeat に 0:ble/widget/dummy を push する様にする。

    o 繰り返し (. に対する引数) はちゃんと動いている。
    o 3ahello<C-[> で元々指定した引数 3 も動いている。
    o ciwcheck<C-c><別の単語に移動>. もちゃんと動いている。
    o a<C-w><C-[>... も動いている。

    x resolved: iA<C-c>ihello<left><C-o>. で A が挿入される。
      ここは hello が挿入されるべきである。
      これは記録を実行するのを忘れていた。修正した。

    x resolved: 試していて気付いたのが vim では iA<C-c>i<C-o>. とした後にちゃんと元の挿入モードに戻る。

      % normal-mode の呼び出しを分解して無駄なものを除きつつ、
      % 有効な部分だけ記述しようと思ったが、存外に複雑である。
      % やはり norma-mode の呼び出しはそのままにして、外部から動作を修正する方が良さそうだ。

      うーん。これは挿入モードの繰り返しに限らず . 一般の問題の様だ。
      実際に繰り返しを行う前に _ble_keymap_vi_single_command を保存して、
      更に最終的に vi_nmap に戻るようにして、
      その上で _ble_keymap_vi_single_command を復元するという具合に修正した。

    o iA<C-c>ihello<C-o>.<C-[>. の動作も OK

  * vi-mode: . 実装 (4) xmap における operator 操作の記録と復元 [#D0555]

    * done: 次に実装するのは xmap の場合の復元である。

      | なんと矩形削除についてもちゃんと再現される。
      | 因みに矩形削除では引数は無視されるが、. に引数を指定するとどうなるか。
      | 試してみた所、無視された。つまり . の引数は繰り返し回数では決してなくて、
      | 以前に実行したコマンドに渡す引数に他ならないのである。
      |
      | 矩形の大きさは何処で保持されているのだろうか。
      | 完全に独立に保持されているのか、それとも gv や 1v と共にしているのか。
      | 調べてみた所、先ず gv と 1v は完全に独立になっている。
      | gv は <C-c> でも記録されるが 1v に関してはキャンセルすると記録されていない。
      | % というか vim で試すと 1v は前回の編集があったときの大きさであって、
      | % 前回の矩形範囲ではないような気がする。現在の実装は怪しい。
      | % →よく考えたら現在の実装でも 1v は前回の編集が合った時の大きさである。
      |
      | また gv は開始行と終了行 (追跡) とそれぞれの行での列 (追跡なし)
      | を覚えている。つまり、mark で覚えている。というか実際に `< と `> で囲むだけ。
      | 一方で 1v は高さと幅だけ覚えている。

      .save-visual-state と 1v によるデータの記録が同時に行われるのだとすれば、
      単に .restore-visual-state を呼び出して vi_xmap を push すれば良さそうである。
      実装してみたが、よく考えると .save-visual-state と
      1v によるデータの記録のタイミングは異なる気がする…。

      <C-v>jll~<C-v>jjly1v<C-c>. とやってみると両者が独立に記録されていることが分かる。
      つまり、先の調査の以下の部分は誤りであったということが分かった。

      | % ところで、矩形繰り返しが 1v と独立なのかどうかについて調べるためには、
      | % 編集操作を伴わずに 1v の範囲を変更すれば良い。そのようなことは可能か。
      | % 調べてみると ble/widget/vi_xmap/.save-visual-state は編集を伴うときにしか呼び出されない。
      | % つまり、矩形繰り返しが 1v と別かどうかを調べる方法はない気がする。
      | % 逆に言えば .save-visual-state を参考にして操作を繰り返せば良いということになる。
      | % (或いは、実際に .restore-visual-state を呼び出して処理するというようにすれば良い)。
      |
      | →マニュアルの記述に反して y は繰り返し対象ではないようである。
      | 1v の場合には y による領域も記録されるから、これを以て繰り返しと 1v の記録が独立かどうか確かめられる。
      | 実際に試してみると両者は独立に記録されているということが分かった。

      さて。1v の記録 (.save-visual-state) ではどのような変数を用いているか。
      _ble_keymap_vi_xmap_prev という変数一つに記録しているようである。
      従って、この変数をすり替えて .save-visual-state/.restore-visual-state を呼び出せば良い。

      と思ったが、repeat/record が呼び出される頃には既に _ble_edit_ind などの位置は変更されているので、
      むしろ独立に .save-visual-state を呼び出すのではなくて、
      .save-visual-state によって記録された領域をコピーして来るので良い。
      但し、その為には repeat/record を呼び出すときに必ず .save-visual-state が呼び出し済みである必要がある。
      これに関しては vi_xmap で編集が起こるときには必ず .save-visual-state が呼び出されるはずだから恐らく大丈夫である。

      ところで、一番下の行などで . を実行したことによって、
      記録されたのよりも小さな領域に対してしか繰り返し処理を実行できなかった時、
      更にそれより後に実行する繰り返しでは領域が狭められるということはあるのか?
      →調べてみると初めに記録された領域の大きさを使い続けるようだ。
        記録された領域の大きさが改めて設定されることはないようだ。OK

    x resolved: xmap 動かない。と思ったら WIDGET の復元に失敗していた。修正した。

  * vi-mode (imap): 挿入モードの引数で C-q ? による繰り返しが正しく再生されていない。 [#D0554]
    これはキーの記録を keymap のレイヤーで実行している為に、
    _ble_decode_key__hook, _ble_decode_char__hook によって
    読み取られたキー・文字を取得できていないためである。

    一旦は quoted-insert の中で keylog に登録することを考えたが、
    よく考えてみると hook をかけるのは key に対してではなく char に対してである。
    key に登録するのだと振る舞いが変わってしまう。

    a 一つの方法は再生時には quoted-insert は key に対して
      hook する様に動作が変わる様にする。

      aa 動作の切り替えは例えば、keylog から C-q を pop して
        特別な key (例えば s-q) を push する。
        s-q に対して key に対して hook する quoted-insert-key 的な widget を登録する。

        x これは keymap に対して vi-insert/quoted-insert を登録するだけでは動かないので分かりにくい。
        といって vi-isnert/quoted-insert の内部で s-q に bind するのは効率が悪い。
        x また、s-q に本当に何かを bind したい時に困る (そのような場合は余りありそうにないが可能性が全くないわけではない)。

      ab 再生時に特別なローカル変数を定義して、
        その変数が非空白のときには key に対して hook する様に動作を変更する。

    b 或いは、keylog として記録するのではなく charlog として記録する。

      charlog で記録する場合には、最後の normal-mode を呼び出す発端となったイベント
      (C-[ など) が、何文字の char によって引き起こされたのかを調べる方法が必要になる。
      これによって最後の C-[ を除去することが可能になる。

      ba 一つの方法は最後に記録した時の長さを覚えておいて、
        それ以降に増えた部分を今回のイベントを引き起こすのに関与した文字と解釈する。

      またこの方法は ble-decode に手を入れる必要がある気がする。
      というのも、keymap 経由だとどんなに頑張っても key の情報しか得られないからである。

    c もしくは widget の列として記録を行う。
      この時には KEYS 及び呼び出す WIDGET の名前の配列として記録する。
      quoted-insert は self-insert に変換することで動作する様にする。

      この方法の方が自然である。例えば keymap が変更された後でもこれなら同じように動作する。
      問題は KEYS と WIDGET だけ保存すれば完全に同じように動作するのかどうかという事である。
      うーん。多分動作する?

    % しかしよく考えてみると vim の qx ... q @x で "レジスタ" に操作を記録する仕組みとの整合性も考えなければならない。
    % そう考えるとむしろ charlog で記録した方が良いのかもしれない。
    %
    % うーん。というかレジスタに記録する機能は挿入モードに限らず全体に渡って適用される。
    % そう考えると、挿入モードの繰り返しとの整合性を考える必要は全く無い。

    思うに c の方法が最も綺麗である。
    しかしその為には挿入モード繰り返しの記録と再生を完全に再実装する必要がある。

2017-10-31

  * vi-mode (xmap): o O [#D0553]

    動作を確認する。v, V では o, O に違いはない。
    単に mark と ind を交換するだけの様な気がする。
    C-v においては o は mark と ind を交換する。
    O は同じ行内で右端から左端または左端から右端に移動する。
    - 選択領域の幅が1文字しか無いときには動かない。
    - 最初の行または最後の行の端に中途半端な全角文字が含まれている場合には
      幅が拡張する方向でどんどん大きくなる。例えば

      | echo ああああああああああ
      | echo aああああああああああ

      のような形にしておいて適当なところで C-v で囲んで、
      O を連打すると少しずつ幅が拡大していく。
    - 末尾拡張の時に o または O を押すと末尾拡張は解除される。

    O はどの様に実装するのが良さそうか。
    一番簡単な実装方法は矩形領域を実際に切り出して、
    mark, ind をそれぞれ行内で丁度反対側の文字になるように移動することである。

    % もう少し効率的な実装方法にするとすれば、
    % 矩形領域の最初の行と最後の行についてだけ範囲を計算すれば良い。
    % しかし、それは似たような処理の再実装になるのでやはり避けたい。
    % もし効率化を測るとすれば extract-block にオプションとして、
    % 最初の行と最後の行に関する情報だけで良いというものを用意する手があるが、
    % 現在の所そんなに遅くて困るということもない気がするので、
    % 取り敢えずは直接 extract-block を呼び出すという実装方法で問題ないだろう。
    % (或いは、そのようなオプションを簡単に導入できるのだとしたら実装しても良いが)
    %
    % 取り敢えず extract-block で実装したら動いた。
    % そしたら急に面倒になったので効率的な実装は問題になるまでは考えない。

    実装した。動いている。

    o ちゃんと全角文字があるときに領域が拡大されていく振る舞いも再現している。

    x resolved: 末尾拡張のときの振る舞いについて少し異なる。
      どうやら末尾拡張を解除した後で、領域を決めて移動先を決定するようだ。
      →修正した。

    x resolved: 更に O の結果としてカーソルが行末に来ることも許される。
      驚くべきことに(?)交換によって mark が行末に来ることも許される。
      これは sfill があるかどうかで判定すれば良いだろう。
      sfill が 1 以上であれば行末に移動する。
      →修正した。試した。期待通り動いている。

    _ble_edit_mark が行末に来るということは想定していなかったが、
    これによって既に書いた機能について何か問題が生じる可能性はあるか。
    つまり、_ble_edit_mark の位置は行末ではないという仮定を行っている箇所があるだろうか。

    o 例えば keymap:vi/mark の枠組みで記録される列の位置に関してはどうだろう。
      実のところ、これについては復元時に行の長さが変化している可能性も考えて、
      位置の調整が行われるので、復元時に nmap として不正な位置にカーソルが来ることはない。
      また gv などで復元する場合を考えるとむしろ行末に mark を設定できるべきである。
      つまり keymap:vi/mark についてはそもそも行末に置けないという制限はないはずなので、問題ないということ。

    o 他に _ble_edit_mark が影響を与えるのは xmap における範囲の決定である。
      これについても mark/index を区別せずに実装しているはずなので、
      mark が index と同様に行末に来たとしても問題は起こらない筈である。

    o 他には vi-mode で _ble_edit_mark が意味を持つことは無い気がする。

    まあ、恐らく大丈夫だろう。問題が出てきたらその時に対処する。

  * vi-mode: どうやら yiw の振る舞いが異なる [#D0552]

    ble.sh では現在 ///日本語 は一つの塊だと考えているが、
    vim では "///" と "日本語" の二つに分けて考えているようだ。
    vim のマニュアルを見てもこの振る舞いについては書いていない。
    非空白文字の連続としか書かれていない。

    調べてみると "日本語ひらがなカタカナ" は
    "日本語" "ひらがな" "カタカナ" の3つに分割されるようである。
    つまり Unicode の Category を見て判定している様である。
    これは厳しい気がする。

    取り敢えずの簡便な実装としては ASCII の記号と、
    それ以外の非空白文字を区別して実装するという事である。
    ASCII の記号は [!-/:-@[-`{-~] で表される。対応した。

2017-10-30

  * vi-mode: . 実装 (3) 取り敢えずの記録の仕組みと再実行の仕組み [#D0551]

    | - diw もちゃんとそのように記録される。
    |   つまり、ただ単に削除範囲の広さを記録するのではなくて、
    |   どの様な motion に伴って削除されたかの情報も記録される。

    どの様に実装したら良いだろうか。
    単にキーシーケンスを覚えるという方法は通用しない。
    visual mode で実行したコマンドは visual mode で実行しなければならないし、
    normal mode で実行したコマンドは normal mode で実行しなければならない。
    挿入モードに入って文字列を入力して抜けたら、挿入モードの種類も含めて再現する必要がある。

    うーん。取り敢えず、set-previous-edit が呼び出されるのと
    同じタイミングで記録を行うようにする。

    | a 一つの一番簡単そうな方法は set-previous-edit が起こった時に、
    |   それを呼び出したコマンド COMMAND を見るというものである。
    |   この情報だけでどの程度までコマンドを知ることができるだろうか。
    |
    |   先ず、diw などの場合には text-object が二文字目を受け取った時に実行される。
    |   この二文字目は _ble_decode_key__hook を介して呼び出されるため、
    |   実は COMMAND 情報を抽出することができない。
    |   或いは、ble-decode を修正して hook の場合には、
    |   hook に設定されていた文字列を指定する方法を提供するようにする。
    |
    |   うーん。実際の vim の実装はどうなっているのだろう。
    |   vim の場合には非同期に実装する必要はないから、
    |   呼び出されたコマンドの中で次の文字も全て処理できる。
    |   つまり、現在の呼び出しの関数というのは容易に分かる。
    |   ただし、読み出した文字などは全て記録しておく必要がある。
    |
    |   個別コマンドについて文字を記録するのは不毛だと考えれば、
    |   実のところ入力されたキーの列を記録する方が現実的なのかもしれない。
    |   とは思ったが、挿入モードの途中でカーソルを動かした時の動作などを考えると、
    |   やはり単純にキーの列を記録すれば良いというわけでもないように思われる。
    |
    |   やはり set-previous-edit からコマンド内容を調査するという方法で頑張ってみる。
    |   ble-decode では _ble_decode_key__hook を一旦変数 hook に移してから実行している。
    |   この hook を BLE_COMMAND, BLE_WIDGET などのような変数に入れて公開することにする。
    |   そしてこの変数を set-previous-edit は記録するようにする。
    |   但し、KEYS やそれまでに用意したローカル変数の様子なども一緒に記録する必要がある。
    |   KEYS は既定で保存することにして、もし特別に保存する必要があるものがある時には、
    |   ble/keymap:vi/save-widget/* という関数を用意することにすれば良い。
    |   set-previous-edit はその関数が存在するかどうかを調べ、
    |   もし存在すればそれを呼び出すことにすれば良い。
    |
    |   保存専用の関数名には議論の余地がある。
    |   ble/widget/vi-command/text-object.hook:save などでも良いかもしれない。
    |
    |   問題点は実際に set-previous-edit が呼び出されるに至るときには、
    |   既に _ble_edit_arg などの変数の値は使用済みとして消去された後であることだ。
    |   これの解決方法は4通りある。
    |
    |   | a get-arg した瞬間にはまだクリアしないことにして、
    |   |   widget の最後でクリアする関数を呼び出すようにすること。
    |   |
    |   |   これの問題点は widget の内側で更に別の widget を呼び出しているときに、
    |   |   引数が残っているがために繰り返し引数が解釈されてしまうことである。
    |   |   更に内側の widget によって引数が消去されてしまうので、
    |   |   この場合には引数を知ることができなくなってしまう。
    |   |
    |   |   内側の widget を実行するときには何らかのフラグを立てるようにして、
    |   |   get-arg によって引数が読み取られないようにするという手もあるが、
    |   |   複雑になるし、今後の widget 実装をを間違える可能性がある。
    |   |
    |   | b 或いは、get-arg する瞬間に引数を別の箇所に退避するという手もある。
    |   |
    |   |   この方法を使うと widget の内側で別の widget を呼び出しても、
    |   |   引数が繰り返し使われてしまうという問題点は防げる。
    |   |   しかし、内側の widget で get-arg を呼び出すと
    |   |   そのときに折角退避した引数が上書きされて消えてしまう。
    |   |
    |   |   つまり、退避はただ1回しか実行しないようにする仕組みが必要である。
    |   |   そのためにフラグを設定するというようにすると、
    |   |   結局 widget 実装の注意点は a と余り変わらない。
    |   |
    |   |   更に、内部で ble-decode-key を呼び出している場合の処理はどうなるか。
    |   |   →その場合は改めて BLE_COMMAND なり何なりが設定されるので、
    |   |   混乱が起こることはない。
    |   |
    |   | c widget の呼び出し元で _ble_edit_arg などの値を退避して記録する
    |   |   という方法もある。しかし、それは ble-decode で退避を行うということを意味する。
    |   |   一応 .before_command という仕組みはあるが、これは _ble_decode_key__hook に対しては効果がない。
    |   |
    |   |   更に、内部で ble-decode-key を呼び出している場合は…これは気にしなくても大丈夫そうだ。
    |   |
    |   | d 或いは arg flag reg の3変数を、get-arg 以外の用途で使用することを禁止するという手もある。
    |   |   そうすれば set-previous-edit の中で単に arg flag reg を参照すれば、
    |   |   それが実際に使われる引数の値であると考えて良いことになる。
    |   |
    |   |   後で widget を実装するときに誤って別の用途で使用しないように、
    |   |   ARG FLAG REG の様に大文字の変数名に変更するという手もある。
    |   |   しかし、それはそれでうるさい。
    |   |
    |   |   また関数で受け渡された変数も arg flag reg の名前を継承しているが、
    |   |   これらの変数に関しても同じ名前を使って良いのかどうかということである。
    |   |
    |   |   - 特に問題になるのは引数を渡すときに、$((-arg)) などのように修正して渡す場合である。
    |   |     このような場合には受け取り側は arg ではない変数名で受け取るように修正しなければならない。
    |   |     あくまでも一番外側の widget を呼び出すときの _ble_edit_arg などなどを記録するためである。
    |   |
    |   |   - 更に引数を握りつぶして何も渡さないということもある。
    |   |     この場合も実のところ引数を記録する必要はなかったりするのかもしれないが、
    |   |     (或いは、そもそも set-previous-edit が発生しない)
    |   |     やはり念のため元々の引数を復元するようにしたいものである。
    |   |
    |   |   - うーん。"オペレータの引数" という概念にも arg を使っているが、
    |   |     これは別名にした方が良い気がする。
    |   |     と思ったがオペレータ内部では一般に set-previous-edit は起こらないような気もする。
    |   |     基本的に自分で set-previous-edit を呼び出すか end-edit (call-operator) で設定される。
    |   |     従って、call-operator の引数名だけ直せばそれで良い。
    |   |     ところが、call-operator の引数名 arg を修正するのであれば、
    |   |     やはり operator の arg も修正する方が自然である。
    |   |
    |   |   色々考え合わせるとやはり get-arg のときだけ大文字にして、
    |   |   それ以外の引数で受け取ったりする引数名は小文字に統一するのが、
    |   |   書き換えとして最も安全なのではないかと思われる。
    |   |   枠組みとしても引数が直接透過して見えるので、それが自然である。
    |
    |   d の方針にする。特に arg flag reg は一番最初に取得するときに大文字にする。
    |   引数で受け渡しするときには今まで通り小文字のままにする。
    |
    | b set-previous-edit と独立に各コマンドで . 情報を記録するようにする可能性はあるか。
    |
    |   単純なコマンドの場合にはそのまま記録する。
    |   motion の場合には通常は何もしなくても良い。
    |   omap から motion/txtobj に貼る時には編集が起こる。
    |   これらに対応するためには motion コマンドにおいて、
    |   flag が設定されている場合には arg flag reg とそのコマンドを記録するという事になる。
    |   flag が設定されているにも拘らず失敗して記録されないということはあるだろうか。
    |   或いはキーを非同期に読み取る為に 27 を返してそのまま終了するという場合もある。
    |
    |   うーん。motion の場合に問題になるとすれば、
    |   或る widget を実装する為に別の widget を呼び出す場合があるということである。
    |   その場合には呼び出し元の widget を繰り返しとして登録するように工夫しなければならない。
    |   しかし、基本的には _ble_edit_arg, _ble_keymap_vi_opfunc などを設定しない限りは、
    |   編集が発生するということはないから、注意が必要な箇所はすぐ分かる。
    |
    |   あと、問題になるとすれば書き込み専用のレジスタに書き込もうとして失敗した時などの動作である。
    |   試してみた所、そのような場合には、やはり . の繰り返しコマンドとしては登録されない。
    |   更に、*.impl で実装している場合には、呼び出し元で設定しなければならないので、
    |   実際に変更があったかどうかの情報を呼び出し元に通知しなければならない。
    |   これはに終了ステータスによってよって行うのが自然であるが、
    |   終了ステータスに別の意味を持たせている場合があるかもしれず、その場合には使えない。
    |   また、全般に終了ステータスを確定させるように書き換えが必要になる。面倒だ。
    |
    |   ただ、この . の実装とは独立に終了ステータスを確定させるというのはあった方が安心な気もする。
    |   → #D0543
    |
    |   うーん。一番外側で情報を記録するようにすると問題になるのは、
    |   オペレータが中で実際に何をしたか分からないということである。
    |   もしかすると opfunc として何もしないものが登録されているかもしれない。
    |   その時にも . の対象とするのだろうか。
    |   Vim script では opfunc は結局キーの列として登録される。
    |   だとすると何か意味のある操作をするとすれば :func() のようになる。
    |   この時 : なので、これは . の繰り返し対象として登録されない気がする。
    |
    |   しかし実際の vim の動作はどうであれ operator が呼び出されれば記録するというのは
    |   一つの一貫した動作であるのでそのように動作するのが適切な気もする。

    やはり a の方針で行くことにする。

      b の方法だと、コマンドが成功したかどうか、
      オペレータが処理を実行したかどうか (例えば y は繰り返し対象ではない)
      などを一番外側の WIDGET に伝達するのは困難なので、苦しい。
      set-previous-edit-area の中か、またはそれと同じ箇所で記録の処理を行う方が現実的と判断する。

    [実装計画A] 主に set-previous-edit で記録する

    * done (→ #D0550): 取り敢えず現在のコードの整理をした。
      ble-decode.sh 側で WIDGET 及び KEYMAP を提供することにした。
      また vi.sh において get-arg にて取得されるパラメータは
      ARG FLAG REG という名前の変数に格納することにした。

    * resolved: set-previous-edit で色々記録を行う。
      これは set-previous-edit で行うのではなくその前後で独立に実装することにした。
      もし後で統合できそうならば統合するが、初めは独立に実装する。

    * done: 再実行するコマンドを取り敢えず何も考えず実装する。

    [振る舞い]

    振る舞いについて再度実装しながら確認していくことにする。

    * done: レジスタの記録

      % 先ず "x などのレジスタ指定は記録されるのか。
      % または改めて . に対して指定されたレジスタ指定はどのように使われるのか。
      %
      % 先ず記録時にレジスタが指定されていた場合には
      % . による繰り返し時にもそのレジスタが使用される。
      % . に対して指定されたレジスタは無視される。
      % 記録時にレジスタが指定されていなかった時には、
      % もし . に対してレジスタが指定されていたらそれを使う。
      % 記録時に既定の "" のレジスタが指定されていた場合には、
      % もし . に対してレジスタが指定されていたらそれを使う。
      %
      % まとめると、記録時に "" 以外のレジスタが指定されていたらそれを使う。
      % それ以外のとき、. 実行時にレジスタが指定されていたらそれを使う。
      %
      % 現在の実装では "" を指定した時はレジスタ指定は削除される。
      % 丁度この振る舞いに符合するので都合が良い。そのままにする。

      これには勘違いが入っていた。"" であっても指定されればそれが使われた。
      なので "" が指定された場合でも _ble_keymap_vi_reg は空欄にせずに 34 を設定することにした。

      | またレジスタが指定されていないときに、レジスタを指定して . を呼び出すと、
      | それ以降の . の呼び出しでは新しく指定したレジスタが使用される様だ。
      | 一度レジスタが指定されれば、それ以降はレジスタが変わることはない。
      | それは "" によるレジスタの指定であっても同様である。
      | つまり、この点に於いて "" とレジスタを指定しないことはやはり異なる。

      記録時にレジスタが指定されていたらそれを使う。
      それ以外のとき、. 実行時にレジスタが指定されていたらそれを使い、
      . の実行に成功したらそのレジスタを新しく記録する。

    * done: 引数の記録

      既に、. に対して引数が指定されていた場合にはそれが優先されることを確かめた。

      | 3x. とすると 3 文字さらに削除される。
      | 3x1. とすると 1 文字さらに削除される。
      | つまり、. に引数を指定しない場合は元の引数を使い、
      | もし . に引数を指定する場合には代わりにその引数を用いる。

      例えば 3d2l の様にした場合には 6 が記録されて、
      . に指定された引数で置き換えられるのか、
      或いは、3 x 2 と記録されて (. に指定された引数) x 2 の様になるのか。
      確かめてみると全体 6 が (. に指定された引数) に変わる様だ。
      つまり記録する時には全体の引数で記録すれば良い。

      | またもうひとつ気づいたことは、. に引数を指定した場合には、
      | 更に後続の . では新しく指定した引数が用いられるということである。
      | これは元々引数が記録されていたときでも記録されていなかったときでも同様である。

      つまり . に指定した引数は記録する。

    * done: フラグの記録は気にしなくて良い

      これは後で任意に指定できるものではないので (というか omap でしか指定できないが、
      omap には . は存在しないので) 優先順位だとか上書きされるかだとかについて気にする必要はない。
      KEYMAP や KEYS についても、WIDGET に紐付いているもののはずだから上書きしない。

    * done: . が失敗したときに引数やレジスタを上書きするかどうか

      | また . が失敗したときの動作についても確認して置かなければならない。
      | →一番下の行で dj をすると失敗する。これを利用して . を失敗させると、
      |   引数の上書きは起こらないようである。つまり、引数の上書きは、
      |   実際に set-previous-edit-area が呼び出されたときに行えば良い。
      | →レジスタについても失敗したときに新しく設定されるかどうか確認する。
      |   レジスタについても失敗したときには新しく設定されない。

      →. を呼び出したときの ARG, REG については成功したときに記録する。
      記録されている ARG/REG と区別するために repeat_arg,
      repeat_reg というローカル変数に記録することにする。

    * KEYMAP の記録に関して:

      | % 更に気付いたことだが、呼び出した時の keymap に依存して振る舞いを変えるコマンドが存在して、
      | % しかし、呼び出しの途中で ble-decode/keymap/push, pop を実行することがある。
      | % この時 set-previous-edit の中から元々の keymap を復元する必要が生じる。
      | % これに関しては .invoke-command にて (zle に倣って) KEYMAP なる変数を定義すれば良いのではないか。
      |
      | - KEYMAP というか _ble_decode_key__kmap によって全く異なる動作になるのは
      |   vi-command/operator ぐらいである。
      | - 他に text objects が xmap で異なる動作をするが、
      |   これは範囲の変更のみで編集を伴わないので . のために記録されることはない。
      | - それ以外については . で繰り返されるとしても _ble_decode_key__kmap
      |   によって振る舞いが変わって自然なものだけである。
      |
      | 従って考えるとしたら vi-command/operator の動作を如何に再現するかについて考えれば良い?
      | よく考えてみると、widget を呼び出した後に _ble_decode_key__kmap が変更されて、
      | その後で vi-command/operator が呼び出された場合、
      | vi-command/operator が参照するべきなのは widget 呼び出し時の KEYMAP ではなくて、
      | vi-command/operator 呼び出し時の _ble_decode_key__kmap ではないだろうか。
      | 但し、そのような場合には WIDGET として記録されるのは vi-command/operator ではなくて、
      | 一番最初に呼び出された widget のはずなので記録される KEYMAP について気にしても仕方がない。
      |
      | ここでの問題は何だったか。KEYMAP を記録したとしてそれをどのように利用して、
      | 元々の処理を再実行するかということであった。
      | 一つの方法は元々の KEYMAP で記録した keymap に一時的に切り替えて WIDGET を呼び出すというもの。
      | しかし、これは keymap の状態遷移がよく分からないことになる。
      | 一時的に切り替えたものは元に戻さなければならないが、
      | 途中で keymap が更に切り替わったらどうすれば良いのか。
      |
      | よく考えてみると . を呼び出せるのは nmap からだけである。
      | omap/imap/cmap からは呼び出せない。xmap についても確かめてみた所 . は呼び出せない。
      | 一方で、編集が起こるのは nmap/omap/xmap/imap のみである。
      | nmap で記録されたものに関しては keymap について気にせずに直接呼び出せば良い。
      | omap/xmap に関しては変更が起これば自動的に nmap に落ちてくるはずなので
      | 一旦 ble-decode/keymap/push してしまえば問題ない。
      | また xmap の . に関しては事前に選択範囲を復元するなどの特別な処理が必要になることに注意する。
      | imap に関しては完全に特殊なので keymap の復元がどうとかそういうものでもない。

      つまり記録した KEYMAP は状態復元に使うというよりは、
      repeat を呼び出すときの特別の処理のときに参照するという実装になるだろう。

    * 実は y は . の繰り返し対象にはならない [要考察]

      つまり set-previous-edit-area で一括して記録するということを想定していたが、
      これについては再考しなければならない。
      更に vim では 0dh などとして 0 文字削除にしたときでも . で dh を繰り返せる。
      一方でこのとき `[ 及び `] は設定されない。
      つまり、これは set-previous-edit-area と . の記録は全く別系統であるということの示唆になっている。
      やはり、set-previous-edit-area の中で記録を呼び出すというのは使えない。

      うーん。それでも set-previous-edit-area を呼び出すのと
      同じ箇所で記録するかしないかを判定するという様に設計するのは有効のはずである。
      これについては再度 (set-previous-edit-area を多目的に拡張する方向性も含めて) 後で考え直すことにする。

      うーん。どの様に対処するべきか。

      | a operator で実際に編集が行われたかどうかと、
      |   edit-area の記録は独立に行う。
      |
      |   この方法の問題点は面倒ということである。
      |   特に、edit-area の場合には _ble_edit_str.replace, reset
      |   における hook を利用して自動的に operator 内の編集を検出できたが、
      |   実際に編集を行う操作が operator 内で呼び出されたかどうかは、
      |   (実際に文字列に変更が行われなかった場合に) 検出できない。
      |   これを正しく実装するためには operator 内で
      |   "記録に値する何かを実行した" というフラグなどを明示的に立てる必要がある。
      |
      | b commit-edit-area による編集範囲の登録と、
      |   実際に行われた編集に基づく編集範囲の記録を独立に行い、
      |   set-previous-edit-area を呼び出すときに両者を合成する?
      |
      |   この方法は問題が色々あるので駄目。
      |
      |   x まず初めに独立に記録を行って後で合成することは不可能である。
      |     それぞれの編集範囲を構成する各操作の順序の情報が失われてしまうので、
      |     後でそれらを合成することは不可能である。
      |
      |   x また、実のところ . で記録するかどうかは、
      |     編集が行われたかどうかなのでわざわざ編集範囲まで記録する必要はない。
      |     編集範囲の更新をするのは処理の無駄である。
      |
      | c start-edit-area で編集が行われたかどうかのフラグを下ろしておいて、
      |   shift-by-dirty-range が呼び出された時にそのフラグを立てる様にする。
      |   そして end-edit-area においてフラグが立っていれば記録を行う。
      |
      |   x この方法の問題点は 0dh などについて、
      |     実際の文字列の変更が発生しなかった時に shift-by-dirty-range が呼び出されず、
      |     最終的に記録されないということである。
      |     vim の動作としては実際の文字列の変更が行われなかったとしても dh が記録される。
      |     そして何処か別のところに移動して . を押せば dh が実行される。
      |
      | d 或いは、operator 毎に記録するべきか記録しないべきかの属性を静的に持たせる。
      |
      |   例えば既定では記録するようにする。
      |   ble/keymap:vi/operator:foo/norecord などの空関数を定義し、
      |   その関数が定義されている場合には記録しないというようにする。
      |   また operator:foo 自身の呼び出しで 0 以外を返した場合も記録しないようにする。
      |
      |   operator 以外に関しては特に指定しない限りは
      |   start-edit-area と end-edit-area で囲んで変更を検出する。
      |   というかこれはそんなに気にしなくても良い。現状の set-previous-edit-area も同様に、
      |   必要な各箇所で end-edit-area か set-previous-edit-area を明示的に呼び出している。
      |   それと同様に実装すればよいだけの筈である。

      ここは d の方法を採用することにする。
      各オペレータ毎に成功した時に記録するかどうかの属性を持たせる。既定では記録する。
      →その様に実装することにした。

2017-10-26

  * vi-mode: . 実装 (2) WIDGET KEYMAP (decode) 及び ARG FLAG REG (vi-mode arg) の整理・対応 [#D0550]

    * done: get-arg, get-arg-reg の出力先の変数名は大文字にする。
      get-arg, get-arg-reg を直接呼び出している関数名の変数は大文字にする。
      引数として受け取っている arg flag reg は大文字にしない。

      直接呼び出し元の arg flag reg を触るような関数は現在存在しないはずなので、これで問題は起こらないはず。
      (直接呼び出し元の変数を触るように設計するのは、
      特に out パラメータとして使う場合かグローバル変数の場合であるが、
      arg flag reg に限って呼び出し元に変更を通知するようなことはないしグローバル変数でもない)

      * done: 先ず初めに vi_nmap からのみ呼び出すことを目的とした widget については、
        関数名を vi-command/* から vi_nmap/* に変更し、更に flag のチェックは省略する。
      * done: 更に get-arg を使っている部分については get-arg-reg を使う様にする。
      * done: get-arg は廃止し、get-arg-reg の関数名を get-arg にする。


      * done: get-arg を呼び出している箇所を機械的に大文字に変換していく。
        これを実行するに当たって良い方法はないだろうか。
        Emacs の置換の文字列で特別な記法があれば良いが難しい。

        こんな記事を見つけた。\,(...) で replacement に S 式を含めることができるようだ。
        https://stackoverflow.com/questions/677021/emacs-regular-expression-replacing-to-change-case

        \_<\(arg\|flag\|reg\)\_> -> \,(upcase \1) これで置換を行った

    * done: ble-decode: _ble_decode_key__hook から読み取ったコマンドを一旦
      BLE_COMMAND 的な変数に入れてから実行する。引数も含めて。
      これは _ble_decode_{char,key}__hook についても同様にする。
      通常の widget 呼び出しに使っているのも COMMAND から BLE_COMMAND 的なものに改名する。
      {BEFORE,AFTER}_COMMAND も同様にする? もし COMMAND -> BLE_WIDGET にするならこれは変えなくても良いかも。
      もしくは __before_command__ 自体を __before_widget__ に変更するか。

      % また、現在の実装では __before_command__ の内部で
      % COMMAND= としてコマンドをキャンセルする手法を用いているが、
      % この手法により何らかの問題が生じないかについても考察する必要がある。
      % というか、実のところ何も実行されないのだから、BEFORE_COMMAND 内部で set-previous-edit
      % が起こるような事態にならなければ大丈夫。むしろ、そのような場合には BLE_COMMAND
      % を記録して再実行したとしても動作を再現することはできないので別の問題が生じる。
      % →これは恐らく問題ない。OK

      そもそも {BEFORE,AFTER}_COMMAND なる変数は定義していないのであった。なので気にしない。
      COMMAND に関しては (BLE_COMMAND などではなく) zle に合わせて WIDGET にする事にした。
      現在の kmap を zle に倣って KEYMAP に記録することにしたのだから WIDGET も同様に zle に倣うのが良い。


2017-10-25

  * 2017-09-16 vi-mode merge 直前に一括して行うテスト・仕様変更など (1) [#D0549]

    以下は先に破壊的変更してしまうことにした。

    * done: vi_command は vi_nmap に変更する?
    * done: vi_insert は vi_imap に変更する?
      →widget で vi_nmap と vi-command (vi_nmap, vi_omap, vi_xmap 用) を区別したかったので、
      早々に名前を変更することにしてしまった。これは破壊的な変更なので、今度 push する時に説明が必要。

    % * vi-insert/@norepeat は @vi-norepeat 辺りに改名する。
    %
    %   C-c の説明は "InsertLeave autocmd が実行されない" である。
    %   これより @vi-cancel-leave などの方が分かりやすいのでは。

    * done: vi-insert/@norepeat は廃止された。従って改名の必要はなくただ消すのみである。
      _ble_keymap_vi_imap_white_list に登録されていない widget は全て
      __before_command__ で repeat を reset するように変更したためである。

    * done: また同時に marked/nomarked も @marked/@nomarked に変更する。
      →2017-10-25 これはもう修正した。今は marked/nomarked は obsoleted とし、
      @marked/@nomarked に振り替える様にしているが、後に削除する。

    * done: vi-insert/@norepeat, marked/nomarked の廃止

2017-10-24

  * 2015-11-18 histexpand: shopt -s histverify histreedit 対応 [#D0548]

  * support: shopt -s lithist? [#D0547]

    % 元々改行を含む履歴項目を登録する機能はあった様である。
    % この時の振る舞いについて調べ ble.sh でもこの形式に従って history を登録するべきだろう。

    先ず初めに echo hello のような感じのコマンドを複数一度にじっこうしても一つの履歴項目にはならない。
    for 等のコマンドが単体行としては不完全な形で実行されると一まとまりに登録される。
    この時 history コマンドで見ると改行がそのまま出力されて表示されている。
    .bash_history を除いてみると行毎に登録した場合と同様に改行で分かたれて登録されている。
    bash を再起動して再度 shopt -s lithist して履歴を遡ってみると
    元々一つの履歴項目であったという情報は消えてばらばらの行になってしまっている。
    つまり、shopt -s lithist をしたとしても改行を含む履歴項目が bash_history に記録されるわけではない。

    従って ble.sh では今までと同様に独自の eval -- 形式で改行を含む履歴項目を記録するということで良い。
    cmdhist, lithist のオプションに関しても、ble.sh では複数行の履歴に元から対応するということで振る舞いは変えない。
    或いは、文法に従った accept 拒否については cmdhist で振る舞いを変更するという手もある。

2017-10-23

  * 時々 kcode と keymap の不整合が起きてキーが効かなくなるのは何故か? [#D0546]

    keymap は bash version 依存がある様だ? と思ったら、
    default.sh のタイムスタンプで keymap/vi.sh のキャッシュを更新していたのが問題だ。
    default.sh から生成されるキャッシュは bash の version によって個別に生成しているので、
    そのタイムスタンプで更新する必要がある。

    local dump="$_ble_base_cache/cmap+default.$_ble_decode_kbd_ver.$TERM.dump"

    と思ったけれど本当だろうか。というか、_ble_decode_kbd_ver 3 と 4 で
    kcode は共有されているのだろうか。うーん。見てみたが共有されているはずである。
    従って bash version によらずに不整合は起こらないはずなのだが…。
    もしかすると過去に default.sh に問題が合ったというだけなのかもしれない。

    と思ったらやはり再現する。これは原因を調べて解決する必要がある。

    多分原因は分かった。default.sh が初期化される前に vi.sh が読み込まれるとなる。
    と思ったら default.sh を先に呼び出しても default.sh の中の最初の ble-bind から
    DEFAULT_KEYMAP の解決のために vi.sh が読み込まれてしまう。
    そして initialize が二重に呼び出されてしまう。
    取り敢えず直した。様子を見る。

2017-10-22

  * 2017-09-11 vi-mode: ESC の問題 (reported by cmplstofB) [#D0545]

    [原因調査]

    | ノーマルモードから挿入モードに移った直後くらいに C-c、C-m 等及び通常のキー入力が「そのようなキーは
    | 設定されていない」という警告とともに無視される時がある。

    * 可能性1

      自分で試していて思ったのは、無意識で clear-screen しようとして C-l を押してしまい、
      ノーマルモードに戻ってしまうことがあるということである。
      ノーマルモードに戻ると C-c は定義されていないので警告が出る。
      また通常のキー入力も何らかのコマンドとして解釈されてエラーになる。
      何か入力して oOiIaA などが入るとそれ以降は入力できるようになる (母音なので確率は高い)。
      "直後" というのはそういうことなのではないかという疑い。

      問題は現在のモードが表示されていないことにあるのではないかという気がする。
      モードが切り替わった時に簡単に表示する仕組みにしてみたが、微妙である。
      切り替わった瞬間には -- INSERT -- と表示されるが、
      補完などによって書き換えられた後は残らない。

      ble-edit/info で恒久的に表示する内容 (default) と、
      一時的に表示する内容を管理できるようにすると良いのではないだろうか。
      結局新しい仕組みを整えることになった。

    | * 2017-09-07 vi-mode: 現在のモードや引数の状態を表示する?
    |   info に表示するか新しく別の status line を追加するか。
    |   info に追加するというので良い気がする。

    実際に C-l を vim で試してみると動かない。
    vimindex を調べると insertmode が設定されているときにのみ C-l は normal-mode だそうだ。
    Qiita の記事の方を見ると C-l は再描画になっている。
    zsh で試してみると C-l は clear-screen である。
    従って C-l は clear-screen である方が妥当である。

    2017-09-13 追加の報告が来た。

    | どうも私の端末の問題でした。Vim で Esc キーを多用するので Esc キーが押下された時 "Meta-"
    | に続く文字をなるべく待たないようにしているのですが、その設定を無効にすると発生しなくなり
    | ました。厳密な再現条件は未だ不明ですが、一応の解決を見たので取り下げます。

    うーん。もしかすると、これは keymap を途中で切り替えた時の話かもしれない。
    一回コマンドを処理した時に残っているキーをどの様に処理するのだったか。
    というか、最近 ble-decode-key の何処かでミスを埋め込んで更にそれを修正したような気がする。
    12f3329 これだ。恐らく現状では直っているのではないかと期待する。

    やはり解決していないそうだ。どうも話を見るに寧ろ連続して文字が来たときではなくて、
    逆に時間が立ってキーが届いた時の問題のようである。
    しかし、それは寧ろ ble.sh としては変なことが起こりにくい状況のはずである。
    先の推理では C-M-m などを ESC + C-m に分解して処理するときに一度に ESC と C-m が来るのが問題かと考えたが、
    どうもそういう訳でもないようだ。

    あー。なんか分かった気がする。vi-mode では M-* を ESC * に分解していない。
    つまり ESC が二重になると失敗する。

    更に ESC を単体で受け取ったとしてもその場で処理されない。
    その場で処理するように ble-decode を改修しようかとも考えたが、
    よく考えると、それをやると矢印キーなどを認識できなくなってしまう。
    或いは、矢印キーを送るなどした場合には通常は一つのパケットで送るので、
    矢印キーの先頭が来ているときにはすでに続きも来ているはずである。
    そういう意味では既に次のキーが来ているかいないかで ESC をその場で処理するかどうかを判定するという手もある。

    取り敢えず処理するようにした。もう少し様子を見て他に問題の可能性が
    なさそうであれば改めて cmplstofB さんに尋ねることにする。

    2017-09-17 うーん。やはり駄目だそうだ。

    | すいません。まだ発生します。@akinomyoga 様の手元で発生しないということは
    | 確実に私の端末側の問題ですので、こちらで対処します。
    | どうかお気になさらないでください。

    2017-10-12 2文字のコマンドの2文字目に ESC が来る場合、
    ble-decode の枠組みでは次の文字をも食らい M-? が 2 文字目に来たとする。
    これにより余分に処理されない文字が出てくる。

    2017-10-22 どうやら ESC 単体を押した時点で元に戻って欲しいようだ。

    * ESC 単体で受け取る方法についての考察

      調べると stty time 0 及び tmux set -sg escape-time 0, screen maptimeout 0 など、
      通過経路全てで timeout を設定するようにすることができる。
      この時、ble.sh でも ESC の次に文字が既に来ているかどうかで単体の ESC かどうかを判定できる。

      % と思ったが実際に実装しようとすると問題があるということが分かった。
      % 現状では bind によって ESC を単体で受け取ることに成功していない。
      % 試しに bind.sh の ESC に関係する work around を bash-4.4 で全て外してみたが、やはり動かない。
      % カーソルキーや Function キーだけでなく、個別に ESC h と入力しても駄目である。
      %
      % と思ったが、bashrc でいきなりロードすることにすれば ESC h だけは動くようだ。
      % カーソルキーの類は動かない。ESC [ だけ定義すればカーソルキーの類も動くようになるようだが、
      % そうすると ESC 単体ですぐに受信できなくなる。
      %
      % 結論: bash readline の bind の仕組みを改修しなければどうにもならない
      % 元々 bash の bind は色々駄目駄目なので、
      % それらの改善も含めて提案してしまえば良い気がする。

      カーソルキーの類が動かなかったのは bleopt_decode_isolated_esc=raw
      の実装が不完全だったからの気がする。しかし、それを除いても (1B5B に bind しなくても)、
      ESC 単体ではすぐに受信できないようだ。と思ったが、事情は複雑である。
      CSI decoder の方が止めている可能性が出てきた。
      これはやはりキーロガーを導入するしかない。

      導入した。しかし、どのタイミングで受信したのかは分からない。
      やはり [[ $bleopt_decode_isolated_esc == meta ]] || ble/util/is-stdin-ready
      の条件をちゃんとした物にする必要がある。あるいは、もっと手っ取り早く確認する方法?

      調べてみると ESC はその場では受け取っていないようだ。
      何かが前にいて止めているように思われる。
      暫くしてから入力すると同時にキーが来る。
      screen で画面を切り替えてから入力すると
      bash_execute_unix_command で見つからないという事になってエラーになる。
      これは screen が何か噛んでいる気がする。

      また ESC を間隔を空けて入力したときには

      整理する

        screen, esc1BXX=0, ESC (wait) h
          → 大丈夫。但し、h を受け取った時に一緒に ESC も受け取る
          どうやら screen が勝手に ESC を待つようなので、
          取り敢えず screen のない環境でテストするべきである。

        esc1BXX=0, ESC (wait) h
          → bash_execute_unix_command error
          h だけが受信される。

    * 0.4 sec 以上間隔を開けると処理されないということについて。
      これは変である。再現しない。

    * 0.4 sec 以上間隔を空けて ESC を連打しても何も起こらない
      これは変である。しかし再現した。

    先に screen の外での振る舞いを正すべきである。
    というか screen の外で正しくなればあとは maptimeout を 0 にするなどすれば良いはずだ。

    再現した…。screen の中でやっていたのが悪かったようだ。
    screen の中でやっていると ESC が次の文字とくっついてからしか送られてこない。
    従って、単体で送られてくることがなかったのだ。
    そして、もし単体で送られてくると bash は解釈できずに駄目。

    [修正1]

    * 修正: \e? に bind しているときは \e 単体には bind しない。

      これをしないと ESC が単体で送られてきたあとに ? が送られてくると、
      bash_execute_unix_command のエラーが発生する。

      これは 0.4 sec 以上間隔を開けると処理されないというエラーと関係していると思われる。
      例えば tmux で escape-time 400 になっていると仮定すると、
      0.4 sec 以内であれば h が入力されたときに ESC h の組で送られてくる。
      0.4 sec 経過すると先に ESC だけが送られてくる。次に h が送られてくる。
      この時点で bash が内部で bash_execute_unix_command エラーを吐いていたのだろう。
      (しかし、何故そのエラーが表示されなかったのかというのは不思議である。
      と思ったがこのエラーメッセージは bash の標準エラー出力に出されるものだから、
      ble-decode ではなくて ble-edit の方から出てきているはずである。
      と思って調べたが check-stderr は無条件に visible-bell を呼び出しているので、
      やはりエラーメッセージが表示されているはずなのである。)

    [確認1]

    o さて、ESC を 4 回押さなければ駄目だったのが 2 回で済むようになった。
      @cmplstofB さんの手許でも 4 回だったので、恐らくこれで多少なりとも改善はしたはず。

    x 但し、間隔を空けて入力するとやはり認識されない。
      何回押しても挿入モードのままである。うーん。これは何だろう。

      調べてみる。

      esc1BXX=1, ESC (wait) ESC (wait) ESC (wait) ESC (wait) h
      → bash_execute_unix_command error になる。h だけ受信する。
      esc1BXX=1, ESC (wait) ESC h
      → bash_execute_unix_command error, ESC h を受信する。
      esc1BXX=1, ESC (wait) ESC (wait) h
      → bash_execute_unix_command error, h だけ受信する。

      esc1BXX=0, ESC (wait) h
      → bash_execute_unix_command error, h だけ受信する。
      esc1BXX=0, ESC h
      → ESC h h を受信する。key は何故かちゃんと C-[ h になる。
        これは ESC h の ESC だけが一致して、その後で再度 h を処理しているからである。

      うーん。間隔を開けると ESC 単体で受信できないようだ。

      ESC を bind -s '"\e": "\xC0\x9B"' で受信するようにしてみたところ動くようになった。
      つまり、その場で直ぐに受信することができるようになる。
      →試してみた所、実は bash-3.1 - bash-4.4 まで全部これで動く。bash-3.0 は動かない。

      うーん。ところで read -n 1 を使えば ESC はその場で受信できるようだ。
      →bind の仕方で ESC 単体で受信することができるらしいと分かったので、これは考えない。

    [修正2]

    * 修正: ESC は bind -s で UTF-8 のエラー表現に移せば良いと分かった。
      この時、ちゃんとその場で ESC を受け取ることができるようになる。

    試してみる。取り敢えず動く?

    * 孤立 ESC はちゃんと C-[ と解釈されているが、
      bash-4.3 以上では timeout を待つ様になっている。
      調べると bash-4.3 では 'keyseq-timout' というものが追加されたようだ。
      何の効果もない。うーん。と思って keyseq-timeout にしてみたら動く様だ。
      単位は恐らくミリ秒である。bind 'set keyseq-timeout 1' などとしておけば良い。

    * 孤立 C-[ はちゃんと処理されているが、
      カーソルキーも誤って孤立キーと判定されている。
      これはどうした物だろうか。というか何故? 貼り付けなどは正しく処理できているのに。

      実際に試してみると確かに is-stdin-ready ではない様だ。
      そして貼り付けを行ったときにはちゃんと is-stdin-ready になっている。
      改めて矢印キーについて調べてみる。全ての文字が is-not-ready である。
      うーん。どうしたものか…。

      これは別のターミナルでやると違うなどということがあるだろうか。
      →mintty でやっても同様だった。矢印キーは is not ready で貼り付けは ready
        従って、これは Poderosa が悪いのではない。
        途中の端末ハンドラが怪しいのではないか。

      或いはやはり ESC * も bind するという方向で動いたりしないか?
      →試してみたが駄目だった。

      screen 越しにやってみても駄目だった。
      つまり、やはり端末ハンドラが悪いということを示唆する。
      というのも screen は完全にキャッシュしてから送る設定に今はなっている。
      ということは、screen と bash の間にある端末ハンドラが悪い。

      んー。或いは。read -n 1 してしまうという手もなくはないが…。
      →read -n 1 で実装してみたが動かない。というか、何故か順序が変更されている気がする。
        | if ((char==27)) && [[ $bleopt_decode_isolated_esc == esc ]]; then
        |   function ble/util/read-byte-with-timeout {
        |     local LC_ALL=C
        |     IFS= read -r -d '' -n 1 -t "$1" byte; local ext=$?
        |     ble/util/sprintf byte %d "'$byte"
        |     return "$ext"
        |   }
        |   local byte
        |   if ((_ble_bash>=40000)) && ble/util/read-byte-with-timeout 1; then
        |     bleopt_decode_isolated_esc=meta ble-decode-char 27
        |     ble-decode-char "$byte"
        |     return
        |   else
        |     ((char=ble_decode_Ctrl|91)) # C-[
        |   fi
        | fi
      ということは何を意味するかというと特殊キーの場合には既にそれを構成する文字を読み取った後ということ。
      そして、現在は ble-decode-char をループか何かで回して処理しているということ。

      と思って一回の ble-decode-char 呼び出しで文字の列を処理できるように修正した。
      しかし効果はなかった。改めて ble-decode-byte+UTF-8 において出力してみると、
      実は ble-decode-byte を呼び出している時点で既に is-stdin-ready は non-ready になっていた。
      つまり、bash が内部で "ESC [ D" などの文字の列を既に標準入力から読み取って
      中で保持しているので、is-stdin-ready では判定できないということになる。
      そしてタイムアウト付きで read しても既に読み取ってしまった文字は読み取れない。

      うーん。だとすれば如何にして timeout を検出すれば良いのか…。
      基本的に現在の枠組みでは難しいような気がする。

      a 全ての可能なキーシーケンスに対して bind して、
        一度に受け取ることができるようにする?

        しかしこれは以下の点で問題がある。
        x 先ず、このキーシーケンスから外れるような入力が合った場合に、
        bash_execute_unix_command などのエラーが出るということが既に知られている。
        キーシーケンスから外れる全ての可能性について bind -x するとしても、
        大量に登録しなければならないので起動が遅くなるし、そもそも bind -x がそんなに信頼できるかも怪しい。
        x また、マウスなどの入力を受け付ける場合や、問い合わせの返答を受け取る場合を考えると、
        全てのキーシーケンスというのは無限個あることになり、全て登録するのは無理である。

      b 或いは bind から read -n 1 ループに入るか。

        それでも一番上のコンテキストで実行するためには
        ループには bind で入らなければならない。
        bind -x 'X: _ble_decode_char=X; eval "$_ble_decode_loop"'
        などのようにして、_ble_decode_loop にループを記述すれば良いだろう。

        x これの問題点は 1 文字目がカーソルキーなどの場合には、
        カーソルキーを構成する 2 バイト目以降は read では決して読み取れないという事である。
        何故なら bash が既に読み取ってしまった後になるためである。

      c 関数内で read -n 1 ループに入るか。

        x この時の問題点は実行の文脈をトップレベルにできないということである。

        x 更に、誤って C-c などを連打してそれがループに対して作用してしまった場合、
        その瞬間に ble.sh から抜けて元の bash になってしまう。
        それだけでも問題であるが、さらに、
        この時、其処までに編集した文字列などが失われるなどの実害もある。

      d ESC * も bind -s 経由で登録したらうまく行くかもしれない?

        もしくは bind '"\e\e": "\xC0\x9B\xC0\x9B"' でも十分かもしれない

      方針 d でうまく行くようになった。しかし、こうすると今度は timeout した時に、
      esc をそのまま処理するか meta として処理するかの切り替えができなくなる。
      或いは逆に C-[ を ESC に戻して処理するという具合にすることは可能か?

      元々 C-[ が \e[27:5:91~ として送られてくることはないはず。
      だとすれば C-[ を ESC に戻せばよいのではないだろうか。

      % と思ったが…よく考えたら C-[ になるのは key の段階なので、
      % ble-decode-char の段階で介入できない。
      %
      % ble-decode-char の段階で介入できるような特別な文字は存在するだろうか?
      % うーん。例えば ble-decode-byte+UTF-8 において ESC の 3 バイト表現の場合には特別なフラグを立てるようにするなど?
      % しかし ble-decode-byte+UTF-8 は文字デコーダとして独立したものにしたい。
      %
      % うーん。或いは \e[27;5;91~ は csi を通して処理されるので、
      % csi から出てくるキーについても修飾キーになる可能性を検査するように修正するという手もある。
      % と思って実装を見たら元々収書キーになるかどうかの判定は csi から出てくる物も含まれていた。
      %
      % 特別に対処する必要はなかった。

    多分解決した。未だ問題がある場合には別項目で立てることにする。

  * ble.pp: readlink -f は Linux でしか使えない [#D0544]

2017-10-19

  * vi-mode: . 実装 (1) ble/widget の終了ステータス確定 [#D0543]

    | Note: __default__, __defchar__ においては要求されたコマンドが成功したかどうか
    | (そして . に記録するに値するかどうか) というよりは、
    | そのキー入力に対する処理が見つかったかどうかという意味を持つ。
    | 見つかったならばその処理自体が無効だったりして失敗したとしても、
    | 別のハンドラーを探しに行くという様な動作は変である。
    | 或いは __default__ に登録するハンドラーについて、
    | それに対応する処理が見つからなかった場合には、単に 1 を返すのではなくて、
    | 特別な値を返すというルールにするのが良い。
    | むしろその方が自然である。
    |
    | Bash の終了ステータスの値を参考にするのが良さそうである。
    |
    | - 127 は一般にコマンドが見つからなかった時に使われる。
    |   特にコマンドが見つからなかった時は command_not_found 関数が使われるが、
    |   これは ble-decode の枠組みにおける __default__ に近い。
    |   更に command_not_found 関数もなかった場合に 127 がコマンドの終了ステータスになる。
    |   これから、__defchar__/__default__ に登録した関数によって、
    |   KEYS に対応する処理が定義されていない場合には 127 を返すというのは自然な気がする。
    |
    |   と思ったが 127 は丁度 7 bit で表現できる最大の数であることから
    |   ソースコード中に頻出する数字である。つまり検索しにくい。
    |   うーん。使われていない 125 を代わりに使うことにしようか。
    |
    | - 126 はコマンドは見つかったが何らかの理由で実行できなかった場合の値である。
    |   これは ble-decode ではするべき操作は決まったが、それが正しく実行できないときになる。
    |   つまり bell を鳴らしたりするような場面である。これは普通に 1 でも返す方が自然だ。
    |
    | - 125 は使われていない
    |
    | - 124 はプログラム補完に於いて、
    |   補完候補生成を最初からやり直すということを要求するのに使われる。
    |
    | - 128 以降はシグナルに使われる。
    |
    | - その他の 12? は特に使われていないようだ
    |
    | - 148 = 128+20 (SIGTSTP) は C-z による中断時。
    |   現在 isearch の fib には 27 を用いているが、根拠は弱い。
    |   こちらの方が説得力があるかもしれない。
    |   また 27 は別の目的でも使われるのでなかなか検索しにくいという問題もある。

    → __default__, __defchar__ の終了ステータス 125 に対応した。
    → 中断・継続のための終了ステータスは 27 から 148 に変更した。

    その他の widget についても終了ステータスについて再確認して、
    全体に終了ステータスを定義済みになるようにした。

2017-10-17

  * 2017-10-14 vi-mode: レジスタ対応 [#D0542]

    operator 呼び出しの前後で _ble_edit_kill_{ring,type}
    を入れ替える実装にする事にした。
    これは単に書き換えて行くだけである。

    * done: call-operator-*wise を改修して kill_ring, kill_type を
      復元・保存する様にする。

    * done: 現在 operator:* は _ble_keymap_vi_operator_delayed
      を用いて処理の継続の情報を呼び出し物に伝えているが、
      これは終了ステータスによる方法の方が自然なのではないかと思われる。
      →終了ステータス 27 によって続きを別のところで処理することを表す事にした。

    * done: call-operator-*wise の呼び出し元を修正する。

    * done: 以下の関数の呼び出し元の修正
      - done: exclusive-goto index flag reg nobell
      - done: inclusive-goto index flag reg nobell
      - done: exclusive-range p q flag reg nobell
      - done: linewise-goto index flag reg opts
      - done: linewise-range p q flag reg opts

    * done: 以下の関数は直接 kill-range/copy-range を呼び出している。

      - done: ble/widget/vi-command/copy-current-line
      - done: ble/widget/vi-command/kill-current-line
        上記の関数については operator 経由で呼び出す様に変更した。

      他にもあると思われる。と思ったら、他は全て operator y/d/c 経由だった。

    * done: 後は kill_ring kill_type を直接触っているコード
      vi-command/paste.impl vi_xmap/paste.impl がある。

    * done: operator:* の終了ステータスを確定させる。
      特に 27 を返すことは特別な意味を持つので。
      27 を返すもの以外は 0 を返すように修正した。

    レジスタへの追記の振る舞い

    "大文字によって既存のレジスタへ内容を追加できるそうだ。
    しかし v V C-v を混在させるとどうなるのか。

    C-v に v を追記したら C-v だった。
    ただし、v で追記した分については nfill は設定されていないようである。

    今の実装の問題点

    * resolved: "x を前置すると実際に変更がなかった場合でも
      レジスタに kill_ring kill_type の内容が登録されてしまうのでは?
      と思ったが "x を前置したときの内容は事前に "x の内容になっているので、
      変更がなかった場合は改めて "x に値を格納しても以前と変わらないので問題ない。

    * resolved: 現在は "x を指定したときにはそのレジスタだけに値を設定している。
      しかし、vim の動作を確認すると無名レジスタにも同じ値をコピーするようである。

      a これに対応するためには、例えば一つの方法は
        local _ble_edit_kill_{ring,type} を事前に設定せずにそのまま処理を実行し、
        後で _ble_edit_kill_{ring,type} の内容をレジスタにコピーするというもの。
        もし追記を指定された場合には、レジスタに追記した後で追記内容を
        _ble_edit_kill_{ring,type} に書き戻す。

        この方法の問題点は実際に _ble_edit_kill_{ring,type} が変更されたか
        どうかを検出しなければならないということである。
        もし "x を設定しても何も変更がなかった場合には、
        _ble_edit_kill_{ring,type} の内容をレジスタにコピー・追記してはならない。
        実際に試してみたが、やはり、例えば "ag~ ではレジスタに変更は起こらない様だ。

        またこの方法だと operator から見える _ble_edit_kill_{ring,type} の内容は
        無名レジスタのそれであって、ユーザが "a で指定したレジスタの内容ではない。
        % (_ble_edit_kill_{ring,type} の内容を変更した時は "a に対する変更であるにも拘らず。
        % と思ったが、これは微妙である。何故ならユーザに依る変更は "" と "a の両方に適用されるから)

      b もう一つの方法は、取り敢えず local _ble_edit_kill_{ring,type} は事前に設定し、
        それをレジスタにコピー・追記した後で、
        unset _ble_edit_kill_{ring,type} して本来の kill_ring に値を戻すというものである。
        しかし、この場合でも kill_ring に変更があったかどうかを検出する必要がある。

      c やはり一番妥当な方法は実際に .copy-range .kill-range する箇所で
        コピー・追記などの処理を行うということである。

      → c の方針で書き直した。operator:* の呼び出しは結局全て
      call-operator 経由で行うことになったので、書き換えは簡単である。
      operator 側でもレジスタに触るものは限られている。

    Note

    * done: omap では "x は使えない。つまりオペレータを入力する前に "x は設定しなければならない。
      →nmap と xmap に個別に '"' を登録することにした。

    色々書き換えたので動作確認を行う。

    * done: レジスタ追記について: (v, V, C-v) x (v, V, C-v) が正しく動作するか。
      - v v, v V, v C-v は確認した。
      - V V, V v, V C-v も確認した。
      - C-v v, C-v C-v, C-v V も確認した。

    x resolved: ysiw" の入力途中に bell がなる。動作は正しい。
      w まで入力したところでなる。どうも operator:ys で 27 を返すとなるようだ。
      →call-operator-* の戻り値をチェックして失敗したら bell を鳴らすようにしていた箇所があった。
        27 を返した時には何もせずに退出するべきである。その様に書き換えた。
        他にも call-operator-* を呼び出しているが戻り値に対応して適切な処理をしていないところが
        幾つか合ったのでそれも直した。

    * resolved: これは前からだと思うが行指向の kill_ring を最終行で貼り付けたとき、
      余分に改行が挿入されるのは何とかならないのだろうか。
      →これは直した。また `[`] で設定される範囲も直した (次の行頭には行かない)。
        両変更について確認した。

2017-10-12

  * ble-edit: 複数行編集時に .SHELL_COMMAND を実行すると、 [#D0541]
    色々と座標計算がずれている。先ず初めに編集中の文字列が残ってしまう。
    更に、.SHELL_COMMAND が出力した内容が上書きされて消えてしまう。

    座標計算は合っている。みたところちゃんとした場所に移動してから実行しているように見える。
    と思ったら分かった。端末の一番下にいるときに起こり、端末の上の方に煎る時には起こらない。
    つまり、描画領域の高さの確保がちゃんとできていないことが原因である。
    取り敢えず一時的に端末の高さを 0 にするということが必要である。

  * vi-mode (visual mode): J gJ [#D0540]

    これは試してみた所 block, char かどうかとは関係なく、常に行指向で処理するようだ。
    これの対応は簡単だった。

  * vi-mode: (insert) で C-c すると表示は (insert) のまま [#D0539]
    ノーマルモードに戻っている気がする。
    よく分からないので、ble.sh では C-c で
    単にノーマルモードに戻ることにする。

  * `[ `] は挿入モード中でのカーソル移動でも途切れるが、 [#D0538]

    % そのようなものにまで対応していると遅くなると思われるので今は対応しない。

    もしかすると white_list に載っていないコマンドで
    dirty-range#clear すれば良いだけかもしれないが。
    いや、移動した後で何も変更しないということも考えられるから、
    end-edit-area, start-edit-area を実行するべきだろうか。

    しかし white_list に含まれるかどうかのチェックには時間がかかるのではないかという心配がある。
    現在の設定では挿入の引数が設定されていない限りは white_list のチェックは行っていない。
    `[`] を設定するためにこれを利用するというのは、常に white_list のチェックを行うという事に等価である。
    self-insert は特に頻繁に通過するだろうから、特別に対処するというのは妥当である。

    さて、結局 `[`] の挿入モードにおける厳密な振る舞いに対応することによるオーバーヘッドは、
    .before_command における white list チェックのオーバーヘッドのことだと考えられると分かった。
    現在の実装では特に white list の使用は繰り返しが指定されたときだけにしているが、
    実のところ将来的に undo を実装する際には結局同様にチェックしなければならない気がする。
    結局、white list のチェックを免れられないのであれば、ここで対応する。

  * vi-mode (xmap I): より vim に違い動作 [#D0537]

    どうも色々ためすと切り出し位置の決定はそんなに簡単ではないようだ。
    現状では行を覚えておいた内容と比較して一番初めに変更の合った点からとしているが、
    これはたまたま挿入した文字列が元々合った内容と一致している場合に切り出し内容がずれて問題になる。
    vim で詳しく調べてみると、どうやら I が始まって以降の変更範囲を覚えているようである。
    どこから開始点よりも前 (前の行での変更も含む) で変更があれば (変更前と変更後が同じだったとしても)、
    切り出し位置は開始点になる。もし変更が開始点よりも後にあれば変更はそこからになる。
    さて、変更範囲は何処に記録されるだろうか。挿入モードによる `[`] はどうか。

    - 試してみた所 C-o から復帰した時点で新しい `[ が始まるようである。
      但し何も入力しない場合には最終的に抜けるときに `[ `] は設定されない。
      これは通常通りに入るときと少し異なる動作である。

    - さて、もし I の InsertLeave が `[ `] を使用しているのだとすれば、
      途中で C-o を挟めば以前の編集について忘れてその点からの挿入になるはずである。
      →試してみた所 C-o をした瞬間に InsertLeave が消去されてしまう。
      因みにこの動作は現在の ble.sh でも同様である。

    従って、`[ `] を用いて変更範囲を決定することが可能である。

    - と思ったが、vim の動作を調べてみると挿入モードの中であっても
      カーソルキーなどを用いて移動したりするとその都度 `[ `] が設定されるようである。
      つまり、正しい実装の `[ `] に頼る訳には行かない。

    - 更に、現状の実装では挿入開始点の記録に `[ を使用しているがこれも正しくない。
      より前に変更があったりすると `[ もずれてしまう。
      別の mark を設定する必要がある → これには特別な mark 1 を用意することにした。

    - 矩形挿入を開始して以降の "変更" を累積して記録するにはどうすればよいか。
      現状の `[ `] はそれに近いが挿入モード開始時に開始点に "変更" を記録してしまうのでこれは微妙に違う。
      更に将来的に vim と同じ `[ `] の動作にしたときに、動作が変わってそれも問題になるだろう。

    結局矩形挿入モードのときだけ更新する dirty-range をもう一つ用意するしかないのだろうか。

  * 2017-10-05 vi-mode (visual): p P [#D0536]

    前回 p または P 消したものを覚えていて、それを貼り付けている気がする。
    vimindex のページには書いていない。ページが古いのかもしれない。
    :help v_P とすると v_p または v_P の説明を見ることができる。

    1 help には挿入してから削除すると書かれているがこれは嘘だ。

      ABC
      ABC

      に対して

      e
      e

      を、初めの B 1文字を矩形選択して p すると

      AeC
      AeBC

      という結果になる。これはつまり選択範囲 B を削除してから e を挿入していることを意味する。
      カーソルは最初の e

    2 文字ビジュアルに矩形を貼り付けるとどうなるか。

      12345
      67890
      xyzwt

      abcde
      fghij

      これについて C-v b → g を v 2 → 9 に対して貼り付けると次のようになる。

      1b0
      xgyzwt

      カーソルは b
      これも先に削除してから貼り付けが起こっていることを示唆している。

    3 文字ビジュアルに改行を貼り付けるとどうなるか。

      ABCDE
      FGHIJ

      の v C → D に行を貼り付けると以下のようになる。

      AB
      12345
      67890
      E
      FGHIJ

    適当に既存の機能の組み合わせで実装した。
    テストする。C-v → C-v は確認した。
    上記のケース 1 2 3 は何れも再現した。

    4 V を C-v に貼り付ける場合

      ABCDE
      FGHIJ

      の C-v B → G に p で貼り付ける場合。

      ACDE
      FHIJ
      12345
      67890

      更に P で貼り付ける場合には前に貼り付けられる。
      現在の実装だと以下のようになってしまう。

      A
      12345
      67890
      CDE
      FHIJ

    5 v を C-v に貼り付ける場合

      A12345CDE
      F12345HIJ

      文字列 12345 を C-v B → G に貼り付ける場合には、各領域に繰り返し挿入される。

      A45
      678CDE
      FHIJ

      貼り付けられる文字列に改行が含まれる場合は、繰り返しは行われない。

    これはどう理解したら良いだろう。
    貼り付けられる対象が C-v のときには特別な対処が必要ということか。

    あとカーソルの位置に関しても確認しておく必要がある。
    1 と 2 は合っている。3 はカーソル位置が違うというか…行末に来ている。
    通常の行指向の p P は行末に来ていない…と思ったが、
    実際に v_p の実装では文字指向の p P を使っているので、この動作は別の問題である。

    結局、3x3 のパターンについて個別に paste の仕方を変えて実行することにした。
    色々と引数を与えた時の動作などを観察するとこの方法で良かったようだ。
    簡単に各場合の動作の確認もした。大丈夫。

2017-10-11

  * isearch が動かなくなっている。 [#D0535]
    リファクタリングの過程で条件が反転していた。

  * complete: complete -p -D が働いていない気がするが… → 124 に対応 [#D0534]

    % complete.sh を見ると対応しているように見えるし、
    % 過去の記録を見ても動いていた様子がある。

    どうも前から動いていなかった疑いがある。
    先ず初めに compgen に -D オプションが混入するとエラーになって、
    そもそも補完関数も呼び出されない。

    さて、無事に補完関数は呼び出されるようになったが、何も候補が生成されていない。
    どうやら __load_completion では定義をロードするだけで候補生成は行わない様だ。
    一方で、素の bash でやるとちゃんと候補が生成できている。
    これが意味するところは素の bash は、もし候補生成がされなかった場合は、
    新しく追加された定義を用いて再度候補生成を行うということである。

    何と。マニュアルに書かれていた。
    -D による補完関数が 124 を返したとき、
    再度補完が試みられるのだと。対応した。

    * git 補完関数の末尾空白の問題

      | * 2015-11-23 プログラム補完: 末尾空白の問題点
      |
      |   現在 git 補完関数に合わせる形で勝手に末尾の空白を除去している。
      |   しかしこれで良いのか? これだと空白で終わるファイル名などがあった場合に問題になる。
      |   (その様なファイル名は滅多にないとは思われるが…。)

      % git の補完関数は変なことをする。候補の末尾に空白を付加し compopt -o nospace を指定する。
      % ble.sh の complete は末尾の空白をエスケープする仕様になっている。
      % これは compgen -A file の空白を含むファイルとの一貫性のためである。
      % 従って git の補完関数の場合には sed で末端の [[:space:]]+ を除去する必要がある。

      git の時にだけ work around を追加しようと思ったが、
      どうやら bash-completion は一般にそのような設計になっている疑いがある。
      分からないので取り敢えず現在の仕様を保持することにする。
      と思ったが、やはり末端に空白のあるファイル名を補完するときに問題になる。

      うーん。やはり git だけ特別扱いすることにする。

    そういえば、やはり git は以前問題になったのだから、
    以前は complete -D が動いていたという事になる。
    恐らく bash の version によって compgen に -D があった時に
    エラーになるかどうかが違うということなのだろう。

    * しかし、不思議なのは素の bash ではこの問題が発生していないということである。
      つまりファイル名の末尾の空白はちゃんとエスケープされるが、
      git subcommand の末尾の空白はエスケープされないというようになっている。

      もしかして git の補完関数はファイル名を補完しているときには
      nospace を指定せずに末尾空白も付加せずに候補を生成するのではないかという説を思いついた。
      つまり nospace は末尾空白をエスケープしないというサインになっているのではないかという説である。
      しかし試してみると、常に nospace を指定している。

      うーん。しかし /usr/share/bash-completion/completions/git に
      compopt -o filenames +o nospace という行がある。この行が実行されているときには、
      ファイル名末尾の空白がちゃんとエスケープされるようになるということではあるまいか。
      そして自前のシェル関数の compopt は実行されないということなのではないだろうか。

      そう思って適当なコマンドを作って試してみた所、
      ちゃんと自前のシェル関数が呼び出されるということが分かった。

        function _alpha { compopt +o nospace; }
        function alpha { echo "$@"; }
        complete -F _alpha alpha
        alpha hello.txt

      ということはやはり git の補完では実際には compopt は呼び出されていないのだろう。
      やはり素の bash で正しく動作できている理由が不明である。

      更に素の bash の補完の振る舞いについても調べてみたが、

        function _alpha { compopt -o nospace; local w=${COMP_WORDS[COMP_CWORD]}; for a in hello world 'abc efg'; do [[ $a == "$w"* ]] && COMPREPLY=("$a "); done; }
        function _alpha { compopt +o nospace; local w=${COMP_WORDS[COMP_CWORD]}; for a in hello world 'abc efg'; do [[ $a == "$w"* ]] && COMPREPLY=("$a "); done; }

      特に -o nospace / +o nospace でエスケープをしたりしなかったりという事はないようだ。
      というか、基本的に補完関数によって生成された候補はエスケープしないようである。

      ということはスペースを含むファイル名を補完した時にエスケープしているのは誰なのかという謎が生じる。
      実のところ、bash は直接 compgen を呼んでいるのではなくて、
      内部的な処理の一環としてファイル名を候補に生成しているので、
      それがファイル名による候補かどうかを知っていて、
      その内部的にしか知り得ない情報を用いてエスケープするかしないかを決めている可能性がある。

      % 面倒なのでここまでにして深入りしない事にする。

      と思って ble.sh でやってみたらいつの間にかに正しく動くようになっている。
      つまり __git* の生成するものについてはエスケープせず、
      ファイル名候補の場合にはエスケープする。
      どうやら git はサブコマンドしか候補を生成しない様だ。
      そして一致するものが見つからない場合には自前でファイル名候補を生成するなどのことはしない。
      これによって ble.sh の通常のファイル名候補にフォールバックする。
      結果としてファイル名候補の場合には正しくエスケープされるという動作になる。

      取り敢えず OK ということにする。

  * 2017-10-10 vi-mode (mark): < > ` ' " . などの設定をそれぞれ実装する必要がある。 [#D0533]

    - done: [] は直前の変更または yank 範囲 → #D0529
    - done: <> は前回のビジュアルモードの選択範囲 → #D0531 で同時に対応
    - `' は最後のジャンプ前の位置

      ジャンプには以下の種類がある。
      - done: 新規ファイル作成 → これは新しい行のロードと解釈して良いだろう
      - done: `x 'x / ? n N L H % G (last-line)
      - 保留: M ( ) [[ ]] { } :s :tag これらのコマンドはそもそも未対応 → #M0006 に記録

      どうやらオペレータによって移動する場合にはジャンプ元の設定は行われない様だ。

    - done: " は最後の終了時の位置
      これはシェルにおいては履歴項目を移動する直前の位置とするので良いだろう。
      しかしどのタイミングで記録するのが良いだろうか。

      a 一つの方法は _ble_edit_str.reset を通して呼び出される
        update-dirty-range の hook でそれを検出して実行することである。
        と思ったが、その呼出のタイミングでは既に元の文字列が失われている可能性がある
        (確認してみたら reset のときはそうではないと分かったがこの仮定に依存することは危険である)
        ので、もっと他の方法があると良い。

      b 或いは、ble-edit 側で history を移動する、もしくは、
        新しい行に移動するときの hook というのを用意するという手がある。

    - done: . は最後の編集位置
    - done: 現在 `[ `] は yank の効果を入れていない。
      yank (copy-range もしくは block copy) があった時にも更新するように設定すべき。
      実のところコピーをしているのは .copy-range を呼び出している箇所か、
      或いは operator:y のみである。他の操作は全ては快適変更を伴うので自動的に登録されている。
      対応した。

  * vi-mode (visual block): 元から行末にいる時に $ を押しても末尾拡張が表示に反映されない。 [#D0532]
    内部的にはちゃんとできているはずだが、描画部に状態変化が伝わらないので、
    表示が更新されないのが問題である。これに対応するためには、
    末尾拡張も _ble_edit_mark_active を使って表現するしかない?

    その場合には従来の _ble_edit_mark_active を参照している箇所も書き換える必要がある。

    →その様に修正した。元々使っていた _ble_keymap_vi_xmap_eol_extended という変数は廃止した
    ble/widget/vi_xmap/linewise-operator.impl の辺りで保存される矩形の種類についても修正した。

  * 2017-10-08 vi-mode (visual): I A [#D0531]

    振る舞いを調べる。先ずは I について。

    | - 矩形ビジュアルのときだけしか特別な動作はしない。
    |   行ビジュアルでもコピーは起こらない。
    |
    | - 先ず途中でカーソルを中で移動しても大丈夫。
    |   これは引数による繰り返しとは振る舞いが異なる。
    |   更に中で動かすのではなくて一回外に出て戻ってきても OK
    |
    |   - 別の行を弄って戻ってきても大丈夫。
    |     行の数が変化すると駄目。行を挿入して削除して合計で変わらなければ OK。
    |     と思ったが範囲よりも後に行を追加しても大丈夫。
    |
    |   - というか同じ行の前後もいじっても大丈夫?
    |
    |   - 同じ行の前を幅が変わらないように弄るとベルが鳴って行頭に移動する。
    |     幅が変わっても何か動く。開始点はずれる前の位置で決まり、終了点は最後に挿入した文字列になる。
    |     重要な結果。
    |
    |     | AAABBB -> AAA123BBBaaa -> AAA123BBBaaa
    |     | AAABBB    AAABBB          AAA123helBBB
    |     | AAABBB    AAABBB          AAA123helBBB
    |
    |     どうやら行内の%%文字数%%幅を数えて増分を計算しているようだ。
    |
    |   - 抜けるときに、挿入文字列の途中にいても大丈夫。但し、外にいると駄目。
    |
    |   - 行の数が変化すると駄目だったが、
    |     もし行番号だけを見ていてカーソルが同じ番号の行にいれば動くということだと、
    |     行の数が変化した分だけカーソルの位置をずらして元々別の行だった所で挿入モードを抜ければ、
    |     同様に働くのではないかと考えた。が、試したら動かなかった。
    |     やはり vim では行は追跡されている気がする (mark の振る舞いを見ると)。
    |
    | - 途中で改行を入れると動かない。I でも A でも。
    |   前に一回動いた(選択領域のかかっている行たちの次の行に新しい内容が挿入されるような動き)
    |   ような気がしたけれどなんだったのだろう。
    |   しかし実際にそのような動作が起こる場合があるとしても分かりにくいので取り敢えず実装しない。
    |   というわけでこの振る舞いに関しては取り敢えずは考えないことにする。
    |
    | - I に対する引数に依る繰り返しが適用されてから、
    |   他の境界に対するコピーが起こる。

    この時点での仮説では I は以下のように動く

    1 矩形範囲の先頭行の行番号と表示横幅と矩形の左端の位置を記録する。
      更にその行自体も覚えておく。
    2 挿入モードから抜けるときの処理として次に続くものを登録する。
      挿入モードから抜けるときは先に引数による繰り返しを実行する。
      これは引数による繰り返しがない場合や、引数に依る繰り返しが無効になった時も含む。
    3 カーソルのある行が 1 で記録したものと一緒でなければキャンセル。
      カーソルのある行の行番号が 1 で記録したものと一緒でなければキャンセル。
    4 表示横幅の変化量を測る。これが正でなければキャンセル。
      変化量の分だけ 1 で記録した左端の位置から文字列を切り出す。
    5 その時点での続く行の、記録した左位置に 4 の文字列を挿入する。
      新しく行が挿入されていたりしても関係なく、
      その時点での先頭行からの相対位置で挿入行が決まる。

    | 矩形範囲の先頭行を覚えておくのには ble.sh の実装では _ble_edit_mark でも使えば良い?
    | ただ挿入モードの操作の途中で _ble_edit_mark が書き換えられることもあるので別に用意するべき
    |
    | ? 途中で行分割が起こった場合は 1 で記録した行はどうするのか。
    |   また分割された行に対して挿入が行われたりするのだろうか。
    |
    |   →試すと行頭に紐付いている気がする。また分割された行に対して挿入が行われる。
    |   うーん。行分割した上で矩形左位置の内容を元と同じにすれば動くが、
    |   行分割した上で矩形左位置よりも前の内容が異なると起動しない?
    |   これは行分割を行わなかった場合と様子が異なる。
    |
    |   うーん。よく分からないのでこれについては無視でも良い気がしてきた。
    |   行分割を行わなかった場合と同じ処理にすれば良い。
    |
    | ? 試すと 以下で C の列で C-v I して、G の後に平仮名を入れて、
    |   それから抜けると以下のようになる。行の内容を記録しておいて、
    |   一番初めに変更のあった位置を検出しているのか?
    |
    |   | ABCDEFGH -> ABCDEFGあH
    |   | ABCDEFGH    ABCDEFGあH
    |   | ABCDEFGH    ABCDEFGあH
    |
    |   うーん。しかし、矩形左位置より前で変更が起こると、
    |   矩形左位置からのコピーになる。
    |
    | - 中途半端に全角文字に被っているとき、
    |   全角文字の前で挿入が開始される。
    |   コピーは矩形範囲内に入った文字列だけ行われる。
    |
    |   挿入した文字列に含まれる全角文字が、
    |   元の矩形の左端に中途半端に被っているときは、
    |   その全角文字全体がコピーの対象になる。
    |   コピーの終端がそれに応じて移動するということはない。
    |
    |   挿入した文字列に含まれる全角文字が、
    |   元の矩形の右端に中途半端に被っているときは、
    |   何か文字が分解されて変なことになる。
    |
    |   | echo hello world
    |   | echo hello world
    |   | echo hello world
    |
    |   | echoあい hello wld
    |   | echo あ<e3><81>hello world
    |   | echo あ<e3><81>hello world
    |
    |   コピー先に全角文字が鎮座しているときの振る舞いはどうか。
    |   →その全角文字の手前に挿入される。
    |   全角文字が鎮座していないその他の行については影響はない。

    以上のことから手順に以下の変更を加える。

    1a 行の内容も記録する
    4a 行の内容を比較して一番初めに変更の合った点を求める。
      この点が矩形左端より左にあれば矩形左端を切り出しの開始点とする。
      もしこの点が矩形左端より右にあればこの点を切り出しの開始点とする。
    4b 切り出し範囲に被る全角文字があればその全角文字も取り込む。
    5a コピー先に全角文字が鎮座しているときには、
      その全角文字の前に挿入する。
      タブが鎮座しているときにはタブは空白に変換する。

    上の手順の 5a での挿入は p による挿入と同じ気がする。
    と思ったが p の場合には全角文字の前に空白を挿入して位置を調整してから
    挿入するのであった。つまり、微妙に振る舞いは異なる。

    % 実装するとすると先に set-mark を統一的に実装しておく必要がある。
    % 1 の開始位置を覚えておくのに使うのは `[ が良いと考えていたが、
    % 実は `< の方が適切なのでは? と思ったが I ではそれで良いが A だと駄目なので、
    % このままで良い。

    - 因みに末尾拡張の状態で A をしてそれから実行するとちゃんとそれぞれの行末に追記される。
      空白が挿入されて桁が合わせられるなどのことは起こらない。
    - また、挟まれた行で短い行があった場合には (末尾拡張でないとき)、
      ちゃんと空白が挿入されて桁が合わせられる。

    取り敢えず実装した。取り敢えず動く。

  * vi-mode: dd を続けて行うと "bash: index: substring expression < 0" というエラーが出る [#D0530]
    これは ble/keymap:vi/mark/end-edit の中の条件式を間違えていた。

  * vi-mode (mark): `[ `] [#D0529]

    直前の変更範囲または yank 範囲と help には書かれている。動作を調べる。

    - 挿入モードの範囲も登録される。
    - 実際に何も入力しなかった場合でも登録される
    - C-o すると `[ は既に設定されていると分かる。
      2回目の C-o でも同じ点のようなので C-o によって挿入モードの範囲が途切れたりはしない。
      一方で、`] に関しては C-o する度に新しく設定し直されている気がする。
      と思ったが、1回目の2回目の C-o の間に何も入力しなければ `] は最初の C-o と同じになる。
      つまり、`] は C-o の度に設定されるのではなくて文字が挿入される度に毎回設定されていると考えるべきだろう。
      一方でその実装は効率が悪いように思われるので、ble.sh の実装では C-o の瞬間に実行することにする。
      振る舞いが多少異なることになるが、これについては何処かに説明を書いておくことにすれば良い。

    取り敢えず operator 呼び出しの箇所と、挿入モードに入る、または出る箇所での `[ `] の設定は書いた。

    - done: x s X delete Y S D C p P J gJ r gr でも set する必要がある気がする。要確認
      ビジュアルモードの各演算子も同様である。他にもバッファ内容に変更を齎すコマンドは全て対象である。

      これは _ble_edit_str/.replace-range 及び _ble_edit_str/.delete-range を全て確認して対応した。
      _ble_edit_str.{reset,replace} は直接は触っていない。
      実のところ殆どの操作は operator の中で行っているので、変更点はそれほどなかった。

      - rx grx に関しては ble/widget/self-insert を介して挿入を行っていたので、
        これは気づきにくかった。他に self-insert を介して nmap から変更を行うものはなかった。
      - Y S D C の内、ble/widget/vi-command/kill-current-line これも見落としていた。直した。
      - x s X delete の類はオペレータを介して操作しているので対策は必要ない。
      - p P J gJ は既に直した。

    - done: operator で beg の更新はしているが end の更新はしていないという場合があるかも。要確認

      というか、そもそも中身を書き換えたりすると end は意味を成さなくなっているのではないだろうか。

      a 一つの手は operator を呼び出す前に beg - end を設定してしまうというものである。
        この時の問題点は2つある。

        x 先ず領域拡張を行って変更した場合に end が beg に落ちてしまうということ。
        x もう一つの問題は end が末端ではなく最後の文字を指していることにより、
        中身に対して変更を行った場合やはり end が beg に落ちてしまうということである。

        だとすると各 operator に対して end を正確に計算してもらうという手しかない。

        x 更に試してみて気付いたことは operator 操作後のカーソル位置と、
        operator による変更位置は必ずしも一致しないということである。
        例えば矩形選択で先頭に全角文字が跨っている状態で d で削除すると、
        全角文字は空白に置き換えられてカーソルは残った空白の後に配置される。
        一方で `[ による変更開始位置は空白の前に設置される。
        実は、既に beg は変換後のカーソルの位置を指示するために使用している。
        ということは、変更範囲を調べるためには別の方法が必要になる。

      b 或いは、変更操作の開始前に空の dirty range を用意して、
        後は shift-by-dirty-range において、その dirty range も一緒に更新する。
        更に変更操作の終了時にその dirty range を元にして mark を設定する。

        この方法を用いれば end が beg に落ちてしまう問題も発生しない。
        各 operator で操作を指定する必要もない。

        効率的には不満な点もあるかもしれないが、複雑さの度合いから言って妥当に思われる。
        或いはもっと良い効率的な方法が見つかればその方法でも良いが…。

      結局 b の方法で再度実装し直すことにする。

  * vi-mode 引数を指定した挿入モードを抜けた時の動きが変だ。 [#D0528]

    先ず初めに繰り返し回数を正しく反映できていない。
    次にカーソル位置が正しくない。
    特に、次のコマンドでカーソルが変な動きをする。

    →decompose-meta で分解される前の M-h が記録されていた。これは駄目だ。直した。

2017-10-10

  * 2017-09-08 vi-mode: gi [#D0527]

    変数 _ble_keymap_vi_insert_mark だけ用意した。

    これは本来は mark を実装してから考えるべきである → #D0526

    次に `^ の設定を実装する。

    - 先ず繰り返しを行っている場合には繰り返しを行ったあとの位置が記録される。
    - C-c で中止をした場合でも記録される。
    - C-o で入ったときは現在地に移動するだけである。つまり、C-o に入る瞬間に記録される。
    - 未だ `^ が設定されていないときは gi はその場で挿入モードになる。

  * vi-mode: mark 実装 [#D0526]

    vim で mark について振る舞いを確認した所、
    行と列をそれぞれ覚えているようだ。
    文字の挿入・削除を行っても列の修正は行われない。
    行の挿入・削除を行うとそれに応じて行は修正される。
    行が削除されると mark も消滅する。

    この振る舞いを厳密に再現する必要があるかは分からない。
    もし厳密に再現するとなると .kill-range / .delete-range に介入して、
    既存の mark について毎回複雑な計算を実行する必要があるということになる。

    また mA と ma の振る舞いの違い (履歴項目ごとのマークかグローバルなマークか)
    の実装についても考える必要がある。履歴項目ごとのマークの場合には、
    履歴項目を移動する毎に保存・復元をするかあるいは履歴番号に紐付いた記録の方法を採用しなければならない。

    a 毎回保存・復元をするとなると色々問題がある。
      先ず初めにどのタイミングで保存・復元を行うかである。

      history/goto で保存・復元を行うとすると何らかの hook の機構を用意するか、
      保存・復元の対象となる変数のリストを外部から指定できるようにする必要がある。
      しかし、何れにしてもこれは遅そうである。

      よく考えてみれば mark に触る機会というのは少ないのだから、
      いざ記録または読み出しを行おうとした段階で、
      現在の履歴項目に対応するものをロードするようにすれば良い。

    b 履歴番号に紐付いた記録の方法の場合には記録に使用する文字を制限すれば (Unicode は使わず ASCII に制限すれば)、
      "256 * 履歴番号 + 文字" のような感じの index で配列に記録すれば良い。
      実際に vim で試してみると "mあ" などはエラー (bell) になる。

      マークを大量に設定すると配列アクセスが遅くなってしまうが、
      そんなに大量のマークを設定することもないだろうからこれは気にしなくても良い。
      或いは処理の時間が気になるのであれば
      bash-4.0 以上では連想配列を用いるように実装を切り替えても良い。

    これは b の実装の方が良いだろう。

      根拠は先ず単純であること。
      また a が現実的であることは履歴項目に対するアクセスが少ないということに立脚しているが、
      もしそうならば b も同様にアクセスが少なければ問題にならない。
      a が b よりも効率的になるのは或る特定の履歴項目に対して連続で mark を大量に呼び出す
      というような場合しか無いがそのような状況は考えにくい。

    mark として使える物にはどの様なものがあるか確認しておく。

      global A-Z    m で設定可能
      local a-z     m で設定可能
      local 0-9     .viminfo で設定する?
                    最後に訪れたときのカーソル位置と思えば良さそう。
      local [ ]     m で設定可能。最後に yank した範囲
      local < >     m で設定可能。最後にビジュアルモードで選択した範囲
      local ' `     m で設定可能。最後のジャンプ前の位置
                    ジャンプリストと関係。
      local "       最後のバッファ内の位置。
      local ^       最後に挿入モードを終了した位置
      local .       最後に変更された位置

    これらの文字の分布には一貫性はない。
    格納する時のインデックスはそもそも密にする意味もないので
    128 (もしくは G0 の 96) をフルに使ってよいのではないかという気がする。

    取り敢えず mark は実装した。

    * resolved: 問題点: 現在の実装では history を load せずに幾つかコマンドを実行して行った時に問題が生じる。

      LINENO を記録するなどして対処するべきなのではないか。
      但し、LINENO が増えたからと言って history にそれらが登録されているとは限らない。
      ということは未だ load していない時の、history に登録したカウントを ble-edit の方で記録するべきではないか。

      うーん。調べてみると HISTCONTROL が設定されていない時には、
      _ble_edit_history_count をインクリメントしているが、
      HISTCONTROL が設定されているときには ignoredups などによって、
      history を実行しても実際には登録されない可能性があるということで、
      _ble_edit_history_count はクリアしている。

      history を調べてみると最新の番号は history 1 で取得することができる。
      これを呼び出すのはそんなに大変ではないので、実のところ、
      これを呼び出して番号を取得しても良いのではないかという気がする。
      と思ったら、既に存在する ble-edit/history/getindex という関数ではこれをやっている。

      1 done: 先ず、ble-edit/history/getcount 及び ble-edit/history/add を変更して、
        毎回 history 1 を実行するのではなくて変更の可能性のある操作をしたときに history 1 を実行するようにする。

        と思ってよく見たらそのような実装になっている。
        寧ろ変更があった時にキャッシュをクリアし、そして getcount における遅延評価になっている。
        寧ろ現状の実装の方が優れていた。1点、ble/util/assign を利用するように変更はした。

      2 done: ble-edit/history/getindex で得られる値を使用して、
        _ble_keymap_vi_mark_local_history を更新するように再実装する。

      という具合にすれば良い。対応した。
      しかし実際に動かすと history/goto の中で呼び出している
      _ble_edit_str.reset で shift が発生してしまいずれてしまう。
      history/goto における reset では shift が起きない様にするにはどうしたら良いか。

      似たような問題として第2のプロンプトに移行する時の reset があった。
      これについては keymap が vi_cmap である時には shift を行わないという方法で対処した。
      しかしながらもっと本質的な解決方法があるのではないかという気がする。

      取り敢えず暫定的な方法を考える。

      a 一つの方法は FUNCNAME 辺りを見て ble/history/goto がなければ良しとする方法である。
        しかしこの方法は ble/history/goto の関数名が変更されると使えなくなる。
        とはいいつつ関数名を変更する時には置換を行うだろうから、
        この関数名が変更されても問題はないように思う。

      b もう一つの方法は ble/history/goto の中で定義されている変数名として特徴的なものを使い、
        それが定義されている場合には shift を行わないというようにする。
        或いは、敢えてそのための変数名を ble/history/goto で定義するという手もある。

      c 或いは _ble_edit_str.reset 関数に、変更の理由を引数で渡すようにして、
        その理由を更に observer に伝達するという手もある。
        この方法が最も妥当な方法であるように思われる。

      上記 c の方法を用いて実装することにした。
      以前の vi_cmap かどうかの判定も渡された引数で判定する様に修正した。
      この方法で実装した所初め動いていない様な気がしたが、
      改めて試してみると動くようになった。何故かは分からないが古いもので試していたのかもしれない。

    * resolved: 問題点: 書いてみたけれどやはりこれは遅いような気がする。

      特に . < > [ ] などは常に記録されていくので使い続けて行く程に
      _ble_keymap_vi_mark_local は肥大化していき、
      文字を入力する度に全てスキャンすることになるので、重くなっていく。

      従って _ble_keymap_vi_mark_local は常に「現在の履歴項目」の情報を保持するようにして、
      更に、履歴項目を切り替える際に _ble_keymap_vi_mark_local を
      _ble_keymap_vi_mark_local_history に退避するなどの処置が必要になる。

      更に言うと各要素を line:bytes としているので、
      これを分解する為の操作も馬鹿にはならない気がする。
      別の配列にして管理するという手も考えられるがそうすると bash の実装のせいで遅くなる。
      一つの配列の偶数番目と奇数番目でそれぞれ情報を格納するという手も考えられる。
      しかし、基本的には疎な配列なのでそれも分かりにくい。

      →これは上記問題点の解決と同時に再実装した。

2017-10-09

  * bash-3.0 local -a arr=() 対策 [#D0525]

    bash-3.0 で local -a arr=() を使うと要素の単語分割がクォート除去よりも後で実行されるようだ。
    調べてみると今の所は要素に空白を含むような場合に使っていないので問題になっていないようだが、
    これについては適宜別の形式に書き換えるなどして、この書き方自体を追放するのが安全である。

    - ble.sh/check に追加した。
      実のところ、この check 用コマンドを詳細に指定すれば
      local -a name=(...) が使える箇所は増えるのであるが、
      複雑な規則になっていると人間の側が間違える可能性が大きくなるので、
      やはり一律に禁止する方が懸命であると思われる。

    - と思ったがやはり local -a arr=() を使えないのは辛いので、
      check の条件を詳しくすることで、特定の local -a arr=() についてはそのまま使えるようにした。

  * vi-mode (visual block): < > [#D0524]
    振る舞いが違う→実装した。

  * vi-mode: indent の幅を設定できるようにするべきなのでは。 [#D0523]

    8 は大きすぎるので既定で 4 にして、自分で 2 に指定するなど。
    というかこれは vi-mode 特有の設定というよりは全体の設定でもある気がする。
    全体の設定に追加することにする。
    bleopt_shell_indent などの変数名が良いだろうか。

    変更対象は vi.sh 及び vim-surround.sh の indent 関係の所にある。
    →対応した。

  * vim-surround.sh: xmap S, gS [#D0522]

    S と gS の振る舞いを調べると、S は v, C-v に対しては ys と同様に働き、
    V に対しては yS と同様に働くようだ。

    %%gS はその振る舞い (ys vs yS) を反転させた物になる。%%
    surround.vim を簡単に見てそう判断したが実際に読んでみると分からない。
    :help surround を見てみると vgS は vS と同じで、VgS は VS のインデントを行わない版で、
    <C-v>gS は末尾拡張した領域に対して囲みを適用するということの様だ。
    <C-v>gS は Vim script からは末尾拡張かどうかが分からないために必要と書かれているが、
    実は ble.sh vi-mode の枠組みでは自然にこれは対応できてしまうので
    敢えてその様に動作させる必要はなかったりする気がする。
    それでもその様に対応することにする。

    その為には先ず yS に対応しなければならない。yS は行指向の動作である。
    囲まれる文字列の前後に改行を挿入してインデントするという動作の様だ。
    因みに空白を指定すると <left><LF><SP><indent>content<LF><SP><indent><right> という感じになる。
    インデントがある場合には空白を前後に置かないのが自然なのではないかと思う。

    実装した。チェックする。

    yS は動いている。ySS も動いている。xmap S も動いている。xmap gS も動いている。
    但し、何れについても再インデントには対応していない。

    序に cS も実装したらどうか。調べてみると cs と殆ど同じで挿入するものが異なるだけだそうだ。
    これは簡単に実装できると思う。実装した。

  * vi-mode: bug: g? を set-operator rot13 にしていたが、 [#D0521]
    これは数字が入っているので使えないのでは?
    →実際にやってみたら使えなくなっていた。修正する必要がある。

    というか、これを機に _ble_edit_arg に全て入れるのを止めた方が良い気がする。
    set-operator も operator 辺りに改名する。
    _ble_edit_arg の形式で場合分けをしているが、これは kmap を以て場合分けするのが良い。
    また、本当に omap の時にしか _ble_edit_arg が存在しないのか確認する必要がある。

    →オペレータの記録の方法を作り直した。
      元々今の仕組みはオペレータの枠組みの全体を知らずに適当に作った物を騙し騙し使っていた物だった。
      今となっては一つの変数で全てを記録するのは辛いし、
      また _ble_edit_arg の形式が本体の ble/widget/ の想定するものと異なる点も良くない。
      _ble_edit_arg は空か数かのどちらかでないと都合が悪いのだ。
      作り直した。余り大きな変更もなく作り直すことができた。

  * vi-mode (normal mode): C-d で抜けても良いのでは。 [#D0520]

    そもそも vim では C-d は何に割り当てられていたのだったろうか。
    →スクロール用のコマンドの様だ。これは滅多に使わないので、
    zsh と同様に C-d でシェルを抜けるようにしても良いように思われる。

    と思ったが、よく考えたら空文字列の時にはそもそもスクロールもしようと思わないだろうから、
    空文字列の時に限り抜けるようにして、それ以外の時にはスクロールという様にすることも可能のはずである。

  * magic-space: 現状の実装では空白を入れてから展開しているが、 [#D0519]
    :s/ などが終端していない状態でこれを実行すると空白が余分についてしまう。
    →修正した。更に dirty-range も最小限になるように修正した。

  * vi-mode (insert): @norepeat [#D0518]

    実は norepeat でないコマンドは数える程しかないのだから、
    それ以外全てで norepeat を実行するように __before_command__ に書くほうが懸命なのでは。

    実装した。動いている。これにより @norepeat は改名対象ではなくて削除対象になった。
    master へ merge する直前に適用することにする。

  * vi-mode (cmap): / ? n N [#D0517]

    * C-c で抜けても実行されてしまう。キャンセルするべき。
      →これは単にバグだった。直した。

    何もないときに DEL を押したときもキャンセルにする?
    これは試してみると / や ? ではキャンセルになるが、
    surround.vim の < ではキャンセルにならない。
    実装によるということである。
    だとすると、(surround.vim で > を打つと終わりになることを含めて、)
    cmap のキーマップに介入できるようにする仕組みを整えたい。

    例えば cmap/__before_command__ で外部関数を呼び出すようにして、
    その外部関数の名前を登録できるようにしておく。
    __before_command__ で好きに処理をして、
    もし元から設定された動作をキャンセルするときには、
    COMMAND= としてしまえば良い (ble-decode.sh の側で次に実行する widget は COMMAND に入れている)。
    というかこれは WIDGET に名称を変更した方が良い気がする。
    と思ったが、-cf で通常のコマンドを呼び出すときにもこれは使っている
    更に、widget を呼び出すときも zsh の所謂 widget ではなくて、前に ble/widget/ の prefix がついている。
    やはり COMMAND で良いような気もする。と思ったが、COMMAND は他の用途にも使われるので、
    後で一括で置換したいときなどに不便である → と思ったが COMMAND という変数はこの用途でしか使っていなかった。

    - 取り敢えず COMMAND はそのまま。__before_command__ で COMMAND= を実行することでキャンセルできる。
    - シェル変数 _ble_keymap_vi_cmap_before_command で async-commandline-mode で呼び出される cmap に介入できるようにした。
    - vim-surround.sh のタグ名入力で > で確定するように修正
    - search / ? で、空文字列で  DEL or C-h することでキャンセルするように修正
    - 序に ble-bind -L で . を含む関数名を表示しないように修正


2017-10-07

  * 2017-10-01 vi-mode (visual mode): r s C S R x D X Y p J U u I A ^] [#D0516]

    done: J gJ → これは別項目 #D0540 で処理
    done: u U r s C S R X D x Y
    done: I A #D0531
    done: p P #D0536
    保留: ^] これは何処で見たものか何故か書かれていたが実際対応しなくて良い。
      b4b4r07/zsh-vimode-visual で見たかと思ったが、改めて確認したところない。

    C は char のとき一旦行指向になってから .save しているようだ。1v などとすると分かる。

    いろいろ試してわかったこと。

    - 矩形モードで C を押すと次に 1v を実行したときに末端までの拡張状態になる。
    - 矩形モードで $ を押すと末端までの拡張の状態になる。
    - 普通の移動の方法では末端までの拡張にはならない。
    - 末端までの拡張の状態で、行末にいる状態で "13|" などとして
      動かないようにしても末端までの拡張モードは解除される。
      つまり位置の移動を監視して末端までの拡張かどうかを切り替えるのではなく、
      移動に関するコマンドが実行されたかどうかで末端までの拡張かどうかが切り替わる。
    - 更に v で $ に行ってから C-v としてもちゃんと末端までの拡張になっている。
      それどころか v $ を復元するときも本の列ではなく末端になるようだ。
    - さすがに OO を押して端点を交換すると末端までの拡張は解除される。
      従って、端点毎に "末端拡張" かどうかの状態があるのではなくて、
      端点の座標とは独立に "末端拡張かどうか" という情報が記録されていると思われる。

    つまり、何か別の変数があって移動すると切り替わるようだ。


    * done: 先ず、現在末端拡張の状態かどうかを保持する変数を用意する。
    * done: 先ず extract-block の末端拡張のときの振る舞いを実装する。
    * done: それから save/restore の振る舞い。
      末端拡張が有効の時は char として $ を記録するようにする。
    * done: 移動コマンドが必ず呼び出している関数として adjust-command-mode がある。
      これに手を入れて末端拡張かどうかを弄るようにしたらどうだろうか。
    * done: また $ のコマンドを弄って xmap のときは adjust-command-mode より後に、
      _ble_keymap_vi_xmap_eol_extended=1 を設定するようにする。

    取り敢えず現状で push することにした。

  * 2017-10-01 vi-mode: 前回からの動作の修正 [#D0515]

    - vi-mode bug: 行単位のインデントオペレータ (`>>` など) でエラーが出るバグを修正
    - vi-mode bug: オペレータ `g~` を呼び出せないバグを修正
    - vi-mode bug: `k` `-` `G` `gg` などで履歴項目を移動したときに(最後の文字でなく)行末にカーソルが来るバグの修正
    - vi-mode bug: オペレータ `>` および `<` で空行が消滅するバグの修正
    - bug: "ble-bind -d" の内部でパス名展開が起こって出力が正しくないバグの修正

    - vi-mode change: `c{linewise}` (`{linewise}` = `j` `k` `H` `L` `+` `-` `gg` `G`) のとき空行を挿入するように修正
    - vi-mode change: `d` で最終行を削除したとき前の行に移動するように修正
    - vi-mode change: `f` `F` `t` `T` `r` `gr` に C-? の形式で文字を指定できるように修正
    - vi-mode change: `dd`, `yy`, etc. および `D` は最終行で 2 以上の引数を与えるとエラーにするように修正

    - vi-mode: _ g0 g<home> g^ g$ g<end> gm go g_ ge gE / ? n N :
    - vi-mode: ビジュアルモード (char, line, block)
    - vi-mode: vim-surround.sh にて囲み文字として t T < を指定したとき、タグ名の入力を受け付ける
    - edit: 複数行編集時スクロール

  * 2017-09-18 vim-surround: ds cs テキストオブジェクト [#D0514]

    - done: pst に対応する。これは本体のテキストオブジェクトを先に対応させる必要がある。
    - done: 更に t に関しては第2のプロンプトを表示できるように改修する必要がある。
      → 第2のプロンプトに対応したので対応した。

  * vi-mode: 正規表現検索 [#D0513]

    | 2016-07-07 isearch: 正規表現検索?
    |
    | incremental にするのは難しい。というのも正規表現の内容を変えると一致位置が戻ってしまうかもしれないから。
    | 例えば abc|def として検索した時に abc まで入力した時に文字列 "def" を通り越して
    | "abc" に一致したとする。すると、続いて |def を入力した時に、通り越した "def" をどの様に処理するのかという問題が生じる。
    | その正規表現に対する "直近の一致" に拘るのであれば、一旦通り越した "def" を拾う為に、再度検索を一からやりなおす必要がある。
    | 或いは、emacs の様に現在の位置から検索の続きを開始するという方法でも良いがこれは直観的でない。
    |
    | 最終的にもし incremental にするとしたら Emacs の様な方式になるだろうが、
    | 必要が生じるまでは incremental な search は提供しなくても良いだろう。
    | というかそもそも正規表現検索自体必要なのか分からない。
    |
    | 正規表現による置換などについては需要があるかもしれない。
    |
    |
    | 更に組み込みの正規表現を用いて一致を行うにしても問題がある。
    | 組み込みの正規表現では途中からの一致に対応していない。
    | 従って、文字列の部分文字列を作成する事によって途中からの一致に対応する事になるが、
    | その様にすると ^ や $ の意味が変わってしまう。そこで、途中で文字列を切った場合には何か padding の様な物を付加するとしても
    | 今度はその padding に一致してしまう事を阻止できない。
    | また %%padding の内容をどうするかによって \b や \B の意味が変わってしまう。%%
    | →これについては隣接する文字をそのまま padding として採用すれば良い。
    |   が、隣接文字に対する一致を阻止できないので、結局文字列を切らずに一致を試みるのと大差ない。
    |
    | - 因みに正規表現の一致位置を探すのはそんなに面倒ではない。正規表現の先頭に ^(.*) などと付加しておけば、
    |   ${#BASH_REMATCH[1]} が一致開始位置になる。ただキャプチャの番号が一つずつずれる事に注意すれば良い。
    |   →と思ったが、これだと .* が greedy に文字を消費してしまう。
    |     それよりは正規表現末尾に (.*)$ を付加した方が精確である。
    |     それにより開始位置は $((${#target}-${#BASH_REMATCH})) になる。
    |     キャプチャグループの番号もずれないのでこれが良い。
    |     但し、一致文字列全体の長さを得る時に $((${#BASH_REMATCH}-${#BASH_REMATCH[n]})) などとする必要がある。
    | - これを応用すれば例えば位置 14 から一致を試みたい時には、正規表現の先頭に
    |   ^(.{14}.*) などという物を付加すれば良いのではないか。
    |   しかしこれだと先に述べたのと同様に .* が greedy に文字を消費してしまう。
    |   それよりは .{14}(rex)(.*)$ 等の様にするのが良さそうだ。

    * 2017-10-07 気付いたのだが実は後方参照 \1 が使える。
      ということは rex を () で囲む為には後方参照の番号のずれも考慮にいれなければならない。
      rex を直接使うのは難しい。何故なら rex=A|B の構造になっているかもしれないから。
      なので、何れにしても .*(rex) または (rex).* などのようにしなければならない。
      そうしないと一致位置を取得するのが難しい。実際できるのか?

      もし () で囲んで後方参照の面倒も見るとすれば、更に余分に () を増やしても構わない。
      なので気にせず色々弄ることができる。

      forward に位置 14 から検索するときは

      rex=".{14}($needle)(.*)\$"

      などとする。backward に位置 len-14 から検索するときは

      rex="^(.*)($needle).{14}"

      などとすれば良い。最初または最後の .{14} は、検索対象の文字列を 13 文字削るなどすれば
      . にまで縮めることができる気がするが、
      それによって特に効率的になるとも思われないので、このままで良い。
      寧ろ検索対象の文字列を削るか削らないかなどの場合分けが面倒である。


      $needle に含まれる後方参照をシフトするためには、
      $needle を簡単に parse しなければならない。
      先頭から順に見ていく。

      '\\.|\[^?\]?(\[:[^]:]*:\]|\[\.[^].]*\.\]|\[=[^]=]*=\]|[^][])*]'

      '\\.'
      '\[^?\]?
      (
      | \[=[^]=]*=\]
      | \[\.[^].]*\.\]
      |
      |[^][])*]'


      - 試してみると [.<collating-char>.] にも対応しているようだ。
        rex='[[.a.]]' ; [[ a =~ $rex ]] # sucsses
        rex='[[.a.]]' ; [[ . =~ $rex ]] # fail

      - [[=<c>=]] にも対応している。
      - \< \> にも対応している。\b も。[[:<:]] などは対応していない。

    * 取り敢えず incremental な検索は現実的ではないが、
      通常の検索として実装するのはそんなに問題はない。

      - done: 先ず検索部分のコードは分離した。
      - done: 後方参照のシフトがちゃんと動くかを確かめる必要がある。

        動いていない。使っている正規表現が正しくないと出ている。確かめる。以下のものが使われている。
        ^(\[^?]?(\[[:][^]:]+[:]\]|\[[=][^]=]+[=]\]|\[[.][^].]+[.]\]|[^][]|\[[^]:=.])*[?\]|\\[^1-8])*\\[1-8]

        ^(\[\^?]?(\[[:][^]:]+[:]\]|\[[=][^]=]+[=]\]|\[[.][^].]+[.]\]|[^][]|\[[^]:=.])*\[?\]|\\[^1-8])*\\[1-8]

        - 一箇所直した [? は \[? であるべきだった。しかしこれは正規表現が正しくない理由にはならない。
        - どうやら \[[:][^]:]+[:]\] が駄目と言っている → と思ったら勘違いだった。
        - 分かった。 ^? ではなくて \^? としなければならない。

        取り敢えず一番簡単な場合で動くことを確かめた。
        色々動かしてみたが、恐らく大丈夫だろう。

    * vi.sh に実装してみたが色々変だ。動作確認する。

      x fixed: n で前の検索を繰り返そうとすると何も起こらない。
        →これは前の検索文字列をロードし忘れていたために空文字列で検索していた。

      x fixed: 一致位置が変だ → 正規表現一致後の範囲の計算が誤っていた。修正した。

      x fixed: 表示が崩れる。これは / ? で第2プロンプトを使用したときでもなるが、
        n N で前の一致を繰り返した時でもなる。つまり第2プロンプトは関係ない。
        更に、何れも2回目以降の一致で変なことになる。

        これは不思議だ。表示と検索機能は完全に直行しているはずなのに起こっている。
        しかも、表示位置が先に進むのではなくて逆方向に戻っている。1文字ずつ戻っている。
        つまり、何か余計な文字列が出力されているという訳ではなく、座標計算の方が怪しい。

        C-l で再描画すると直るが n で検索し直すと再度発生する。
        つまり、検索の関数の中で何か誤ったことをしている。
        もう一つの手がかりは更新される内容がずれているということである。
        region layer が怪しい。umin umax の問題か、或いは buff の繋ぎ変えに失敗しているか。

        うーん。S-left に依る移動などでも再現することが分かった。
        つまり、これは region レイヤーでの buff の繋ぎ変えが怪しい。
        しかし、改めて試してみると変な状態になっているときには S-left は不味いが、
        検索機能を使っていない限りは S-left が変なことになることはない様だ。

        search を実行することによって何かの機能が破壊されている。
        うーん。正規表現かどうかは関係なく発現するようだ。
        調べてみたら、なんと plain_buff が滅茶苦茶なことになっている。何故?
        あー。分かった。。plain_buff が textarea の復元の対象になっていないということか。

        ところがちゃんと復元リストの中には入っているようだ。
        と思ったがそもそもこの復元リストも変だ。何か重複があるし、復元しなくても良いものまで入っている。
        よく見たら ${!_ble_highlight_layer_$layer*} とするべきところが ${!_ble_highlight_layer_$name*} になっていた。
        そしたら直った。何故だろう。前のミスでは過剰に復元変数が列挙されていたのが問題だった。
        今回の修正で復元対象の変数は減少したはずなのに正しく復元できるようになったのは不思議だ。

      - done: 一致している状態で次の一致を探して失敗したとき、
        今一致している状態を保持したい。

      x fixed: 範囲がずれている。

      x 履歴後方で末端で一致したときに再一致できない
        これは行の最後の文字にカーソルがいるときに一致しないということだろうか、と思ったら違った。
        調べると .call-search の中で範囲を調整する条件がいけなかった。
        同じものに再一致することを防ぐための条件がいけなかった。

      x fixed: というか G で編集文字列の行末に移動できる

      x fixed: 履歴検索に時間がかかった後、progress が表示されたままになっている。

      x fixed: 履歴検索の progress で検索文字列が表示されていない。
        これは変数 _ble_edit_isearch_str を指定しなければならない。

      x fixed: progress の表示間隔が短いのは何故だろう。
        forward search 時に 1項目ごとに表示されている気がする。
        従来の isearch ではちゃんと期待通りに 1000 項目ごとにしか表示されていない。
        従って、コードが破壊されたとかそういうことではないはず。
        と思ったら stop_check のときにしか isearch_time を incr していなかった。修正した。

      後は空一致のときに何がおこるのかという事である。
      現在の実装では空一致のときには一致しなかったのと同じ状態になる。
      この時 n や N をしても次の空一致に移動するということが起こらない。
      というかむしろ backward に検索するときには逆方向に移動していく気がする。

      念のため vim でどういう振る舞いになるかを確認することにする。
      と思ったら vim は空一致の場合にはパターンが見つからなかったと勘違いするようである。
      もしもっと前に進めば非空な一致を見つけることができるとしても、
      途中で空一致にぶつかってしまったらそれ以上探すのをやめ、見つからなかったという扱いの様だ。
      (これは例えば h? のような正規表現で確認することができる)

      →対応した。

    * done: 次に引数に対応しなければならない。これは繰り返し一致させるというようにするしかない。

      さて、{count} 番目の一致が見つからないときの動作はどうするべきか。
      vim で試してみるとまた buffer の先頭に戻って続きを検索するので、
      1 つでも一致するのであれば、必ず一致する。

      ble.sh でどうするか。また履歴の最初に戻るというのはとても分かりにくい。
      従って、取り敢えず一番最後に一致したものということで問題ない気がする。
      そう考えれば、単に繰り返し回すだけで良いので実装としても楽だ。

      取り敢えず対応した。

    取り敢えず現在の問題点を解決したら commit する。

    x fixed: オペレータから呼び出せない → これは omap にも登録しなければならないからだった。

    x fixed: 引数を指定しようとすると一致状態が解除されてしまい、ずれる。

      →やはり matched の状態を設定・解除するのは adjust-command-mode のタイミングであるべき。
      その様に修正した。同時に他のモードに移行するなどの場合に _ble_edit_mark_active を解除する必要がある。

    x fixed: 今度は最後に一致した状態で次の一致が見つからないときに、
      一致状態が解除されてしまう問題について。
      これは新しい _ble_edit_mark_active の設定・解除にしてから起こるようになった。
      →どうやら adjust-command-mode が search.impl の中から複数回呼び出されているのが行けない。
      唯一回だけ呼び出されるように修正した。直った。


2017-10-05

  * vi-mode: dd yy ... の最終行での振る舞い [#D0512]

    行数が足りないときにはエラーになる。
    他のオペレータについても一様に同じようだ。

    % 更に D は dd と違って末尾にいても行を削除しないようだ。
    % D も行数が足りないときにはエラーになる。
    % と思ったらこれはそもそもぜんぜん異なる働きをするコマンドだった。

    D は 1 より大きい引数を指定して一行も動けないときエラー。

    実は dd や yy の場合も同様のようだ。直した。

  * vi-mode (visual mode): S [#D0511]

    何やら次の引数を読み取ろうとしている気がする。何故か。
    と思ったら、これは surround.vim の仕業だった。

  * vi-mode (visual block): 行末にいるときの範囲がずれている。 [#D0510]
    行末から右に1文字のところが境界になる。

  * vi-mode (visual): vim では | で行末に行けるようだ。 [#D0509]

  * 2017-09-12 表示レイアウト管理の方法について [#D0508]

    | これは現在問題になっている、一番下の行で info が表示されなくなってしまうこととも関連する。
    |
    | presentation : form
    |  \_ textarea : control
    |  |   \_ content : ble-edit/content
    |  |   \_ prompt : ble-edit/prompt
    |  |   \_ layout : ble/textmap 文字の配置
    |  |   \_ render : ble-edit/layout
    |  \_ info : control
    |
    | もし本格的なウィンドウシステムを実装するとしたら、
    |
    | 1 textarea は一つのコントロールとして管理するべきである。
    | 2 textarea 毎に _ble_edit_str などの content が存在するべき。
    | 3 着色の設定も textarea 毎に管理するべきだ。
    |
    | 4 全ての入力は textarea を一回経由してから処理する。
    |   というのも処理対象の _ble_edit_str を選択するため。
    |   というかそもそも keymap だって textarea に紐付いているのではないか。
    |
    |   と思ったが、これは少し違う。
    |   ウィンドウは単一で機能を持つこともあれば、
    |   一つの機能を提供するために複数のウィンドウを組み合わせることもある。
    |   現在ある info や将来実装するかもしれない補完候補のメニューなどは、
    |   固有の機能を持っているものではなくて、textarea と組み合わせて使うものである。
    |
    |   そのように考えるとウィンドウの集合と keymap は対応付けられるべきである。
    |   .NET Frameworks の類推で親ウィンドウを form と称して
    |   子ウィンドウを control と称して考えると分かりやすそうだ。
    |
    | 何か話がとんでもない方向にそれている。元々は関数名の話だった。
    |
    | これは別の話として切り離すべきだ → #D0439 から切り離した。

    #D0505, #D0507 取り敢えず ble/textarea として分離して実装し、
    第2のプロンプトを表示できるようにした。
    ble/textarea としての振る舞いを観察して、
    また需要が出てきたら control などの仕組みについては再度考え直す。

  * 2017-09-17 第二のプロンプト・編集文字列を出すということについて。 [#D0507]

    info の上で表示する様に再実装しても良いが、
    やはり似たようなコードが重複して存在するのは気になる。
    将来的にも必要になると思われるので、現状の ble-edit の仕組みを
    複数の編集文字列に対して適用できるように拡張する方が自然なのではないだろうか。

    更に info はカーソルの位置に関しては管理しない。
    カーソルの位置は現在全て本体の編集文字列の描画で設定されている。

    さて、複数の編集文字列を取り扱えるようにするには何が必要であるかを考える必要がある。

    | * 先ず初めにどの変数を差し替えれば
    |   別の編集文字列を取り扱えるようになるかを調べる必要がある。
    |
    |   それらの変数をひとまとまりとして textbox 的な概念にまとめるのが良い。
    |   もっというと、今回の第二の編集文字列を出すということに特化したものではなくて、
    |   一般に textbox としての component を独立させるとしたらどうなるかという事を意識して
    |   実装したほうが汎用的で整理された実装になる気がする。それを目指す。

    → これは ble/textarea としてまとめることにした。状態の保存・復元にも対応した。#D0505

    * 序にいうと表示の幅や高さも管理できるようにしたい。

    * 実は ble-decode の decode 状態も textbox 毎に用意するべきなのではないか。
      だとすると先ずは ble-decode について切り替える仕組みを整える必要が出てくる。

    % うーん。思ったのだが、面倒なので第二のプロンプトなどと言わずに read -e -p / で良いのでは?
    % →と思ったが bind で全て上書きしているのが祟って動かない。
    % これは read -e も再実装する必要があるということを意味する。

    [実装]

    取り敢えずは decode 状態については考えないことにする。
    textarea を切り替えると同時に keymap も変更するということにする。
    動いた。取り敢えず : を簡単に実装してみた。動く。

  * _ble_bash_loaded_in_function 条件が反転している [#D0506]

  * 2017-09-17 第二のプロンプト・編集文字列を出すということについて (1) 状態を保存・復元する仕組み [#D0505]

    1 存在する変数について整理する。

      _ble_edit_prompt=("" 0 0 0 32 0 "" "")

      ble/textmap#
        _ble_textmap_*

      ble-highlight-layer
        _ble_highlight_layer_RandomColor2_buff
        _ble_highlight_layer_RandomColor_buff
        _ble_highlight_layer__list
        _ble_highlight_layer_disabled_buff
        _ble_highlight_layer_disabled_prev
        _ble_highlight_layer_overwrite_mode_buff
        _ble_highlight_layer_overwrite_mode_index
        _ble_highlight_layer_plain_buff
        _ble_highlight_layer_region_buff
        _ble_highlight_layer_region_osel
        _ble_highlight_layer_syntax1_table
        _ble_highlight_layer_syntax2_table
        _ble_highlight_layer_syntax3_list
        _ble_highlight_layer_syntax3_table
        _ble_highlight_layer_syntax_buff

        誰も使っていない _ble_highlight_layer__buff=() は削除することにした。
        _ble_draw_trace_{brack,scorc} は関数内で定義することにした。

      % ble-edit/text/update
      %   _ble_line_text_buff=()
      %   _ble_line_text_buffName=
      %
      % ble-edit/render/*
      %
      %   _ble_line_cur=(0 0 32 0)
      %   _ble_line_scroll=
      %   _ble_line_gendx=0
      %   _ble_line_gendy=0
      %   _ble_line_dirty=-1

      ble/textarea
        _ble_textarea_buffer=()
        _ble_textarea_bufferName=
        _ble_textarea_cur=(0 0 32 0)
        _ble_textarea_scroll=
        _ble_textarea_gendx=0
        _ble_textarea_gendy=0
        _ble_textarea_invalidated=1
        _ble_textarea_cache=()

      ble-syntax
        _ble_syntax_text=
        _ble_syntax_stat=()
        _ble_syntax_nest=()
        _ble_syntax_tree=()
        _ble_syntax_attr=()

        _ble_syntax_attr_umin=-1
        _ble_syntax_attr_umax=-1
        _ble_syntax_word_umin=-1
        _ble_syntax_word_umax=-1
        これらの変数は ble-highlight-layer:syntax から参照するためにある。

        _ble_syntax_vanishing_word_umin=-1
        _ble_syntax_vanishing_word_umax=-1
        これは ble-highlight-layer:syntax/update-word-table の暫定的(?)な実装に使っている。

        _ble_syntax_dbeg=-1
        _ble_syntax_dend=-1
        これは ble-syntax/parse 解析中断をした時に復元するためにある。
        但し現在は解析の中断の対応していないので、常に -1 である。

        因みに文法を指定しているのは ble-syntax/parse 中の以下の行である。

          ctx="$CTX_CMDX"

        他の文法にも対応するためにはこの値を何らかの変数を用いて初期化する必要がある。
        例えば、_ble_syntax_lang=bash としておいて、

          ble-syntax:$_ble_syntax_lang/initialize-context

        のような関数を呼び出すと ctx に呼び出しが入るなど。

      こうして見てみるととても沢山の変数が存在している。
      これらをえいやと切り替えるのはとても大変そうだ。

    2 ble-edit/render 統合

      ble-edit/text/update は ble/textarea#update-text-buffer とすることにする。
      ble-edit/render/* は ble/textarea#render/* にする。
      ble/textmap#slice は実のところ ble/textarea#slice-text-buffer が良い。

      ble-edit/render/update-adjusted では、
        $bleopt_suppress_bash_output であっても念のためと称して
        READLINE_LINE, READLINE_POINT を設定していたが、
        何か問題になるとも思われないので、
        $bleopt_suppress_bash_output の時には適当な値を設定して抜けることにした。
        また、関数名は ble/textarea#adjust-for-bash-bind とした。

      _ble_line_dirty
        現在 _ble_textarea_dirty は -1 か空文字列かのどちらかの気がする。
        と思ったが、一応 _ble_edit_str.replace で設定はしている。
        一方で、実際に使っているのかどうかは怪しい。
        結局、_ble_edit_dirty_draw_beg と役割が重複しているので、
        _ble_textarea_dirty 改め _ble_textarea_invalidated は、
        完全再描画の要求がされたかどうかだけの状態を保持することにした。

      現在以下の変数が存在している。

      _ble_textarea_buffer=()
      _ble_textarea_bufferName
      _ble_textarea_cur=(0 0 32 0)
      _ble_textarea_scroll=
      _ble_textarea_gendx=0
      _ble_textarea_gendy=0
      _ble_textarea_invalidated=1
      _ble_textarea_cache=()

    3 切替方法について

      何処に値を保存しておくかということ。
      そのまま保存すると沢山の変数を汚すことになる。
      何処か一つの変数に保存しておいて eval するだけで復元するということにならないか。

      | a "declare -p" の出力を利用する方法
      |
      |   但し、直接使うとローカル変数に勝手になってしまったり、復元できなかったりするケースがあるので、
      |   出力は可能しなければならない。その為に以前書いた関数 ble/util/declare-print-definitions を見てみると、
      |   これは出力を整形するために awk を使っている。遅い。頻繁に呼び出せるものではない。
      |
      | 或いは、テキストボックスのフォーカスが移動するのはそんなに頻繁ではないはずだから、
      | 毎回瞬間的に切り替えるのではなく、現在フォーカスが当たっているものが常に表を占拠するようにすれば良い。
      | だとすれば多少重くても良いかもしれない。しかし重くても良いのであれば、やはり沢山の変数を汚しても良い?
      | と思ったけれど、むしろローカル変数で瞬間的にというわけではなく、まとめて退避するということから、
      | やはり一つの変数に記録する方が良い。
      |
      | さて declare や typeset を用いるとごみが入る。set だとごみが入らない。
      | と思ってマニュアルを探したが set で指定した変数だけ出力するということはできない。
      | というか declare でも引数を指定せずに呼び出すとごみは入らない。
      | declare -p のようにするとゴミが入る。typeset -p でも同様。
      | local -p とすると何も表示されない。何故?
      |
      | b ローカル変数にコピーして local する案
      |
      |   所で、local とすると現在のフレームの変数だけ出力されるようだ。
      |   最終的にはこれを使うという手もある…と思ったが、
      |   同じ変数名で local a=$a として外の値を継承できるのか? bash-3.0 で試してみると
      |
      |   - local a だと変数は空になる。
      |   - local a=$a だと外の値を持つ (bash-3.0-4.4)。
      |   - local -a a=($a) だと空になる (bash-3.1, 4.3-4.4)。外の値を持つ (bash-3.0, 3.2-4.2)。
      |
      |   最後の項目に関しては興味深い。実は同じスコープで既に local となっていても空になる。
      |   うーん。従って。一旦、別の変数にコピーして、それから改めて同名の local 変数に書き戻して、
      |   その上で local を実行するか。
      |
      |   或いは、変数名を   __to_remove___ble_edit_str などのようにして、そこにコピーして、
      |   それから local を実行してから、変数の中身の __to_remove__ を削除するか。
      |   但し、それだと変数の値に __to_remove__  が含まれているとそれが消滅する。
      |   特に、これの動作のテストのために丁度コマンドラインに同じ文字列 __to_remove__ が含まれる可能性はある。
      |   何れにしても、恣意的に構成されたコマンドラインで問題になるので一種の脆弱性になるかもしれない。
      |
      |   何れにしても、この方法だと全変数を一旦 local 変数にコピーするという操作は不可避なので、
      |   単に全変数を直接退避する方法と比べると、変数を減らすということ以外に利点がない。
      |
      | c 或いは手動で生成できるか。
      |
      |   すぐに eval できる形にするのは難しい。
      |   それに一発で eval できなくても良いのではないだろうか。
      |   そう考えると
      |
      |   aaa=(_ble_edit_str content
      |     _some_array[3] hello1 hello2 hello3
      |     _some_scalar value)
      |
      |   などの形に配列に格納するというのも手である。
      |   と思ったが、これは構築も復元もいかにも遅そうである。
      |   すぐ eval できる形に手動で整形するのは難しい。printf %q には古い bash でバグが有るし、
      |   もし printf %q を用いるとしても 文字列の結合を繰り返さなければならないことに変わりはない。
      |
      |   ただ、awk を起動するよりは速いかもしれない。
      |   (それでも長い編集文字列を扱うとこれは格段に遅くなるだろう)

      うーん。結局単一の変数にコピーするのは難しそうである。
      方法があるとすれば一旦ローカル変数にコピーしておいて、
      そこで local を実行するという方法しか現実的なものはないと思われる。

      取り敢えずは変数の集合として保存するという方法で我慢することにする。

    取り敢えず ble/textarea の状態を保存・復元する仕組みは整えた。
    見た目は動いているように見える。取りこぼしの変数はあるかもしれないが、それは後で考える。

2017-10-04

  * 2017-10-02 vi-mode (visual block): 矩形選択から text/update/position を呼び出せるようにする [#D0504]

    連続して入力をしたときには配置情報が更新されていないことがある。
    その様な場合には現在は論理列による矩形にフォールバックしているが、
    これは直感的ではないので問題になる。

    従って text/update/position を外部から呼び出せるようにして、
    配置情報が更新されていない場合にはこれを呼び出すようにする必要がある。
    しかし、現在は text/update/position の更新範囲は、
    着色の更新範囲と一緒に管理しているがために、
    text/update/position を単体で呼び出すことができない。
    更新範囲の情報を分離する必要がある。

    * 同時に _ble_line_text_* の変数名を何とかする。案を考える。

      _ble_line_text_cache_length=  -> _ble_textmap_length
      _ble_line_text_cols=80        -> _ble_textmap_cols
      _ble_line_text_cache_pos=()   -> _ble_textmap_pos
      _ble_line_text_cache_cs=()    -> _ble_textmap_glyph
      _ble_line_text_cache_ichg=()  -> _ble_textmap_ichg
      _ble_line_text_begx=0         -> _ble_textmap_begx
      _ble_line_text_begy=0         -> _ble_textmap_begy
      _ble_line_text_endx=0         -> _ble_textmap_endx
      _ble_line_text_endy=0         -> _ble_textmap_endy

      | うーん。text_layout よりも良い名前はないか。
      |
      | - 文字の配置を素直に英語にすると character arrangement になる。長い。
      |
      | - .NET では Sysmtem.Drawing.Graphics に MeasureString および MeasureCharacterRanges がある。
      |
      | - _ble_text は既に s2c などの名前空間として使用されている。
      |   従って、_ble_textbox, _ble_textarea, _ble_line を使う必要がある。
      |   _ble_line は今まで使ってきたものだが実態に合わないので変更したい。
      |   textbox だと任意の場所に任意のサイズで表示できそうな気がするのでよくない。
      |   (或いは将来的にそのような機能を実装するかもしれないが)
      |   よく考えたら現状の配置情報の計算は textbox かどうかなどとは直交する実装になっている。
      |   現に render/update でスクロール機能を実装したときも _ble_line_text 側には何も変更はなかった。
      |
      |   従って、_ble_textbox や _ble_textarea というのも微妙である。
      |   或いは、_ble_graphics_textlayout_ などにするか。
      |   短くすれば _ble_draw_textrange もしくは _ble_draw_txtlayout。
      |   うーん。もはや draw/graphics とか要らないかもしれない。
      |
      |   _ble_textlayout_ とするか。_ble_textrange_ でも良いかも。
      |   TextRange については調べてみたが色々と意味が違うような気がするのでやめる。
      |
      |   うーん。実際には glyph などの描画に関する情報も保持している。
      |   なので単に layout という訳でもないのではないか。
      |   但し着色などについての情報は持っていないので、やはり layout に近いというべきか。
      |
      | _ble_textlayout に収束しつつある。
      |
      |   少し変種を考えてみる。_ble_txtlayout, _ble_txtout, _ble_txtpos,
      |   _ble_charpos, _ble_txtarrange, _ble_txtconfiguration, _ble_txtdisposition,
      |   _ble_txtgeometry, _ble_txtgeo, _ble_txtmetric, _ble_txtmeasure,
      |   _ble_txtmap, _ble_textmap.
      |
      |   良さそうなのは、_ble_txtpos, _ble_txtmap, _ble_textpos, _ble_textmap 辺りである。
      |   取り敢えず _ble_textmap にする。

      _ble_textmap に統一した。

    * 次に _ble_textmap 用の dirty-range を新設することにする。
      現在は外部から指定した BLELINE_RANGE_UPDATE を使用している。
      これは ble-edit/render/update で設定される変数で、
      dirty-range _ble_edit_dirty_draw_* を元にしている。
      従って、_ble_edit_dirty_draw_* の複製を作れば良いのである。

      今までは外部からこれらの変更範囲について管理して、
      BLELINE_RANGE_UPDATE などの変数を介して指定できるようにしていたが、
      今回の変更のように内部で保持するようにしてしまって問題ないだろうか。

      恐らく問題ないという気がする。
      但し、これらの変数の更新はそれ専用の関数を用いて行うようにした方が良い気がする。

    * うーん。問題がある。

      | ble/textmap#update では "再描画の必要がある範囲" を POS_UMIN, POS_UMAX で返す。
      | これは別の場所に記録して置かなければならない。
      | ところが、ble/textmap#update を呼び出した後で
      | 更に文字列に更新があった場合はこの更新範囲がどうなるかは非自明だ。
      |
      | (dbeg dend dend0) のペアを用いて範囲を更新することはできるがそれで十分だろうか。
      | - umin-umax で変更範囲より前にある場合はそのままで良い。
      | - umin-umax で変更範囲より後にある場合は…その分だけ index をシフトすれば良い。
      |   もし変更範囲の長さが変わらない場合や変更範囲での違いが改行で吸収できるときは、
      |   umin-umax の変更範囲はそのままシフトするだけで良いし、
      |   もしそれで不充分であるのであれば次の ble/textmap#update でそこまで umin-umax が拡張されるはずである。
      | - 変更範囲が被っている場合には削って良い。
      |   変更範囲の領域はどうせ次の更新で再描画の対象になるだろうから。
      |
      | →_ble_edit_str の更新をする度に毎回 _ble_textmap の更新もするべきかと思ったが、
      |   ble/textmap#update を呼び出したときに、蓄積した dirty-range を用いて
      |   _ble_textmap_u{min,max} を shift して更新すれば良いのだと気付いた。
      |   _ble_textmap_u{min,max} で公開するのであれば飽くまで最後の配置計算の際の更新必要範囲で良いのだ。

      配置情報に関連する umin,umax は独自に管理し、
      _ble_textmap_umin, _ble_textmap_umax に蓄積することにした。
      これは修正した。OK

    * ble/textmap#update のインターフェイスに疑問が生じてきた。

      外から呼び出す時にグローバル変数と密結合にならないように、
      text BLELINE_DIRTY_RANGE POS_UMIN POS_UMAX などの変数を介して呼び出すようにしてきた。
      しかしながら現在の実装では不可避的に _ble_textmap_* という内部状態を持つので、
      完全に外部から自由に取り扱うためには _ble_textmap_* の変数を宣言して呼び出す必要があった。

      一方で、今回の書き換えによって BLELINE_DIRTY_RANGE やら POS_UMIN POS_UMAX などの変数も全て、
      _ble_textmap_* で管理するようにした。これは順当な書き換えである。
      現在残っている変数は text x y である。
      一方でこの text というのはそれまでに渡した _ble_textmap_d* と符合するものでなければならない。
      ここで _ble_textmap_d* と独立に渡せるようになっているのは不自然である。
      それよりは寧ろ update-dirty-range を呼び出すときに一緒に text も指定する方が自然である。
      しかしそれはそれでデータが巨大になってくると無駄な気がする。
      やはり text というローカル変数で再計算の時に受け渡しするというのが良いのだろうか。

      だとすると ble/textmap#update を呼び出す側で現在どのような目的で textmap#update を呼び出すのか
      ということを承知で行わなければならない。ということは簡易な ble/textmap#update-auto 的な関数で、
      local text=$_ble_edit_str x=... y=... して呼び出すのは変だということになる。
      或いは、これは widget として提供するべきか。

    * さてここまでの書き換えによって ble/textmap#is-up-to-date でなくても、
      ble/widget/.update-textmap を呼び出せば最新状態になるということになった筈だ。
      しかし本当にちゃんと動作するのかについては謎だ。確認方法がない…。

      一つのテスト方法は _ble_edit_str.replace の中で毎回 ble/widget/.update-textmap を呼び出すことだ。
      とても遅くなるが取り敢えず動作することを確認する上ではこれで良いだろうという気がする。
      →遅いが、何事もなく動作した。本当にこれで大丈夫なのだろうか…。
        分からないが取り敢えず暫く動かしてみることにする。

  * vi-mode: ge gE [#D0503]

    簡単かと思ったらちょっとよく分からなくなった。

    - 先ずカーソルが単語の中に載っているときは前の単語の末端に行く
    - 実は [[:alnum:]]+ と [^[:space:][:alnum:]]+ の間も単語の境になりうる。
    - 実は二重改行にも止まる
    - それ以上後ろに進めないときはバッファの初めに行く

    % 要件 1 を満たすようにするためには以下をすれば良い。
    %
    %   ${str::ind+1} =~ (wb+w*){0,arg}$
    %
    % 但し、w が単語を構成する文字で b がそれ以外の文字である。
    % 問題は空行である。Bash 正規表現には当然前方先読みなどは存在しない。
    % 従って、これを用いない形式に変換する必要がある。
    % 用いない形式で初めから考えようとしたがよく分からなくなった。
    %
    % % 仕方がないので、取り敢えず用いる形で書いてみることにする。
    % %
    % %   ((w|(?<=n)n)(b|(?<!n)n)+w*){0,arg}
    % %
    % % 但し n が改行を表す。さて、(b|(?<!n)n)+ は、
    % %
    % %   (b|(?<!n)n)(b*|(?<!n)n)*
    % %
    % %   b(b+n)*b* | bn(b+n)*b* | (?<!n)n(b+n)*b*
    % %
    % %   (bn?|(?<!n)n)(b+n)*b*
    % %
    % % と変形される。一方で (?<=n)n は苦しい。というか1文字戻り読みしないときつい。
    % % 繰り返しになるとどうすれば良いのだろうか。
    % %
    % % % 前回の最後は (bn?|(?<!n)n)(b+n)*b*w* と分かっている。
    % % % これを最後が n のものとそれ以外のものに分類できれば良い。
    % % % 最後が n のものは以下の形をしている。
    % % %
    % % %   (bn?|(?<!n)n)(b+n)+ | (bn|(?<!n)n)
    % % %
    % % % 最後が n 以外のものは以下の形をしている。
    % % %
    % % %   (bn?|(?<!n)n)(b+n)*b*w+ |
    % % %   (bn?|(?<!n)n)(b+n)*b+ |
    % % %   b
    % % %
    % % % と思ったが、これは使わない気がする。
    % %
    % % あと思ったのは、さきに (?<!n) を消去した方が良い。
    % % 改めて
    % %
    % %   (w|(?<=n)n)(b|(?<!n)n)+w*
    % %   = (w|(?<=n)n)(bn?|(?<!n)n)(b+n)*b*w*
    % %   = (wbn?|wn|(?<=n)nbn?)(b+n)*b*w*
    % %   = (w(b|b?n)|(?<=n)nbn?)(b+n)*b*w*
    % %
    % % これに後ろから (?<=n) をかけるとどうなるか。
    % %
    % %   (w(b|b?n)|(?<=n)nbn?)(b+n)*b*w* (?<=n)
    % %   = (w(b|b?n)|(?<=n)nbn?)(b+n)+ | (wb?n|(?<=n)nbn)
    % %   = (?<=n) nbn? (b+n)+ | (?<=n) nbn
    % %     | w(b|b?n)(b+n)+ | wb?n
    % %   = (?<=n)(nb)(n? (b+n)+ | n)
    % %     | w(b|b?n)(b+n)+ | wb?n
    % %
    % % 何かおかしい。二重改行の後には空白は必要ないはずだ。
    %
    % 初めの時点で間違えている。修正する。
    %
    %   (w (b|(?<!n)n)+w* |(?<=n)n (b|(?<!n)n)*w*){0,arg}
    %   :
    %   : w(b|(?<!n)n)+w*
    %   : = w(b|b?n)(b+n)*b*w*
    %   :
    %   : (?<=n)n (b|(?<!n)n)*w*
    %   : = (?<=n) n(b+n)*b*w*
    %   :
    %   = ((?<=n) n | w(b|b?n)) (b+n)*b*w*
    %
    % うーん。これを見るに変換は厳しい。
    % (?<=n) は前のループの最後の文字を見るが、
    % n 自身がそれになっている。うーん。よく分からない。
    %
    % 取り敢えず後ろから (?<=n) をかけてみる。
    %
    %   ((?<=n) n | w(b|b?n)) (b+n)*b*w* (?<=n)
    %   = ((?<=n) n | w(b|b?n)) (b+n)+
    %     | ((?<=n) n | wb?n)
    %   = (?<=n) n (b+n)+ | w(b|b?n) (b+n)+
    %     | (?<=n) n | wb?n
    %   = (?<=n) n (b+n)* | wb (b+n)+ | wb?n (b+n)*
    %   = (?<=n) (nb+)* n | wb b+(nb+)*n | wb? (nb+)*n
    %   = ((?<=n) | wbb+ | wb?) (nb+)*n
    %   = ((?<=n) | wb*) (nb+)*n
    %
    % 或いは、後ろから (?<!n) をかけてみる。
    %
    %   ((?<=n) n | w(b|b?n)) (b+n)*b*w* (?<!n)
    %   = ((?<=n) n | w(b|b?n)) (b+n)*b*w+
    %     | ((?<=n) n | w(b|b?n)) (b+n)*b+ | wb
    %   = (?<=n) n (b+n)*(b*w+ | b+)
    %     | w(b|b?n) (b+n)*(b*w+ | b+) | wb
    %   = (?<=n) (nb+)*n (b*w+ | b+)
    %     | w(b|b?n) (b+n)*b*w+
    %     | wn b+(nb+)*
    %     | wb nb+(nb+)*
    %     | wb b+(nb+)*
    %     | wb
    %   = (?<=n) (nb+)*n (b*w+ | b+)
    %     | w(b|b?n) (b+n)*b*w+
    %     | wn? b+(nb+)*
    %
    %     w(b|b?n) (b+n)*b*w+
    %     = wb    b* w+
    %       | wbb+ (nb+)*n b* w+
    %       | wb   (nb+)*n b* w+
    %       | w    (nb+)*n b* w+
    %     = wb+ w+ | wb* (nb+)*n b* w+
    %     = w (b+ | b* (nb+)*n b*) w+
    %     = w (b|b*(nb+)*n) b*w+
    %
    %
    % % やはり駄目だ。一つの希望は (?<=n) の部分と最後の文字に対する要件を分離できれば、
    % % (つまり "((?<=n) ... | ...) (1文字以上)" の形になれば順番を反転させることができたが、
    % % 今回の場合については2の累乗でパターンが増えるので駄目の気がする。)
    % % 正規表現ではやはり不可能と結論付けるべき気がする。
    %
    % しかしやはり変だ。やはり、明らかに DFA なのでそれに対応する正規表現があるはずだ。
    % と思ったが、問題は個数を {0,arg} で制限していることになる気がする。
    % これの所為で実質的に状態を数え上げなければならない。
    % これに対応して大体 2 * (arg+1) の状態が生まれる。
    % しかしそれでも有限個である。うーん。
    %
    % また、思うにもし無限個だったとしたら OK なら、
    % 無限個だったときの正規表現をまずは考えるべきなのでは。
    % うーん。今回の場合は NFA になって、更に面倒なことになりそうだ。
    %
    %   (?<=n) (nb+)*n                             (?<=n)
    %   any    wb* (nb+)*n                         (?<=n)
    %   (?<=n) (nb+)*n (b*w+ | b+)                 (?<!n)
    %   any    w (b|b*(nb+)*n) b*w+ | wn? b+(nb+)* (?<!n)
    %
    % とここで気付いたが w には二種類あって wW の境目には空白がなくても良い。
    % また完全に考え直しになった気がする…。

    うーん。結局単語の種類があるとなると単語を左右に分割するわけには行かない。
    つまり、単語はやはり1単位として読み取るしかない。
    やはり、今までの実装と同じように厳密な正規表現の実装は諦めて、
    貪欲な一致で初めに一致するものが正しくなるように構成するしかない
    (或いは方法もあるかもしれないが人の手には負えない程複雑になりそうな気がする)。

    取り敢えず後方に単語を探索することにする。

    :w[nb]* 但し二重改行は含まない (:w は単語の正規表現とする)
    = :wb*(n(b+n)*b*)?
    = :wn?(b+n)*b*

    (?<!n)n [nb]* 但し二重改行は含まない
    = (?<!n) n(b+n)*b*

    常に最長一致するようにしていれば前の単語が終了するのは、
    二重改行のあとか次の :w が始まるところだけのはずである。
    従って、これで問題ないはず。

    (:wn?|n) (b+n)*b*

    但し、一番最初の一致点を制限する方法が必要である。
    特に一番最初を二重改行以外とする場合にはどうするのか。。
    うーん。結局 backward-word で使われている正規表現と同じものになるのか…。

      (:wn?|b+n?|n) (b+n)*b*
      = (:wn?|n) (b+n)*b*
        | b+ (b+n)*b*
        | b+n (b+n)*b*
      = :wn? (b+n)*b*
        | n (b+n)*b*
        | b (b+n)*b*
        | b+n (b+n)*b*

    しかし、これの問題点は arg 回一致したのかそれ未満で終わったのかが分からないということである。
    うーん。文字列先頭でのεを許して {0,arg} から　{arg} に変えてはどうだろう。

      ((:wn?|b+n?|n) (b+n)*b* | ^)
      = (:wn?|b*n?|n|^) (b+n)*b*

    もっというと b+n が親として現れるのは文字列先頭のみである。

      = (:wn?|n|^(b+n|b+)?) (b+n)*b*
      = (:wn?|n|^((b+n)?|b*)) (b+n)*b*
      = (:wn?|n|^) (b+n)*b*

    うーん。こうしておいて一番初めの一致だけを切り出しておけばよいか。
    本当にこれで問題ないか? 本当に一番はじめの一致が空になるのだろうか。
    というのも数が足りない場合にはどういうことになるかというと、

      [[ abcd =~ ((:wn?|n|^) (b+n)*b*){4}$ ]] → (a)(b)(c)(d)

    ということも可能だからである。繰り返し回数の少ないものから順に一致するというようにすればOK?
    そうすればできるだけ少ない数で一致するようにできる。

      [[ abcd =~ ((^|:wn?|n) (b+n)*b*){4}$ ]] → ()()()(abcd)

  * 2017-10-03 vi-mode (visual block): 行折り返しがあるときの着色がおかしい。 [#D0502]

    振る舞いは正しい。一度折り返しがあると、
    その後で画面を大きくして折り返しを解消しても振る舞いはおかしい。

    そもそも sub_ranges は正しく計算されているのだろうか。
    振る舞いが正しいので sub_ranges 自体は問題がなくて、
    それよりは着色の方の問題のような気がするのだが、確認はしておく。
    やはり sub_ranges 周りは問題ないようだ。
    というより計算結果の _ble_highlight_layer_region_buff の中身まで問題ない。

    これは ble-highlight-layer:region/getg を複数の範囲に対応していないのが問題だった。
    対応した。同時に中の処理も整理した。

2017-10-03

  * vi-mode (visual): 前回のビジュアルモードの復元について [#D0501]

    | 2017-09-17
    | * ビジュアルモードに入る時の動作を調べる。
    |
    |   v, V, C-v はそれぞれ charwise-visual-mode, linewise-visual-mode,
    |   blockwise-visual-mode と名前をつけることにする。
    |
    |   引数を指定したときは v V C-v は何れも同じ動作になる気がする。
    |
    |   前回のビジュアルモードが v/V/C-v の別も含めて記録されている。
    |   但し、C-c などで終わったビジュアルモードは記録されていない。
    |
    |   - blockwise-visual-mode は行と列をそれぞれ別々に記録している。
    |   - 実は v で記録したときも行と列が別々に記録されている。
    |     異なる行に移動するときには列は相対値ではなくて固定値で解釈される。
    |     引数の倍率は行だけにかかる。起点の次の行に終点があるとき行数は 2 と解釈され、
    |     引数の倍率はこれに乗算される。
    |   - V を記録したときには恐らく列の情報は使用されない。
    |     復元するときも列は復元されず、ただ j で行を移動しているように見える。
    |   - 負の方向に選択したかどうかは記録されていない。
    |     つまり、常に現在位置を左上の基点として復元される。
    |
    |   オペレータを指定した場合はどうなるかと yv などを試すと、
    |   どうも全然違う機能が呼び出されているような気がするが一体何かは分からない。
    |   何れにしても v は omap ではなくて nmap に追加されるということ。

    取り敢えず現状で簡単に実装してみることにする。

    複数行に跨っているときの相対位置は表示位置の
    y*cols+x による比較で問題ないように見える。
    行末に行送りの全角文字がある場合でも表示位置に依る差である。

    実装した。

  * 2017-10-02 vi-mode (visual block): 貼り付け時に貼り付け先にあるタブは空白に変換されるようだ。 [#D0500]

    | 2017-10-02 タブも機械的に押し出されるのか?

  * bash-3.0: up down が bind できていない。 [#D0499]

    - うーん。手で bind するとちゃんと bind できている。
    - ble_bind_keymap=vi_insert を通して keymap を指定した場合もできている。

    だとすると dump 結果がおかしくて駄目なのだろうか。

    - ble-bind -d で出力するとちゃんと登録されているのが確認できる。
    - ble-decode/keymap/dump vi_insert で見てみると登録されている。
      と思ったが複数の異なる特殊キーで登録されている。変だ。
      改めて ble-bind -d で確認してみると f4 に何故か割り当てられている。
      更に f1 - f5 に本来別のキーに割り当てられるべきものが登録されている。

    一つの可能性は keymap を生成したときの kcode と現在の kcode がずれているということである。
    しかし vi.sh は頻繁に更新している一方で kcode はそんなに変更していないので、
    これは余り考えにくい → と思って vi.sh を touch してみたら直ってしまった。
    一体何だったのだろう。これはもしかすると先に直した ble-bind -d の問題?
    でも同関係してくるのか謎。

    或いはキャッシュからキーマップを読み取ると駄目ということなのかもしれない。
    と思って再度 bash-3.0 を起動して試してみたが問題は再現しない。
    確かに、新しくキーマップを生成してはいないのでキャッシュから読み取っているはずである。
    結局問題はよく分からず消滅したようだ。

    先程までは何度再起動しても問題だった一方で、
    今は再起動しても何も問題は起こらないので何かの拍子で直ったと考えて問題ないだろう。

  * ble-decode: bug [#D0498]

    vi_digraph の binding でグロブ展開が起こっている。
    と思ったら、ble-bind -d の表示するときのバグだった。直した。

  * vi-mode: ble/string#split arr $'\n' "$text" などが用いられているが、 [#D0497]
    これらは非空行について処理したい場合は良いが、
    行の数を保持したい場合には使えない。

    改行で分割するための特別な関数を用意する必要がある。
    改行で分割する良い方法はあるだろうか。

    a 一つの方法は改行を一旦別の文字 @ に置き換えてから処理する方法である。
      しかしこれだとその文字 @ について事前に escape しなければならない。
      しかし \@ のようにエスケープしても意味が無いので、完全に別の文字に置き換える必要がある。
      つまり、\ → \A, @ → \B, 改行 → @ としてから分割を実行する。
      その後で、\A → @, \B → \ というように元に戻する必要がある。
      @ が含まれていない場合には幾らか工程をスキップすることができるが、
      面倒な方法であることに変わりはない。

    b 或いは正規表現などを用いて手で刻んでいく方法である。
      これの欠点は大量の行が存在するときに遅くなってしまうということである。

    c もう一つの方法は mapfile <<< $text を用いるというものである。
      これは古い bash では使えないので実装の切り替えが必要になる。

    bash の version に応じて c または a ということになるだろうか。
    取り敢えず今の所は ble/string#split arr $'\n' を用いて実装する。

    というか、調べてみると例え空白類で分割していなかったとしても、
    ble/string#split では、末尾にある sep は無視されるようだ。
    但し、数が一定している場合には特に問題にはならない。
    更に、最後の sep 一個だけが無視されるようなので、
    手で初めから最後に sep を追加しておけば問題ない。
    →実装した。期待通りの動作になった。

    更に改行で区切る関数も実装する。

    split1.measure (改行を別文字に置換してから)
      time 242.40 usec/eval
      time 728.20 usec/eval (分割に用いる文字が重複しているとき)
    split2.measure (正規表現で切り出す)
      time 1502.40 usec/eval
    split3.measure (mapfile を用いる)
      time 135.40 usec/eval
    split4.measure (グロブで切り出す)
      time 895.40 usec/eval

    取り敢えず mapfile を用いて正しく実装でき、さらに速い。
    bash-4.0 以上では mapfile を用い、それ未満では別文字に置換してから split する方法で実装した。

  * 2017-10-02 vi-mode (visual block): 矩形選択が遅い。 [#D0496]

    行が増えてくるとやはり遅い。

    * get-index-at の最適化?

      get-index-at は二分探索を行っているが、
      この範囲を最初から行内に制限する方が良い。

      更に、get-index-at を観察して気づいたが、
      getxy.cur を使用している。一方で、
      現在の矩形範囲の実装は getxy.out を用いている想定で行っていた。
      この辺りの動作の違いがどのような影響を受けるか再度考える必要がある。
      →実は大した影響はない? ような気がする。
        が、それでも getxy.out を用いる方が速いのでそちらを使うものを用意する方が良い。

      更に、思うことは get-index-at を実行した時点で、
      それが厳密一致かそれとも前方に戻ったかは分かるし、
      更にいうと隣接する次の文字の位置も分かるはず。
      これらを全て一挙に取得する generic な get-index-at があっても良い気がする。

      ※同様の探索を paste.impl でも実施している。
      他にも色々あるのではないか。

    ble-edit/text/hit という関数を用意した。配列アクセスが遅くならないように、
    内部では配列として _ble_line_text_cache_pos しか触らないようにした。

    さらにこれを利用して extract-graphical-block を再実装する。

    % 実装の都合で vim の不自然な動作の再現は諦めた。つまり、
    %
    % |1234567>|
    % |あ89ab$ |
    % |stuvwxyz|
    % |lmnop$  |
    %
    % において C-v で 8 から z を選んで y すると、
    %
    % | あ8|
    % |zlmn|
    %
    % になる。vim では "あ" の前に空白は付加されず、ずれる。

    やはりこの振る舞いは関係ない?
    現状の実装では全て out で計算しているので、
    > の位置から文字があると勘違いする。
    従って、切り取られる内容で左側に空白は付加されない。
    ということは、新しい実装でも左側に空白は入らないはずである。

    実際に試してみるとそもそも色々表示がおかしい。
    これは表示のバグなのかそれとも範囲切り出しのバグなのか。
    →これは折り返しがあるときの座標計算のずれが悪い気がする。
      一度折り返しを作って、その後で画面のサイズを変更すると変なことになった。
      特にサイズに変更のあった文字が絡んだ時に文字の幅と座標の幅がずれているのだと思う。
    →これは別項目で対策する #D0502

    どうも表示が悪いだけの気がするので、先に振る舞いを確認してから、
    表示に関しては後で処置することにする。

    x done: 先ず矩形の左端について。行送りがあるときに行送り前の位置からになっている。
      これは vim の振る舞いと異なる。修正した。
    o 行送りされた文字が消滅するとき、行送りの分だけ空白が残るという動作は正しい。
    o 切り取られる内容について、行送りに代わる空白は補填されないという振る舞いも一致している。
    o 現状の実装だと行送りされた文字が被っていないのに空白に変換されてしまうという問題 (以下)
      があるのではないかと思ったが、vim で試してみた所全く同じ動作だったので気にしないことにする。

      |abcd>| → (c から i までの矩形) d → |ab  x|
      |あx  |                               |efjkl|
      |efghi|
      |jkl  |

    多分、特別に変な処置はしなくても現状の実装のままで vim の動作と区別がつかない気がする。

    改めて速度について確認してみる。やはり遅い。が、以前よりはましになった気がする。
    (もしかして extract-graphical-block 単体が律速しているわけではないのかもしれない。)

  * 2017-10-01 vi-mode: 最終行で dd としたらその行を消して一つ上の行へ移動する [#D0495]

    引数を指定して一番下の行まで全て削除する場合も同様
    dj で一番最後の行まで消すときも同様。
    これは operator:d (type=line) を修正する。

  * 2017-10-02 vi-mode (block): 貼り付け時に全角文字が邪魔な時はどうなるのだろう。 [#D0494]

    | aa → ahelloa
    | あ     helloあ

    空白が補填されて邪魔だった全角文字は右に押し出されるようだ。

    ここで当初の計画の矩形選択の貼り付けには対応することにする。

    | 2017-09-17
    |
    | * C-v の矩形選択について。どの様な範囲が選択されるのだろうか。
    |
    |   - 先ず全角文字の幅は考慮される。つまり見た目の幅で矩形になるように選択される。
    |     また、一部でも全角文字にかかればその全角文字は範囲に含まれる。
    |     開始点と同じ列かより右側の全角文字の上にカーソルがある場合は、
    |     その全角文字の終端までを矩形の右端とする。
    |   - 次に行折り返しになっている場合は、論理行での矩形選択になる。
    |
    |   矩形選択のときのオペレータの動作はどうなるだろうか。
    |   これは kill-range, delete-range, copy-range 辺りを修正すれば簡単かもしれない。
    |
    |   矩形選択のときの表示はどうすれば良いか。
    |   実のところ、全体を反転表示している場合との違いは、
    |   途中に着色されない部分があるということだけなのではないか。
    |   だとすれば着色の処理はそんなに難しくないのでは。
    |
    |   →と思ったが左下から初めて右上に進んだ場合や、
    |   右上から初めて左下に進んだ場合には、
    |   _ble_edit_ind, _ble_edit_mark の範囲外に着色がはみ出るのではないか。
    |
    |   a これに対応するためには着色範囲の決定に直接 _ble_edit_ind, _ble_edit_mark を用いるのではなく、
    |     それを修正した値を用いるようにするという手がある。
    |
    |   b 或いは別の方法として _ble_edit_ind, _ble_edit_mark を移動する毎に補正するという手もある。
    |     ただこれだと現在のカーソルの位置が正しくないことになるので、
    |     (overwrite mode でやっているように) カーソルを消して代替表現を使う必要がある。
    |     更に移動コマンド全てについてこの調整を呼び出すようにしなければならない
    |     (これは __after_command__ でできるかもしれない)。
    |     この方法は汚い上に色々辻褄を合わせるのが大変そうなので、良い方法ではない。
    |
    |   後、各オペレータを矩形選択に対応させる必要がある。
    |   更に paste の際に矩形選択されたものがどう貼り付けられるのかも調べる。

    [動作確認]

    貼り付けを実装した。取り敢えず動くことをみた。
    これから細かく動作確認する。

    o fill が働くか。
    o 行末では fill は入らない。
    o 中途半端な全角文字は空白になって貼り付けられる。右端も左端もOK

2017-10-02

  * 2017-10-01 vi-mode (visual mode): ビジュアルモードでオペレータに引数を指定したときはどういう動作なのだろう。 [#D0493]

    少なくとも v で試してみた所は引数を指定しても何も効果はないようである。
    もし引数に意味があるのであれば ble/widget/vi-command/set-operator を書き換える必要がある。

    うーん。3> とすると 3 回インデントを深くするという動作が例示されている。
    これは同じ範囲に対して > を 3 回呼び出していると解釈できる。
    だとすれば y や d や c も繰り返しされているということなのだろうか。
    うーん。試しに 2~ を実行してみると小文字から大文字になったので、
    ただ愚直に繰り返されるわけではないようだ。
    或いは、寧ろオペレータに対する "引数" のようなものが指定されると考えるべきか。

    オペレータに第4引数を渡して、それを繰り返し回数か何かとして取り扱ってもらう。
    取り敢えずオペレータに引数を渡すようにした。
    更に < > についてはインデントの幅を指定するものとして処理するようにした。
    現状で対応している他のオペレータ (y d c u U ~ ?) については全て引数は無視するようである。

  * vi-mode: 履歴項目を移動したときのモードおよびモード表示 [#D0492]

    - done: ノーマルモードは保持するべき。但しカーソル位置の補正が必要になる。

      履歴の移動は .history-relative-line で起こる。修正した。

      履歴検索をする時も常に気にする必要がある。
      →現在は履歴検索はノーマルモードから呼び出せないので関係ない。
      (逆に言えば将来的に対応する場合には注意が必要ということになるが。)

    - ok: 挿入モードは保持するべき

    - ok: オペレータ待機モードは解除されるはず

    - resolved: ビジュアルモード・選択モードは解除するべき
      現状では解除されずに変なことになる。
      というか履歴移動が起こるようなコマンドを登録しているのが悪い。
      初めから履歴移動が起こらないようになっていれば解除だのを考えなくて良い。

      →これは forward-line, backward-line において、
        _ble_decode_key__kmap=vi_command の時にのみ、
        履歴項目の移動をするように変更することで対処する。変更した。
        他にも .history-relative-line を呼び出している箇所を修正した。

  * 2017-10-01 vi-mode (visual mode): 範囲の表示 [#D0491]

    * done: _ble_edit_mark_active=line, block の時の着色。
    * done: 範囲の表示 charwise であったとしても右に 1 文字拡大しなければならない。

    色々試したが、どうも範囲の表示と矩形領域の決定を独立に計算するのはよくない。
    ということなので矩形範囲の計算方法をここで調査する。

    | ★矩形選択の実装でよく分からない動作を発見した。以下の様に入力しておいて
    |
    | | あa
    | | aaa
    | | aあ
    |
    | 1 行目の行頭で C-v して jj とすると、以下が選択(ハイライト)される。
    |
    | あ
    | aa
    | aあ
    |
    | この状態で y として適当なところに移動して p をすると
    |
    | あ
    | aa
    | a
    |
    | が貼り付けられる。もう少し幅のあるもので試してみる。
    |
    | あいうえお
    | aaaaaあaaa
    | aaaaaaせそ
    |
    | これにおいて、選択範囲と貼付け結果は以下のようになる。
    |
    | | あいう      あいう
    | | aaaaaあ  → aaaaa
    | | aaaaaa      aaaaaa
    |
    | |  えお    えお
    | | あaaa →  aaa
    | |  せそ    せそ
    |
    | と思ったら、中途半端になっている文字に関しては空白で埋められている様である。
    |
    | ★更に試すと
    |
    | | あ
    | | a
    |
    | 上に対して 1 行目の先頭から C-v jly とすると、p で以下が貼り付けられる。
    |
    | | あ
    | | a
    |
    | "つまり始点・終点のうちより右にあるものの右端" が矩形の右端になるのではなく、
    | "始点の右端・終点の右端のうちより右にあるもの" あ矩形の右端になるのだと思われる。
    | しかしながら a の後に空白が入るのは行の途中に挿入されたとき、
    | 続きに別の文字がある場合に限られるようである。
    | 先程との違いはそこに実際に文字があるかどうかである。
    | 先程は "あ" という文字が中途半端に切り出されて空白になっていた。
    | 一方で、今回は元々そこに文字がなくて空白で埋められていた。
    |
    | ★貼り付け時または読み取り時にタブは
    | 空白に変換するべきなのではと思ったが、
    | 実際に試してみるとタブはそのまま切り取られそのまま貼り付けられるようだ。
    | 従って、タブが含まれている場合は貼り付けの時に幅はばらばらになる。

    分かったこと。

    - 矩形の左端としては 始点・終点 のうちより左にあるものが選ばれる。
    - 矩形の右端としては 始点・終点 の右端のうちより右にあるものが選ばれる。
      (左端がより右にあるものの右端というわけではない。)
    - 中途半端な位置にある全角文字は空白に置き換えられる。
    - 貼り付け時には幅を合わせるように空白が追加される。
    - タブに対して "幅を保持するように空白に変換する" などの操作は特に行われない。

    折り返しになっているときの動作はどうだろう。
    特に行末に全角文字が入り切らずに文字送りされた場合。
    試してみた所、

    - 表示の行での矩形ではなくて論理行での矩形である。
    - ただし、列は文字の幅の勘定ではなくて行頭からの相対表示位置に従って列が決定される。
      (これは特に行末に入り切らない全角文字が合って文字送りされたときに違いが出る。)
    - この状態で切り取って、貼り付けを行うと以下のように挿入される。

      *hello heあlo*
      *hello hello h*

      つまり、貼り付け時に矩形になるようにする調整は切り取り時の表示幅
      で計算されていて、貼り付け時の表示幅で計算されるわけではない。

    - 更に末尾の空行もちゃんと記録される。

    矩形範囲の各断片の決定のときに計算するべきことは何か。以下を計算すれば良い。

    1 各断片について
      1 開始位置と終了位置 (これは範囲表示用なので中途半端な全角を含む)
      2 切り取る場合の文字列 (中途半端な全角は空白に変換)
      3 貼り付け時に矩形になるようにするために必要な空白の数
    2 最初の非空白断片の番号・最後の非空白断片の番号
      (これは範囲表示用である。もしかすると直接 rmin, rmax でも良いかも)

    * 切り取り時に境界の上に載っている全角文字があるとき、
      境界の外に出ている部分に関しては空白に置き換えられる。
      その全角文字が行送りされているとき、
      行送りの幅についても空白に置き換えられる。

      例えば以下は C-v で "o" から "x" を切り取ったときの変化である。
      元々行送りマーク ">" のあったところに空白が付加される。

      |.....>|    |..... |
      |あxyz$| -> | yz$  |
      |....he|    |....he|
      |lopqr$|    |lqr$  |

2017-10-01

  * vi-mode (visual mode): ビジュアルモードの間の切り替え [#D0490]

    visual mode で v とすると visual mode を抜ける。
    この時、抜けた瞬間の状態は記録されるのだろうか。
    試してみた所記録されなかった。つまり、キャンセルに相当する。

  * vi-mode: ビジュアルモード 第一実装 [#D0489]

    そもそもビジュアルモードと選択モードの違いは何なのか。

    zsh の vivis の実装を見れば最低限の雰囲気は分かるかもしれない。

    _ble_edit_mark_active で区別する?

    例えば単に _ble_edit_mark _ble_edit_mark_active を指定して、
    少数のコマンドにおいて kill ring に何かを設定するように改修すれば良かったりしないだろうか。

    取り敢えず初めて visual mode を使ってみることにする。
    オペレータを入力するとその場で現在の範囲を確定させるようだ。

    * ビジュアルモードを抜けるのはどの時か確認する必要がある。

      - done: 先ずオペレータを実行した時。
      - v V C-v などを指定したときは別のビジュアルモードに切り替わったり今のビジュアルモードを抜けたりする。
        これは別項目を立てて処理することにする。 #D0490
      - done: C-c をすると現在のビジュアルモードをそのまま抜ける

      C-o v として入った後に抜ける時、
      - done: オペレータを実行する場合には元の挿入モードに戻る。
      - done: C-[, ESC をすると元の挿入モードに戻る。
        "前回のビジュアルモードの情報" は記録しない。
      - done: C-c をすると全て忘れてノーマルモードになる。
        この時、当然、カーソル位置の行末補正は起こる。
        行末以外の場所にいるときは後退するなどの動作はしない。
        "前回のビジュアルモードの情報" は記録しない。

    * done: カーソルの動作

      - done: 行末に移動することは可能である。
        つまり needs-eol-fix は false を返すべき。
        →そのようにした。

      - done: 既存の nonbol-eolp の判定の部分はそのままで良いだろうか。
        つまり ^ などで行末に移動しなくて良いだろうか。

        - ok: ^ の場合はそのままで良い。移動しない。元から visual mode では、
          現在のカーソルの右にいる文字も取り込むようになっているので、
          わざわざ行末に移動しなくても行末まで範囲に含まれる。

        - done: forward-char m (SP) で nonbol-eolp 補正をしているが、これは xmap では使わないと思う。
          と思って試してみたら xmap でも使うし、更にいうと行末まで移動した。
          これについては実装しなければならない。

          % というか single-command-mode でも SP の動作が誤っていたりするような気がする
          % →と思って試してみたら single-command-mode での SP においては、
          % 次の行頭に移動するようだ。つまり、xmap の時にだけ nonbol-eolp に移動するという事になる。

          forward-char m (SP), backward-char m (DEL) について
          個別に vi_xmap の時の条件分岐で修正を加えた。

        - ok: 他は、行単位の移動だけれどこれはどうだろうか。
          例えば preserve_clumn のような移動をした時にどうなるか。
          試してみるとより短い行に移動するときに行末にも止まるようだ。
          これについてもちゃんと実装しなければならない。

          →これは .relative-line を呼び出し最終的には needs-eol-fix
            に帰着するので特別に対応する必要はなかった。

    * done: 更に挿入モードで C-o v として入ると入れ子になる。

      これは _ble_keymap_vi_single_command{,_overwrite} 変数をそのままにしておけば良い。
      その後で set-operator だか何だかで xmap を抜ける時に復元を行えば良い。

      動作を確認した。動いている。OK

    [実装]

    後の細かいことは実装しながら調べていくことにする。
    先ず初めに実装するのはビジュアルモードに入る時の動作である。

    取り敢えず "前回のビジュアルモードを復元する" というもの以外は実装した。
    ビジュアルモードの種類は _ble_edit_mark_active に設定した文字列 char/line/block で区別する。
    また C-c, C-[ (ESC) によりビジュアルモードを抜ける動作についても実装した。
    オペレータに対応する前にこの状態でカーソル移動などの動作試験を行う。

    取り敢えず動くことだけは確認した。

    x done: ESC で抜けられないと思ったら Meta 修飾になっていた。直した。
      また ESC の動作はハードコードするのではなくて keymap を通して解決する様に修正した。
    x done: また、ble/keymap:vi/setup-map において
      M-left M-right が束縛されていたのを削除した。
      これらは ESC left, ESC right の動作を上書きしてしまっていた。

    次にオペレータの呼び出しを実装する。

      取り敢えず cc dd などの行単位の操作を統合する形で ble/keymap:vi/call-operator-linewise を実装した。
      と思ったら cc dd が動かなくなった。と思ったら get-arg を呼び出すのが抜けていた。直した。
      また、cc dd の振る舞いについても修正を行った #D0488。

      次に ble/keymap:vi/call-operator-charwise も実装する。実装した。

      他にオペレータを呼び出している箇所は ble/widget/vi-command/linewise-range.impl である。
      これはオペレータ作用後の位置の移動が単純ではないので call-operator-linewise に統合するのはやめた。
      但し、[cd] を特別扱いしていた部分を整理して最小限にした ([cd] は、常に first-non-space に移るという点で特別である)。

      ble/keymap:vi/call-operator-linewise においては完全に [cd] は他のオペレータと同様の取り扱いに統合した。

    更にオペレータを呼び出した後に元のモードに戻るのを実装する。

      これは多分 vi_xmap/exit を呼び出せば良いだけではないか?

    さて動作確認をする必要がある。

    o オペレータ呼び出し後にちゃんと正しいモードに戻るか。
      OK 通常通りに呼び出した時はノーマルモードに戻り、
      挿入モードから C-o v を呼び出した時は上書きモードに対応する挿入モードに戻る。

    o y の動作 d の動作 c の動作

    x done: 範囲が足りていない。カーソルの右の文字も含めなければならない。
      更に vim で確かめてみると行末にあるときには更にその次の改行も含められるようだ。
      但し、一番最後の行の行末にいるとき (行末に行くことが出来る) には改行が付加されたりはしない。

      そのような動作に修正した。確認した。

    o 様々の移動コマンドを使うことができているか。特に引数付きで。

    o 通常の文脈での c や d を書き換えたが、ちゃんと動いているだろうか。
      dw と cw で確認した。動いている。

    x done: cj dj は動いている。と思ったら cj の後に行末 (インデント) に来ていない…。
      .relative-first-non-space の中の nonbol-eolp を needs-eol-fix に直した。直った。

    o cc と dd もちゃんと動いているように見える。

    x ok: 何だか分からないが上下に移動できなくなっている。
      と思ったら最新版ではなくて古いので試していた。

    o 範囲が反転しているときには大丈夫か。大丈夫。

    まあ恐らく大丈夫だろう。取り敢えずこの時点で commit しておくことにする。
    今までのメモで考慮するべきものに関しては分割して議論することにする。

  * kill-current-line (dd), kill-current-line-and-insert (cc) の動作が違う気がする。 [#D0488]

    先ず kill-current-line は first-non-space に移動しなければならない。
    kill-current-line-and-insert は新しい行を挿入して挿入モードにならなければならない。
    しかも元々あった行 (1行目) のインデントを保持しておかなければならない。

    - dd で first-non-space に移動するように直した。
    - cc で元のインデントを保持して新しい行を挿入するように修正した。
    - cj でインデントを保持するのは未だ直っていない。直した。
      というか cj で行を消していたが実際には
      1 個新しい行を入れなければならなかったのだ。

2017-09-28

  * ble-edit: 貼り付け対策のせいで RET を押しっぱなしにした時に [#D0487]

    改行が入力されてしまう。これはそもそも自分の悪い癖なのであるが、
    似たようなことをする人は幾らかいると思われるし、
    編集文字列が空のときにはそのまま改行を実行と解釈しても問題はない。

    従って編集文字列が空の時には次に文字が来ていたとしても
    そのまま実行と解釈して良いということにする。

2017-09-27

  * 2017-09-06 ble-edit: BASH_REMATCH 復元について [#D0486]

    任意の配列 BASH_REMATCH を、[[ some =~ some ]] を用いて復元するのは難しい。

    % だとすると一つの方法は local BASH_REMATCH を ble-decode/.hook で定義することである。
    %
    % - 但し、exec:exec の場合には関数の内部でユーザコマンドを実行するので、
    %   その際に unset BASH_REMATCH を実行する必要がある。
    %   そしてユーザコマンドを呼び出した後で、適切な位置で再度 BASH_REMATCH を呼び出す必要がある。
    %
    %   関数 ble-decode/EPILOGUE の以下の行の直後で良いだろう。
    %
    %   "ble-edit/exec:$bleopt_exec_type/process" && return 0
    %
    % - また exec:gexec の場合には ble-decode/.hook の外側でも処理を行うので、
    %   その外で呼び出されうる全ての関数について local BASH_REMATCH を指定する必要がある。
    %   外で呼び出されうる関数に関しては変数 _ble_decode_bind_hook に設定されうる関数を調べれば良い。
    %   _ble_decode_bind_hook に対する値の設定は現状でただ一箇所 ble-edit/exec:gexec/.setup の中である。
    %   ここで指定される関数として以下のものがある。
    %
    %   - ble-edit/exec:gexec/.eval-prologue
    %   - ble-edit/exec:gexec/.save-params
    %   - ble-edit/exec:gexec/.eval-epilogue"
    %   - ble-edit/exec:gexec/.end
    %
    % - 他に trap を通して呼び出される関数がある。
    %
    %   - ble-decode: ble-stty/TRAPEXIT これは単純な関数なので中で正規表現を使わないことは自明である。
    %   - ble-edit: ble-edit/attach/TRAPWINCH 必要
    %   - ble-edit: ble-edit/exec:exec/.eval-TRAPDEBUG 不要
    %   - ble-edit: ble-edit/exec:exec/.eval-TRAPINT 不要
    %   - ble-edit: ble-edit/exec:gexec/.eval-TRAPDEBUG 必要
    %   - ble-edit: ble-edit/exec:gexec/.eval-TRAPINT 不要
    %   - ble-edit: ble-edit/bind/stdout/TRAPUSR1 不要
    %   - ble-edit: ble-edit/bind/.exit-TRAPRTMAX 不要
    %
    % また将来的に trap や _ble_decode_bind_hook を追加するときのために、
    % どの様な関数において local BASH_REMATCH をつける必要があるかについて
    % Note にまとめておく必要がある。

    とここまでまとめて気付いたが local BASH_REMATCH を実行しても
    読み取り専用の変数ですと表示されて怒られる。
    更に、BASH_REMATCH に対する変更の影響は結局関数の外でも残る。
    つまり local BASH_REMATCH としても効果はなくエラーメッセージが表示されるだけである。

    一番理想的な方法は正規表現の一致に使用された文字列と正規表現を特定することだがそれは難しい。
    もし一致全体 ${BASH_REMATCH[0]} のことを気にしないで良いのであれば、
    ${BASH_REMATCH[i]} に対して (.{${#BASH_REMATCH[i]}}) を一致させるようにすれば良い。
    問題は一致全体である。結局一致全体は不動なので [[ $BASH_REMATCH =~ 某 ]] とするしかない。
    この時各子一致は独立ではなくて overlap があることに注意する。

    特に、各子一致は入れ子構造になっていなければならないという制限が存在する。
    さて、問題は子一致の内容が指定されたときに入れ子構造を再現することができるのかということである。
    また各子一致の順序も保持しなければならない。

    1 各子一致について先頭から順に見ていくとする。
      或る子一致について、先ず既存の子一致に対する入れ子関係を決定する。
      一般に複数の可能性がある。つまり、全体一致の部分列として複数の位置に存在する可能性があって、
      更に既存の子一致に対する入れ子関係と矛盾しない (既存の子一致の終端を跨がない) という条件を課しても、
      複数の候補が残る可能性がある。

    2 この時、一番初めの (即ち、一番内側の入れ子になるような) 可能性を選んでも問題は起こらない。
      何故ならば後続の子一致は、現在処理している子一致に完全に含まれるか、
      或いは現在処理している子一致より明確に後に位置するかであるため、
      本来の一致位置より左側に平行移動する分には何も問題が起こらないからである。

    この手順によって各子一致の開始位置を決定することができる。
    その後に対応する正規表現を () と .{幅} の組み合わせで構築すれば良い。
    後は $BASH_REMATCH と構築した正規表現を何処かの変数に保存しておけば、
    [[ $saved_rematch =~ $saved_rex ]] でいつでも BASH_REMATCH の状態を復元できる。

    [実装]

    取り敢えず実装した。動いている気がする。実装している途中に気付いた点として、

    - 一致に失敗すると BASH_REMATCH は空になる。
    - 初期の状態では BASH_REMATCH は unset の状態になっている。
    - BASH_REMATCH を手で unset することはできない。

    初期の unset の状態には戻せないので ble.sh では BASH_REMATCH を空にする
    (具体的には [[ '' =~ none ]] を実行する) ことにした。

  * 2017-09-25 ble-edit: 貼り付け対策 [#D0485]

    % 誤って貼り付けを行ってしまってあらぬコマンドが次々に実行されてしまうという事故がある。
    % 実はこれは検出可能なのではないだろうか。
    % 前の入力に対して間髪を入れずに改行が入力された場合は怪しい。
    %
    % ただ IME を通して日本語を大量に入力して、その処理が終わっていない内に改行を押すこともあって、
    % そのような場合に改行として入力されてしまうと分かりにくいので、複数行編集の表示はやはり必要である。
    %
    % また isearch で処理に時間がかかっているときに改行を押す場合も考えられる。
    % この場合には accept するか無視するかにした方が良い。
    % 現在は accept になっているが本来は無視するのが正しい気がする。
    %
    % これの判定は以下のようにする
    % - self-insert に引き続いて改行を入力したときは、改行を挿入する
    % - それ以外に引き続いて改行を入力したときは、bell
    % - idle 時に改行を入力したときは accept-line または複数行編集ならば改行挿入

    実は、その改行が前の文字に間髪入れずに入ってきたとかではなくて、
    単に改行に引き続いて何かが入力されているという判定で良いのでは?

    できるかと思ってやってみたができない。
    貼り付けているとしても改行を処理しているときには次の文字は未だ来ていないのだろうか。
    と思ったが、よく見ると実行の遅延はちゃんと処理できている。
    ということは ble/util/is-stdin-ready は真になっているはずである。
    なのに accept-single-line-or をすり抜けるのはおかしい。

    と思ったら accept-single-line-or を通過していない。何故?
    実は vi-{command,insert}/accept-single-line-or の方は独立した実装になっていた。
    これらも同時に修正する必要がある。修正した。ちゃんと動くようになった。

  * 2017-09-25 ble-edit: 複数行編集のスクロールについて [#D0484]

    現状の実装では端末の高さよりも高くなると変な表示になることを甘受している。
    zsh で試してみたら ... と表示して前方の行を省略するようである。
    これは ble.sh でも実装可能のはずである。

    描画範囲を制限する様にすれば良い。
    描画は関数 ble-edit/render/update で行っている。
    幸い現在の実装では描画内容の決定と実際に描画を行う部分が分離されている。
    この実際に描画を行う部分の改修で済めば嬉しい。

    実際に何に気をつけなければならないかというと、

    1. 現在の先頭行の行番号を保持するということ、
      現在の先頭行の行番号は現在のカーソルの位置に依存して修正する必要があること。
    2. 先頭行の行番号を変更するときにはスクロールを伴うこと、
      特に、スクロールにより隠れていた部分は再描画が必要になる。
    3. 実はスクロール処理と変更部分の更新描画は分離できるということ。

    恐らくスクロールがある場合には先にスクロール処理をしてしまってから、
    変更部分の描画を行うようにすれば良い。

    * ところで、スクロールによって再描画された部分については後で再度描画する必要はなかったりする。
      下手すると完全に 2 度描画してしまうということも考えられる。
      これについてはどのように処理すればよいかは微妙。
      と思ったが、再描画範囲は現在単一の range で管理しているのだから、
      実はスクロールによって再描画範囲を削るというのの実装はそんなに難しくないのでは。
      →実際に観察してみると umin, umax で再描画範囲を管理している。
        スクロールによる描画でこれらの境界を踏む場合には umin, umax を狭めることで対処できる。

    * と思ったけれど info が複数行ある場合などを考えると全体で収まるように調整しなければならない。

    [実装]

    * コメントアウトされている古いコードで
      - プロンプトは更新しないけれど編集文字列は全描画するものと、
      - 全体描画後にカーソル位置を設定するときに SC/RC を利用するものは、
      コードの管理・維持が面倒になったし今後使われるとも思われないので削除する。
      前者については、今後必要になったらその時に新しく書き起こせば問題ない。
      後者については、わざわざカーソル位置で表示文字列をスライスしなければならないので、
      処理としても無駄が多いし、ユーザの設定する SC/RC と干渉するのも嫌である。

    [動作確認]

    x resolved: カーソル位置が二重になっている。これはどういうことか。
      _ble_line_cur に収めるカーソル位置の値は実際に表示されている位置であった。
      修正したらこれは直った。

    x resolved: スクロール状態になっているとき、最下行にいたとしても margin が加えられている。
      カーソル位置に対応するスクロール量の上限・下限の値の計算方法を書き直した。直った。

    x resolved: 一番上の行に移動するとき、上へのスクロールが実施されていない気がする。
      シフト量の符号が逆転していた→直した。

    x resolved?: X座標の位置計算をミスっている。
      スクロール時に常にカーソル位置が左端になっている。
      →スクロール量の修正をしたあとで再度確かめてみたら直っていた。
      結局、何が行けなかったのかは謎。

    x resolved: C-l で clear-screen すると表示されてはならないところまで全部表示されてしまう。

      % これは、実際に描画内容を出力している部分を全部列挙して、
      % 全ての箇所に対してスクロールの対応を加える必要がある。
      % 取り敢えずは、これについては保留として、
      % 初めに通常編集時の表示のずれを修正する。

      確認してみたら単に render/update の全体描画の際の、
      スクロールがあるかないかの判定の部分が反転していただけであった。
      と思って直したら、今度は何も表示されないしカーソル位置がずれている。

      うーん。と思ったら部分描画の部分のコードが色々間違っている。
      存在していない変数を使って計算していた。これを直したら直った。
      恐らく描画範囲が負になったりしていたのだろう。
      それで位置がずれたりしていたのだと思われる。
      修正した。直った。

    + done: history-forward で編集文字列の末端に移動するのはどうだろう。
      これは編集文字列の一行目の末端に移動するのが良いのではないだろうか。
      振る舞いを修正した。OK

    + done: [[ ! $bleopt_suppress_bash_output ]] のときに使われる
      ble-edit/render/redraw-cache の中での再描画は、
      現状では全体再描画になっていてスクロールに対応していない。
      仕方がないので [[ $_ble_line_scroll ]] の場合には最初から全部描画することにした。
      しかし、これはちらつきの原因になる。

      現状では ! $bleopt_suppress_bash_output はデバグ用途でしたか使われないとはいえ、
      中途半端な実装になっているのは気分が悪いので後で対応を考えることにする。

    x resolved: 弄っていたら何故か履歴項目を移動したときに
      スクロール領域を制限せずに全てぺろりと表示されるようになってしまった。何故か。

      色々調べた結果、get-index-at の内部で
      _ble_line_begy _ble_line_endy を使っているのにも拘らず、
      これを更新する前に get-index-at を使用していたからであった。
      しかし、もし get-index-at の内部でこれを使用するのであれば、
      寧ろ _ble_line_{beg,end}{x,y} は ble-edit/text/update の中で更新するべきなのではないだろうか。

      → ble-edit/text/update/position の中で更新する様に変更した。
      更に変数名をそれに合わせて _ble_line_text_* に変更した。動作している。
      また勝手に中身をクリアしたりしている箇所でもクリアしないことにした。
      更新は ble-edit/text/update が呼び出された時に行われるであろう。
      逆に言えば ble-edit/text/update が呼び出されていない状態で
      _ble_line_text_{beg,end}{x,y} を使用することは不正である。
      これについても確認してみると、何れの場合でもちゃんと
      ble-edit/text/update が呼び出されていることをチェックしてから使用していたので、問題ない。

    取り敢えず複数行編集のスクロールの対応は一段落したことにする。
    これからまたバグや不整合が出て来る気がするが、それはその都度対応することにする。

2017-09-25

  * bleopt での値チェックを実装する [#D0483]

    これは以前発案の onchange と合わせて考察する。

    | * 2015-11-18 bleopt コマンド: onchange
    |
    |   変数の値が変わった時に onchange イベントを起こす仕組みを整えても良い。
    |   これは変数の内容変更にともなって処理が必要な変数が出てきてから考える。

    或いは値を設定する関数を定義できるようにするのが一番柔軟だろうか。
    しかしそれは変数としての実体が存在しないものに対しては良いが、
    そうでないもの (bleopt 変数) に関しては適していない気もする。

    value というローカル変数を設定してから関数を呼び出してチェック・修正してから、
    値を設定するというようにするのが良い気がする。


2017-09-24

  * vi-mode: 前回からの修正: [#D0482]

    - vi-mode: 行単位の操作 (2yj など) をするとエラーになるバグの修正
    - vi-mode: 現在位置よりも先に操作対象があるとき (yib など) 位置の移動が起こらないバグの修正
    - vi-mode: isearch の途中でノーマルモードに移行すると選択状態がそのままになるバグの修正
    - char_width=emacs のとき、★などの文字 (U+2000 - U+2600) の文字幅が常に 1 になっていたバグの修正
    - $? 及び $_ の再設定が動かなくなっていたバグの修正
    - vi-mode: {count}L で現在行より上に行く場合、{count}H で現在行より下に行く場合などで範囲が裏返るバグの修正
    - vi-mode: + - H L yib などで非空白行頭に移る条件の修正
    - vi-mode: オペレータを指定したときの gg G は現在のコマンド内の移動だが、引数省略時に引数 1 と解釈していたバグを修正

    - vi-mode: rx grx で上書き対象を着色
    - vi-mode: imap: C-m, C-h, DEL; nmap: o, O でインデントを特別扱い

    - テキストオブジェクト [ia][pst]
    - コマンド % {count}%
    - vim-surround.sh: 設定 "bleopt vi_surround_45", etc. に対応

  * 2017-09-22 vi-mode: "-- NORMAL --" という表示をした方が良いか? [#D0481]

    zsh vi-mode で検索したら以下のような記事を見つけた。
    -- NORMAL -- を表示している。色も変えられる様にしている。

    https://qiita.com/b4b4r07/items/8db0257d2e6f6b19ecb9

    或いは (複数行編集のときのために) ~ を表示するようにするのが分かりやすい気がする。
    やはり現在複数行編集なのかどうかが分からないので ~ (もしくは -- NORMAL --) は表示するべきの気がする。

    これは既定で ~ (太字) とし、設定項目で指定できるようにした。

  * 2017-09-08 vi-mode: % [#D0480]

    引数を指定した時の動作についてはよく分からない。
    括弧の上にいるときは対応する括弧の上に移動する。
    括弧の上にいないときは同じ行内で右に向かって括弧を探し、
    最初に当たった括弧に対応する括弧に移動するようだ。

    <> は括弧として認識しない。[] () {} は括弧として認識する。
    引数を指定した時の動作は不明である。

    cmplstofB: 2017-09-17 要望が入った。

    | Vim のノーマルモードにおいて % は「対応する括弧(もしくはそれに準ずるもの)の対に飛ぶ」
    | という機能が割り当てられています。(:help %) 実装していただくととても嬉しいです。

    * :help % で見てみると引数は許されないと書かれている。
      {count}% で count % だけ次の行に行くそうだ。
      成る程。確かに試してみるとそうなっている。
      :help N% というので説明が見られるようなので調べると、式も与えられている。

        ({count} * number-of-lines + 99) / 100

      count% だけ下に移動するのではなくて、 count% の位置にある行に移動するようだ。

    * matchpairs という変数で指定できるということになっている様だが、
      どのように指定するものなのかは :help % には書かれていない気がする。
      :help matchpairs で見てみると default "(:),{:},[:]" と書かれている。

    まあ取り敢えずこれの事は考えないことにする。

    初めの括弧に関しては行内での探索のようである。

  * vi-mode: o O でもインデントは認識する [#D0479]

    O は一つ前の行のインデントではなくて、現在の行のインデントを継承する。

  * vi-mode: 空白だけの行でインデントは有効か? [#D0478]
    → 有効である。C-m でも継承されるし、DEL でも一度に消せる。OK

  * 2017-09-23 vi-mode (text object ?s): どうも実装が不完全だ。 [#D0477]

    - 先ず yas yis で引数を指定したとき、段落を越えて範囲は拡大する。
    - 更に、初めに空行にいた時の動作も引数が指定したときに対応できていない。

    連続改行は一つの文として取り扱われている気配がある。

    正規表現を改良すればなんとかなるかもしれないしならないかもしれない。
    よく分からないが取り敢えず先に p を実装する。実装した。

    * 先ずは段落を跨ぐように改造する必要がある。

      少なくとも段落の終端は使わないようにする必要がある。
      更には段落の先頭も使う必要がない可能性がある。
      これについては先ずは段落の終端を使わないように修正し、
      その後で更に段落の先頭も使わないように変更できるかを考察する。

      取り敢えず段落の終端を越えて当たるように修正する。
      段落の境界の取り扱いがどうなっているのかについては、
      yis を使って調べることができる。

      以下 @ がカーソルの位置で、
      数字は "{数字}yis" とした時に何処まで範囲とするかを示したものである。

      | @echo hello.1 2echo world.34
      |
      |
      | 56
      | echo hello.7 8echo world.9

      % これを見るに、恐らく本来は
      %
      % | @echo hello.1 2echo world.3
      % | 4
      % |
      % | 5
      % | 6echo hello.7 8echo world.9
      %
      % の様になっていて、但し補正されて上記のようになっているのではないかと思われる。
      % ここで疑問となるのが 5 が何故補正されないのかということである。うーん。
      %
      % - 前の行の内容が存在している時には補正する (4)
      % - その行の内容が存在している時には補正する (6)
      %
      % という規則を考えれば良いだろうか。
      %
      % 更に、この補正前の 3456 の動きについて考える。
      %
      % (1) 3->4 に関しては行末にいて、
      %   現在行が非空行であれば次の行頭に行くということになろうか。
      %
      %   もう少し検証する。行末に空白があるときの動作はどうだろう。
      %
      %   | @echo hello.1 2echo world.3   (←空白がある)
      %   | 4
      %   |
      %   | 5
      %   | 6echo hello.7 8echo world.9
      %
      %   変わっていないように見える。
      %   うーん。空行にいない限りは通常の空白探索の動作ということにして、
      %   更に通常の空白探索では連続する LF の内 2 番目のものを受け取らないという事にするべきか。
      %
      % (2) 4->5 に関しては、
      %
      %   1 空行にいるときに \n の連続を読み取る。
      %   2 最後の \n だけは読み取らずに一つ戻る。
      %
      %   と理解できるだろうか。しかし幾つか疑問点が残る。
      %   先ず間に空行が1個しかない場合の動作はどうなるのか。
      %   その場で動かないのか、或いは、次の段落の頭に移動してしまうのか。
      %
      %   →試してみた所以下のようになった。
      %
      %   | @echo hello.1 2echo world.3   (←空白がある)
      %   | 45
      %   | 6echo hello.7 8echo world.9
      %
      %   これは変だ。ということはやはり 45 のどちらかは補正前でも
      %   別の場所にあると考えるべきなのだろうか。うーん。
      %   所が、3-6 の間にカーソル位置は 3 つしかない。
      %   その中に 4 つの停止点があるということは、
      %   他の内部状態が存在するか (exclusive inclusive など)、
      %   或いは、実は停止などしていなくて arg を
      %   2 消費する移動が存在するかのどちらかである。
      %
      %   うーん。2消費する移動だと解釈することにする。
      %   どちらであったとしても区別可能であるとは思えないので。

    もう分からないのでまた vim のソースコードを見ることにした。
    どうやら文の終端は /[.!?]\s/ ではなくて /[.!?][])'"]*\s/

    うーん。どうも "現在空白" と "現在文" という二つの読み取りを交互に行っている様だ。
    そして、空行の集合のスキップは "現在文" の状態の時に行われる。

    多分以下のようになっている。
    偶数番から奇数番の時にだけ空行を跨ぐことができると思われる。

    | @echo hello.1 2echo world.3
    | 4
    |
    |
    | 56echo hello.7 8echo world.9

    他の場合にも調べることにする。
    空行で初めた時には、試した結果、恐らく以下のようになっている。

    | @
    |
    | 0
    | 12echo.3

    うーん。結局実装し直しということになりそうだ。
    実装し直した。動作確認する。

    o 空行しか無い時に全てを取り尽くすことを確認した。
    o これ。
      | @echo hello.1 2echo world.3   4(←空白)
      |
      |
      |
      | 56echo hello.7 8echo world.9
    o これ。OK
      | @
      |
      | 0
      | 12echo.3 4world.
    x 行末に空白がない時に backward に空白を取るのができていない。
      →LF, HT の定数が定義されていない状態でそれを使って正規表現を構築していた。直した。
    x 今度は段落を越えて backward に空白が取られている。
      この正規表現の場合には一番最初に当たるのは $LF$LF だと思ったのだが…。
      →正規表現が悪かった。二重改行があったとしても終端 $ に接することを要求していたのが悪い。修正した。
    x 段落の末端にいるときに前方の空白を取り込んでくれない。
      →どうも試してみると正しく取り込めている。
      どうやら linewise で実行されると first-non-space に移動しているというだけだった。
      しかし vim では行頭に移動する。これは新しい linewise のオプションを追加する必要がありそう。

      うーん。これは…。このまえ修正した linewise は正しくない気がする。

    linewise を大修正した。これで再度チェックをやり直してみる。

    o "@echo hello.1 2echo world.34^J^J^J^J56echo hello.7 8echo world.9" OK
    o "@echo hello.1 2echo world.3   4^J" OK
    o "@^J^J0^J12echo world.3^J" OK
    x yis で何故か前方の空白を取り込んでいる?

      うーん。これはよく考えたら実装の過程では考えなかったことである。
      つまり、文の区切りは "二重改行" または "句読点+空白" ではなくて、
      "二重改行[+空白]" または "句読点+空白" なのである。修正する。

      →修正した。yas yis の動作確認もした。
        最終行の時、次に空行があるときのそれぞれについても確認した。OK
    o 段落を越えて前の空白を取り込むということはない。
    o 単一行段落の末端にいるときの yas で前方の空白を取り込んでかつ、
      行頭に移動するという動作に関しては、既に試したようにちゃんと実装できている。

    恐らくだいたい大丈夫であろう。

  * vi-mode (linewise-range): bug in reverted [#D0476]

    linewise-range.impl の実装を調べていて気がついたが。
    例えば一番下から 2 つ目の行で 5yL などとすると、
    linewise-range.impl の中の reverted の判定に失敗する。

    結果として "先頭行の末端" から "最終行の先頭" までが切り取られ、
    更に切り取り後のカーソル位置は先頭行ではなくて最終行になる。

    現在のインターフェイスを変えるのも面倒なので、
    linewise-range.impl の reverted の計算を厳密にやるようにするか。
    或いは、呼び出し元で全て解決してから渡すようにするという手もある。
    →呼び出し元で処理する場合には、それぞれで両端の前後関係に応じた場合分けが必要になり面倒である。
    その辺りのごちゃごちゃも一緒に統一したのが linewise-range.impl であった。
    従って、やはり linewise-range.impl の中でごちゃごちゃと計算したほうが良い気がする。

    実装した。結局その場で各先頭行と最終行の行頭を計算するようにした。

    # 合成する際に各実装の最適化をそのままにくっつけたのが混乱の原因だ。
    # もし初めからこの様にくっつけて実装するのだとしたら、以前のような変なことにはしない。
    # (或いは、もっと上等な遅延評価の仕組みを整えてから実装する必要があるだろう。)
    # 整理されたコードというのはその分だけ非効率的な部分も許容しなければならないのである。

    次に動作チェックを行う必要がある。

    - 特に実装の過程で require_multiline の辺りのコードも一緒に整理された。
    - また y オペレータの後に非空白行頭に行く処理も変更があったが、
      これはその処理の修正をこれからするところなのでそれが終わってからチェックすれば良い。

    % x 2行目で 3yH を実行すると 3 行目に移動してしまう。これは変だ。
    %   と思ったら修正までのコードで動かしていただけだった。問題なかった。
    % x 下から 2 行目で 5yL を実行すると、下から3-4行目だけが切り取られ、
    %   下から2行目に現在位置は留まる。この動作を直す為に修正したはずなのに直っていない。
    %   と思ったらこれはまた古いコードで動かして試していた。

    x 下から2行目で5yLを実行したら以下のようなエラーが発生した。
      ((: 48:-4: 式に構文エラーがあります (エラーのあるトークンは ":-4")
      →これは reverted かどうかの判定で直接 p q を用いていたのがいけない。直した。
    o 下から2行目で4yLを実行して正しく動作することを確認した。

    [require_multiline の確認]

    o 一番下の行で yj y+ をしてエラーになること
    o 一番上の行で yk y- をしてエラーになること
    o それ以外の場合にはエラーにならないこと


  * vi-mode (linewise-range): #D0470 の修正はやはり変だ。 [#D0475]

    % relative-line では行を移動しない場合はないと書いたが、
    % y+ のように下に移動するときには beg は初めと同じ行にある。
    % この時のどの位置に移動する(移動しない)のかというのは非自明である。
    %
    % - 更に ygg としたときに nol が ind よりも後にある場合には ind は動かない。
    %   これは個別に動作を考えたほうが良いような気がしてきた。
    %   先ず初めに言えることは従来の実装では ind は
    %   必ず beg-end の範囲に入っている (はず) ということである。
    %
    % 更に ind!=beg のときだけ処理を行うということになっているが本当だろうか。
    % これは preserve_column など各々の動作で異なるのではないだろうか。
    % →各処理法毎に判定することにし、外側では ind!=beg の判定はしないことにした。

    修正した。と思って動作確認をしようとしたらやはり実装を間違えている気がする。
    一旦動作について整理する必要がある。

    % y+, 2yH とすると非空白行頭へは行かないが 1yH とすると非空白行頭へ戻る。
    % つまり + - H G L などでは、先頭行が行き先の行であるときには非空白行頭へ移動する。
    % 先頭行が行き先の行でないときには、ind が先頭行にいないときに非空白行頭へ移動する。
    % それ以外の (先頭行が行き先ではなく、かつ ind が元からそこにある) ときは、動かない。
    %
    % "+ - H G L" の動作について整理する。
    %
    % - 先頭行が行き先の行であるとき
    %   - 現在行が他の行にあるときは非空白行頭に移動する
    %   - 現在行が先頭行にあるときは、現在位置が非空白行頭より後にあるときに限り非空白行頭に移動する
    % - 先頭行が行き先の行でないとき
    %   - 現在行が他の行にあるときは非空白行頭に移動する
    %   - 現在行が先頭行にあるときは、動かない
    %
    % これはもっと簡単にできる。
    %
    % - 現在行が先頭行にあるとき
    %   - 先頭行が行き先の行であるとき、現在位置が非空白行頭より後なら非空白行頭に移動する
    %   - 先頭行が行き先の行でないとき、動かない
    % - 現在行が他の行にあるときは非空白行頭に移動する

    - 現在行が他の行にあるか先頭行が行き先の行であるとき、
      - 現在位置が他の行にあるか非空白行頭より後なら、非空白行頭に移動する

    動作確認

    - yib (block.impl) の動作確認
    - yis の動作確認 → これは現在実装している途中なので後でチェックするので今はいい。

    o 2行目で 3yH, y+ を実行して動かないこと、
    o 2行目で 2yH を実行して非空白行頭に後退すること
    o 2行目の行頭空白で 2yH を実行して動かないこと

    [yib の動作確認]

    o "(^J  echo hello^J  echo world^J)" に対して、
      ちゃんと vim の動作と同様に、中身の行頭に移動することを確かめた。

2017-09-23

  * memo.txt: ユーザ名 B-bar を cmplstofB に統一した [#D0474]

  * vi-mode: by cmplstofB [#D0473]

    | Bash の vi-mode にはないのですが、テキストオブジェクトを実装して欲しいです。
    | Zsh の vim-mode では実装されています。

    これは実装したい。が、コマンド体系がよく分からないのでどのように dispatch するのが良いか微妙。
    vimindex に色々なテキストオブジェクトについて記述がある。
    [ydc] が設定されている時に [ia] が来たら、その時点で別のキーマップに切り替えるなどすれば良いのだろうか。

    更に ysiw" は体系としてかなり謎である → これは独立した項目 #D0446 を立てて対応することにした。

    現在未実装なのは [ia][pst] である。

    * t は #D0461

    * s は #D0472

    * p について調べる。

      これまで試した様子からいうと二重改行なのではないかと思われる。
      と思ったが、間に空白だけの行が含まれていても段落の分割になるようだ。

      ip と ap は区別はないような気がする。
      と思ったが dap と dip を比べると dip は段落の次の空行を残すようだが、
      dap は段落に続く行たち (複数可能) も一緒に削除する。

      また行指向の切り取りになっている。

      1 つまり段落は1つ以上の空行 (空白だけの行) で区切られる。
      2 ap は段落に後続の空行たちを含む。
        後続の空行がない場合には前にある空行たちを含むようになる。
        ip は含まない。

      うーん。これについても詳細に動作を調べる必要がある。
      sentence の動作に大分似ている様だ。

      調べて実装した。

      [確認] 動作を確認する。

      o yap で段落の数を指定して選択し、
        yip で段落または空行たちの個数を指定して選択する。
      o yap で最後に空行のない段落の場合に前方にある空行たちを取り込む
      o 空行しか無い場合の yap, yip の動作も大丈夫。

      取り敢えずは OK ということにする。

  * vi-mode: text object is as [#D0472]

    s について調べる。先ずは as

    - "日本語。abc. 日本語。" を試すと
      "日本語。abc. " と " 日本語。" になる。
      日本語の句読点は認識していないということと、
      前後の空白も含まれるということ。
    - "Hello, i.e., this is a test. This is Q.E.D."
      これは "Hello, i.e., this is a test. " と " This is Q.E.D." になる。
      思ったよりは賢い。仮説: . の後に空白があれば文が切れると判定している。
    - 前後の改行も含まれるようだ? しかしよく分からない。
      1. 先ず行末の . でも良いということ
      2. 更に行末の . であり次の行頭にすぐ文字がある場合は、
         前の行の空白も含むようだ?

    実は改行か空白かは余り区別していない気がする。
    先ず初めに一番最初の非空白文字から . 後の空白までを範囲とする。
    途中に連続改行がある場合はそこで終わるように範囲をせばめる。
    更に末端に改行があればそれを除くように範囲をせばめる。
    もし . が一番最後の文字になっている場合は、文の先頭にある空白を取り込む。
    これは前の行にも遡り、前の行末に空白がなくても改行だけを取り込む。

    % 以下の方法で文の範囲を決定する。
    %
    % 1 どうも先ず二重改行で区切られている領域 (段落) を決定し、
    %   更にその範囲の中で探索を行っているようだ。
    %   二重改行は空白行を含んではいけない、厳密な二重改行である。
    % 2 その範囲の中で "最初の単語から . に続く空白類" までを文の範囲とする。
    % 3 範囲末端に改行がある場合にはそれを除くように範囲をせばめる
    % 4 もしこの時点で . に続く空白類が一つも範囲に含まれないのであれば、
    %   文の前にある空白類(改行も)を範囲に入れるように拡大する。
    % 5 但し、先頭の改行は除外するようにせばめる。
    %
    % 文の区切りは "! " "? " でも良い。 ": " や "; " は駄目。
    % [!?.] の前に非空白文字があるかどうかは問わない。
    %
    % is についてはどうだろう。これは空白類を除くだけのようだ。
    % つまり [!?.] の類は含まれる。
    %
    % 取り敢えず実装したと思って今度は yis を実装し始めたら思わぬ動作をする。
    % 空白の位置にカーソルがある場合には空白が対象になる。

    - これは実装方法を間違えたかもしれない。
    - しかも引数のことも完全に忘れていた。
    - linewise になる条件はよく分からない。
      改行が含まれていれば linewise になるという訳でもない。
      恐らく行頭から行末までを切り取った時に限り
      linewise になるのではという気がする。

    実装し直した。

    [確認]

    動作確認をする。

    x yis も yas も後方に向かって空白も取り込んでいる。何故?
      → backward-extend を確認したら空白の幅を足し忘れていた。直した。
    x 文の真ん中の空白で実行するとそこから文が始まると勘違いする。
      →よく考えたら backward-extend で空白かどうかだけを見るのでは駄目だ。直した。
    x 丁度行全体を捕まえるときカーソルが移動しない。オペレータは動作している → #D0470
    x 一番最初の空行が段落に含まれてしまっている → これは直した。
    x 空行だけで構成されているとき ${str:offset:len} で len が負になるエラーが出る
      範囲拡大の起点が piv ではなくて _ble_edit_ind になっていた → これも直した。
    x 空行だけで構成されているとき対象となっている行数が少ない?
      これは空行だけで構成されているかどうかの判定が誤っていた → s/_ble_edit_ind/piv/ 直した。
    x 空行に続いて段落がある場合にカーソルが移動しない → #D0471
    o yis yas のそれぞれについて引数は試した。
      yas が後方の空白を取り込むことも確かめた。
    o 後方の空白が次の行にある場合にも取り込むことを確かめた。
    x 同じ行内の後方の空白が取り込まれていない…
      いや、空白は取り込まれているけれど何故か前方にも空白を取り込んでいる。
      →改めて末尾に関する条件を見たら良くわからない条件になっていたので直した。動作確認した。
    o 段落の末端または行末に達する場合に、
      前方の空白を取り込むことも確認した。
    o 前方の空白が改行だけの場合それを取り込まないことも確認した。
    o 前方の空白が前の行の末尾にある場合それを取り込むことも確認した。

  * vi-mode: linewise-range.impl において [#D0471]
    現在位置が作用対象よりも前に存在するときに、
    作用後に非空白行頭に移動しないのは変なのではないか。

    これについては vim の動作を調べる。
    - "カーソル ( 改行 echo 改行 )" のときに yib とすると
      vim では echo の先頭にカーソルが移動する。
      ble.sh ではカーソルは移動しない。
    ^ その他の既存のものでは現在位置が作用対象よりも
      前に来ることはなかったはずである。

    直した。

  * vi-mode: linewise-range.impl において [#D0470]
    行を移動しないときに非空白行頭に移動しないのは変なのではないか。

    実際にこれを呼び出している各機能の振る舞いについて vim で再度確認する。
    - yib は vim では行頭に移るが ble.sh の現在の実装では移らない。
    - nth-line, nth-last-line, last-line に関しては、2行目にいるときに
      vim で 2yH とすると行頭に移るが ble.sh で 2yH としてもそのままである。
    - relative-line などでは行を移動しない場合はないので、これは気にしなくて良い。

    以上の調査の結果、linewise-range.impl では、
    preserve_column でないとき行を移動しない時でも行頭に移動するべきである。

  * 2017-09-17 vi-mode: 改行挿入時 [#D0469]

    前の行のインデントを引き継ぐようだ。
    但し何も入力しない場合はインデントは消滅してなくなる。
    面倒なので何も入力しないときにインデントが消滅することには対応しない。

    C-m でも C-j でも同様に動作する。
    更に気付いたことは BS, C-h でインデントが削除されるということ。
    (インデント以外であればちゃんと一文字ずつ削除される。)

  * 2017-09-19 起動して未だ初期化している途中に入力した文字列が下に押し出されてしまう。 [#D0468]
    起動した瞬間の ble-form/panel の状態を別のものにした方が良いのかもしれない。
    →対策した。

  * 2017-09-23 ble-edit: [bug] ble/util/c2w: 何か ★ の幅の計算が間違っている気がする。 [#D0467]
    emacs, screen (修正済), poderosa のどれにおいても★で変な動作になっていないが、
    ble.sh で★を入力した時にずれる。
    実際にやってみると 1 と表示される。これは変だ。

    $ ble/util/s2c ★; echo $ret
    9733
    $ ble/util/c2w 9733
    1

    自前の screen では 2 になっているのではないかという気がする。ずれていないので。
    しかし同じ表を使って計算している筈なのに変だ。
    もしかすると表の引き方を間違えているのではないかという疑惑がある。

    9733 は表の 1797 に対応して、その周辺では 1776 1797 1799 となっている。
    試してみると 9732 9733 9734 9735 と全部試しても 1 になる。変だ。

    調べてみた所 9733 が tIndex=1797 に修正されるべきところで、
    そのまま透過して tIndex=9733 になっている。
    なんと! tIndex の値を折角計算したのに上書きしていた…。修正した。動作確認した。

  * 2017-09-20 今気づいたのだが実は現状で exit status の復元に失敗している? [#D0466]
    →やはりそうだ。またコードを確認する必要がある。

    コードの編集に明らかに失敗している。
    そして確かめてみたところ $_ は同じ関数呼び出しレベルにおける最後の引数を指すようだ。
    ということは今まで通りに eval の中に設定する必要がある。

    終了ステータスと最後の引数を同時に設定するためには
    ble-edit/exec/.setexit "$_ble_edit_exec_lastarg" とするしかない。
    と思って実際に試してみたところ $_ が常に /usr/bin/bash になってしまった。
    うーん。試してみたが関数だと /usr/bin/bash になってしまうということもないようだ。
    と思ったらそれまでに一度も引数ありでコマンドを実行していなかったために、
    最初の値の /usr/bin/bash が受け継がれて中に入っていただけだった。
    現状の実装でちゃんと復元はできている。

  * 2017-09-19 bash -v で起動すると恐ろしいことになる。 [#D0465]

    これは [[ -o verbose ]] で確認することができて、
    また set +v / set -v で切り替えられるはず。

    必ずしもすべてのコマンドが出力されている訳ではない様だと思ったが、
    どうも eval ごとに実行したコマンドが出力されている気がする。

    →取り敢えず対策した。[[ -o verbose ]] の状態を記録・復元することにした。
    それでも未だ色々と変な者が出力されている。
    もちろんこれらを完全に解決することは難しい。
    しかしながら、できるだけ出力内容が少なくするようにすることはできる。

    そもそも何故 prologue, setexit, save-params, epilogue の 4 つに分かれていたのか。
    save-params と epilogue については理由はある。
    コマンド本体は文法がおかしい場合に後段の処理が潰れないように eval で囲む必要があった。
    しかしそうすると $_ が取れなくなってしまうので save-params だけは
    同じ eval の中で評価しなければならなかった (そうしないと eval に渡した引数が $_ に入ってしまう)。
    といってもコマンド本体に文法のおかしいものを指定したときに実行されなくなるのは困るので、
    重要なものに関しては eval の外に置かなければならない。

    今一つの案は

    1. prologue と setexit をくっつけ更に eval の中に移動する。
      (正しく実装している限りは prologue/setexit の中で失敗することはないと期待する)
    2. save-params の中で -o verbose の記録・無効化を実行し、
      もしそれに失敗したときのために念のため epilogue でも
      実行済みかチェックした上でこれを実行する。

    修正した。現状では .save-params だけ余分に出力されている状態である。
    これに関してはこれ以上どうしようもないが名称を変えることはできる。

    * .save-params 名称を変えることにする。どのような名称が良いか。

      ble-edit/exec:gexec/ の部分は変えようがない。
      .save-params よりも何のために表示されているかが分かりやすい1つの単語が良い。
      うーん。考えるに現在の名前が的確である。これの存在意義は $_ を保存するということ1点のみにある。
      序でに $? も保存しているがこれは続く epilogue で改めて保存し直すのでおまけである。
      そう考えると .save-last-arg が的確な気がしてきた (readline 関数に yank-last-arg がある)。

      →関数名は変更した。OK

    * exec:exec の方でも動作しているか確認する。

      確認した。実はそのままでも動いているようだ。
      関数内で実行しているのでそもそもそんなに出力の機会が多くはないようだ。

  * 2017-09-22 vi-mode: bug: isearch から C-c などで戻ると選択状態がそのままになる。 [#D0464]

    何らかの方法で選択状態を解除するようにした方が良いのでは。
    或いは、挿入モードのみで isearch をするのだとすれば、
    normal-mode など vi で追加した機能に対して
    全て選択状態をクリアするようにしても良い。

    取り敢えずのところは normal mode に入る時に選択状態をクリアするようにし、
    また他に類似の修正が必要であれば修正する。

    思うに今まで何故問題が起こらなかったのかというと、
    emacs の移動は全て marked/nomarked で登録していたからであった。
    vi-command は当然 nomarked を明示的に指定するということはしていないので、
    カーソル移動などをしても選択が解除されないのである。

    vi/vim mode ではビジュアルモードまたは選択モードのみで
    選択状態になるという制限を設けると考えることにすれば良い。
    或いは、_ble_edit_mark_active の時を選択モード・ビジュアルモードと解釈することにする。

  * 2017-09-15 cmplstofB: C-@ と accept-and-next に関する提案 [#D0463]

    C-@ を accept-and-next にすることについて考察する。
    これは README.md あたりに書くということでも良いかもしれない。

    →これは gh wiki に書いたのでよしということにする。

2017-09-22

  * vi-mode: r gr で次の文字を待つまでは overwrite で色をつけても良いのでは。 [#D0462]

  * 2017-09-11 vi-mode: text object: it, at [#D0461]

    t について調べる。

    どうやらちゃんとタグ名が一致するかどうかも見るようだ。
    また現在位置から左に < を検索して一番最初に当たったものについて、
    タグ名を読み取ろうとするようである。
    一番最初に当たったものが不正なタグで、
    それよりも前に正しいタグが合ったとしても失敗になる。
    タグの入れ子には対応している。

    引数を指定すると 2 つ外側のタグに行く。

    - 途中で不正なタグが存在する場合には、失敗する。
      目的地よりも外側に不正なタグが存在する場合には大丈夫。
    - 対応する終わりタグのないものは無視される
      (<br> などのためだろう。勿論、実際にはタグ名には関係ない)。
    - 途中に改行が入っていても問題ない。
    - <a> A <a> B <br> C </a> </a> </br> に対して、
      - <br> ... </br> は正しいタグということになる。
      - C の位置で 2yat とすると <a> B <br> C </a> になる。これは </br> がなくても同様
      - <br> の位置で 2yat とすると <a> B <br> C </a> になる。これは </br> がなくても同様
        このことから引数を指定したときに飛ばす始まりのタグに関しては、
        対応する終了タグがあるかどうかの確認を行わないということが分かる。
    - <a> A <b> </b> <c> </d> <p> </a> に対して、
      - A の位置で yat とすると全体を捕まえる。
        これにより同じ名称のタグしか数えていないということが分かる。
    - < a> hello </a> に対しては失敗する。
      つまりタグの形式は意外と厳密に調べられる。
    - <a href="<a"> helo </a> </a> を実行すると、
      中にある <a"> には決して引っかからない。
      <a href="<a"> helo </a> でひとまとまりであると認識される。
      href の位置にカーソルがある場合でも中の a の位置にカーソルがある場合でも同様である。
      エラーにもならない。

    | - <check x="
    |   <a href="<a "> helo </a> </a> だと <a "> に引っかかる。
    | - <!--<check x=" -->
    |   <a href="<a "> helo </a> </a> でも <a "> に引っかかる。
    | - <check x="
    |   <a href="<a"> helo </a> </a> だと <a"> には引っかからない。
    | - <a href="<a"> helo </a> </a> だと <a "> に引っかかる。

    →初めは <check x=" に続く引用符の入れ子を考慮に入れているのかと思ったが、
      実は全然関係なくて <a" だと引っかからないが <a "> だと引っかかるということの様だ。

    % 従って以下のような実装になるだろう。
    %
    % 1 引数の回数だけ繰り返し実行するようにする
    % 2 それぞれのステップでは先ず < を backward 検索する。
    %   次にその < のタグを読み取り、タグ名を取得する。
    %   もし正しいタグならば続ける。
    % 3 2 を引数の回数分だけ見つけたらそれが始まり。
    %   そこから forward に終わりタグを見つける。
    %   同じ名称のタグだけを数えて終わりタグを見つける。

    - <a> < </a> 改めて。"<a> " の何れかにカーソルがある時は成功する。
      "< " の何れかにある場合は失敗する。"</a>" にある場合は成功する。
    - <a> <> </a> これの場合には何処にカーソルがあっても成功して全体に一致する。
    - <a> <b> <c> </c> </b> </a> hello
      " hello" の上で yat すると失敗する。
      "</a>" の上で yat すると成功する。
      "</a>" の上で 2yat すると失敗する。
      "</b>" の上で 2yat すると "<a> ... </a>" に一致する。

    これから分かることは現在終わりタグの中にいる場合はそのタグに対応する始まりのタグを探すということ?
    更に、引数は始まりのタグを見つけてからそこから外側に向かって探索するということ。
    現在の < がタグとして成立していない時にはエラーになり、
    タグとして閉じてはいるが不正の場合は更に前の < を見つける?

    - <a> <b> <b> </c> </b> </a> において "</b>" の上で yat すると何故か "<a> ... </a>" が選択される。
    - "</c>" の上で yat すると "<b> </c> </b>" が選択される。
      これは <a> <c> <b> </c> </b> </a> としても同じ。
      <a> <b> <c> </c> </b> </a> とすればさすがにどこでやっても期待する結果になる。

    少なくとも正しいことは、タグ名は必ず対応するように取られるということ。
    どのタグが選ばれるのかという規則は不明。
    また <c> <b> </c> </b> で </c> にいるときに "<b> </c> </b>" にあたる事から、
    "終わりタグを先に確定させてからそれに対応する始まりのタグを見つける" という動作ではありえない。
    常に始まりのタグを先に確定させると考えなければならない。

    % - なんと <a> <b> <b> <c> </b> </a> で "</b>" でやると
    %   "<c> </b> </a>" が選択される。ついに異なるタグ名で一致する例が見つかってしまった。
    % と思ったら違った。次の行まで探索していって複数行で一致していたのだった。

    これは vim のソースコードを見るしかない。
    さて git clone した。何処に対応するコードがあるだろうか。
    ファイルを眺めてみたら tag.c というまさにそれっぽいファイル名があった。
    と思ったら駄目だ。違う。これは関係ない tag だ。
    "text obj" で検索してみると以下の 2 行しかない。

    ./normal.c:9023:    /* in Visual mode and after an operator "a" and "i" are for text objects */
    ./search.c:4501:             * target text object. */

    前者を見ると nv_object という関数を呼んでいる。
    nv_object の関数の定義は normal.c:9185 に存在する。
    というか vim はキー操作がハードコーディングされているのか…。
    何れにしても normal.c:9236 で current_tagblock という関数を呼んでいる。
    current_tagblock は search.c:3908 に定義が存在する。
    https://github.com/vim/vim/blob/0263146b5dbbb6c120ce2e7720256503b864425d/src/search.c#L3828-L4111

    実装を見るとたぶんこんな感じになっている:

    1 後退して <.*> を探す。ただしそれよりあとに </.*> があることが条件。
      この時点ではタグ名が一致しているかどうかについては問わない。
      細かい動作は do_searchpair の中を見ないと分からない。
      これを count 回繰り返す。もし途中で見つからなくなったら失敗。

    2 更にタグ名を読み取って (空なら失敗)、そのタグ名で do_searchpair を前進で実行し直す。
      これで終わりタグの位置を見つけることができる。
      見つかった組が現在地よりも前で終わっているときには更に後退する。
      恐らく do_seachpair は入れ子をカウントする仕組みになっているのだろう。

      # ところで search.c:4033 の r < 1 は制御の流れ的に
      # 絶対に満たされない気がするが…

    これにより今までの動作は大体説明がつくが以下の動作については不明

    - <a> <b> <b> </c> </b> </a> の "</b>" で yat すると全体に一致する。
      →あー。これは初めに <a> の直後の <b> が見つかって、
      その後で終わりの対応する </b> が見つからずに後退したという動作だ。
      これは理解できる。

    - <a> < </a> の "< " で yat → 失敗。"</a>" で成功する。

      うーん。謎だ。<a><</a> でも同様に駄目だ。
      →これは以下の in_html_tag 関数に依る処理が犯人だった。

    % タグの正規表現について調べる。うーん。謎。
    % これを見ても孤立した < で引っかかる要素がない気がする。
    %
    %   <[^ \t>/!]\+\%(\_s\_[^>]\{-}[^/]>\|$\|\_s\=>\)
    %   </[^>]*>
    %
    %   vim の正規表現は以下にあった。
    %   https://qiita.com/kawaz/items/d0708a4ab08e572f38f3
    %
    % うーん。ビルドして動かす?
    % ビルドして何処で失敗したかを調べると、一番最初の後退で失敗している。
    % つまり、正規表現で駄目…。分からない。
    %
    % その場で改めて do_searchpair を実行してみるとちゃんと一致する。
    % ということは何らかの理由で位置がずれているのか?
    % →curwin->w_cursor = old_pos; を直前に実行したら動いた。
    %   ということは 1 で後退する前にカーソルの位置が調整されていることになる。
    % →初めに < の中にいる場合には > まで移動するようだ。
    %   そうすると <a> < </a>★ の位置にまで移動する。
    %   ここで yat を実行しようとすると外側にタグが必要になるので失敗する。

    正規表現の問題ではなくて、最初にカーソルの位置を調整するというのの問題だった。
    in_html_tag 関数で判定が行われている。
    in_html_tag は現在位置の右が < か見て、或いは行内で <> を後退して探して判定する。
    つまり以下の手順を加えれば良い。

    0 現在の位置の右に < があれば html タグ内にいるとする。
      現在位置から行内で後退して [<>] を探して < があれば html タグ内にいるとする。
      html タグ内にいるときはそれが開始タグならば前進して > の直前まで行き、
      終了タグならば後退して < の直前まで行く。
      開始タグかそうでないかは次の文字が / かどうかで判定する。

    it の方の動作も調べる。
    - at のときと同じタグを捕まえる。
      終わりタグや始まりタグの上に載っていたとしても、
      その中身になる。つまり、初めのカーソルの位置を含まない形になりうる。
    - タグの内側にある空白・改行の類は削除されない。
      特に終わりタグの最後に改行があっても削除されないし、
      また改行が含まれていても linewise になることもない。


    [確認]

    vim のソースコードを見て動作が分かったので実装した。
    正しいタグの場合の動作の確認は行った。引数も確認した。
    次に今まで試した色々のケースをチェックする必要がある。
    以下に試すべきことをまとめる。

    以下 @ の位置にカーソルがあった時に yat をしたときの期待動作を示す。

    1 @<@a@aa@>@hello@<@/@a@aa@> → 全部成功
    2 <a> @A <b> </b> <c> </d> <p> </a> → 全体
    3 < a> @hello </a> → 失敗
    4 <a href="<a"> @helo </a> </a> → 最初から一つ目の </a>
    5 <a>@ < @</a> → 成功
    6 <a> @<@ </a> → 失敗
    7 <a> <b> <b> </c> </@b> </a> → 全体
    8 <a> <b> <b> </@c> </b> </a> → 二つ目の <b> から </b> まで

    早速 1 で引っかかった。一番初めの <aaa> の中で実行すると失敗する。
    →直した。開始タグの中にいるときに開始タグの終端に行く所、
    貪欲に全てのタグの終端に行っていた。

    他は期待通りに動いている。OK


2017-09-18

  * cmplstofB: vim-surround.sh: $( \r ) $(( \r )) [#D0460]

  * vim-surround: 実は ys の引数も / ./ の形式で指定できる。 [#D0459]

  * cmplstofB: vim-surround.sh: ds cs [#D0458]

    ds の振る舞いについて調べる → #D0456
    surround.vim と vim-surround.sh の実装の違いについてまとめる → #D0457

    cs の振る舞いについて調べる。
    引数は / ?./ の形式である。
    後は ys の時と同じな気がする。
    取り敢えず実装した。

  * vim-surround: ds 実装について surround.vim との違いについてまとめる [#D0457]

    以下の項目がある。

    * surround.vim には引用符に引数を指定した時のバグがある

      | "A "B "C D" E" F"
      |                ^
      | 2ds"
      |
      | "A "B "C D" " F" E

      | A "B "C" D"
      | ^
      | 2ds"
      |
      | A  C"B "

      vim-surround.sh では引数は無視することにした。

    * surround.vim には閉じ括弧が行頭にある時のバグがある。

      | (A (B (C
      | ) E) F)
      |
      | C の上にカーソルを置く。ds( とする。
      |
      | (A C F)

      このバグは以下で報告されているが取り込まれていない。

      https://github.com/tpope/vim-surround/issues/232
      https://github.com/tpope/vim-surround/pull/217
      https://github.com/tpope/vim-surround/issues/215

      vim-surround.sh ではちゃんと対応する括弧だけを削除する。

    * surround.vim ds* では現在位置より前に * がないときにバグがある

      | A *B*
      | ^
      | ds*
      |
      | A

      vim-surround.sh では ** 対の探索に失敗させる。

    * surround.vim では /* だけがあるときに失敗するが、カーソル移動する

      | /* hello
      |        ^
      | ds/
      |
      | /* hello
      | ^

      カーソル移動しない方が自然なので、vim-surround.sh では移動しない。

    * surround.vim では囲まれた部分が改行を含むときにインデントを行うが、
      vim-surround.sh では未対応である。その内に対応する予定。

    * surround.vim では ** や () を ds* や ds) で削除できないが、
      vim-surround.sh では削除できる。

    * surround.vim では /**/ においてカーソル位置が先頭にあると削除できないが、
      vim-surround.sh では削除できるようにする。

      | /* a */
      | ^
      |
      | /* a */
      |  ^
      |
      | surround.vim では ds/ で削除できない。

  * vim-surround: ds [#D0456]

    取り敢えず先に ds の動作を調べてそれを実装することにする。

    当初行内での削除に限られるようだと思ったが、
    これは ds に続いて入力する囲みの種類に依存するようだ。

    [引用符の時の動作について]

    | 2ds" は謎。3ds" としても同じ動作に見える。
    | 1つ目の " を残して、そこから2つ目の " までを削除するようだ。
    | 具体的な動作について調べる。
    |
    |   前
    |
    |   | "A "B "C★ D" E" F"
    |
    |   ds" 後 (これはOK)
    |
    |   | "A "B C D E" F"
    |
    |   2ds" / 3ds" / 4ds" 後 (謎)
    |
    |   | "A "C D" F"
    |
    |
    |   前
    |
    |   | "A "B "C D" E" ★F"
    |
    |   2ds" 後 (beep が鳴る) (謎)
    |
    |   | "A "B "C D" " F" E
    |
    |   →これは d2i" によって "...F" が削除された後に、
    |     カーソルが E の手前に移動してしまって、そこで空白を挿入し、
    |     更に削除するべき引用符が見つからずに beep を鳴らして、
    |     その後に改めて " F" が挿入されるということが起こった結果である。
    |
    |   前
    |
    |   | ★A "B"
    |
    |   ds" 後: これは理解できる。前方に見つけた " を先頭とする。
    |
    |   | A B
    |
    |   前
    |
    |   | ★A "B "C" D"
    |
    |   2ds" 後: これは理解できない。謎。そもそも順番が変わっている…。
    |
    |   | A  C"B "
    |
    |   →これは surround.vim の中で
    |   以下のような手順によって発生している。
    |     ★A "B "C" D"
    |     (d2i")     → A ★C" D" (clipboard = "B ")
    |     (i \ed2i") → A  C★
    |     (""p)      → A  C"B "
    |
    | よく分からない。これは surround.vim を読むしか無いのか。
    |
    | surround.vim を観察した結果、ds は dosurround を呼び出している。
    | cs も最終的には dosurround を呼び出しているが、
    | dosurround に対する引数の指定の仕方で cs と動作を変えている。
    |
    | さて、どうやら受け取った文字によって text-object または、
    | 独自の方法で範囲を計算・削除しているように見える。
    | " の場合には text-object i" を用いているようだ。
    | 恐らく 3ds" とすると、内部的には d3i" が呼び出されている。
    | 更に、その後で空白を一旦挿入して、それから再び da" を呼び出す。
    | 更に、その後で貼り付け p を行っている。
    | 何を貼り付けるのかの制御をどのようにしているのかは謎だが、
    | これは一番最初に切り取った内容をもとに戻しているということだろう。
    |
    | 結局 {count}ds" は exe 'norm! ""d'.count.'i"i \<Esc>d2i""p`[' に翻訳される。

    引用符に関する振る舞いについては surround.vim の中を調べることによって解決した。

    * Note: 問題は引数を指定している時には i" が a" と同じ動作になっていることにある気がする。
      →やはりそうだった。つまり、これは surround.vim のバグである気がする。
      これは報告したほうが良いのだろうか。

      これについては GitHub vim-surround の Issue には登録されていなかったが、
      Issue に大量のものが報告されて５つもそれらが放置されているのを見ると報告しても仕方がないだろう。
      これについては放置することにする。

    * done: 更にそれと共に現在の ble.sh の text-object で i" は引数を無視しているので修正したい→修正した。

    * done: また、注記すべきこととして 3ds2" などの指定の方法も可能のようであるということ。
      この引数の読み取りは surround.vim において inputtarget() という関数で独自に実装されている。
      つまり共通の枠組みとしてそういうものがあるというわけではないので安心して新規実装できる。


    [括弧の動作について]

    | 2ds) は二つ目の括弧と対応する括弧を削除する。
    |
    | と思ったら括弧の場合には同じ行内に見つからない場合には一番外側の括弧を削除する?
    | いや、何だか良くわからない。どうやら1つ目の () から 2つ目の () までを削除するようだ。
    | この場合は1つ目も 2つ目も削除してしまう。よく分からないので改めて試して整理していくことにする。
    |
    |   前
    |
    |   | (A (B (★C
    |   | D) E) F)
    |
    |   ds( 後
    |
    |   | (A (B C
    |   |     D E) F)
    |
    |   前
    |
    |   | (A (B (★C
    |   | ) E) F)
    |
    |   ds( 後 → これは謎である。
    |
    |   | (A C F)
    |
    |   →これも分かった。
    |
    |     (A (B (★C
    |     ) E) F)
    |
    |     (A (B ★(
    |     ) E) F)
    |
    |     (A (B★ (
    |     ) E) F)
    |
    |     (A ★ F)
    |
    | どうやら ds( は以下に翻訳されるようだ。
    |
    |   norm! ""di(
    |   call search('\m.', 'bW')
    |   norm! da(""p`[
    |
    | ここで行末になった時に問題が生じる。
    | norm! ""ci(\<Esc> とすれば一文字戻る必要があるときにだけ戻るし良いのではないだろうか。
    | というかそもそも戻る必要はあったのだろうか?
    |
    |
    | 次に 3ds( とすると3階層目の括弧が削除されるものの、中身がインデントされる。
    |
    |   前
    |
    |   | (A (B (C
    |   | ) E) F)
    |
    |   3ds( 後
    |
    |   | A (B (C
    |   |      ) E) F
    |
    |   前
    |
    |   | (A (B (★C
    |   | )
    |   | E) F)
    |
    |   3ds( 後
    |
    |   | A (B (C
    |   |      )
    |   |                 E) F
    |
    | うーん。これはインデントの規則さえ分かればそんなにはおかしくはない気がする。
    | あと、明示的にインデントを調整している箇所があるのだろうか。うーん。
    | どうも surround.vim の中に call s:reindent() という行がある。これだろう。
    |
    |
    | 後実装を観察していて思ったのだが、行末にある括弧で ds( を実行するとずれる気がする。
    |
    |   前      | A(★B)
    |   ds( 後  | AB
    |
    | あれ。正しい結果になっている。pP の切り替えによるものか。
    | よく考えたら p は後ろに挿入するもので、P が前に挿入するものだ。
    | なので p を使っている限りはこれは大丈夫。
    | 恐らく判定も大丈夫。念のため試す。
    |
    |   前      | (★A)B
    |   ds( 後  | AB
    |
    | 正しい結果になっている。問題ない。

    * done: 先ず yi( は囲む対象の末端が改行の場合はその改行は含まない。
      これは現在の ble.sh の振る舞いと異なる。修正が必要だ。
      これには対応した。

    * note: 更に surround.vim は 1 文字戻るといって戻っているところが怪しい。
      これもバグなのだろうか。

      報告しようと思って GitHub の vim-surround に行ったら、
      大量の Issue と PR が溜まっている。vim-surround は駄目だ。
      そして既に報告されていた。

      https://github.com/tpope/vim-surround/issues/232
      https://github.com/tpope/vim-surround/pull/217
      https://github.com/tpope/vim-surround/issues/215

      つまりこれはバグだと思って良いだろう。

    * done: 文字が [ ( { < T の何れかのときには前後の空白を削除する。

    * note: surround.vim では改行が絡むとき s:reindent を呼び出している。
      これにより括弧の階層によってインデントが付加される。
      これは 3== を実行した時と同じ結果になった。
      つまり = によるインデントを実装しておけばただそれを呼び出すだけである。

      →これについては別項目で議論することにする。

    更に以下の機能もある。これらは今既に実装した分のテストが
    終わってからにするのが良いだろう。

    * done: / を指定すると /**/ を捕まえる。
      cs の第2引数に / を指定した場合は単に / で囲む。

    * done: 他の文字を指定すると行内で検索する。引数は認識しないようだ。

    [実装]

    * done: 取り敢えず実装した部分 ds(text-object) の動作確認をする。

      ds" を試したが動かない… → 直した。
      exclusive-range.impl の終了ステータスが問題だった。

      2ds( は動いている。

      ds( において空白がある場合に中身が消えてなくなる。
      → ble/string#trim の誤りだった。直した。

      ds( と ds) の振る舞いの違いは正しく動いている。
      2ds( と 2ds) も動いている。

      2ds" もちゃんと ds" と同じ動作になっている。
      2ds " と 2ds" の違いも動いている。

      wW は何も変化が起こらない筈である → 宜しい。
      これは csw/ などでテストするべきである。

    * done: / を指定した時の動作を実装する。

      動作を調べると先ず、★/★**/ の ★の位置にいるときに ds/ としても効かない。
      また、それ以降の位置にいればいつでも効く。
      /**/ の外側にいても効くし、更に次の行にいても効く。
      恐らく現在位置以前の最近の /* を先ず初めに探して、
      その後で対応する */ を見つけるのだろう。

      () との対称性を考えると先頭にいるときでも見つけられるようにして良いのではないか。

      surround.vim では arg は最初の /* を見つけるときに ({arg}[/ として) 使っているようだ。
      ということは [/ の振る舞いを調べてから実装した方が良い。
      vimindex に載っている (vimindex の後方・前方は分かりにくい。forward/backward の訳と考えれば分かる)。
      これを見ると引数は N 個前の /* を見つけるという意味に解釈されるようだ。

      [/ の振る舞いを調べてみると引数の数より少なくしか見つからない場合には、
      一番最後に見つかったものに一致するようだ。
      つまり現在の ble/string#last-index-of ではなくて正規表現を用いた実装にするべきである。

      実装した。

    * done: / の動作確認を実行する。

      ds/ としてもエラーになる → 直した。古いコードが残っていた。
      しかし変な部分が消される → end の計算を修正した。2 足し忘れていた。
      2ds/ とすると期待通りに動く。2ds / の方も期待通りに動く。
      取り敢えず OK

    * done: 次に行内の文字検索を実装する。
      先ず初めに backward search で文字を見つける。
      次に forward search で文字を見つける。

      surround.vim は変な動作しかしないので模倣は諦めた。

      取り敢えず実装した。

    * done: ds* の動作確認をする。

      *★* を ds* で消そうとしたが消せなかった。
      これは _ble_edit_ind+1 から last-index-of で検索しているために、
      2文字目の * を最初の文字と勘違いすることによって起こっている。
      先ず初めに現在のカーソル位置が開始に含まれているかどうかを確かめて、
      その後で _ble_edit_ind+1 から backward 検索するべきだ。

      と思ったが問題はそういうことではない気がする。
      問題は +1 してしまうことによって図らずも終端の文字を拾ってしまう事にある。
      しかし何故そもそも +1 していたのかを考えると、
      現在位置が元から開始文字に含まれている場合を考慮してのことである。
      うーん。初めに現在位置が開始位置に含まれているかを確認し、
      そうでなければ +${#del} するというようにするのが正しい?

      例えば del が3文字あるとする (現状の実装では1文字のはずだが汎用性を持たせるため)
      この時、調べなければならない範囲は現在位置より (3-1) = 2 文字手前の位置から、
      現在位置より 3 文字あとまでである。

      うーん。本質は「現在位置より forward 方向に対しては index-of で、
      現在位置より backward 方向に対しては last-index-of」で検索するということだ。

      | del="===" だとする。以下 ^ をカーソルの位置とする。
      |
      | ===== hello === ... この場合は色々な解釈方法が可能である。
      |   ^
      | ====== ... この場合は可能性としては "===" + "==="と解釈するしかない。
      |   ^        できるだけ組を見つけられるようにするには ind-(${#del}-1) から検索するのが良い。

      →対策した、と思ったら動かない。よく考えてみたら本質と違うことを考察していた。

      問題は、現在開始文字の上にいるときではなくて、
      現在終了文字の上にいるときに起こるのであった。
      うーん。ということは base を ind - (${#del}-1) にするのではなくて、
      ind - (2*${#del} - 1) にすれば良いということなのだろうか。。
      うーん。色々曖昧性はあるけれどもその実装が妥当に思われる。

      と思ったら、今度は *hello★* において ds* が使えなくなった。駄目だ。
      これの場合 * を開始位置と勘違いしている。本来は終端位置と捉えるべきである。

      うーん。手順を逆転するべきだろうか。
      先ず初めに line::ind に対して検索を実行し、
      もし見つからなかったら、前方に検索を実行する。
      これを直したら、雰囲気動いている気がするので良いことにする。

    * Note: 以下も surround.vim のバグである。

      | というか以下のようになる。この動作はおかしい。
      | 前     | ★A *B*
      | ds* 後 | ★A

    * Note: あと surround.vim は /* が孤立して存在するときに
      ds/ とすると / の位置にカーソルが移動してから失敗する。
      元の位置には戻らない。

    * Note: surround.vim では ** の様な空の場合には認識されない。
      これは () で試しても同様だった。
      ble.sh の実装では () や ** も削除できることにしたい。

    * done: surround.vim との動作の違いについて纏める。
      これは vim-suround.sh のコメント内に書けば良いだろう。

  * cmplstofB: テキストオブジェクトに対する c の振る舞い [#D0455]

    | テキストオブジェクトに対する c (削除後挿入モードに移行) が、 d と同じ振舞いになります。

    本当だ…。何故だろう → vi_omap を追加したのに .insert-mode でそれが pop されていないのが問題だ。
    今までは adjust-command-mode でそれを調整していたが、.insert-mode を先に実行すると駄目なのだ。
    今回は対策として .insert-mode の中で vi_omap を pop するようにしたがこれが正しい解決法かは分からない。

    本来であれば vi_omap に紐付けられたコマンドについては全て実行直前に vi_omap を pop するのが良さそうだが。
    但し __before_command__ で pop する訳には行かない。引数などの場合には pop しないからである。
    結局 adjust-command-mode を呼び出しているのと同じタイミングで vi_omap を pop する必要があるのである。
    しかし、現状では adjust-command-mode に先立って .insert-mode が呼び出されることがあり問題になった。

    - 一般に keymap に関連するコマンドにおいてこのような不整合が生じる。
      取り敢えず keymap を push, pop しているところに関しては確認した。

    - 更に ble-decode-key などで新たなキーを処理したりしている場合には、
      vi_omap を pop した上で ble-decode-key を呼び出す必要があるのではないかという気がする。
      そのような事をしているコマンドは現状では… __default__ と、vi-insert の中のコマンドのみである。
      今の所は問題がないが、実のところ将来的に不意に追加してしまう危険性もある。

    うーん。原則を考える必要がある。先ず問題が発生するのは omap 周りだけである。
    omap に登録されているコマンドは 引数・motion・text-object・set-operator である。

    - 引数の場合はそのまま透過して良い
    - motion の場合は基本的には最終的に adjust-command-mode する。
      但し、その前に c (.insert-mode) などを実行すると normal mode になってしまって駄目。
    - text-object は motion と同様である。
      ただ、これは omap にくっついているのでそんなに意識しなくても変な改変はしないと思う
    - set-operator
      これは既に vi_omap にいるのに更に vi_omap を積み重ねる危険性がある。
      実際には _ble_edit_arg の中身の状態が vi_omap と対応しているはずだから起こらないはずだが、
      何らかの拍子に変なことになるかもしれないということである。
      念のためチェックをしてから vi_omap を積み重ねるようにする。

2017-09-17

  * vi-mode: imap C-k [#D0454]

    ところで C-k は元々 (readline でも) kill-line だったところを digraph にしてしまってよかったのだろうか。
    そもそも digraph を使う機会なんてそんなになさそうだし、kill-line の方が便利なのではないだろうか。
    これはやはりマニュアルに記述して、実際には対応しないという方法のほうが良いのではないだろうか。

    bash が C-k を kill-line にしているので、やはり C-k は kill-line であるべきだ。

  * cmplstofB: f が失敗した時にも検索を記録する。 [#D0453]

    更に提示された :help f を見ると digraph や Unicode 結合文字にも対応しているようだ。

    | digraph には対応できるけれども、Unicode の結合文字についてはそもそも現状の ble.sh の枠組みで取り扱えていないので駄目。
    | さて digraph http://vim-jp.org/vimdoc-ja/digraph.html を参照すると普通のアルファベットの組で digraph が登録されている。
    | 更に :help r などを参照してみるとこれも digraph を受け取るようになっている。
    | :dig を参考に試しに rNU として見たが、N が入力されて "U" によって undo されてしまう。
    | 引数に指定する場合には digraph-arg というのを参照しなければならないということか。
    | と思ったら C-k に続いて入力しなければならないようだ。
    |
    | さて、digraph に対応するにはどうしたら良いか。
    | _ble_decode_key__hook だと問答無用で一文字だけ取ってしまうので駄目だ。
    | 或いは、_ble_decode_key__hook のチェーンを作って無理やり処理するか。
    |
    | それよりは cmap を登録した方が良い様な気もする。
    | しかし個別に登録すると大変である。
    | といっても結局はテーブルを作って処理することになるのだから、
    | 余り変わらないのかもしれない。
    |
    | 或いは新しい keymap を追加してしまうことにするか。
    | と思ったら、よく考えると :help f に lmap が効くと書かれている。
    | lmap と言っているのは lang-arg といっているもので、
    | もしかするとこれが一文字引数を受け取るための keymap なのではないだろうか。
    |
    | 更に vi_digraph のような感じの keymap を用意するのが良さそうだ。

    先に digraph に対応してから考える。対応した。

    fFtT については取り敢えず修正だけ先に行う。
    その後で digraph の対応について考える。
    当初は一文字読取るだけのために lmap なる keymap を作成する事を考えていたが、
    よく考えてみると C-k に対応するだけであれば
    別に fFtT 内で vi_digraph keymap に入れば良いだけのような気もする。

    →結局 aread-char-arg という仕組みを整えて
    fFtT 及び r gr はこれを呼び出すことにした。
    現在のところ動作している。

  * vi-mode: digraph 対応 [#D0452]

    先に #D0453 で考察したように keymap を生成するのが良いだろう。

    digraph の一覧は http://vim-jp.org/vimdoc-ja/digraph.html を wget して加工する。
    HTML 実体参照 (&nbsp;&lt;&gt;&quot;) を戻して適当に列を切り出す。
    keymap/vi_digraph.txt に保存した。

    vi_digraph の keymap は巨大なので vi.sh が更新される度に再生成するのは損である。
    という訳で vi_digraph.sh に分離して頻繁に更新しなくても良いようにする。
    通常文字にしか依存しないので [[ $fname_keymap_cache -nt $_ble_base/cmap/default.sh ]]
    のキャッシュ更新用のチェックも外して良いだろう。

  * 2017-09-04 vi-mode: 全てのキー入力を横取りできているかどうかを確認する [#D0451]

    → bind -p, bind -s, bind -X を見る限りは大丈夫に見える。

  * 2017-09-11 vi-mode: by cmplstofB [#D0450]

    | 複数行編集において、最初の行を削除した後に移動モードが機能しない。

    これは分からない。再現しない。

    2017-09-17 取り敢えず現在は再現しないということ。

    | これは 1b9e2a4 において発生しませんでした。ありがとうございます。

    本当に解決したのかどうかは謎だが、取り敢えずは解決したことにする。

2017-09-16

  * dd の引数が効かなくなっている。 [#D0449]
    これは勘違いで追加した行が原因だった。

  * vim-surround.sh において bBra は )}]> の aliases である。 [#D0448]

  * vim-surround.sh について C-] / C-} に対応する。 [#D0447]

  * cmplstofB: vi-mode ysiw" [#D0446]

    | 更に ysiw" は体系としてかなり謎である。
    | と思って vim で試してみたら動かない。ys まで打った時点でエラーになる。
    | もしかしてビジュアルモードの機能なんだろうか。と思ったけれどそうでもないようだ。
    | 調べてみると surround.vim というのがあるようだ。拡張?
    | そうだとすると恐らく "ys" に対して直接 bind しているのだろうと理解できる。
    | - [surround.vimの使い方 | Memo on the Web](http://motw.mods.jp/Vim/surround.html)
    | - [What does the "y" stand for in "ysiw"? · Issue #128 · tpope/vim-surround](https://github.com/tpope/vim-surround/issues/128)
    |
    | でもそれをやると "yy" がその場で実行されなくなる。"yy" に対しても同時に bind することを考慮する必要がある。
    | が、もっと体系的なやりかたはないのだろうか。
    | →よく考えたら "y3y" などにも対応しなければならないので単に "yy" に bind するだけでは駄目だ。
    |
    | surround.vim を除けば i の直後には引数などが来る余地はないようなので (試した)、
    | 単に次のキーを一つ読み取るという具合にすれば良い。下手に keymap を追加すると
    | insert-mode で単に ble-decode/keymap/pop などとしているのがずれて問題になるので、
    | 下手に insert-mode を呼び出せない (もしくはその追加した keymap に追加する widget では必ず最初に pop をすれば良い?)。
    |
    | 取り敢えず入れてみた。結局日本語のページは古くて使い物にならなかった?
    | よく分からないので surround.vim 本家に書かれている方法でインストールした。
    |
    | | surround.vim インストール
    | |
    | | $ mkdir -p ~/.vim/autoload ~/.vim/bundle && curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    | | $ (cd ~/.vim/bundle && git clone https://github.com/tpope/vim-sensible.git)
    | | $ (cd ~/.vim/bundle && git clone git://github.com/tpope/vim-surround.git)
    | |
    | | ~/.vimrc に以下を追記
    | |
    | |   execute pathogen#infect()
    | |   filetype plugin indent on
    | |
    | | vim を起動して以下を実行
    | |
    | |   :Helptags
    | |   :help surround
    |
    | 試しに y3y としても問題は起こらない。ysiw" も動いている。
    | 更に y3ys でも y3y + s と解釈されているようだ。
    | どの様に処理しているのかは気になる。中を覗いてみる。
    |
    |   nmap ys  <Plug>Ysurround
    |
    | という所が怪しい。更に、Ysurround は以下の行にしか現れない。
    |
    |   nnoremap <silent> <Plug>Ysurround  :<C-U>set opfunc=<SID>opfunc<CR>g@
    |   nnoremap <silent> <Plug>YSurround  :<C-U>set opfunc=<SID>opfunc2<CR>g@
    |
    | どうやら opfunc=... となっているのでオペレータとして実装されている?
    | 更に s:opfunc, s:opfunc2 という関数が内部で実装されているので、これが本体だろう。
    |
    | しかしやはり ys から直接束縛している。そして問題は起こっていない。
    | これが意味するところは nmap に対する設定は、
    | オペレータが設定されている時の動作には影響を与えないという事である。
    |
    | 後気付いたことは引数を認識していない気がするという事。
    | 2ysiw" も ys2iw" も変わらなかった。
    | 更に y2s はエラーになったのでやはり "ys" の組で登録されているという事。
    |
    | うーん。調べると nmap (normal-mode map) と
    | omap (operator-pending mode map) という二種類のモードに対する map が存在して、
    | 更にそれぞれ独立に設定を行うことができるようだ。
    | 更に同時に設定ができるコマンドも用意されている。
    |
    | うーん。vi_omap を新しく導入することにするか。
    | 何が必要か。keymap を作ること自体はそんなに難しくはない。
    | さて問題なのは元の状態に戻るというのをどのように実装するかだ。
    | check-single-command に類似のものを更に用意しなければならないのか。
    | と思ったが、check-single-command に追加の実装をすれば良いだけの気もしてきた。
    |
    | 後、念のため現在のモードの表示については vi_omap も vi_command と同じ扱いにするという事。

    [結論] vim には nmap の他に omap という独立した keymap が存在して、
    それぞれ独立に設定を行うことができる。ble.sh の実装でもこれにならう必要がある。

    http://vim-jp.org/vimdoc-ja/map.html
     \_ map           ... normal, visual, select, operator-pending
     |   \_ nmap      ... normal mode
     |   \_ vmap      ... visual/select mode
     |   |   \_ smap  ... select mode
     |   |   \_ xmap  ... visual mode
     |   \_ omap      ... operator-pending mode
     \_ lmap          ... lang-arg, insert, commandline
         \_ map!      ... insert, commandline
             \_ imap  ... insert
             \_ cmap  ... commandline

    ys は nmap にだけ設定を行う。これにより yy などと矛盾しなくて済む。

    [変更]

    * done: 先ず初めに omap を追加する必要がある。

    * cancel: 次に外部ファイルを読み込む仕組みを整える必要がある。
      或いは、取り敢えずは単に source "$_ble_base/lib/vim-surround.sh" を実行してもらうか。
      結局現状では ble-source または ble-import を実装するとしても $_ble_base/lib を前置するぐらいしかない。
      直接指定してもらうので問題ない気がする。

      いよいよ ble-import などが必要になるのは複数のライブラリの間で依存関係が合って、
      更にそれぞれのライブラリを何処にインストールしているかを事前に決定できないときである。
      現状では全て $_ble_base/lib に放り込むので問題ない。

    * done: 取り敢えず ys/yss だけ実装する。実装した。

2017-09-15

  * vi-mode: operator: < > [#D0445]

    オペレータの >< の動作について調べている。
    次の行の非空白行頭に行くときは前の行に範囲が縮まる。
    非空白行頭よりも後に行くときはその行も処理対象に含まれる。
    現在よりも前の行に移動するときはどうだろう。
    前の行の最後の文字に移動する時は、前の行も含まれる。
    現在の行は現在の行の行頭にいたときには対象にならない。
    現在の行の非空白行頭にいたときは対象になる。

    < > で行頭の8空白はタブに変換される。
    また [空白][タブ] となっていると表示上はタブ一個と変わらない。
    この時に < > を実行するとはじめにあった空白は消える。
    つまり、最初に "表示" に従って全てタブに変換されてしまうようである。

  * 2017-09-08 vi-mode: ~ [#D0444]

    大文字小文字を変換する。ydc の引数には対応していない。
    また変更範囲に大文字と小文字が混在している場合には、
    それぞれの文字について大文字・小文字を反転する。
    同じ行内で移動する。

    2017-09-15 要望が入った by cmplstofB

    移動先は l と同じ扱いで良いのだろうか。試してみた限り同じように見える。
    但し一番右に行ってカーソルが動かなかったとしても bell は鳴らない。

  * cmplstofB: iw aw の違い [#D0443]

    これは対応したつもりで対応できていなかったと思ったが、
    改めて調べてみると aw の動作は思っていたよりもずっと複雑だった。

    - 先ずカーソルの位置が空白の場合にはそれに続く単語の末端までを範囲とし、
      このとき単語に後続の空白は含まれない。引数が複数ある場合についても同様である。
      一番最後の単語に後続の空白は含まれない。先頭の空白には改行が含まれていても良い。

    - 一方で、カーソルの位置が単語の内部にある場合には、
      一番最後の単語に後続の空白は含まれる。
      また後続の単語に改行は含まれない。

    これに基いて正規表現を改定する。

2017-09-13

  * ble-edit: 補完候補の表示で座標計算がずれる。 [#D0442]

    info を通して表示しているはずだから、info 周りの座標系参加 ble-form#panel が悪い。
    これは書き換えのケアレスミスだった。

  * ble-edit: info が表示されているとき一番下の行で、上の行に侵食する。 [#D0441]

    ind の数が足りていないのではないかという疑惑がある。
    と思ったら set-height の方では ind していたけれども、
    set-height-and-clear の方では ind するのを忘れていた。追加した。

2017-09-12

  * ble-edit/info が一番下の行で消える問題 [#D0440]

    ターミナルの一番下にいる時に C-q C-j で本体の行数を高くした時に info が消える。
    これは、render/update が info の高さを認識していないということと、
    行数が変わった後に info を再描画していないことのどちらかまたは両方がいけない。

    本来どのようにするべきかはもう少し考える必要がある。
    render/update は描画領域を確保するために IL してから NL を行数分発行する筈である。
    この時、 IL で一番下の行に表示されていた info は消滅する。
    行数が変化した時には info も再描画すべきなのだろうか。
    だとするとそもそも IL して表示を消さないようにしていた意味がなくなる。
    表示が消えないことを保証できないということなのだから。

    うーん。現在のレイアウト (種類+行数のリスト) を管理するための仕組みを追加するほうが速いかもしれない。
    これは将来的なレイアウト管理への布石にもなる。取り敢えずファイルを追加してみるのが良い。

    ble-form.sh を追加した。取り敢えずすこしずつ機能を移行していくことにすれば良い。
    先ずは高さに応じた領域を確保すること。

    取り敢えず簡単に実装した。ble-edit.sh も大分すっきりしたような気がする。

  * ble-edit: 新しく追加した関数の ble-edit/text/find-* という関数名は正しくない。 [#D0439]

    今調べた所、従来の配置計算のための ble-edit/text/* という関数群は、
    _ble_edit_str とは独立に動作する物であった。
    つまり、他の文字列の配置計算にも転用できるようになっているのである。
    (ただ、その為にはどの変数に結果が格納されるかなどの情報をちゃんと調べて、
    それらの変数を対比する仕組みも作る必要があるが。)

    従って、_ble_edit_str に対して様々な情報を取り出すための
    新しく追加した関数群には別の名前をつけるべきである。
    既存の関数を観察すると _ble_edit_str に対する操作は、以下の様になっている。

    - _ble_edit_str.*
    - _ble_edit_str/*
    - ble/widget/*

    今回の場合は特に公開する編集関数に直接に紐付いたものではないので、ble/widget/* は適当ではないだろう。
    一方で、_ble_edit_str.* のような関数名は他の関数との整合性が取りにくいので本当は廃止したい。
    しかしながらこれは大きな変更になると思われるから、取り敢えずはそのままが良いのではないか。
    というか、_ble_edit_str だけでなく _ble_edit_ind にも関わってくる関数の場合は、
    やはり _ble_edit_str.* は余り良くないのではないだろうか。

    後でよりまともな関数名に変えるとしたらどのようなものになるかについては今此処で考えておく。
    比較のために既存の他のモジュールの名前も考慮する。


    | ble-edit/prompt : これは _ble_edit_PS1 を元にプロンプトを更新する仕組み。
    |
    |   内部状態の記録に使用している変数は恐らく以下のみである。
    |
    |   _ble_edit_prompt=("" 0 0 0 32 0 "" "")
    |
    |   参照している変数は以下の通りである。更に、他にも様々なシェルの状態をを参照している。
    |
    |   _ble_edit_PS1
    |   _ble_edit_LINENO
    |   _ble_edit_CMD
    |
    |
    | ble-edit/text : これは文字列の中の文字の配置情報を計算・キャッシュする仕組みである。
    |   外部から初期位置 (プロンプト末端の座標) と文字列を受け取って配置情報を計算する。
    |   内部状態の記録に指定している変数は以下の通り。
    |
    |   _ble_line_text_cache_pos=()
    |   _ble_line_text_cache_cs=()
    |   _ble_line_text_cache_ichg=()
    |   _ble_line_text_cache_length=
    |
    |
    | ble/widget : これは ble-decode の ble-bind から使うことを想定した関数群をいれておく場所である。
    |   ユーザが自由にここに関数を追加して良い。但し、実際には更にshチアの階層を作って使うのが望ましい。
    |
    | _ble_edit_str : これは実際の編集文字列の管理をするところ。
    |
    |   _ble_edit_str=
    |   _ble_edit_ind=0
    |   _ble_edit_mark=0
    |   _ble_edit_mark_active=
    |   _ble_edit_overwrite_mode=
    |   _ble_edit_arg=
    |
    |   _ble_edit_dirty_draw_beg=-1
    |   _ble_edit_dirty_draw_end=-1
    |   _ble_edit_dirty_draw_end0=-1
    |
    |   _ble_edit_dirty_syntax_beg=0
    |   _ble_edit_dirty_syntax_end=0
    |   _ble_edit_dirty_syntax_end0=1
    |
    |   _ble_edit_kill_ring=
    |   _ble_edit_kill_type=
    |
    |   _ble_edit_line_disabled=
    |
    | ble-edit/render : 編集文字列の表示にまつわる機能
    |
    |   これは雑多な他の機能をまとめて描画を行っているところ。
    |
    |   _ble_line_cur=(0 0 32 0)
    |   _ble_line_x=0 _ble_line_y=0
    |   _ble_line_begx=0
    |   _ble_line_begy=0
    |   _ble_line_endx=0
    |   _ble_line_endy=0
    |   _ble_edit_dirty=-1 -> _ble_line_dirty に改名
    |
    |   _ble_edit_render_caret_state=
    |   _ble_line_cache=()
    |
    |
    | ble-edit/info : 追加情報を表示するところ。
    |
    |   これは更に ble-edit/render の管理外で、
    |   ble-edit/render の表示内容の下に表示を行う。
    |
    |   _ble_line_info=(0 0 "")
    |   _ble_line_info_default=(0 0 "")
    |   _ble_line_info_scene=default

    どうも変数名は _ble_line_* と _ble_edit_* が混ざり合ってしまっているが、
    関数に関しては ble-edit に統一されているように見える。

    うーん。ble-edit/content にするのが良いような気がしてきた。
    →変更した。

    更に、ble-edit/text は ble-edit/layout にするのはどうだろうか。
    と思ったが、将来的には pane の配置も考えたいので、単に layout というのは余り好ましくない。
    しかしだからと言って ble-edit/text-layout というのも長い。
    更に ble-edit/text は配色情報のかんりもしているし、
    ble-highlight-layer の呼び出しも行っている。
    つまり、単にレイアウトというよりは文字列描画一般の機能を担っている。
    ble-edit/textbox だとか ble-edit/text-rendering だとかそういうのが適切だ。
    うーん。然し実際に描画をおこなっているのは ble-edit/render の方である。

    うーん。色々考えると現在の構成は割りと現実的になっている。
    本来は以下のようになっているべきなのだ。

    presentation : form
     \_ textarea : control
     |   \_ content : ble-edit/content
     |   \_ prompt : ble-edit/prompt
     |   \_ layout : ble-edit/text
     |   \_ render : ble-edit/layout
     \_ info : control

    この話は別項目として切り離す事にした。

  * ble-edit/info/default [#D0438]

    実はその場で表示しなくても良いのではないだろうか。
    一回のコマンドの中で複数の書き換えがあった場合にちらつきが気になる。
    default は常に bind/.tail で更新するように修正することにした。

  * vi-mode: operator ydc... 再編 [#D0437]

    このページを見るとどうも ydc に対してどの様に動作するかというのはいくつかの種類があるようだ。

    - linewise
    - characterwise inclusive
    - characterwise exclusive

      "移動後に列1" のとき前の行の行末に移動する。

      →これは w で試したが再現しないと思ったが、dw cw とやると確認できる。

      "最初に first-non-space またはその直前にいて、移動後に同じ行の列1" のとき行単位になる。

      →これは h で試してみても再現しない気がする。
        exclusive-linewise とマークされているコマンドだけという事か。

    現在の実装を調べてみると inclusive/exclusive の区別がついていない。
    改めてどの様な振る舞いの違いが起こるべきかをマニュアルで見て、
    更にそれを実際に動かして見てそれから判断する必要がある。

    どうも inclusive/exclusive の違いは ydc で処理する範囲の取り扱いのようである。
    exclusive だと終端の文字は対象ではなく (境界指向)、
    inclusive だと終端の文字も対象になる (文字指向)。
    殆どが exclusive であるが fx tx が inclusive である。
    vi.sh を読んでみたが対応していないように見える。と思ったら対応している様に見える。何故?
    と思ったら以下の行によって対応されているようだ。

      [[ $flag ]] && ((index++))

    これで良い理由は以下の通り。

      $flag がある場合には先頭に移動するか (y)、
      そもそも範囲内の文字列を削除 (c d) するので移動しなくても良い。
      なので index を弄ってしまっても問題ないのである。

    では、新しいオペレータを追加してもこの方策で良いのかというのは疑問である。

    - g~ gu gU g? → 先頭に移動する。
    - ! > < → これは行を丸ごと変更して先頭に移動する。
    - = も ! と同じと思われる。
    - zf も行単位である。但し複数行以上の場合でないと無効。
    - gq g@ は分からない。gq は行単位の疑いがある。
    - g@ は見ると行単位か文字単位か矩形単位かは文脈で変わる (恐らく y や g~ などと同じ)。

    どうもこれで問題ない気がする。
    つまり inclusive のときは $flag が立っている時に終端を ++ する。

    何れにしても現在の実装では operators の処理を個別に実装しすぎている。
    これらの実装を統合したい。

    1 先ず inclusive-goto-char.impl を exclusive-goto-char.impl に対する補正として実装する。
    2 次に forward-eol の実装については inclusive-goto-char.impl に置き換えた。
    3 更に common-goto-line と .relative-line と .relative-first-non-space は実装が似る。
      これらを統合することを考える。

      いきなり全体をくっつけることができるのかどうかは不明なので、
      取り敢えず $flag が立っている場合だけを統合することを考える。
      特に三者から呼び出すことのできる共通の関数を定義することが目標になる。

    滅茶苦茶に書き換えたので改めて各コマンドについて動作確認する必要がある。
    チェックが必要なのは ^-+jkHLG である。
    それぞれについて ydc と組み合わせての確認も必要である。
    更に ftFTeE$ も inclusive の動作について確認が必要である。

    確認事項 preserve_column require_multiline
    確認済み H L yH dH c2L
    確認済み j k yk dk ck yj dj cj
    確認済み + - y+ y- d+ c+ d- c-
    確認済み ^ $ d^ c^ y^ c$ d$ y$
    確認済み e ce ye de
    確認済み fx yfx cfx dfx tx ytx

    恐らく問題ないだろう。

2017-09-11

  * ble-edit: stty sane をしなくて済む方法? [#D0436]

    ble-edit/bind/.check-detach を見ていて思ったこと…
    もしかして stty sane はシグナルハンドラで実行すれば良いのではないだろうか。
    これは後で試してみる。

    どうも試してみると stty sane を実行しなくても問題ないようになっている気がする。
    それよりも、readline が PS1 が空だと思っていることによる表示のずれがあるので、
    何でもいいからコマンドを一回実行する必要があった。
    stty sane はそれを実行させるための茶番の様だ (当初は意味もあったのだろうが)。

    面倒だし ble-detach することも余りないだろうから、
    これはこのまま茶番として残しておく。

  * clear-screen 直後に info が表示されない。 [#D0435]

    直した。

  * vi-mode: C-o の復帰位置 [#D0434]

    現在のアルゴリズムは以下の通りである。

    - コマンド実行直後の位置 (eol 補正される前の位置) で復帰する。

      Note: p, P の "eol 補正" は挿入文字列の末端から最後の文字に移動するものである。

    - C-o 時点での位置が行末であり、コマンド実行直後の位置が最後の文字のとき行末に移動する。

    以下の動作は現在再現している。

    - 同じ長さの行が並んでいるとき、$ i C-o k は最後の文字であり、A C-o k は行末である。
    - A C-o y l で行末に行く
    - 6文字の行で A C-o 6 | とすると行末に行く
    - A C-o r 8 で行末に行く

    しかし以下の動作は再現していない。

    - 空白だけの行で A C-o ^ とした時の位置は (行末ではなく) 最後の文字でなければならない。

      Note: ^ は空白だけの行において最後の文字に移動する。

    色々試すと first-non-space (^ + - や行単位の p P など) は例外のようである。
    取り敢えず個別規則ではあるが追加した。
    他にも何か vim との振る舞いの違いがまだあるのではないかと思われるが、
    それらは発覚してから対処するということにする。

  * 初回起動時の INSERT がずれるようになった。何故? [#D0433]

    ble/widget/vi-insert/.attach で呼び出すのは default ではなくて set-default であるべきだった様だ。

    % 何故かは詳しく考えていないが、初期化と描画の順序の問題だろう。

    ble-decode-attach より後に、プロンプトを表示する位置が確定する。
    先に info を描画してしまうと表示がずれることになる。初めは set-default で内容だけ指定しておいて、
    プロンプトの表示位置が確定した後に info も描画させるようにする必要がアアル。

  * vi-mode: by cmplstofB [#D0432]

    | ble.sh における vi-insert モードでの C-o は "accept-and-next" となっていますが、
    | vi/Vim の標準では「次に入力される「一回」のキー[^1]をノーマルモードに対する
    | キーとして解釈し実行した後、再び挿入モードに移る。

    これはあとで実装する。

    # C-o http://qiita.com/takasianpride/items/6900eebb7cde9fbb5298

    動作を確認する。

    - R や gR で C-o して戻るとどうなるのか。i と同じになる可能性はあるのか。
      試してみた所また元の R, gR の状態に戻る。
      表示もそれに応じて (replace) や (vreplace) になる。

    - C-o した上で更に i, a などで挿入モードに入るとどうなるのか。
      どんどん入れ子で C-o できるのだろうか。
      試してみた所、R C-o i ESC l としても REPLACE に戻るということはなかった。
      つまり i, a などをすると C-o した効果は消える。

    - 行末で C-o するとどうなるのか。
      A C-o y y としたら一時的にノーマルモードに戻っているときは
      行末から一つ戻った位置にカーソルが移動するが、終わるとまた行末に行くようだ。
      勿論いつでも元の位置に戻る訳ではなくて C-o のあとに移動コマンドを挟むと元の位置には戻らない。
      また $ i C-o y y としても行末には行かずに直前の位置に戻る。

      % これは厄介な動作である。vim は内部的には "insert での位置"
      % と "normal での位置" を二重に管理している可能性がある。
      % だとすると現在の実装では色々と問題が残る。
      %
      % - うーん。A C-o y l をやっても行末に戻った。
      %   不思議だ。内部的には y l をした時点で yank した範囲の先頭に移動してもおかしくない。
      %
      %   a 可能性1: 移動先が現在位置よりも前方にある時には、内部的な移動は起こらない。
      %   b 可能性2: 実は内部的な位置というものは元から存在していなくて、
      %     単に C-o する直前の位置と直後の位置を記録しているのに過ぎないのかも知れない。
      %     しかしそれは妙だ。編集によって行の中身が変わったときなどに困る。
      %
      % - 念のため A を使わずに $ i right C-o y l としても同じだった。
      %
      % - 次に "echo 6" という内の行で A C-o 6 | としてみた。
      %   何と修了後に行末 (位置 7) に移動した。
      %
      % ここから結論付けられることは、内部的な位置というのは実は存在していなくて、
      % やはり C-o した時の位置を記録していて、
      % 位置が変わっていなければ元に戻すということのようである。
      %
      % さて、では行の内容が変わっている場合にはどうなのであろうか。
      %
      % - A C-o r 8 としたがやはり行末に戻った。位置しか見ていない?
      %
      % では行の長さが変わっているときにはどうなるのだろうか。
      % しかし位置を変えずに行の長さを変えるコマンドが思い浮かばない。
      % y l で一文字だけ貼り付けになるとき P をすれば位置が変わらずに行の長さが変わるのではないか。
      %
      % - 0 y l A C-o P を試してみた所それでも行末に移動した。これは不思議だ
      %
      % - 同じ長さの行が並んでいるところで A C-o k としたところ上の行の行末に移動した。
      %   $ i C-o k としても行末には移動しない。
      %
      % つまり位置を記録しているのではなくて C-o した時点で行末にいたかどうかを記録し、
      % C-o から抜けた時点で行末の一つ手前にいる場合に復元するという方針なのではないか。
      %
      % と思ったが P で行の長さを変えた実験からそれはおかしい。
      % やはり内部的な位置を二重に管理していて k を実行する時には両方移動しているのだろうか。
      % しかしそれは | の実験と矛盾する。或いは、| で 6 | とした時は実際の位置が変わらないということで、
      % 実際の処理としては無視されたことになっているという可能性もある。

      % うーん。P の動作はそもそも不自然な気がするし、
      % 取り敢えず "行末にいたかどうか記録" 方式でいい気がする。
      % P の件に関しては別個に質問することにする
      %
      % - というかそもそも I C-o P としても次の文字に行くようだ。
      %
      % - 0 4 y l I C-o p でも同じように "貼り付けた内容の最後の文字" ではなく、
      %   "更にその次の文字" の位置で INSERT に復帰するようだ。
      %
      % つまり p, P は内部的には一旦貼り付けた内容の末端に位置が移動して、
      % しかしノーマルモードに移る際に一つ戻るという動作をしているということに思われる。

      % "行末にいたかどうか記録" という仮説が合っているのか確かめる。
      %
      % - 以下の内容で、文字 2 の位置にいる時に i C-o k としたら行末に移動した。
      %
      %   echo 1
      %   echo 12
      %
      %   % つまり "行末にいたかどうかを記録" という仮説は間違っている。
      %   これは勘違い。行末にいたかどうかが効くのはコマンド実行後に行末直前にいたときのみ。
      %   コマンド実行後に行末にいた場合はそのまま行末になる。
      %
      % 代わりの仮説として "各コマンドを実行した直後の位置" というのが実はあって、
      % ノーマルモードにいるときには更にその位置から補正が起こるというものを立てる。
      %
      % しかしこれによると A C-o y l で行末に移動するというのは、
      % y l を実行した直後の位置が行末にあるということを示唆するが、
      % 複数文字の y l の動作からすると変だ。念のため複数文字の y l を試す。
      %
      % - $ h i C-o y 2 l → 別に行末に移動するということはない。

      [結論] つまり、以下の通り。

      - C-o をした時点で行末にいたかどうかを記録する。
        コマンドを実行直後 (行末補正前) に行末にいた場合は、そのまま行末に行く。
        行末直前にいた場合は、"C-o をした時に行末にいた" 場合に行末に補正する。
        それ以外の場合にはそのままの位置に行く。

      - p, P の "直後の位置" は貼り付け範囲の末端である。
        ノーマルモードではその後で最後の文字に補正される。

    - R C-o から抜けるのに c を使うとどうなるか?
      ただの INSERT になった。つまり i や a と同じ。

    - d 3 l で行末まで丁度全ての文字を消すと復帰した時の位置はどうなるか?
      行末になった。つまり c を使うのと同様である。
      但し c と違って R C-o d 3 l としたらちゃんと REPLACE に戻る。

    - I C-o back は前の行の行末に移動する
    - I C-o 2 r x は 2 文字目に移動する。
    - 空白だけの行において I C-o ^ は行末ではなくて最後の文字に移動する。
      これは I c ^ としても分かる。最後の空白が残る。
      +, - も同様。つまり ^ + - は行末には一時的にも移動しない。
    - 一方で I C-o $ は行末に移動する。
    - 6文字の行において c 7 | は最後の文字を削除しない。つまり | は行末には一時的にも移動しない。


    実装した。しかし微妙に振る舞いが異なる。

    - 空白だけの行において A C-o ^ とすると vim では最後の文字に行く。
      変だ。今までの実験では最後の文字にいる時には修正されるはずだったのではないのか。

    うーん。面倒だ。これは別の問題として残すことにする。

    > * p の動作が正しくない気がする。 → 条件が反転していた。直した。
    > * あとカーソルの位置がおかしい。 → 条件を修正するべきところ eol 補正を完全に削除していた。直した。

  * 2017-09-05 vi-mode: gR? [#D0431]

    http://qiita.com/sfuta/items/0de4ead865c15e9e9b68

    overwrite mode には R/gR の区別があるようだ。
    さて overwrite mode まで来ると複雑である。
    特に self-insert が複雑になる。
    これは再実装すると面倒なので何らかの変数を用いて vi/emacs を内部で
    判定して動作を微妙に変えるという様にするのが良いのではないだろうか。
    ところで self-insert に関しては emacs/vi で動作の違いはあっただろうか?

    実際に vim で試してみると gR と押しても何も起こらないどういうことか?

    これは vi ではなく vim で起動しなければならなかったという話だった。


  * 2017-09-09 テストユーザ (vim) に説明すること [#D0430]

    - 編集文字列内に改行 LF が含まれないとき単一行編集と呼び、あるとき複数行編集と呼ぶことにする。
      単一行編集のとき LF を挿入して複数行編集に移るには C-v C-j (または端末のフロー制御を無効にしていれば C-q C-j でもよい) とすれば良い。
      複数行編集のとき RET (C-m) はコマンド実行ではなく改行挿入になる (ノーマルモードでは次の非空白行頭に移動になる)。
      この時コマンドの実行は RET (C-m) ではなく C-j で行う。
      複数行編集では端末の表示行数よりも多くの行を含むコマンド編集は想定していない。

    実装の仕様(または妥協点・疑問点)

    - gr が vim で動かないこと。gR が動かないこと
    - H L が現在の履歴項目内の移動で、G gg が履歴内の移動であること。
    - jk+- で現在の履歴項目の上下を踏み越えると次の履歴項目に移動すること。

  * vi-mode: vi.sh から keymap/isearch を使っているが [#D0429]
    keymap/isearch は emacs.sh の中で定義されている。
    どうやら現状では .inputrc で vi が設定されていたとしても、
    ble.sh をロードした段階では -o emacs であり、
    後で -o vi になる様である。

    % どうも .bashrc の中では殆ど -o emacs のようである。
    % ところが何処かの時点で -o vi に変わる様である。
    % 調べてみると ble-decode-attach の
    % eval -- "$(ble-decode-bind/.generate-source-to-unbind-default)" で結果が変わっている。
    % つまり初回の bind 実行で変化しているように思われる。
    % 試してみるとどうやら単に "bind" としただけでも readline が呼び出されるようである。
    % なので -o emacs/vi を最初にチェックする前に bind を実行すれば良い。
    % # さて、不思議なのはこの仕様の場合、ble.pp の最初のチェックをすり抜けるのではないかということ…。
    % # やはりすり抜けていた。このチェックの時点で readline をロードすれば良いだろう。

    [結論] 最初に -o emacs/vi を参照する前に "bind &>/dev/null" を実行すれば良い。

    さて、この時 keymap/isearch はどうなるだろうか。
    調べてみた所、何も操作できない状態になった。

    二つの変更を加える必要がある。

    1. 先ず初めに isearch.sh を分離するということ。
      それでも、キャッシュが複数に分かれるのは得策でないので
      キャッシュは emacs.sh, vi.sh で出力するようにする。

    2. 次に ble-decode/keymap/push する時に keymap の存在をチェックするということ。
      もし keymap が存在しない場合にはそのキーマップに移行するべきではない。
      keymap の存在判定で色々手間取ったがなんとかできた。

2017-09-10

  * 2017-09-07 vi-mode: C-c ESC C-| の違い。 [#D0428]

    http://d.hatena.ne.jp/yuta84q/20101216/1292508997

    引数を保存して繰り返し適用する? しかし途中で変な操作があると難しい。

    % どうも途中で矢印で移動すると無効になるようである。
    % backspace で内容を削除する場合には問題は起こらない。
    % つまり許容できる操作に制限があるということだろう。
    % そして制限された動作を用いている限りにおいては、
    % 編集によって追加された文字列は、
    % 編集開始点から編集終了点までということが保証される。
    %
    % もう少し調べてみる。backspace の場合には引数は無効にならない。
    % では元々あった文字数よりも少なくなった場合にはどうするのか。
    % →どうやら backspace が繰り返し実行されるようである。
    % 更にこの backspace は (挿入モードの性質として) 行を跨って実行されるようだ。
    %
    % さて、backspace 以外の削除するコマンド (例えば前の単語を削除するコマンド) を実行した時にどうなるかは気になる。
    % 単語単位で削除した回数を覚えておいて引数の数だけ掛け算してそれを適用するのか、
    % 或いは減少した文字数だけを覚えておいて引数の数だけ掛け算したぶんだけ更に文字数を減少させるのか。
    % 実装としては文字数を記録するだけの方が自然である。行った操作の履歴を保持するのは大変である。
    % と思ったが、よく考えてみたらそもそも挿入モードで単語単位で削除するような操作があったのかどうか怪しい。
    %
    % そう思って vimindex を眺めてみたら C-w でそれを行うことができる様である。
    % 実際に試してみた所、ちゃんと C-w を行ったのだということを覚えているようだ。
    % ということはどの様な編集を行ったのかという履歴を残すということになる。
    % 寧ろマクロの一種と考えるほうが良いということである。
    % さて、ということであればこの機能に対応するならば先にキーボードマクロに対応する方が先である。

    どうも途中で行った操作を全て記録しているようである。
    また、矢印などで移動をしたりするとキャンセルされる。

    これはキーボードマクロの仕組みを整えてから対応した方が良い。

    →より汎用的に ble-decode.sh を拡張するとしたら、__defchar__ や __default__ の様に、
    keymap に __before_command__ のような特殊バインディングを用意するのが良い気がする。
    そしてキーボードマクロその他の仕組を整えるのに利用できるようにする。

    しかしよく考えたら単にキーボードマクロとする場合、
    その時の背景の変数の状態などを記録しなくても良いのだろうか。
    というのもノーマルモードでキーボードマクロを記録している時にどのように処理されるのかが気になる。
    ノーマルモードの __before_command__ でキーボードマクロを記録しているときに
    挿入モードに入ると、その間記録がされないことになってしまう。それはおかしい。
    つまり、今回追加した仕組みは実はキーボードマクロの仕組みには使用できない。
    キーボードマクロにしたければ実は keymap に依存しない hook を取り付ける仕組みを追加するべきだ。
    更に入れ子になっている場合なども考えれば複数取り付けられるようにするべきかもしれない。
    何れにしてもキーボードマクロは今回の仕組みとは独立に用意しなければならない。
    この事はキーボードマクロの計画の方に追記しておくことにする。

  * vi-mode: C-home C-end は現在の編集文字列内の移動としても良いかもしれない。 [#D0427]

2017-09-09

  * vi-mode: f F t T ; , [#D0426]

    bash の動作を確認してみると同じ履歴項目の中だけを検索するようである。
    vim で試してみる。同じ行内でしか一致しない。
    現在位置にある文字には一致しない。
    t T では一つ先の文字に一致するので何回も一致する。

    ycd は効く。f t は終端までを範囲とするのが他と少し異なる。
    つまり空一致は存在し得ない。
    引数を指定すると n 個目の文字に移動できる。
    n 個目がない場合には何もせずに bell である。

  * ble-edit: 下キーなど履歴項目を移動するもの全般に… [#D0425]
    現在一番下の行にいるということが分かっているのであれば、
    下に行こうとした時に history/load する必要はないのではないだろうか。

  * ble-edit, ble-decode: declare で宣言しているグローバル変数は [#D0424]

    何も指定せずにただ代入するべきなのではないか。
    なぜならば関数内から source などした時にローカル変数になってしまうので。

    定数として宣言するために declare -ir しているものもあるが、
    これらは結局 ble.sh を複数回ロードしたときのために定義されているかどうかを確認してから
    declare -ir するのなどの面倒な処理の原因になっている。
    やはり勝手に書き換える人が悪いという事にして、declare -ir は除くのが良いだろう。

    問題になるのは declare -A である。declare を使わずして配列が連想配列であることを指定する方法はない。
    bash-4.2 移行であれば declare -gA で解決するが bash-4.0, 4.1 ではそれができない。
    bash-4.0, 4.1 では bash-3.* 用の declare -a を用いる fallback を使うという手もあるが、速度が遅くなってしまう。
    実のところ、関数内からロードするという事は現在考えていないし、
    また 4.0, 4.1 はまだまだ現役だと思われるので速度を重視したほうが良い気がする。
    という訳で今の所は 4.0, 4.1 に関しては関数内からロードする時に問題になるとしても取り敢えず放置することにする。

    或いは現在関数内からロードしているかどうかを判定して、
    declare -A を行うかどうかを切り替えるという手もある。
    どうも関数内にいるかどうかは ${FUNCNAME+set} で判定できるように思う。
    但し FUNCNAME がユーザにより勝手に unset されていないことが前提である。
    従って、関数内にいてかつ bash-4.2 未満の場合には配列実装に fallback すれば良い。

    * 確認: 関数内から source したとき source されたスクリプトの中からそれを判定できるのだろうか?

      もしかすると source した時点で関数でないという様に解釈されて
      FUNCNAME が見えないという可能性も否定できない。

      以下のようなファイルを用意しておいて、

      ```bash:a.bash_source
      # bash_source

      if [[ ${FUNCNAME+set} ]]; then
        echo 'source from a function'
      else
        echo 'source from out of functions'
      fi
      ```

      bashrc から呼び出して正しく判定できるか確認する。

      ```bash:~/.bashrc
      function atest1() { source ~/prog/ble/a.bash_source; }
      atest1

      source ~/prog/ble/a.bash_source
      ```

      どうやら正しく判定できる様だ。

    * 確認: 既に同様の仕組みによって ble.sh を関数内からロードしている場合に警告を発したりしていないか。
      もしそうであればわざわざ関数内からロードした時について対応するのは無駄である。
      少なくとも FUNCNAME で検索した限りにおいてはそのような判定は行っていないようである。

      というより実際に関数内からロードしてみれば確認は済む。
      試してみた所ロードできた。動作している。

  * vi-mode: J gJ o O [#D0423]

    J は行末に LF がある場合にはそれを SP に変える。
    それ以外の場合には bell を鳴らして移動もしない。
    gJ は SP に変えるのではなくて単に削除する。

    o は行末に改行を挿入して挿入モードに入る。
    O は行頭に改行を挿入して挿入モードに入る。
    o O は共に新しい行の先頭にカーソルをおく。

    これらの J gJ o O のコマンドは何れも、
    引数に ydc が含まれる場合は bell で、
    引数の数字は単に無視されるように思われる。
    →o O に関しては挿入モードを抜けるときの繰り返し回数を指定するようだ。

  * そろそろ leak variables を再度チェックする。 [#D0422]

    ble-syntax.sh で rex がリークしていた。
    単にロードしただけでは他にリークは見つかっていない。

    本来はもっと長時間使用した後で leak を確かめるべきである。
    という訳で ble を編集しているシェルで試してみた。
    他に complete.sh で compgen がリークしていた。直した。

  * vi-mode: r [#D0421]

    f や F でも同じことであるが、引数をどのように受け取るかが問題である。

    % quoted-insert の場合には ble-decode に特別な項目を設定して処理した。
    % 同じ仕組みを採用しようとするとキー入力ではなくて生の文字を受け取ることになる。
    % 一方で rx fx Fx などでは通常の文字を引数に取ることを想定するので生の文字を受け取る必要はない。
    % 寧ろ変な操作を検出するために生の文字ではなくて生のキーコードを受け取るようにしたい。
    % そのためには ble-decode に同様の仕組みとして生のキーコードを受け取るようにすると良いだろうか。
    % しかしよく考えてみるとそれ専用の keymap を定義することができるのだから ble-decode を弄る程でもない気がする。
    %
    % 念のため quoted-insert の利用している ble-decode の機能について確認し、
    % どちらの実装にするほうがきれいになるかを判定してから処理するようにする。
    % quoted-insert では _ble_decode_char__hook=ble/widget/quoted-insert/.hook を設定し、
    % ble-decode にこの .hook 関数を呼ばせている。
    % 更によく見ると既に ble-decode に _ble_decode_key__hook という変数が用意されている。
    % 因みに誰も使っていない。
    %
    % さて既にその仕組が整っているのだとしたら、_ble_decode_key__hook を利用したほうが簡潔なのではないだろうか。
    % keymap を自前で定義するにしてもコマンド毎に定義するのは変だし、
    % だからと言って一つ keymap を用意して _ble_keymap_vi_hook などの変数に操作を記録するという方式にすると、
    % 既にこれは汎用の _ble_decode_key__hook と同様な仕組みになってしまっている。
    % もしそうだとしたら _ble_decode_key__hook の方が keymap を通さないだけ素直な実装になっているので良い。

    [結論] これには既存の _ble_decode_key__hook の仕組みを利用すれば良い。

    実際の実装では overwrite をするのでその仕組を既に持っている self-insert を用いる。
    但し、2つの点において self-insert を改修しなければならない。

    - 先ず 1 つ目に引数を用いて繰り返し self-insert を行うということ。
      効率の面から言って一気に複数文字を挿入するようにした方が良い。
      また、emacs 用の .get-arg を用意する必要があるのでは。

    - 次に overwrite する時に表示幅で overwrite するのか、論理列数で overwrite するのかということ。
      これは r gr で異なるので両方に対応しなければならない。
      これは _ble_edit_overwrite_mode=R というのに対応する必要がある。
      先ずはどこで _ble_edit_overwrite_mode が使われているかを調べる。

    変更を実施する。

    * self-insert の実装をいじっていて思ったこと。
      delta の実装はこれで良いのか。
      delta は変更範囲より後ろにある _ble_edit_mark の位置を更新するのに使っている。
      しかし _ble_edit_str.replace で _ble_edit_mark は更新されないのだろうか。

      →今確認してみた所 _ble_edit_mark だけでなく _ble_edit_ind も更新しないようだ。
      これは _ble_edit_str.replace を呼び出した後で結局再び _ble_edit_{ind,mark} を移動するなどの場合があって、
      そのような時に無駄な計算をしないための効率によるものと思う。

      つまり、呼び出し元で両者とも管理しなければならない。

    * さて、現在の self-insert の delta はどのようなものになっているだろうか。
      特に全角文字を空白文字で置き換えた時に delta を 1 だけ増やすのは何故だろうか。
      repw-w でないのには理由があるのか、それとも単なるミスだろうか。
      (或いは全角文字は幅 2 という仮定があればこれで問題ないが、
      それだとわざわざ挿入する空白の数を repw-w と計算している理由がわからない。)

      更によく見てみるとこれは実際に使用するところで
      delta=${#ins}-(iend-ibeg) として計算すれば良いだけの気がする。
      今まで delta を別に計算していたのはそちらの方が速いと判断からなのだろう。
      しかし現状の実装ではむしろ複雑になっている気がするので、
      delta の値はその場で計算することにして delta 自身は廃止することにする。

      一応テストする。挿入・上書きのそれぞれで全角・半角を書くのを試した。
      全角半角で半角・全角を上書きするのも試した。問題ない。OK

    * _ble_edit_overwrite_mode=R には対応した。

    * その他の _ble_edit_overwrite_mode を参照している箇所は、

      overwrite mode の設定、caret_state の保存・復元、表示時の着色を除けば
      ble/widget/.delete-backward-char のみである。
      これについては _ble_edit_overwrite_mode=R に対応した。
      (引数には対応していない。引数は今後少しずつ対応していく予定である。
      というかそもそも keymap emacs では引数を導入できない。)

    * r gr した後のカーソルの位置が異なる→直した。

    * r gr ではその行内に既に足るだけの文字数がない時 bell である。

    * vim で試すと gr は必ず bell になる。
      何か使い方が間違っているのだろうか。
      これは vim ユーザを見つけて相談するべきである。
      取り敢えず有効にしておくことにする。


2017-09-08

  * vi-mode: G H L gg [#D0420]

    元々の vim では H L は現在画面に写っている範囲での移動である。
    また G は全体の行番号を指定して移動するものである。
    引数を省略した場合には一番最後の行に移動する。
    gg は引数省略時に一番最初の行に移動することの他は G と同じ。
    何れも非空白行頭に移動する。

    ble.sh の実装では H L は現在の履歴項目の中での移動とし、
    G/gg は履歴の番号を指定した移動とするのが良さそうである。
    但し ydc が指定されているときには gg/G は H/L と同様に現在の項目の中で処理する。

  * vi-mode: K [#D0419]

    vim ではデフォルトでは現在の単語について man を呼び出すようである。
    ble.sh では丁度 command-help というものを既に用意している。
    これは現在のコマンドラインのコマンド名で --help または man を呼び出す。
    vim の動作とは異なるが引数について man を呼び出しても仕方がない気がするので、
    ここは寧ろ command-help の動作で問題ない気がする。

  * vi-mode: 編集文字列に改行が含まれるときの RET の動作 [#D0418]

    編集文字列に改行が含まれるとき、
    現在 insert mode に戻って改行を挿入する操作になっているが、
    これは下に移動する動作にするべきなのではないかという気がする。
    実際に試してみると + と同じ動作になっている様に思われる。

2017-09-07

  * ble-edit: ble-edit/text/getxy は ble-edit/text/getxy.out に改名する。 [#D0417]

  * vi-mode: accept-line したら vi_insert に戻るべきなのでは。 [#D0416]

  * vi-mode: yh でカーソルは動かなければならない [#D0415]

    yh でカーソルは動く。yl でカーソルは動かない。
    どうもコピーした領域の先頭に移動するということかもしれない。
    また共に範囲が空のときには kill ring の内容も空になる。

    dl dh で領域が空の時には kill ring の内容は変更されない。

  * vi-mode: vim の dd dj yy yj などは行単位でコピーしたということを覚えている。 [#D0414]
    つまり貼り付けの際に行頭に移動してから行単位で挿入を行うのである。

    現在コピーした内容は _ble_edit_kill_ring という変数に記録している。
    これとは別に _ble_edit_kill_type などの変数を用意して
    其処に行単位かどうかの情報を記録するのはどうだろう。

    これに関しては後で実装する→と思ったが結局 yy と同時に実装する事にした。

  * vi-mode: 先に dd yy cc を実装する。0 も実装する [#D0413]

    これは arg の実装の特殊なケースなので現状で中途半端になっている。

  * ble-edit: 履歴の初期位置がおかしい。 [#D0412]

    これは先程 ble-edit/history/load は ble-edit/history/goto
    でどうせ使うから呼び出さなくても良いとして削除したのがいけない。
    goto の引数に渡している値を取得するのに load が必要である。

  * ble-edit で ble-edit/text/update/position が実行済みかのチェックを入れたら [#D0411]
    history-next, history-prev を実行した後の
    forward-line, backward-line で引っかかる様になった。

    当初は一つの入力に対して forward-line, backward-line のみを呼び出すならば、
    編集文字列の変更はなく常に配置情報は最新になっているはずに違いないと考えたが、
    よく考えたら stdin に入力が溜まっている場合には配置計算を省略するようにしているので、
    上下のキーを連打すると容易に配置情報が更新されていない状態で forward-line/backward-line が呼び出される。

    これは今までもチェックしていなかったために気付いていなかっただけで、
    今までも getxy.cur や get-index-at の計算が誤っていた事になる。
    実はこれが今までの _ble_edit_ind out of range のエラーの原因だったのではないか。
    これについては再現するかどうかを確かめた後に検証する必要がある。

    →修正した。配置情報を使うコマンドに関しては
      ble-edit/text/update/position の結果が最新の場合とそうでない場合で
      動作を切り替える様に改修した。

    →検証するのは面倒なのでやめた。
      今までの assertion failure は全て履歴の移動の後に起こっていたので
      もうこれが原因だということで恐らく間違いないだろう。
      取り敢えず今までの assertion failure の報告は全て解決済みとする。
      その上でまた assertion failure が出たらその時に改めて調査する事にする。

    | 2016-09-14
    |
    | * stackdump がまた出た。
    |
    |   | stackdump: 0 <= beg=28 <= end=29 <= len=1; beg=28, end=28, ins(1)=e
    |   |   @ /home/murase/prog/ble/ble.sh:5133 (_ble_edit_str.replace)
    |   |   @ /home/murase/prog/ble/ble.sh:-2006 (ble/widget/self-insert)
    |   |   @ /home/murase/prog/ble/ble.sh:33 (ble-decode-key/.invoke-command)
    |   |   @ /home/murase/prog/ble/ble.sh:22 (ble-decode-key/.invoke-partial-match)
    |   |   @ /home/murase/prog/ble/ble.sh:37 (ble-decode-key)
    |   |   @ /home/murase/prog/ble/ble.sh:92 (ble-decode-char/.send-modified-key)
    |   |   @ /home/murase/prog/ble/ble.sh:50 (ble-decode-char)
    |   |   @ /home/murase/prog/ble/ble.sh:-966 (ble-decode-byte+UTF-8)
    |   |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |   | stackdump: 0 <= beg=2 <= end=3 <= len=2; beg=2, end=2, ins(1)=c
    |   |   @ /home/murase/prog/ble/ble.sh:5133 (_ble_edit_str.replace)
    |   |   @ /home/murase/prog/ble/ble.sh:-2006 (ble/widget/self-insert)
    |   |   @ /home/murase/prog/ble/ble.sh:33 (ble-decode-key/.invoke-command)
    |   |   @ /home/murase/prog/ble/ble.sh:22 (ble-decode-key/.invoke-partial-match)
    |   |   @ /home/murase/prog/ble/ble.sh:37 (ble-decode-key)
    |   |   @ /home/murase/prog/ble/ble.sh:92 (ble-decode-char/.send-modified-key)
    |   |   @ /home/murase/prog/ble/ble.sh:50 (ble-decode-char)
    |   |   @ /home/murase/prog/ble/ble.sh:-966 (ble-decode-byte+UTF-8)
    |   |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |   | stackdump: 0 <= beg=3 <= end=4 <= len=3; beg=3, end=3, ins(1)=h
    |   |   @ /home/murase/prog/ble/ble.sh:5133 (_ble_edit_str.replace)
    |   |   @ /home/murase/prog/ble/ble.sh:-2006 (ble/widget/self-insert)
    |   |   @ /home/murase/prog/ble/ble.sh:33 (ble-decode-key/.invoke-command)
    |   |   @ /home/murase/prog/ble/ble.sh:22 (ble-decode-key/.invoke-partial-match)
    |   |   @ /home/murase/prog/ble/ble.sh:37 (ble-decode-key)
    |   |   @ /home/murase/prog/ble/ble.sh:92 (ble-decode-char/.send-modified-key)
    |   |   @ /home/murase/prog/ble/ble.sh:50 (ble-decode-char)
    |   |   @ /home/murase/prog/ble/ble.sh:-966 (ble-decode-byte+UTF-8)
    |   |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |   | (略) つづきは同様
    |
    |   1 不思議なのは _ble_edit_str.replace で修正が入っている筈なのに、
    |     エラー状態が継続している事である。
    |     よく見ると、修正によって初回よりはましな値になっていると言え
    |     end の値が文字列の長さよりも一つ多いものになっている。
    |
    |     取り敢えず、初めに発生したエラーの原因は別の所にあるとしても、
    |     修正部分のコードが間違っている可能性があるので修正する。
    |
    |     確認してみたところ、_ble_edit_str.replace は _ble_edit_ind を修正するとは言っても、
    |     その場で許容される値に修正するだけで _ble_edit_str.replace 呼び出し元での
    |     _ble_edit_ind に対する操作も含めての修正ではない。
    |     従って、_ble_edit_str.replace の中で _ble_edit_ind を修正しても仕方がない。
    |
    |     →どうも観察してみたところ、_ble_edit_str.replace の呼び出し元では、全て、
    |     _ble_edit_str.replace を呼び出した後に _ble_edit_ind を更新している様である。
    |     つまり、_ble_edit_str.replace 呼び出し時点では、_ble_edit_ind の値は
    |     文字列挿入前の値になっていると想定して良い。
    |     と思ったが、そうでは無い物もあったので、それについては処理の順序を入れ替える。
    |     という訳で、これでエラーが発生した時の _ble_edit_ind の修正は正しくなった筈である。
    |     序に _ble_edit_mark に関しても同様の修正を行う様にする。
    |
    |   2 もう一つの問題点はそもそも何故初めに変な値になったのかという事である。
    |     特に beg=28 end=28 という値になっている。
    |     因みにこの時前に実行したコマンドは "gunzip -c xp.img.gz | wc -c" の 27 文字であり、
    |     またエラーが発生したのは最新の編集行に echo と入力しようとした瞬間である。
    |     勿論、最新の編集行に入力しようとすると必ずなる訳ではなく
    |     (恐らく直前の操作手順に応じて) このエラーが発生したりしなかったりする。
    |
    |
    | 2016-06-25
    |
    | * また stackdump が出た。
    |
    |   .ble-edit/delete-backward-char および insert-char で起こっている。
    |   表示されている内容から察するに、_ble_edit_ind が変な値になっている様だ。
    |   また、履歴を上下で移動した後に起こっている事も分かっている。
    |
    |   | stackdump: 0 <= beg=10 <= end=10 <= len=8; beg=10, end=11, ins(0)=
    |   |   @ /home/murase/prog/ble/ble.sh:17 (_ble_edit_str.replace)
    |   |   @ /home/murase/prog/ble/ble.sh:11 (.ble-edit/delete-backward-char)
    |   |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit.delete-char)
    |   |   @ /home/murase/prog/ble/ble.sh:4 (ble/widget/delete-backward-char)
    |   |   @ /home/murase/prog/ble/ble.sh:-1794 (ble/widget/delete-region-or)
    |   |   @ /home/murase/prog/ble/ble.sh:16 (ble-decode-key/.invoke-command)
    |
    |   この前の修正で完全に直っていたはずだと思ったのだが何故だろうか。
    |   make を実行したら ble.sh が更新されてしまったので ble.sh
    |   が中途半端な状態にあったのかも知れない。
    |   丁度最近、検索の速度向上の為に一時的に単一の配列だけを参照する様に
    |   書き換えたりなどしていた後である。
    |   また、暫く様子を見てそれでも出る様だったらまた原因を探る必要がある。
    |
    |   或いは、今先程エラーが起こったシェルの history next 関数を調べて、
    |   その内容がどの様な状態になっているかを確認すれば、
    |   エラーが起こる様な状態に丁度編集していた最中だったかどうかが分かる。
    |   →実際のループ処理を行っているのは ble-edit/isearch/next-history-resume.fib
    |   の中である。ロードされている関数の中身を確認してみた所、
    |   ちゃんとこの前修正した二つの配列を参照して内容を決定する部分は正しい。
    |
    |   | if [[ ${_ble_edit_history_edit[i]-${_ble_edit_history[i]}} == *"$needle"* ]]; then
    |   |     ind="$i";
    |   |     break;
    |   | fi;
    |
    |   では何が悪いのだろうか。考えてみると長い履歴項目を弄った後に、
    |   一番下の (空の) 項目に戻ってきた時に起こった様な気がする。
    |   うーんそれでも再現は簡単にはしない…。
    |   又エラーの起こった状態から復帰する為に
    |   _ble_edit_ind は調整を行ってしまうのが良い。


  * 2017-09-04 vi-mode に対応する (初期計画) [#D0410]

    取り敢えずブランチを切る。

    取り敢えず vi 用の keymap に切り替える仕組みを作る。

    | - set -o vi が有効になっている時には keymap viins を使う様にする。
    | - 途中で set -o emacs から set -o vi になった時に ble.sh のモードも変更する様にする。
    | - ble-decode-attach において -m vi-insert に対して bind するようにする?
    |
    |   或いは飽くまで emacs-standard を使う様にするか。
    |   emacs-standard を使うようにしていると [[ -o vi ]] などが意図と反する結果になるので良くない。
    |   コマンドを実行する瞬間だけ戻すという手もあるがそれだと
    |   - ^C などで中断した時に set -o emacs に戻す機会が失われて、また応答しなくなる状況に陥るという問題が発生する。
    |   - ユーザが自分で定義した widget 関数の中などではやはり set -o emacs になっている様に見えてしまう。
    |
    |   従って、やはり -m vi-insert に対して設定を行う必要がある。
    |   ところで bind で設定されるのは既定ではどの keymap なのだろうか。
    |   set -o vi の時には vi-insert (vi-command ではなく) だと考えてよいのだろうか。
    |   或いは emacs-standard になってしまうという可能性もある。
    |
    | →vi_insert keymap を導入した。現在は emacs の clone である。動作している。
    |   これから vi_insert としての振る舞いになるように少しずつ widget などを実装していけば良い。

    先に mode の間の切り替えを実装する。

    次に引数を管理する仕組みを考える。

    | 初めは数字の引数を記録する枠組みを作って、
    | それを emacs と共有するようにしようと考えたが、
    | 操作体系を調べると 2d3 なども引数として処理した方が良い様に思われる。
    | というのも d3h d3l などは削除コマンド d に対する細かい動作の制御ではなくて、
    | 移動コマンド h l に対する修飾として働いている様に思われるからである。
    |
    | 引数はどの様に管理すれば良いだろうか。
    | これは単純に引数を記録しておく変数を用意すれば良い気がする。
    |
    | - ble_edit_str ble_edit_ind ble_edit_mark と同様に管理すれば良いだろうか?
    |   引数の入力状態は直接表示の仕方に影響を与えるものではないので
    |   これらと同様に管理する必要はない。
    |   つまり引数が変更されたとしても表示の更新を行う必要はないので、
    |   表示が更新されたかどうかの判定に用いる必要もない。
    | - また各履歴項目に紐付いた物でもないので、履歴を移動した時に記録する必要もない。
    |
    | さてもう一つ考えて置かなければならないのは editing-mode = emacs の時の
    | arg と統一的に扱うかどうかである。emacs の時は arg は唯の整数である。
    | しかし vi の時は上で決定したように d などの文字も含む。
    | ただ結局どのような文字を引数に入れるのかはキーバインディングに依存するので、
    | emacs でも vi でも同様に実装して問題ないように思われる。

    ところで同じ forward-char であっても emacs vi で引数の取り扱いが異なる。
    vi では右端に行ったら次の行には行かないが emacs では次の行に行く。
    従って結局 emacs と vi で別々に forward-char を実装する必要があるのではないか。

    先ずは hjkl について実装した。
    大体の仕組みは整ったので後は少しずつ実装していくだけの気がする。

  * 2017-09-05 vi-mode: forward-line-or-history-next, forward-line-or-history-next [#D0409]

    引数に対応する。そもそも emacs では引数に修飾文字が入らないことを考えると、
    共通で vi の引数の仕組みで実行するようにしてしまって問題ない気がする。
    つまり、現在 vi 専用の引数の仕組みになっているものを emacs にも拡張する。

    と思ったが、forward-line-or-history-next は修飾に対応していない。
    しかし、異なる history entry の間でコピー・切り取りに対応するのは変だ。
    従って、修飾文字が含まれている場合には現在の履歴項目の中での移動に制限するのが自然である。


    forward-line/backward-line において見た目の行を移動するか論理的な行を移動するかが問題である。
    また列も見た目の列を保持するか、論理的な列 (文字数) を保持するかが問題である。
    emacs mode の方では見た目の行を見た目の列を保持して移動する様になっている。

    vim で実際に試してみると一番最後に forward-line/backward-line
    を実行した時の見た目の列を保持している。
    また当然のことながら論理的な行を移動するようになっている。
    論理行が複数行にまたがる時、全角・半角の都合により異なる位置で改行されることがある。
    調べてみるとそのような場合でも "見た目" の列を保持しているようである。
    従って、もし厳密にこの動作に従うのだとすると、
    1. まず初めに論理行頭からの見た目の行・列を取得し
    2. 次に移動先の論理行頭の位置を求め、
      更に論理行頭を保持するということにする必要がある。

    - ble-edit/text/update/positions の問題

      所で、行の内容を変更した後に ble/widget/forward-line を呼び出す時には
      ble-edit/text/update/position を呼び出す必要があることには注意しなければならないのではないか。
      何故なら中で使用している ble-edit/text/getxy.cur などの関数は内部で
      配列 _ble_line_text_cache_pos を参照するがこの配列は ble-edit/text/update/position
      で更新される。ここで手で ble-edit/text/update/position を呼び出すというても考えられるかもしれないが、
      その為には変更範囲 BLELINE_RANGE_UPDATE (中身は _ble_edit_dirty_draw_{beg,end,end0}) が必要で、
      更にこの変更範囲は "描画" や "色つけ" と共有しているので、
      ble-edit/text/update/position を実行するためにはこれらと一緒に更新する必要がある。
      従って現状では途中で _ble_line_text_cache_pos を更新するのは難しい。

      - もし対応させようとするならば ble-edit/text/update/position の dirty range を
        描画の dirty range とは独立に管理する様にしなければならない。

      - 従って現状では変更後に forward-line は呼び出してはならないという制限を設けなければならない。
        安全の為に変更がないということを確認する必要はあるかもしれない。
        このチェックは _ble_edit_dirty_draw_beg=-1 である事を確認すれば十分である。
        →確認する様に修正する。

      [結論] dirty になっていないか確認し、dirty ならエラー。


    - ble-edit/text/getxy と ble-edit/text/getxy.cur の違い

      何であったか。memo.txt を探すと getxy は出力位置で getxy.cur はカーソルの表示位置だという。
      これは一体どういうことか。両者は同じではないのか。
      調べると _ble_line_text_cache_pos[i+1] の第3フィールドが非ゼロの時に、
      getxy.cur は次の行頭を指し示す様になっている。
      % 第3フィールドは左の文字が ASCII 表示文字以外 (isprint 以外) で、かつ、
      % その行に収まりきらない時に、非ゼロになる。
      つまり幅2以上の文字でその行に収まりきらない時に非ゼロになる。

      うーん。getxy は左側の文字の終端位置で、
      getxy.cur は右側の文字の開始位置と解釈すれば良いだろうか。

      考えていたら分かった気がする。先ず右側で折り返す文字は、
      行末の幅を補填する空白が追加される。これにより二行にまたがる文字になる。
      getxy はこの空白も含めた開始位置であり、実際に _ble_line_text_cache_cs を切り出して出力する場合には、
      この位置から出力を開始する必要がある。getxy.cur は実際に空白を除いた文字の本体が表示される位置である。
      実用的には、実際の所 getxy は左側の文字の州単一で getxy.cur は右側の文字の開始位置と解釈して問題なさそうだ。

      [結論] 分かりにくいので getxy, getxy.cur の関数に説明を追加しておく。

2017-09-06

  * ble-edit: 余分な ble-edit/history/load 呼び出しがあったので削除 [#D0408]

2017-09-05

  * ble-edit: .goto-char [#D0407]

    何やら意味のない関数のように思われたが、
    履歴を調べてみると以前は変更があったときのみ set-dirty を実行していた様だ。
    現在はカーソルの位置は別に記録してあるし表示内容の変更と
    カーソル位置の移動は別々に管理しているのでその必要はなくなったのであった。

    さて、ということはこの関数の内容は単純化できる。

  * vi-mode: (()) は bash-3.0 でエラーになる。{ :; } が意味的にも無難 [#D0406]

    →どうやら function f () (()) ならば bash-3.0 でも OK の様である。

2017-09-04

  * vi-mode: ble-edit/bind/.check-detach で編集モード切り替わり判定を行う [#D0405]

    うーん。bleopt_default_keymap=auto のとき、これも一緒に切り替える必要があるのではないだろうか。
    一方で、bleopt_default_keymap を直接指定しているときには一緒に切り替えてしまっては駄目である。
    また切り替えた場合には必要に応じて source keymap/vi.sh などが必要である。

    % うーん。しかし bleopt_default_keymap として auto を許容すると複雑になる。
    % 問題点は bleopt_default_keymap は既に別の用途で使われているということである。
    % その様に考えると bleopt_default_keymap とは別に bleopt_editing_mode のような感じの変数を用意するのが妥当である。
    % →使い方を多少変更した。改名はしないことにした。#D0402 を参照のこと。

    [変更]

    編集モードが変わった時には単に ble-decode-detach してから
    ble-decode-attach すれば良い。ble-decode-detach は前回の attach の際の編集モードで解除を行い、
    attach は現在の編集モードで設定を行うからである。

    また keymap/vi.sh は DEFAULT_KEYMAP から呼び出すことにした。
    既に呼び出し済みかどうかの判定は関数 ble-edit/load-keymap-definition:$name
    を空関数にすることによって設定する。

    vi.sh に関しては vi.sh 内部に widget を定義したいので、
    何れにしても必ず読み込むようにする。
    その場合は keymap の定義の部分のみキャッシュする。
    キャッシュがある場合は vi.sh の中から呼び出す様にする。

    Note: この動作は emacs.sh の場合と異なることに注意する。
      emacs.sh の widget は全て ble 本体の中に定義してあるので、
      emacs.sh でやることは keymap の定義のみである。
      ということはキャッシュがある場合にはそもそも emacs.sh すら呼び出さなくて良いので、
      ble-edit.sh 側の ble-edit/load-keymap-definition:emacs でその操作を定義する。

    実装した。テストした。
    問題が合ったので以下の変更も行った。

    * 変数 ble-bind: ble_bind_keymap の導入

      ble-bind で既定の keymap を指定するのに bleopt_default_keymap を local で書き換えて呼び出していたが、
      現在 bleopt_default_keymap は DEFAULT_KEYMAP を通して呼び出されるものであり、
      keymap/kmap.sh などから定義を探し出す仕組みに組み込まれているので、
      bleopt_default_keymap を任意に書き換えて実行するというのは良い方策ではない。
      従って、新しい変数として ble_bind_keymap という変数を用意した。
      ble_bind_keymap が設定されている場合には DEFAULT_KEYMAP は使用されない。

  * vi-mode: どうやら set +o emacs を検知できない。 [対処不可][#D0404]

    % set +o emacs を含む builtin eval を抜けるとそこですぐに終了してしまうようだ。
    %
    % 一応 set +o emacs を含む builtin eval の中にあるコマンドは全て実行されるようだ。
    % builtin eval の中で細工して一旦 set -o emacs に戻すことによって
    % 後処理をしてその後で抜けるという様にはできるかもしれない。
    %
    % どうやら builtin eval の中に直接 echo を書いたら実行されるが、
    % 関数呼び出しを通して echo を呼び出そうとしても駄目のようだ。
    % 関数呼び出しより後に書いても駄目のようだ。
    % もしかすると .save-params 関数が悪さをしている可能性もある。
    %
    % .save-params でなくて空の関数 function AAA { :; } を使ってみたが同様に駄目だった。
    % 関数定義が見えなくなっているのではないかと思って function AAA { :; } を eval の中に書いてみたが、
    % 関数定義を書いただけでそれ以降は実行されなくなってしまう。
    %
    % と思ったが今度は直接 echo を書いても実行されなくなってしまった。何故?
    % しかし依然として set +o emacs; echo world などとした場合の world は出力される。

    もしかして改行があるかないかが関係しているのだろうか。
    →試してみたらそうだった。何と改行があると駄目なのだ。

    でもそうだとすると実行しようとしているコマンド自体に改行が含まれている場合には、
    それ以降のコマンドは実行されないという事になる。実際に試してみた所そうなった。

    また改行さえ無ければ eval の外も実行されるのかと思いきやそういう訳でもない。

    更に .save-params を改行ではなく ; で区切れば良いのではないかと考えたが、
    それだと "echo ;" などのコマンドを実行した時に ";" の重複により構文エラーになってしまう。

    [結論]

    仕方がないので以下の制限は置く必要がある。

    - ユーザが set +o emacs を実行すると正しく ble.sh から抜けることができない。
    - 更に set +o emacs に続けて改行が含まれる場合にはコマンド自体も正しく実行されることは保証できない。

  * ble-decode: 分離: ble-decode/keymap/resolve-name 関連 [#D0403]

    他に以下のようなものが ble-edit.sh の存在・使用方法を想定している。

    - _ble_decode_key__kmap=emacs の既定値
    - bleopt_default_keymap=auto の既定値

    ble-decode/keymap/resolve-name に関しては外部で関数定義できるようにするのが良い。
    bleopt_default_keymap に関しては元々外部から設定するべきものである気がする。
    _ble_decode_key__kmap=emacs の既定値もその時に同時に指定するべきな気がする。

    →整理した。

    1. ble-decode/keymap/resolve-name は外部から上書きして使う事にした。

      またこれを機に外部から上書きして設定を行うことを目的とする関数を "設定関数" とし、
      またその名前をできるだけ "モジュール/大文字名" の形式になるようにした。
      ここで "モジュール" とは ble-decode などのことである。
      現在以下の設定関数が ble-decode.sh には定義されている。何れも ble-edit.sh で上書きされる。

      - 設定関数 ble-decode/PROLOGUE
      - 設定関数 ble-decode/EPILOGUE
      - 設定関数 ble-decode/DEFAULT_KEYMAP -v varname
      - 設定関数 ble/widget/.SHELL_COMMAND command
      - 設定関数 ble/widget/.EDIT_COMMAND command

      またこれに伴って ble-decode-byte:bind も ble-decode/.hook に改名した。
      使われていない ble-decode-char:bind 及び ble-decode-key:bind は削除した。
      (これらの関数は恐らく初期の実装のときのテストに使われたものであった。)

    2. bleopt_default_keymap は ble-edit.sh 側で管理することにした。ble-decode.sh は関知しない。

    3. _ble_decode_key__kmap=emacs の既定値は ble-decode.sh を単体で読み込んだ時には何れにしても
      (例え動作しないとしても) 何らかの値を設定しておく必要があるので現状通り取り敢えず emacs を設定することにした。
      同様に既定の ble-decode/DEFAULT_KEYMAP も emacs を設定するようにする。

  * vi-mode: bleopt_default_keymap [#D0402]

    % 結局、ble.sh で編集モードに対応しているのは bleopt_default_keymap である。
    %
    % 更に具体的な emacs keymap の定義は ble-edit/load-default-key-bindings から
    % source "$_ble_base/keymap/emacs.sh" を通して読み込まれている。
    % この時 bleopt_default_keymap などは参照せずに直に emacs.sh が指定されている。
    %
    % この辺りは bleopt_default_keymap を参照するようにして良いのではないか。
    % 或いは bleopt_default_keymap は動的に変わったりする物であっただろうか。

    [現状]

    改めて bleopt_default_keymap がどの様に使われているかについて確認しておく。

    - 先ず ble-decode において _ble_decode_key__kmap が空の時の既定の keymap 名として使われている。

      これについては _ble_decode_key__kmap による。調べてみると
      _ble_decode_key__kmap は最初は中身は空のようである。
      先に中身を設定してしまうと、ble の設定箇所で bleopt_default_keymap が変更された場合に対応できないからであろう。
      これに関しては ble-attach のタイミングで _ble_decode_key__kmap=$bleopt_default_keymap を実行するようにすれば良い。

    - また ble-bind において既定の keymap として使われている。

      これは、その時の _ble_decode_key__kmap がどうであれ bleopt_default_keymap に設定を行いたい。

    - keymap/emacs.sh で ble-bind を呼び出す時の bleopt_default_keymap を上書きしている。

    こう調べてみると bleopt_default_keymap は (_ble_decode_key__kmap さえ正しく設定されていれば)
    単に keymap の構築時に使用されるだけであり実際の処理に使われる訳ではない。

    [変更]

    結局 bleopt_default_keymap は改名しないことにした。
    但し特別な値 auto が入っている場合には、実際に bleopt_default_keymap の値を読み出す時に、
    現在の [[ -o emacs/vi ]] の状態に応じて値を解決するというようにした。
    これらの処理は素朴に考えると ble-edit.sh にあるべき気もするが、
    取り敢えず暫定的な実装として ble-decode.sh の方に配置することにした。

  * vi-mode: 次に ble-edit-attach を改修する [不要][#D0401]

    中で何をしているかというと

    1. 先ず初めに ble-edit/attach を呼び出している。

      中ではどうも大したことはしていない。
      attach, detach で PS1, IFS の保存と復元を行っている。

    2. また履歴の再読込の設定を行っている。

    他は特に何もしていない。keymap に関する設定は別の関数で行っている様だ。
    つまり、この関数は何も変更はいらない。

  * 所で set -o vi してから source ble.sh した時に動かなかったというのは何故なのか。 [#D0400]

    % GitHub #1 によるとそのように報告されていた。
    % しかし ble-decode-attach の現状の実装方法で特に問題がないように思われた。どういうことか。
    % これはよく分からないので改めて set -o vi で source ble.sh して動作を確認してみる必要がある。
    %
    % うーん。動いているような気がする。
    % よく考えてみたら set -o vi にしてから source すると死ぬのではなくて、
    % .inputrc に記述して ble.sh つきで起動すると駄目だということだった様にも思う。
    %
    % さて .inputrc に vi を使うという事を指定するにはどうしたら良いのか。
    % http://d.hatena.ne.jp/yamazakiccs/20081207/1216817670
    % → set editing-mode vi と記述すれば良いようだ。
    %
    % さて実際にやってみると特に問題もなく ble.sh が読み込まれている。
    % 変な動作も簡単に見た感じでは現れていない。
    % (もしかすると或る種のキー入力に関しては入力を奪いきれていないという可能性も残っているが、
    % それらの検証は後回しにして良いだろう。)
    %
    % 改めて #1 を読んでみると "無効になる" としか書かれていない。
    % もしかして無効になるとは set -o vi をした時と同様に反応がなくなるという意味ではなくて、
    % 単に set -o vi (の動作) が無効になるという意味なのではないだろうか。
    % だとするとこれには対応していないのだから当然のことである。
    % 実はこれについては対策しなくても良かったのではないかと思われる。

    "無効" というのは #1 の報告者の苛立ちというか "いやみ" が入った表現で、
    実際に動かないということではなかった。気にしなくて良い。

    因みに inputrc に set editing-mode vi とした場合でも、
    ちゃんと [[ -o vi ]] に反映されるので inputrc で指定されたかどうかなどのことは意識しなくても良い。

  * vi-mode: まずは ble-decode-attach を改修する。 [#D0399]

    取り敢えずは ble.sh を起動している最中に set -o emacs/vi が切り替わる場合については考慮しないで良いだろう。
    切り替わった時にするべき操作は別に実装することになるだろうからである。
    そして切り替わった時にするべき操作が具体的に何になるかは、ble-decode-attach の内容に依存する。

    [現状]

    どのような変更が必要になるのか改めて調べるために取り敢えず現在の実装について観察しておく。

    1. ble-decode-bind/.generate-source-to-unbind-default

      先ず初めに現在の bind の状態を調べてそれを .save ファイルに記録する。
      そして ESC に関しては unbind するためのコードを生成する。

      この .save ファイルはキャッシュするような性質のものではなく、
      ble-decode-bind を実行する度に毎回生成するものである。

      これは set -o vi でも同じ動作で問題ないだろうか。
      つまり vi と emacs で .save のファイル名を切り替えなくても良いのではないか。
      一度に両方の keymap を上書きしていると混乱の元だし状態の把握が面倒である。
      一度に片方しか上書きしないのだとしたら同じファイル名でも問題ないように思われる。

      但し、「現在どちらのモードに対して上書きを実行しているか」の状態を管理する変数は別に保持する必要がある。
      これは実際 _ble_decode_bind_attached が担っている。現在は「上書きを実行しているか」「していないか」の2状態だが、
      emacs として上書きしているか vi として上書きしているかの情報を持たせるようにすれば良い。

      →取り敢えず現状のままで問題ないだろう。

    2. 次に source "$_ble_base/bind.sh" を呼び出す。

      ここでは ble_decode_bind.40412.bind (40412 は実際は bash の version) を生成する。
      このファイルの中にはその bash の version において、
      キー入力を全て横取りする為に必要な bind の列が含まれる。

      実はこれについても set -o vi と set -o emacs で違いはないように思われる。
      念のため bind.sh の中身についても確認しておく。やはり vi/emacs に依存する処理は行っていない。

    [変更]

    従って、変更は _ble_decode_bind_attached の管理だけである様に思われる。
    _ble_decode_bind_attached は他に ble-decode-detach が参照している。
    他の箇所からは参照されていない。

    ble-decode-attach ではどのモードで attach したかを記録しておくだけで良い。
    ble-decode-detach では _ble_decode_bind_attached の内容に応じて、
    set -o vi/emacs で attach した時のモードに戻しておいて、
    その状態で bind を復元してから元のモードに戻るようにすれば良い。

    (モードを復元している最中に ^C で中断などが入ると変なことになるがそれは仕方がないだろう。
    ただ簡単に状態を復元する方法というのを実装しておいても良いかもしれない。)

    この変更により ble-decode-detach を呼び出す時の編集モードは気にしなくて良くなった。
    つまり、先の変更により ble-decode-detach を呼び出す前に set -o emacs に戻していたが、
    ble-decode-detach の中で適切な編集モードに切り替えるので、外でその操作をする必要はなくなる。

    取り敢えず変更は実施した。


2017-09-03

  * ble-syntax: here string が here document と解釈されている。 [#D0398]

    これは ble-syntax.sh の .check-delimiter-or-redirect の中の判定の順序であった。

  * 2017-09-01 permission のないディレクトリで補完しようとすると以下のメッセージが表示される。 [#D0397]

    ヒアドキュメント用一時ファイルを作成できません: 許可がありません
    -bash: ヒアドキュメント用一時ファイルを作成できません: 許可がありません

    % TERM に依存して出たり出なかったりする様だ。
    % 現在 tkyntn の上でしか再現していない。
    % 元々 tkyntn は色々とおかしいのでもしかすると他では再現しないのかもしれない。
    %
    % どうも TERM ではなくてログインシェルかどうかで変わるようである。
    % ログインした後に bash として入ると大丈夫である。
    % 一方で、bash --login とすると駄目である。
    % TERM=xterm-256color でも再現することを確認した。
    %
    % どうやら ble の中で起こる問題というわけでもない様だ?
    % bash --norc で入って cd ~yabe して cat <<< hello とするとエラーを吐く。

    更に以下のコマンドだけでエラーが再現する。

    $ bash -c 'cd ~yabe; cat <<< hello'

    これは ble.sh の問題ではなくて bash の問題かもしくは tkyntn の問題である。
    特に tkyntn は最近様子がおかしいので高確率で tkyntn が悪いのであろう。

    % 何れにしてもエラーメッセージがそのまま外部に漏れるというのは変な気がするので、
    % これについては何処かで対策をしたほうが良いだろうか。
    % うーん。どのタイミングでエラーメッセージを無視するのが良いかは微妙である。
    % というよりエラーメッセージをそのまま握りつぶして良いのだろうかという問題もある。
    % もしかすると ble.sh 専用のログファイルを何処かに用意してそこにエラーを出力するようにする方が良いのかもしれない。
    % ただし、もしそうするのだとすると、これは今回の問題だけでなくて ble.sh 全般に関わることなので全体的に整備しなければならない。

    改めて問題になっている ble-complete/source/argument/.compgen の ble/util/assign の中のヒアストリングの周りを見る。
    丁度一つ上の行で 2>/dev/null でエラーをそのまま握りつぶしているので、
    問題になっている行でも同様に握りつぶすという対策で問題ないだろう。

2017-08-30

  * GitHub で Issue が来た。set -o vi の人だ。 [#D0396]

    以下の点について修正する。

    - [[ -o vi ]] の時は ble.sh をロードしない

    - コマンドの実行の結果 -o vi になった時は ble-detach する。

    - ble-detach する時には本来の emacs keymap に対して実行するために
      一時的に現在の編集モードを退避して後で復元する。

      将来的に set -o vi に対応した時には両方で keymap を復元する様に
      ble-detach の中を書き換えるか、emacs/vi mode に拘らず
      常に bash "set -o emacs" の上で ble.sh "emacs/vi" の動作を実装すれば良い。

    - ble-attach の時に [[ -o emacs ]] をチェックする。


2017-08-19

  * ble-edit: C-x C-x で内部的なカーソル位置は変わっているが表示に反映されない。 [#D0395]

    →どうも反映されないというよりは移動前の位置にカーソルが表示される様だ。
    C-x C-x を二回実行すると分かる。これは何故だろう。
    ble/widget/exchange-point-and-mark では単に _ble_edit_ind と _ble_edit_mark の内容を交換している。
    その他の箇所からはこの関数は参照されていない。という事はこの関数の問題というよりは表示の問題だろう。

    そもそもカーソル位置の更新は何処で実行されているだろうか。
    ble-edit/render/update が怪しい。この関数の先頭で _ble_edit_ind/_ble_edit_mark
    がどのような状態になっているか確認する。
    どうやらこの関数を呼出した時点では _ble_edit_ind 及び _ble_edit_mark は更新前の値になっている様だ。

    % もしかして exchange-point-and-mark が呼び出されていないのでは? と考えたが、
    % 実際に入力すると期待する位置に文字が挿入されるため、exchange-point-and-mark は呼び出されているはずだ。
    % もしかすると bash が入力を食らっていて C-x C-x をユーザ側で入力しても未だ処理されていないのかもしれない。
    % しかしそうだとすると C-x C-x を入力した時に ble-edit/render/update がちゃんと2回呼び出されている事と矛盾する。
    % よくわからないので exchange-point-and-mark の中で鳴く様にしてちゃんとこの関数が呼びだれているか、
    % 呼び出されているとすればどのタイミングで呼び出されているかを確認する。

    →どうやら exchange-point-and-mark が呼び出されていない。
    疑わしいのは decode の方である。もしかすると C-x C-x ? の様な形のコマンドが登録されてしまっているのかもしれない。
    或いは ble-decode が壊れていて C-x ? の様な形のキーシーケンスがその場で呼び出されない可能性もある。
    →これについては C-x C-v が即座に実行される事から考えにくい。
    何れにしても C-x C-x ? の様な紛らわしいコマンドが登録されていないかを確認する必要がある。

    →ble-bind -d で確認してみた。C-x C-x が曖昧になるようなキーシーケンスは登録されていない。
      と思ったら ble-bind -k 'CAN @ h' などが怪しい。CAN は C-x に一致するはずなので、
      バイト C-x が単体で来た状態の場合にはそれがキー C-x なのかキー hyper, etc. なのかの判断が付かない。
      これが怪しい。これについては試しに CAN @ の bind を削除してみれば分かる事である。

    取り敢えず "CAN @ ?" を削除してみたら動くようにはなった。
    しかしそれでも微妙な遅延が見られる。emacs では遅延がないのでこれは端末の設定だろう。
    少し stty 周りを見ても分からないし大きな問題でもないのでこれは後回しで良いだろう。

  * [2017-06-12] ble-edit: 選択した状態で self-insert したら選択した範囲の文字列は消えてほしい。 [#D0394]

2017-06-09

  * bash-4.2 で何か入力しようとすると segfault する。 [#D0393]

    初めは mathieu の上で気付いたが padparadscha でも再現する。
    bash-4.0, bash-4.1, bash-4.3, bash-4.4 では大丈夫。
    これは bash-4.2 の算術式のバグを踏んでいる可能性が高い。

    grep で '],' を探してみる。
    2015-02-23 04:46:57 ble-edit.sh:1286:     if ((ichg=old_ichg[j],
    2017-03-01 10:09:47 ble-syntax.sh:1401:         ((_ble_syntax_attr[i++]=_ble_syntax_attr[inest],

    二つ目が怪しい → 修正したけれど治らない。
    これはクラッシュする箇所を少しずつ絞り込んでいくしかない。
    怪しいのは self-insert の前後と、描画部分である。
    しかし、描画部分に関してはプロンプトは表示されているのだから、
    大体大丈夫なのではないかという気がする。
    或いは文法に従った着色の部分が怪しいか、文法の解析部分が怪しいか。
    一番怪しいのは文法周りなので、先ずはそこを囲んで print してみる事にする。

    ble-syntax/parse を呼び出しているのは function _ble_edit_str.update-syntax だけである。
    _ble_edit_str.update-syntax は ble-syntax.sh:3830 と complete.sh から呼び出される。
    complete.sh は今回の場合は使っていないので、これは関係ない。
    ble-syntax.sh では関数 ble-highlight-layer:syntax/update から呼び出している。
    更にこれは ble-edit.sh の関数 ble-edit/text/update から
    ble-highlight-layer/update を呼び出しているのが引き金になっている。
    更に呼び出し元は ble-edit/render/update である。
    取り敢えずこの関数で echo をしてみる事にする。

    -> ble-edit/text/update の中で起こっている
    -> ble-highlight-layer/update の中で起こっている
    -> ble-syntax/parse の中で起こっている
    -> ble-syntax:bash/ctx-command の中で起こっている
    -> ble-syntax:bash/ctx-command/.check-word-begin の中で起こっている
    分かった。(((wtype=_ble_syntax_bash_command_bwtype[octx])||(wtype=ctx))) だ。
    修正したら大丈夫になった。念のため、類似の危険な箇所がないか確認する。

    $ grc '\]\)[^)]'

    ./ble-core.sh:713:      if (((time2[0]-time1[0])*1000+(10#0${time2[1]::3}-10#0${time1[1]::3})>=msec)); then
    ./ble-syntax.sh:720:    ((onest[3]<0?(parent_inest=onest[3]):(parent_inest-=onest[3])))
    ./ble-syntax.sh:2585:      (((klen=stat[k])<0)) && continue

    bash-4.2 のバグは式の構造だけに依存しているので、文脈によらずに実際のその式を実行してみれば良い。
    現に問題になっていた式をそのまま bash-4.2 の対話シェルから実行してみると segfault が再現する。
    上で見つかった物についてチェックする。1つ目の式構造は大丈夫だった。2つ目も大丈夫。3つめも大丈夫。OK

    因みに一番最初に見つけて修正した ble-syntax.sh:1401 についても bash-4.2 はクラッシュした。
    結局 2 箇所修正が必要だったという事である。

2017-05-20

  * ble を再度 source すると history を再度読み込む様になるのは何故か。 [#D0392]
    既にロードされている時は無視するのではなかったか。

    恐らく ble-attach を呼び出しているせいである。
    既に ble-attach されている状態で再度 ble-attach している場合何が起こるのか。
    現在は状態のチェックを行っていないがこれには理由はあっただろうか。

    ble-decode-attach は内部で現在の状態を記録しているので
    重複して呼び出しても実際には処理は実施されない。

    ble-edit-attach は内部でのチェックは行っていない。
    ここで history の情報を初期化しているので、
    これが原因で再度読み込む様になっているのだろう。
    history を再度読み込む必要があるのは、
    detach している間に実行したコマンドがあるかもしれず、
    その為に history と ble の管理している履歴情報に
    ずれが生じているかもしれないためである。
    なので既に attach しているかどうかの情報を保持する必要がある。

    ble-attach 自体で既に attach しているかどうかの情報を管理する様にしたい。
    既に _ble_edit_detach_flag という変数がある様だがこれは何のために使っているのだろう。
    →これは次にキーに対する処理が終わる時にシェルを終了するかどうかを管理するのに使う。
      通常時は常に空欄になっている変数である。この変数は使えない。
    従って新しい変数を導入する必要がある。ble-decode-attach と同様に管理すれば良いだろう。
    そして ble-decode-attach の使っている変数 _ble_decode_bind_attached は単純に局所的に
    使われているだけであるのでこれで問題ないだろう。


2017-04-21

  * [2017-04-15] bash-4.4: C-x ? のキーバインドができなくなっている? [#D0391]

    bash-4.2 以下と同様に C-x ? だけ特別に処理する様に戻した。
    結局、C-x ? に特別な処理が必要ないのは bash-4.3 だけということであった。

2017-03-13

  * [2017-03-11] LANG=C./a 等の様に locale に変な文字列があると毎回エラーメッセージが表示されてうるさい。 [#D0390]
    エラーは抑制するべきではないか。

    概ね、LC_COLLATE=C command &>/dev/null とすれば良い様だが、
    function ble/util/is-stdin-ready { IFS= LC_ALL=C read -t 0 &>/dev/null; }
    としてみたが LC_ALL に変な値が入っている時のメッセージは抑制できなかった。
    function ble/util/is-stdin-ready { IFS= LC_ALL=C read -t 0; } &>/dev/null
    の様にすれば大丈夫だった。

    # そもそもの問題として read -t 0 の仕様として
    # IFS や LC_ALL を設定する必要があるのかどうかは分からないが。

2017-03-05

  * complete.sh: bug 補完対象に ` \n \t が含まれる場合にエスケープされていなかった。 [#D0389]

  * ble-core: ble_util_upvar_setup で local ret するべきなのでは。 [#D0388]
    ble_util_upvar で $ret を参照しているので。

    調べてみた所、全ての ble_util_upvar_setup 使用箇所で結局 local ret を宣言している。
    また、ちゃんと ble_util_upvar_setup は ble_util_upvar と対になって使用されている。
    従って local ret を ble_util_upvar_setup の中に入れるのが適切である。


  * syntax: ヒアドキュメント: << <<- の違いや EOF 'EOF' の違いが働いているかどうか確認する。 [#D0387]

    <<- が効いていない。というか nparam のフラグが I になっていない。
    と思ったら参照している ctx が nest-pop 後の ctx だった。
    nest-pop 前の ctx を octx に保存して、その octx を用いて判定する事にした。

    EOF と 'EOF' の違いに関してはちゃんと期待通りに動いているので良かった。

  * color: 古い仕組みの layer とそのアダプターの機能は流石に削除してよいのではないだろうか。 [#D0386]

    ble-syntax-highlight+* 云々という関数は全て古い仕組みである。
    また変数 bleopt_syntax_highlight_mode は古い仕組みに置ける highlighter 選択の為に用いられる。
    これらの仕組みはアダプター ble-highlight-layer:adapter/* から参照され、
    アダプターは _ble_highlight_layer__list=(plain adapter) 等とする事で登録される。

    一方でアダプターは zsh 方式の highlighter を import するのにも使えるのではないか?
    という気がしないでもない。これ自体そんなに長いコードでもないので残しても良いかもしれない。
    しかしその様に考えると実装例も一緒に残しておいた方が良いという事になり、
    結局古い仕組みも残しておくという事になりはすまいか。
    だとすれば思い切って此処で捨ててしまうのの方が良いようにも思う。

    うーん。highlighter のサンプルとして別ファイルに残しておくという手もあるかもしれない。
    というかそれが良いような気がしてきた。

  * IFS guard [#D0385]

    所でよく考えてみたら IFS をユーザが変更した場合には色々と大惨事が起こるのではないか…
    bind 及び exec の部分でちゃんと local IFS=$' \t\n' を設定する様にしなければならない。
    →試してみた所やはり大変な事になる…。これは後で最優先で対処しなければならない。

    何処で対処するのが良かろうか。
    例えば関数内で local IFS= を設定する様にするというのが一つの手である。
    もう一つはコマンドを実行する直前に IFS を戻して、
    コマンドを実行した直後に IFS を保存するという様にする方法である。

    シグナルハンドラを設定する場合はどうだろうか。
    シグナルハンドラの中ではユーザの設定した IFS が見えて欲しい。
    そういう事を考えると local IFS= が良い様な気がする。
    一方で exec:exec では結局 IFS を保存・復元しなければならない。
    実際の所シグナルハンドラの中にいる時は LINENO 等の値も変な物になっているので、
    IFS だけに拘っても仕方がないかもしれない…と言いつつ IFS は影響範囲が大きいので
    やはりシグナルハンドラの中であってもユーザの期待する物になっているべきである。

    うーん。以下の項目について対処すれば良いだろう。

    - 関数内で local IFS= を設定する。
      1. bind から呼び出される関数
      2. _ble_decode_bind_hook から呼び出される関数
      3. シグナルハンドラから呼び出される関数
        → これは trap を検索すれば良い。
      4. 初期化時に呼び出される関数 (ble-attach 及びロード時に強制的に実行する関数たち)
        →これは漏れがあると行けないし汚くなるのが嫌なので、
          ble.pp で IFS を保存して自分の物に設定し最後に復元するというので良いだろう。
    - exec:exec では IFS の保存・復元を実行する

    [書き換え]

    - ble-decode-byte:bind
    - ble-edit/exec:gexec/.begin
    - ble-edit/exec:gexec/.eval-prologue
    - ble-edit/exec:gexec/.eval-epilogue
    - ble-edit/exec:gexec/.end
    - ble-edit/exec:gexec/.eval-TRAPDEBUG
    - ble-attach

    以下の関数は明らかに影響がないので IFS の設定は省略する。
    - ble-stty/TRAPEXIT
    - ble-edit/exec:gexec/.eval-TRAPINT
    - ble-edit/exec:exec/.eval-TRAPINT
    - ble-edit/exec:exec/.eval-TRAPDEBUG
    - ble-detach

    ble.pp では ble/.check-environment の直前で IFS を設定し、
    ble-attach の直前で IFS を復元する。

    exec:exec は関数内でユーザコマンドを実行するため IFS を復元・保存しなければならない。
    _ble_edit_PS1 と同じ箇所で同様に復元・保存すればよいだろう。
    但し ble-edit/attach, detach に関しては bleopt exec_type=exec の場合のみに
    _ble_edit_IFS への保存と復元を行う事にする。

    - ble-edit/attach 保存
    - ble-edit/detach 復元
    - ble-edit/exec:exec/.eval-epilogue (保存)
    - ble-edit/exec:exec/.eval-recursive (復元)

    取り敢えず動いているので良い事にする。
    未だ何処かに漏れがある可能性もあるが、
    IFS に変な値を入れる人もそんなにいないだろう。

  * memo.txt: 項目に番号を振っても良いのではないだろうか。 [#D0384]

    過去の項目について参照する機会も度々ある。
    少なくとも Done に送られた項目に対して番号を振るというのはありなのではないだろうか。

    いま確認してみると比較的複雑な問題解決に関しては、ごく初期の頃に X1-X6 の番号を振って記録している。
    しかしより単純な物については番号が振られていないし、また X1-X6 の番号づけもすぐに廃れている。
    今度改めてこれらを整理し、大小に拘らず番号を機械的に振っていくというので良いのではないだろうか。
    また過去の記録の形式と現在の記録の形式を合わせるというのにも役立つ。

    取り敢えず番号を付けた。この項目は #D0384 である。

  * syntax: select name [in ...]; do ... done [#D0383]

    考えてみたら select には対応していなかった。

    試してみると select name do ...; done の形式でも OK の様だ。
    また select name; { ... } の形式も可能である。
    マニュアルには書かれていないが。
    実の所 for と殆ど同じである。
    違うのは単語が一つ以上必要という事と、
    for ((;;)) の形式がないという事である。

  * syntax: bug 6b84ee7 の修正はバグである。元々 CTX_ARGX0F という特殊な文脈値を用いて [#D0382]

    特別に { を受け付ける様にしていたのであった。なので、CTX_CMDXE にするのではなくて、
    CTX_ARGX0F の処理の方で do も受け付ける様に修正するべきであったのである。

    と思って CTX_ARGX0F の方で { に一致しなかったら CTX_CMDXE にする様にしてみたが、
    いろいろ考えて見るに CTX_CMDXE と同様に処理する CTX_CMDXD という物を用意する方が良いという事になった。
    結局 CTX_ARGX0F を CTX_CMDXD という名前に改めて実際の文脈値として取り扱う事になった。

  * syntax: ヒアドキュメント (here documents) 対応 [#D0381]

    > * [2015-02-16] ble-syntax.sh ToDo
    >
    >   - Here document
    >     Here document は次の行から始まるというのが厄介である。
    >
    >     一旦始まってしまえば Here Document の処理は比較的簡単であろう。
    >     <<EOF の形式では $() 及び `` だけ特別に処理を行えばよい。
    >     <<'EOF' 等の形式ではそのまま EOF を探せばよい。
    >
    >     始まる迄は何処かで待ちになっている HEREDOC の情報を記録する必要がある。
    >     そして改行が現れた際にヒアドキュメントを開始するのである。
    >     ヒアドキュメントは quote の中などでは始まらない。
    >     結局 CTX_CMD, CTX_ARG 等で改行が来た時にヒアドキュメント開始を調べる感じだろうか。

    [考察]

    何処に開始待ちになっている HEREDOC を記録するか。新しい変数を導入するのか。
    或いは、既存の変数またはネストに記録を行うのか。

    a ネストに記録するのだとすると新しく HEREDOC を導入する為だけに新しいネストを
      導入しなければならない。文法構造の変化がどの様になるかはちゃんと考えていないので分からないが、
      本来あるべき構造と離れるために変なことになりそうに思うのでこの方法は良くない。

    b だとすると新しい変数を導入して状態を記録するしかないように思われる。

    因みに現在使っている変数としてどの様な物があるか改めて確認してみる事にする。
    結局 stat (ctx wlen wtype nlen tclen tplen) に格納される情報が全てである。
    その他の情報は復元の対象にならないから、これに依存した解析にはできない。
    stat の各要素に対応する変数は実際には関数 ble-syntax/parse/generate-stat にて
    変数 ctx wbegin wtype inest tchild tprev から生成される。

    ctx wbegin wtype 等はヒアドキュメントとは異なる寿命を持つ構造なのでこれにヒアドキュメントの情報を格納する事はできない。
    inest tchild tprev は何れも位置を表す変数であるからこれにヒアドキュメントの文字列を格納する事もできない。
    ただ、文字列を格納する代わりにヒアドキュメントの word の位置を記録するというやり方もある。
    その方がシフトも簡単だろう。更に、入れ子構造も考慮に入れて改行が現れたらヒアドキュメントを開始するという事にするのだとすれば、
    tprev と同様の取り扱いにするのが良いようなきがする。シフトについても tprev と同様で良いのではないだろうか。
    やはりこの様に考えてみると解析用の変数を追加する事は免れない。

    a 新しい変数の値を文字列で記録するのだとすれば shift の必要性はない。
      また、後々にヒアドキュメント以外の情報を格納したくなった時の拡張も比較的簡単にできる様になると思われる。
      同じ変数の中に文字列として連結して情報を格納できるからである。

    b もしヒアドキュメントの単語の位置を記録するのだとすれば shift は tprev と同様にすれば良い。
      しかしよく考えてみれば単語の内容に依存するのであるから stat が一致しているかどうかを判定するために、
      その位置にある単語の内容に関しても一致するかどうか判定しなければならなくなる
      (丁度 inest から nest を辿っていって全て一致しているかどうかを確かめる時の様に)。
      更に毎回単語を読み取ってそこから終端の記号を確認しなければならない。大変である。

    この様に考えると直接文字列で保持するのが良い。単語の内容に依存した参照である必要は全くない。

    | 実は nest もこの様に保持するという手があったかもしれない。ただそれだと複雑なネストの場合に、
    | ネスト構造を記録する変数の内容がどんどん長く・複雑になっていくという問題があったという事だろうか。
    | 或いは、ネスト構造を判定する度に情報を毎回抽出するのが面倒?という事だろうか。
    | しかし、思うに nest で重要なのはその時点での状態だけであって、
    | nest の開始位置というのは実はそれ以降の解析に影響を与えない。
    | 更に shift の必要もないし、やはり nest も文字列情報として記録したほうが良かったのではないかという気がしてくる。
    | 現在 nest 構造を記録する度に 7 つの変数を記録しているが、
    | 別に一回の nest で 7 個ずつ変数を使うというので問題ない気がする。
    | うーん。これに関しては以下で考察を与える:
    |
    | cf. #D0377 "2017-03-04 syntax: [考察] _ble_syntax_nest の取り扱い。"

    さて変数を追加する場合には何処を修正しなければならないだろうか。
    先ず stat と nest のフィールドの数は増加させなければならない。

    nest に関しては _ble_syntax_nest を参照している箇所を確認すれば良い。
    stat に関しては沢山ある…。
    面倒なので先に変数を増やししまってから少しずつ変更していく事にする。

    新しく増やす変数はどの様な名前にするのが良いだろうか。

      現状の考えでは nest level に固有の文字列であり、
      nest-push すれば空になり、nest-pop すればまた復元するという物を考えている。
      (この様な動作は、将来的な do done や { } の対応を取る場合にも都合が良いだろう。)
      従って、その事を反映して n* という名前にするのが良さそうである。
      解析途中状態を記録するための一般の変数名として良いのは何だろうか。
      例えば Emacs の font-lock では文章中に text-property を設定できて、
      その text-property を様々な解析状態の記録に利用する事ができる。
      Visual Studio の AddIn を作る場合 (着色を設計する場合) はどうであっただろうか。
      これは行毎に何らかの値を保存できる様になっていたはずだが変数名までは覚えていない。
      しかし何か System.IntPtr だった様な気もする。LPARAM, WPARAM の様な物だろうか。
      その様に考えると nparam という名前で良いような気がしてきた。

    →nparam にする。

    [実装]

    1 変数の追加

      nparam という変数を導入すると共に先ずは stat 関連の修正を行う。
      比較的変更は少なくて済むような印象である。
      基本的には初期化の部分、ble-syntax/parse/generate-stat の修正と、
      ble-syntax/parse/shift.stat をすれば動作する。
      更にデバグ用の出力のために ble-syntax/print-status/stat.get-text
      (今回 stat の内容を文字列化する処理の部分を切り出して作った関数) を修正すれば良い。
      nest に関しても同様でそんなに大局的な変更は必要ないようである。
      つまり、nest-push, nest-pop, nest-type を抑えれば良い様だ。
      nest-type の実装を考えると ntype は一番最後の引数にするのが良い。
      だとすると nparam='' の時に nparam を記録する際には何か代替になる値を指定しなければならない。
      ntype と統一するのであれば none という値にするのが良い。格納する時と取り出す時に気をつければ良い。

      →取り敢えず nparam という解析状態変数の追加と stat/nest の変更は完了した。

    2 次に here documents 指定があった場合に nparam を設定するコードを追加する。

      これは特別な文脈値 RDRH を導入して処理する事にする。
      RDRH の単語の終了時に nparam を設定する。

    quote した時に指定する事のできる文字列

      | 所で here document の quote で空白を含む文字列を指定した場合はどうなるのか。
      | →試してみた所、何と delimiter に空白を含ませる事も可能な様だ。
      | もっと色々試してみるとセミコロンなども含める事ができる。
      | stat や nest に格納する場合には空白類は含められない。
      | という事は nparam に設定する際に空白類はエスケープしなければならない。
      | 或いは stat や nest に設定する時にエスケープをするか。
      | stat/nest に設定する時にエスケープをするというのだと色々の箇所で対処をしなければならず面倒である。
      | なので初めから nparam には空白類が入らない様に構成する方が現実的である様に思う。
      |
      | 更に delimiter に改行が含まれていると、
      | 2行に渡って delimiter を指定したとしてもそれには引っかからず
      | 最後まで here documents が終わらないと解釈され、警告が出る (でも警告なのでコマンド実行は為される)。
      | つまり delimiter の判定をする際には行毎に切って、
      | その上で期待する delimiter との比較を行わなければならない。
      | これは step3 で処理する。

      まとめると、何でも指定できる。
      空白を含める事もできるし改行を含める事もできる。
      但し、改行が含まれている場合には決して終端に一致する事はできない。
      どうやら終端文字列は行毎に判定される様だからである。

      nparam に delimiter を格納する為にはエスケープが必要になる。

    here documents word の bash の解析方法の確認

      | 然し、本当に bash は $ を特別扱いしないという様な parse の仕方をしているのだろうか。
      | もしかすると通常通りに parse してその上で一番外側の "" だけを除去するという事をするのかもしれない。
      | その場合にはまた一層処理が面倒である。と思って試してみた。
      |
      |   << "$(echo "lll")"
      |
      | の様に指定すると終端の文字列として '$(echo lll)' を要求する様だ。
      | つまり予想通りに $ を認識していないという事になる。多分。もうひとつ試してみる。
      |
      |   << "$(echo "(lll)")"
      |
      | もし入れ子を認識していないのであれば裸の () が現れるのでエラーになるはず。
      | もし入れ子を認識しているのであれば構文エラーにはならずに '$(echo (lll))' 全体を終端文字列として要求するだろう。
      | →何と '$(echo (lll))' を終端文字列として要求して構文エラーにはならなかった…。
      |
      |   << ""(lll)""
      |
      | で試すとちゃんと構文エラーになる。つまり、ヒアドキュメントの word には () が指定できる等ということでも無いようだ。
      | つまり、これらの動作から推測するに bash の解析は、先ず初めに $() の入れ子なども考慮に入れて解析を行う。
      | その後で $() の置換を実行せずに字面でクォート除去に進む。という事なのだろう。
      | だとすると解析時とクォート除去時で不整合が生じる様なケースを人為的に作成する事ができる様な気がする。
      | 試してみる。
      |
      |   << "$(echo "'")"
      |
      | これを実行したらエラーにはならなかったが終端文字列として '$(echo ()")"' という物を要求する様になった。
      | つまり ' の終端が欠けている形と見なされている様だ。この動作は先程の bash の動作の推測と合致する。

      まとめると bash はコマンド置換などの入れ子も考慮に入れて解析を行うが、
      最終的には入れ子構造は無視して字面で quote 除去を実行する。
      中途半端な '' "" などの quote があった場合には最後まで囲まれていると見なす。
      除去する quote は \? '' "" $'' $"" である。

    うーん。入れ子も考慮に入れた解析は実はそんなには難しくないような気がする。
    結局のところ $( が来たら対応する括弧 ) まで読み飛ばすという様に実装すれば良いのだ。
    内部の細かい文法規則まで追跡する必要はない。
    最終的には専用の文脈値を用意するという方針で行くのが良い様に思う。
    現状では、もっと素朴な実装をしてしまった。通常の RDRS と同様の実装に戻す事も可能であるが
    勿体ないので暫定的に現状の実装で進める事にする。

      もっと bash で試してみると

        << $(echo ${hello/)/))}) → 終端文字列 '$(echo ${hello/)/))})'

      という事になった。つまり、(1) quote が全然なくてもちゃんと入れ子を含めて単語を認識している。
      (2) $() の括弧の入れ子だけではなくて ${} の入れ子についても追跡をしなければならない。
      これを考えると従来の方法で解析しておいた方がやはり良いのかもしれない…。

      後で折を見て従来の方法に戻す事にする。
      取り敢えずは here documents の対応を完成させる事を目指す。

    % さてここで一つの懸念に思い至った…こうした複雑な解析の結果を nparam に指定した後で
    % 保存されてそれから shift が起こった時に変な事にならないかという事である。
    % これは考えて見るに大丈夫である。というのも結局はやはり過去の情報しか参照していないという事。
    % そして shift などが起こって word の内部で更新が起こったとしても、
    % 結果として起こるのは nparam の不位置に依る stat の不一致であり、
    % "解析が殆ど全部やり直しになる" という事以外の問題点は発生しない。
    % 解析がやり直しになることについては here documents である以上は避けられない事なので気にしなくて良い。
    % →気にしなくて良い。

    2.1 quote 除去も実装しなければならない。

      →ble-syntax:bash/ctx-heredoc-word/remove-quotes に実装した。
      簡単にテストを実行してみる。
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes fire; echo $delimiter
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes "\"\$(echo \"(fire)\")\""; echo $delimiter
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes "\"\$(echo \"(fire)\")"; echo $delimiter
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes "\"\$(echo \"(')\")\""; echo $delimiter
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes '\[\$hello\`\]'; echo $delimiter
      NG ble-syntax:bash/ctx-heredoc-word/remove-quotes '"\[\$\"\`\\\]"'; echo $delimiter
        変だ。\$ (など) が $ (など) にならない
        → OK str=${str//"$b"/$a} の様にしなければならなかった。修正した。
      OK ble-syntax:bash/ctx-heredoc-word/remove-quotes 'hello$'"'\e[1mthis\e[m'"'world'; echo $delimiter

      取り敢えず良さそうである。

      追記: 終わっていない "" or '' で中途半端な \ が末尾にある場合にはどういう扱いになるのだろう。
      試してみると…。

        $ eval 'echo << "$(echo '\''"\'\'')"\'
        bash: 警告: ヒアドキュメントの 10 行目でファイル終了 (EOF) に達しました (`$(echo '')' が必要)
        $ ble-syntax:bash/ctx-heredoc-word/remove-quotes '"$(echo '\''"\'\'')"\'; echo "$delimiter"
        $(echo '')\

      bash の振る舞いとしては終わっていない \ は消えてなくなる様である。
      一方で、現在の remove-quotes の実装だと \ が残ってしまう
      →直した。

    2.2 nparam に設定する時の escape を実装する。

      どの様にエスケープするのが良いだろうか。
      先ず除去しなければならないのは空白類である。つまり、空白・タブ・改行である。
      更に nparam 自体のフィールドセパレータも考慮に入れなければならない。
      今まではコロンをセパレータに使おうと考えていたが…。

      また復元する時に簡単にできる様にするには \\ でエスケープして
      $'' で戻すという様にするのが良いかもしれない。
      パラメータ展開の置換 ${var//a/b} を繰り返すよりは、
      一回 eval を実行してしまった方が早かろう。
      ただ、変な文字が含まれていない限りはエスケープは必要ないので、
      変換方法についてはそんなに気にする事もないかもしれない。
      然しながら何れにしても必ずエスケープ表現は定めなければならないので、
      \ でエスケープする様にすれば良いだろう。実際に復元を行う場合に、

      a if [[ $str == *\\* ]]; then str=${str//a/b}; ...; fi
      b eval "str=\$'$str'"

      のどちらが良いのかというのは表現方法に関係なく選択できる。
      但し b を選ぶとすると追加で ' もエスケープしなければならない。
      しかしそうだとしても b の方が良い様な気がする。

      また nparam 自体のフィールドセパレータに関しては、
      完全に変換を行って除去しなければならない。
      例えば 8 進数表現にするなどの方法で。
      しかし例えばコロン : を使うとなるとその 8 進表現が何であるかを確認する必要が出てくる。
      適当に ASCII C0 の FS 等を使うというのでは駄目なのか。
      しかし FS だって実際の描画文字と被るかどうかわからない…と言いつつ C0 領域が ASCII である
      事を仮定した様なコードは既に ble の中に沢山ある。という事はやはり FS で良いか。
      でも、一方でコロンの 8 進表現だって ble/util/s2c を使えば簡単に計算できる。
      何処かにキャッシュしておけば良い。或いはもう ASCII を仮定してしまっても良いかもしれない。
      うーん。まあ、取り敢えず FS を使うという方針で行くことにする。
      →FS は \034 である。もしくは ^\ である。term.sh に _ble_term_fs として追加する事にした。

      実装した。関数 ble-syntax:bash/ctx-heredoc-word/escape-delimiters である。

      更に nparam への値の設定も行う。
      ble-syntax/print-status/stat.get-text での FS のエスケープも実装する。
      ble_debug=1 bash で確認する限り、期待通りにエスケープ・nparam への設定が動いている様子である。


    3 コマンドの解析の文脈で改行が来た時に nparam に here documents が指定されていれば
      here documents の文脈値に移行する。

    3.1 先ず初めに here documents の文脈値を実装しなければならない。

      取り敢えず実装した。nparam として専用の特別な形式の値を持たせる事にした。
      ここにヒアドキュメントの属性や終端文字列を格納する。

    3.2 改行で CTX_HERE0 に入る様にする。

      これは ctx-command だけで良い?

      どのタイミングでヒアドキュメントが始まりうるのかを確認しなければならない。
      先ず \<newline> でヒアドキュメントが始まる事はない。
      ${} $() $(()) の内部で始まる事もない。
      配列の arr=() の中では始まる。

        ```bash
        cat <<EOF; \
        echo line2 ${hello#
        } line2b $(
        echo line2c
        ) $((
        1+1
        ))
        hello test1 world
        EOF
        ```

      多分、ctx-command と ctx-values で対応すれば良い。
      取り敢えず ctx-command の中を見てみる。
      ble-syntax:bash/ctx-command/.check-delimiter-or-redirect で改行を処理している。
      この関数の呼び出し元は ble-syntax:bash/ctx-command だけなので
      此処でそのまま here documents に突入して問題ないだろう。

    3.3 後は ctx-values でも同様に処理すれば良い。

      と思ったら問題が生じる。ctx-values は入れ子レベルを形成する。
      入れ子レベルを形成するのは復帰時にまた元の文脈に戻る為である。
      元の文脈は 2 種類存在する (VRHS 及び ARGVI)?
      この2種類の対応する VALX, VALI を導入しても良いが、別の方法を取る。

      nest-push nest-pop の際に nparam を持ち越す様にする。
      そのままだと規約が分かりにくいので enter/leave という関数を作って、
      それを介して nest-push nest-pop を行う様にする。

      取り敢えずは動いている様子である。

    取り敢えず動いているので、初期実装として一旦保存する事にする。

2017-03-04

  * syntax: bug: } fi done 等の直後に ; を置けなくなっている。 [#D0380]

  * syntax: 実は for name do ...; done という形式も可能の様だ。 [#D0379]

  * syntax: 実は for (()) の直後に do が来ても良いようだ。 [#D0378]
    http://qiita.com/yz2cm/items/bc5726e8aef0f2e6906e を見て気付く。

    for ((i=0;i<10;i++)) do echo $i; done
    一方で while(()) の直後は駄目。

    for (()) の直後だけは特別な文脈と考えるのが良さそうだ。
    while { true; } do done の } の直後と同様の文法的な取り扱いなのであろうか。
    取り敢えず fi を指定した時のエラーメッセージを観察してみると同じである。

    文脈的には do しか来てはならない所を他の一部のコマンドも許すというのは変かもしれないが、
    ((;;)) を抜けた直後の文脈は CTX_CMDXD という事にする。

  * syntax: [考察] _ble_syntax_nest の取り扱い。 [#D0377]

    実は nest 構造を一つの文字列にまとめてしまった方が解析が楽になるのではないか。

    - 現在は inest の情報を頼りに stat を比較する度に nest 構造を掘り出している。
      しかしそれなば flat に一つの変数に情報を詰め込んでも良いのではないだろうか。

    - shift についても複雑な処理を行う必要はない。というか shift の必要はない?
      入れ子構造の保持には shift の必要はないが、よく考えてみれば
      単語の位置などの木構造を構築するために nest の中に単語の開始位置などの情報も記録されている。
      これらを shift する必要がある。寧ろ inest の shift だけで良かった所が
      現在の全ての nest 階層でのシフトが毎回必要になる。寧ろ面倒になる可能性がある。

    - 以降の解析に影響を与えるのは nest 構造の中身だけであって inest は関係ない。
      言い換えれば、影響をあたえるのは現在どの様な入れ子になっているかの情報だけであって、
      現在の入れ子構造がそれぞれ何処で開始したのかという情報は関係ない。

    考えて見るに、初めから nest 構造を一つの文字列にまとめて実装したほうが簡単だったかもしれない。
    一方で、shift の取り扱いなどで余計なコストがかかる様になるので、
    既に nest を inest で実装する様にしてしまった現状、
    既存のコードを捨てて nest 構造を一つの文字列にまとめる様に書き換える利点はないように思われる。

2017-03-02

  * syntax: } の直後には then else elif do も来て良い。 [#D0376]
    但しこれらの直後は文脈はそれぞれの物に変化する。

  * [2016-08-06] syntax: extquote と "${}" の入れ子に関して [#D0375]
    [cf memo/D0375.quote-in-param-expansion.sh]

    "${var# ... }" などの中の '' $'' $"" は無効になる。
    では "${var:-${var: ... }}" などの入れ子になっている場合はどうなのか?
    現在の実装ではこの様な入れ子の場合には quote が有効になってしまっている。

    | どの様な状況で '' $'' $"" が無効になるのか、入れ子になっている場合も含めて調べる。
    |   少なくとも echo "${x:-${arr:'1'}}" の quote '1' は無効 (つまりそのまま "'1'" として解釈される) のようだ。
    |
    | より厳密な判定方法について調べる。
    |
    | $ hello=check-hello; echo "${hello#check}"
    | $ hello=check-hello; echo "${hello#'check'}"
    | $ hello=check-hello; echo "${hello#$'check'}"
    | $ hello=check-hello; echo "${hello#"check"}"
    |
    | 以上は全て期待通りに動作する。つまり quote 除去は実施される。result="${...}" の形式でも同様であった。
    |
    | より詳しく調査してみる [cf memo/D0375.quote-in-param-expansion.sh]
    |
    | 実は算術式として解釈する時だけの問題なのではないか。
    |
    | というか現在の実装では $(()) の中の "" や '' も許容しているが実際の bash では許されない。
    | 実際の bash で "" や '' が許されるのは (()) の時である。
    | arr['1234'] も許される。${arr['1234']} も許される。一回整理した方が良い。
    |
    | OK: (('1234')) / arr['1234'] / ${arr['1234']} / arr=(['1234']=1)
    | NG: ${var:'1234'} / $(('1234')) / $['1234']

    色々調べた結果をまとめてみる。

    - 先ず初めに算術式 ${var:...:...} / $((...)) / $[...] については、
      如何なる quote も有効にはならない。但し例外はあって、
      "${var:...:...}" でかつ shopt -q extquote の場合には $'' $"" の quote のみ許される。

    - またそれ以外のパラメータ展開の中身 (${var#...}) に関しては、
      '' と "" は何時でも有効である。そして ${} が裸の場合には $'' $"" も有効である。
      "${}" の場合には shopt -q extquote の場合にのみ $'' $"" が有効になる。

    - 更に入れ子になった場合の振る舞いはどうだろう。
      試して見た限りでは "${var#...}" / "${var:...}" の中に
      更に ${} を入れた場合は "${}" と同じ振る舞いになる様である。
      一方で "$(())" の中に ${} を入れた場合は ${} と同じ振る舞いになる様である。

    取り敢えず入れ子になっていない場合の振る舞いについて実装する。
    算術式については算術式を記述している箇所によって振る舞いが異なるので、
    その文脈を引き継げる様にしなければならない。
    現在の算術式の実装では基本的に ntype を参照しながら括弧を数えているので、
    (これまで通り) この ntype を活用して quote の有効・無効を判定するのが良いだろう。
    現在は (()) の中身と $(()) の中身で ntype を区別していないのでそれを区別する必要がある。
    同様に [] のネストと $[] の中身で ntype を区別していないのでこれも区別する。
    その為に新しい ntype '$[' と '$((' を導入する。'NQ(' も導入する。

    ここで現在の ntype について整理しておく。

    '${'      PARAM パラメータ展開の修飾 (EXPR に流れる可能性あり)
    '"${'     PARAM パラメータ展開の修飾 (すぐ外が CTX_QUOT の場合) (EXPR に流れる可能性あり)
    'v['      EXPR  パラメータ展開の配列添え字
    '$(('     EXPR  $(()) の中身 (ARGX0 に流れる可能性あり)
    '$['      EXPR  $[] の中身
    '$('      CMDX1 $() の中身
    ''        QUOT  "" の中身
    '('       CMDX  <() の中身
    ctx=?     PATN  @() の中身
    nest      PATN  @() の中身
    ''        PATN  case in () の中身
    '('/'NQ(' EXPR  式の括弧の入れ子
    '['       EXPR  式の括弧の入れ子
    ''        CONDX [[ ]] の中身
    '('       CMDX1 function f () の中身 (エラー)
    ''        PATN  f () の中身 (エラー)
    色々      RDR?  リダイレクトの右辺
                    (色々 = > &> >> &>> >| >& < <> <& << <<<)
                    (これに応じて文脈も色々 RDRF, RDRD, RDRS, )
    '('       CMDX1 () の中身
    '(('      EXPR  (()) の中身
    ''        PATN  echo ... () の中身
    'a['      EXPR  a[]= の中身
    ''        VALX  a=() の中身
    'd['      EXPR  a=([]=) の中身

    | 更に () [] のネストに際しても、$[ / $(( の中身であるかどうかを
    | 伝播させなければならないのではないだろうか。
    | (※ ${var:} の中身はネストしないのでこの点は考慮しなくて良い。)
    | →と思ったら $['1+2'] はエラーになる一方で $[a['1+2']=3] はエラーにならない様だ。
    |   つまり [] のネストに関しては必ず配列添え字であって内部ではあらゆる quote が許される。
    |   $[] の中身であるかどうかの情報は必要なく一律に今まで通りに扱って良い。
    | →逆に言えば $(()) の中身であっても途中で [] が現れたならば、その中では quote できる。
    |   現在の実装では $(()) の場合には () の入れ子だけを数え、
    |   $[] の場合には [] の入れ子だけを数えという様に取り扱っているが特別な処置が必要である様に思う。
    |
    | うーん。echo $(('1+2))')) という物を bash に食わせると
    | $(( / '1+2))' / )) というまとまりで解釈されて、
    | '1+2))' という算術式の評価の中で構文エラーになる。
    | 決して $(( / '1+2 / )) / ')) という分割になる訳ではない。
    | つまり字句レベルではやはり quote は解釈しているけれども
    | 算術式評価がその quote を受け付けないと考えるべき?
    | だとすると ble はどの様に動作するべきであろうか。
    | 自然に考えれば算術式評価に渡る前の字句的なレベルでのチェックにするのが良い。
    | もし算術式評価の際の算術式の文法について取り扱うのだとすれば別の場所で行うべき。
    |
    | 他にも解析と解釈が一致していない例はある。
    | echo "${hello:-'aa}" は構文エラーになるので quote を解釈しているのかと思えば、
    | echo "${hello:-'aa'}" で出力されるのは 'aa' であり quote 除去は為されない。
    | 一方で echo "${hello:-"aa"}" で出力されるのは "aa" であり quote 除去はされている。
    | 以前の実装で '' の quote を解釈しない様にしていたのはこれが理由であろう。
    | 因みに "${hello:-$'aa}" "${hello:-$"aa}" "${hello:-"aa}" は全て構文エラーになる。

    振る舞い云々以前に字句的な定義から言えば何れの文脈でも quote は解釈されている様だ。
    その上でその quote を含んだ文字列 (引数) について quote 除去が行われるかどうか
    が文脈に依って異なるのだという様に考える必要がある。
    - そうすると基本的な実装としては常に quote は解釈する。
    - quote が除去されない文脈では) quote の着色を外側の文脈と同じにする
    という様に実装しなければならない。

    ここで quote が除去されない文脈を判定する為に何ができるかという事である。
    但し、字句的な観点から言えば常に quote は解釈するというので間違いないのだから、
    quote 除去が実施されるかされないかについては余り実装に凝っても仕方がない気がする。
    取り敢えず現在の ntype 等の構成の範囲で対応できる所までにしておく事にする。

    - 算術式の中に直接 quote がある場合の振る舞いについて対応した。
    - "${ ... }" の中に入れ子で ${} が入る場合には "${}" と同じ扱いにする対策はした。

    そしてより凝った実装にする為にはどの様なことができるかについて記録を残す事にする。

2017-03-01

  * ble-edit: ble-edit/info/{draw-text,draw} overflow 対策。 [#D0374]

    ble-edit/info/draw-text の方は COLUMNS/LINES に従った truncate を加えた。
    一方で ble-edit/info/draw の方は truncate は加えていない。
    様々な制御機能が指定される可能性があることを考えると難しい。
    (改行や SGR だけ受け付けるという方針でまた別の draw 関数を用意するということも考えられなくはないが)。
    制御機能を受け付けるぐらいであれば、呼び出し元で高さの調整は済んでいる物と考えたい所である。

  * ble-edit: 一番下の行で複数行の編集を開始するとずれる。 [#D0373]
    これは制御機能 IL で行の挿入までは行わないという事に起因する。
    IND (LF) で行を増やしてから IL を実行する様にしなければならない。
    これで一応直った。

    然し、今度は一番下の行で行を accept した直後の動作が変である。
    直前の行を上書きしている。
    試しに ble-edit/render/update で行を追加削除する直前に各変数の値を確認してみる。

    declare -- endx="27"
    declare -- endy="0"
    declare -- begx="27"
    declare -- begy="0"
    declare -- _ble_line_endx="10"
    declare -- _ble_line_endy="3"

    変である。accept した時に _ble_line_endx _ble_line_endy の各変数の値は 0 にしている筈である。
    と思ったら、0 にしているのはカーソルの位置 _ble_line_x, _ble_line_y だけであった。

  * syntax: 実は } の直後に } が来ても良いようだ。 [#D0372]

    更に fi の直後に } が来ても良い…。同様に esac done の直後も OK の様子。
    更に } の後に done が来ても良い。fi の後に done が来ても良い。
    これらを総合すると } fi esac done は重ねる事ができるという事だろう。

    ((1+1)) の直後の場合は駄目な様だ。

    うーん。取り敢えず } fi esac done で現在 CTX_ARGX0 としているのは
    CTX_CMDX に変更すれば良い。そして更にコマンドの種類を限定する為に、
    CTX_CMDXE 的な物を用意するという様な方針でも良いだろう。
    そして同様の処理を既に CTX_CMDXC で行っているのでそれの真似をすれば良い。

    異なる点は CTX_CMDXC の状態でコマンドが終わる事はできない
    (関数の中身が指定されていなければならない) 一方で、
    CTX_CMDXE の状態でそのままコマンドが終わっても良いという点である。

  * syntax: for (()) { に対応する。 [#D0371]

    ble-syntax:bash/ctx-command/.check-delimiter-or-redirect で、
    復帰後の文脈値を CTX_ARGX0F という物に指定して、
    CTX_ARGX0F では { を受け取るかまたは CTX_ARGX1 の処理を行うかという様に処理する。

    これの対応により以下の項目については完了した。
    (残るのはヒアドキュメントのみである。)

    | * [2015-02-16] ble-syntax.sh ToDo
    |
    |   - case構文の中の文法
    |     > ;; ;& ;;& の後に case のパターンを受ける
    |   - for (()) { ...; } (obsolete)

  * syntax: ((echo)>/dev/null) を何とかする。 [#D0370]

    二種類のパターンがある。
    1. ((echo)>/dev/null)
    2. $((echo)>/dev/null)

    少なくとも文法エラーが出ない様にはするべき。

    算術式 (だと思っていた文脈) の中で単体の ) が来た場合には
    ( もしくは $( を nest-push し直す等。
    →この方法だとうまく行かない。というのも、要件として少なくとも i++ してから nest-pop しなければならず、
    また、データを格納する為には nest-push してから少なくとも i++ しなければならない。
    つまり合計で少なくとも 2 文字なければ1回の解析ループで nest-pop と nest-push を連続で行う事はできない。

    方針を変えて単体の ')' が現れたらそのまま ctx=CTX_CMDX1 に移行する事にする。
    そしてコマンドの ')' の処理において開始が '((' であった場合も考慮に入れる事にした。

  * ble-syntax: CTX_CARGI2, CTX_FARGI2, CTX_CARGX2, CTX_FARGX2 に対して補完候補として "in" を生成する。 [#D0369]
    complete.sh で "in" を生成する source を定義して、
    ble-syntax/completion-context/check-prefix と ble-syntax/completion-context/check-here において、
    CTX_ARGI, CTX_ARGX と同様に判定して、"in" を生成する source を指定すれば良い。

  * syntax: for VAR in 及び case VAL in に対応する。 [#D0368]

    | * [2015-12-24] (ble-syntax:bash): case 対応
    |
    |   case コマンドの直後は一つ単語を受け取って、
    |   次に in を受け取って更に CTX_CASE に突入する。
    |   それ以外の単語の場合には文法エラーとなる。
    |
    |   一つ単語を受け取るのは RDRF 等と同様に処理すれば良い。
    |   というか寧ろ RDRF で処理してしまっても良いのかもしれない?
    |   →それだとファイル存在チェックなどに引っかかって変な事になる。

    これは CTX_RDRS を流用する事ができそうな気がする。
    VAL に関しては補完候補の生成という側面から見ても CTX_RDRS に等価なのでは。
    VAR に関しては新しく CTX_RDRV という名前の文脈値でも定義することにすれば良いだろうか。

    しかし流用する前に確認しておくべきことがある。
    先ず初めに、リダイレクトの中で用いる事のできる文法要素と
    VAR/VAL で用いる事のできる文法要素は本当に一致しているのかという事である。
    特に VAR/VAL については素朴には CTX_ARGI と同様の扱いと考えるのが自然である。
    この時 CTX_RDRS と CTX_ARGI の扱いの差は何であるのかについて整理しておく必要がある。

    | 違い1 ble-syntax:bash/ctx-redirect/check-word-end において、
    |   プロセス置換が <() 続きにある場合には単語は続くとしている。
    |   一方で ble-syntax:bash/ctx-command/check-word-end では、
    |   プロセス置換が続きにあるかどうかは考えずに単語は終了としている。
    |
    | [bug1]
    |
    |   これは ble-syntax:bash/ctx-command/check-word-end のバグなのではないか?
    |   実際に bash で以下を実行すると、A<(echo) はまとめて一つの引数であると分かる。
    |
    |   $ printf '(%s)\n' A<(echo)
    |
    |   つまり、単語が終了するかどうかの判定を行う場合には
    |   続きにプロセス置換がないかどうかも確認しなければならない。
    |   取り敢えず単体で fix して commit する事にした。
    |
    | 違い2 ble/syntax:bash/ctx-redirect/check-word-end において、
    |   単語の終了と判定された場合には nest-pop を実行している。
    |   これは CTX_RDRS を導入する際に nest-push を伴う事に対応している。
    |
    |   何故 nest-push/nest-pop をする必要があるのかというと、
    |   元々の文脈を復元する必要があったからである。
    |   リダイレクトにおける元々の文脈は様々な可能性があるので、
    |   元々の文脈に応じてリダイレクトの文脈値を切り替える手法では、
    |   文脈値をたくさん定義しなければならず非効率的である。
    |   従って、入れ子に依って文脈を保存するというアプローチを取った。
    |
    |   ★一方で、for VAR in 及び case VAL in に関しては、
    |   抜けた後の文脈は一意に定まるのでわざわざリダイレクトの仕組みを間借りして、
    |   分かりにくくするという必要性はないのかもしれない。
    |
    | check-word-end に関してはこれ以上の違いはない様である。
    | (ctx-command の方では個別 ctx 毎に追加の処理をしているが、
    | 特に全ての文脈値に対して共通の処理をしている訳ではないということである。)
    |
    | 次に ble-syntax:bash/ctx-command と ble-syntax:bash/ctx-redirect を比べる。
    |
    | 違い3 ctx-redirect では改行やリダイレクト・コマンドの終端 (&& や | など) が来るとエラーである。
    |   コメントが其処に入った場合も駄目である。
    |   一方で ctx-command では改行やコマンドの終端が来れば単に次のコマンドに移るし、
    |   リダイレクトが来れば其処でリダイレクトを挟む事が許される。
    |   同じ理由でコメントが来る事も許される。
    |
    | [bug2]
    |
    |   だとすると既存の ctx-redirect ではコメントに対する対策をしていないので、
    |   リダイレクトの直後にコメントがあった場合にそれをファイル名と勘違いする事になる。
    |   これについて確認する必要がある…と思ったら普通に bash がエラーを吐く。
    |
    |   bash: 対応する `)' を探索中に予期しないファイル終了(EOF)です
    |
    |   何処からこれが出ているのかは分からない。いろいろ試した結果、
    |   エラーが出ているのは ctx-redirect の処理中ではなくて ble-syntax/parse の処理中ですらない様だ。
    |   恐らく tree enumerate の辺りでエラーが出ているのではないという気がする。
    |   しかし考えて見るに parse の外で tree enumerate 関係の関数を呼び出す機会はあっただろうか。
    |   →いや色付を単語ごとに実行する際に使用している筈である。
    |   もし tree enumerate 関係で出ているエラーなのだとすれば、ble_debug=1 で実行すれば
    |   より速いタイミングでエラーが出そうな物である。試してみる→特に問題はない?
    |   だとすれば着色の方が怪しい。あ、何か分かった気がする…。引数の内容を展開する時に、
    |   content=($content) 的な事をするが、その時に content が # で始まると駄目という事か。
    |   引数の内容を展開するコードは以下の2箇所にある。特に前者で問題になっている。
    |   後者に関しては問題にはならない。
    |
    |   ble-syntax.sh: eval "value=($wtxt)"
    |   complete.sh: builtin eval "COMPV=$COMPS"
    |
    |   これについても修正した。
    |
    | [bug3]
    |
    |   さて、そもそも # で始まる単語という物が生成されるというのも行けない
    |   (※よく考えたら shopt -u interactive_comments の場合にはその様な単語が生成されても問題ない)。
    |   ctx-redirect でもコメントのチェックはするべきである。
    |   そしてコメントがあった場合には delimiter の時と同様にエラーにする。
    |
    |   ctx-command と同様に comment をチェックする。
    |   コメントが有効であった場合には、そのコメント自体をエラー色にすれば良い。
    |
    | 他には本質的な違いはないようである。
    | 見た目上の違いとしては ctx-redirect では check-assign をしていないという事であるが、
    | これは ctx-command の側でも特定の ctx の場合にしか意味を持たない。
    | また、unexpectedWbegin のチェックをしていないという違いもあるが、
    | これも ctx-command で unexpectedWbegin が起こるのも ctx == CTX_ARGX0 の時だけである。
    | 従って、これらについて ctx-redirect と ctx-command が異なる点はないと考えて良い。

    まとめる。

    - 違い1 は単なるバグであったので現在は違いはない。
    - 違い2 は CTX_RDRS で引数を受け取った後に任意の文脈値に移行できるようにするための物であった。
    - 違い3 CTX_RDRS は少なくとも1つの引数を要求するので、
      単語の先頭で delimiters, comments, 改行が来るとエラーである。
      ※コメントのチェックが抜けていたのはバグであったが、修正後も取り扱いは異なる。

    結局振る舞いとしての違いは "違い3" だけである。
    一方で "違い2" に関しては CTX_RDRS の枠組みの方が柔軟であるが、
    今回の for VAR in, case VAL in の場合には不要な機能である。
    今回採用するとすれば

    - CTX_RDRS の枠組みを使えば比較的楽に実装できる。
      CTX_RDRS と全く同じ機能を持つ文脈値を増やすか、
      或いは CTX_RDRS をそのまま流用してしまって問題ない。

    - CTX_ARGX 等と同様の枠組みを使う方が仕組みとしては綺麗な気がする。
      但し、"単語を少なくとも一つ受け取る" 機能と、
      "単語が終端したら別の文脈値に移行する" 機能を
      ctx-command に追加しなければならない。

      ctx-command がまた無駄に複雑になってしまう。
      一方でこれを機に ctx-command を整理するという方向性も考えられる。

    取り敢えず ctx-command を整理してから考える事にする。
    整理した。矢張り ctx-command の枠組みで処理した方が良い様に思われる。

    1 先ずは新しい文脈値を定義して ARGX, ARGI と同様に処理する様に設定を行う。

    Note: CTX_CARGX1 によって導入される単語だけは wtype として CTX_ARGI を設定する。
      これによって case の第一引数のみが、
      case のコマンド引数として抽出されたり (in ble-syntax:bash/extract-command/.construct-proc)、
      ファイル名としての着色がなされたりする (in ble-highlight-layer:syntax/word/.update-attributes/.proc)。

    2 CTX_ARGI に対して指定されている特別の処理について一つ一つ確認し、
      必要であれば新しい文脈値にも適用する。

    3 CTX_ARGX についても同様に確認・適用していく。

    4 後は導入部分について。

      観察してみたが、思うに CTX_CMDXF と CTX_FARGX1 は同一ではないかという気がする。
      という訳で CTX_CMDXF を廃止して CTX_FARGX1 に統合する。
      取り敢えずこの時点で既に for については動いている様である。

      case についてはどうだろうか。check-word-end で 'for' の時に ctx=CTX_FARGX1 とした様に、
      'case' で CTX_CARGX1 を設定すればそのまま大丈夫だろうか。
      試してみた所ちゃんと動いている様である。
      # CTX_CASE については以前に実装していたのでそのまま通用する様だ。
      # ちゃんとパターンと esac の区別もついている。少し気になって試してみたのだが、
      # "esac)" というパターンを指定すると構文エラーになるという振る舞いも bash のそれと一致しているので OK。

    5 check-word-end において in 以外の場合にエラーを吐くようにする。
      これは意外と簡単に対応できた。

    取り敢えず動作しているのでこれで確定する。

  * bug: ((echo) >/dev/null) を入力しようとすると無限ループになる。 [#D0367]
    というか ) を入力しただけで無限ループになる。
    ごく最近の ble.sh ではこの現象は起こっていなかった。
    という事は、先程までに行った変更によってできたバグと考えられる。

    function ble-syntax:bash/ctx-command/.check-delimiter-or-redirect だった。

    ")" で閉じた時に対応する nest が存在しない場合の処理において、
    戻り値が return 1 になっていなかった。
    関数に分ける時に顕在化したバグであった。

    今までは return 1 し忘れていても次の処理へと進んでいき、
    (以降の処理では引っかからないので) 最終的に return 1 になっていた。
    これによって結果として問題になっていなかった。
    しかし、本来 delimiter が来てかつ対応する nest が存在しない時点で
    return 1 であるという事が確定しているのですぐさま return 1 するべきであった。
    つまり、これは顕在化していなかっただけであり、意図しない実装という意味でバグであった。

    然し、今回 delimiter が来た時の部分を関数に分けて、
    そのままその関数の終了ステータスで return する様に変更したことで問題が顕在化した。
    処理がなされなかった場合には return 1 する様に変更した。


2017-02-28

  * ble-edit: 関数名の整理 [#D0366]

    .ble-edit/stdout/on       -> ble-edit/bind/stdout.on
    .ble-edit/stdout/off      -> ble-edit/bind/stdout.off
    .ble-edit/stdout/finalize -> ble-edit/bind/stdout.finalize
    .ble-edit/stdout/*        -> ble-edit/bind/stdout/*

    .ble-line-text.          -> ble-edit/text/
    .ble-line-info.          -> ble-edit/info/
    .ble-line-cur.xyo        -> ble-edit/info/.put
    .ble-edit-draw.          -> ble-edit/render/
    .ble-edit-draw.set-dirty -> ble-edit/render/invalidate

    ble-edit/draw/goto             -> ble-edit/render/goto
    ble-edit/draw/clear-line       -> ble-edit/render/clear-line
    ble-edit/draw/clear-line-after -> ble-edit/render/clear-line-after

    .ble-edit.locate-forward-xword  -> ble/widget/.locate-forward-genword
    .ble-edit.locate-backward-xword -> ble/widget/.locate-backward-genword
    .ble-edit.locate-current-xword  -> ble/widget/.locate-current-genword
    単語関連については全体的に整理した。

    .ble-edit.bell -> ble/widget/.bell
    .ble-edit.*-range -> ble/widget/.*-range
    .ble-edit.quoted-insert.hook -> ble/widget/quoted-insert/.hook
    .ble-edit/delete-backward-char -> ble/widget/.delete-backward-char
    .ble-edit.delete-char -> ble/widget/.delete-char
    .ble-edit.goto-char -> ble/widget/.goto-char
    .ble-edit.forward-char -> ble/widget/.forward-char
    .ble-edit/newline -> ble/widget/.newline

    .ble-edit.default-key-bindings -> ble-edit/load-default-key-bindings
    .ble-edit-finalize -> ble-edit-finalize

  * [2016-08-08] 改行&プロンプト出力を一度に行う? [#D0365]

    唯単に RET を押すだけだと普通の bash では一気に新しいプロンプトが表示される。
    然し現状の ble の実装では一旦次の行の行頭に行ってから暫くして (計算をしてから) プロンプトが表示される。
    その為にちらつきというか変な遅延がある様に思われる。
    次の行の行頭に行くのも同時に出力するべきではないか。

    これは .ble-edit/newline の中で改行を出力してから、
    コマンドの有無を確認して…云々という処理をしているからである。
    また、プロンプトの出力部分についても確認しておく。
    ble-edit/prompt/update を呼び出している箇所は一箇所しかない。
    .ble-edit-draw.update である。
    .ble-edit-draw.update 自体は幾つかの場所から呼び出されている。

    1 ble-core に専用の buffer を作成する事にするのが良いだろうか。
      →ble/util/buffer ble/util/buffer.flush という関数を作った。
      更に ble-edit/draw/bflush で ble/util/buffer に対して内容を出力する物を用意した。
      同様に ble/util/joblist.bflush という物も用意した。

    2 .ble-edit-draw.update を直接 stderr に出力するのではなくて
      ble/util/buffer に対して出力する様に書き換える。
      同時に呼び出し元で必要に応じて flush を実行する様にする。

    3 .ble-edit-draw.update-adjusted については呼び出し元は一箇所しか無い。

    究極的には外部コマンドの呼び出し時と
    ble-edit/stdout/off の時にだけ flush すれば良いだけなのでは。
    結局、以下の箇所でのみ buffer.flush を実行すれば良い筈である。

    * .ble-edit/stdout/off
      bind の終わりで最終的に必ず (何らかの異常やシグナルで止まる事はあるが)
      この関数が呼ばれて次の入力を受け取る状態に入る筈である。
      また出力の制御という観点で密接に関係がある。
      従って、この関数の中で buffer.flush をするのが良い。

      但し bleopt_suppress_bash_output を設定していない時にはこの関数は空だったが、
      今回は bleopt_suppress_bash_output であっても .ble-edit/stdout/off で
      buffer.flush を実行する様に変更した。bleopt_suppress_bash_output の場合には
      実際 "stdout を off にする" という動作は必要としないが buffer.flush は必要である。
      その様な意味合いで .ble-edit/stdout/off という関数名は良くないのではないかという気がする。
      これは後で考え直したい。

    * ble-edit/exec の内部では直接出力を行う。
      exec を開始する直前に buffer.flush を実行すれば良い。

    * .ble-line-info.draw, .ble-line-info.clear
      これは時間のかかる計算 (isearch) の進捗状況を表示するのに用いている為。
      (実のところ、isearch の側で buffer.flush を実行しても良い様な気もする。

    * ble/widget/command-help
      これはその場で less を使って内容を表示する。
      buffer.flush をした後に less を起動する必要がある。

    * 終了コマンド
      以下の bash を終了させるコマンドを実行する時には buffer.flush を行う。

      ble/widget/delete-forward-char-or-exit
      ble-edit/bind/.check-detach (ble-edit/bind/.exit-trap をシグナル経由で呼び出して終了する)

    取り敢えず簡単な実装は終わった。

2017-02-25

  * [2017-02-14] stackdump [#D0364]

    [[ -x /home/murase ]] と入力したらなった。
    具体的には [[ -x a と入力して、x を消して再度 x を入力するとなる。
    これは再現性がある。

    | assertion failure: [[ ${_ble_syntax_nest[inest]} ]]
    | ble-syntax/tree-enumerate/.initialize/FATAL1
    |   @ /home/murase/prog/ble/ble.sh:25 (ble-assert)
    |   @ /home/murase/prog/ble/ble.sh:3 (ble-syntax/tree-enumerate/.initialize)
    |   @ /home/murase/prog/ble/ble.sh:5 (ble-syntax/tree-enumerate)
    |   @ /home/murase/prog/ble/ble.sh:5 (ble-syntax/parse/shift.method2)
    |   @ /home/murase/prog/ble/ble.sh:2167 (ble-syntax/parse/shift)
    |   @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |   @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |   @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/prog/ble/ble.sh:4630 (ble-highlight-layer/update)
    |   @ /home/murase/prog/ble/ble.sh:4981 (.ble-line-text/update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   @ /home/murase/prog/ble/ble.sh:1196 (ble-edit/bind/.tail)
    |   @ /home/murase/prog/ble/ble.sh:-4307 (ble-decode-byte:bind/EPILOGUE)
    |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)

    木構造の破壊が度々起こるので ble-syntax/print-status/.dump-arrays で
    構造を確認して問題がある部分を着色して表示する様に変更した。
    これによって確認してみた所、入れ子構造になっている部分の内部で
    二個目以降の単語を編集した時には大体の場合に nest の参照が壊れているという事が分かった。
    ただ単に顕在化するのが "[[ -x a" の場合だけだったという事になる。

    これは明らかに nest の shift に失敗しているのが原因である。
    現在の shift は基本的に e74c11631d62880a2600fb559e4135b8cf268110 (11ヶ月前) で作られた物である。
    長らくエラーが出た覚えもないのでもっと最近の変更によって問題が埋め込まれた可能性がある。

    その他では一番最近の 0757230b41a2adfe5eb6a52ce4c97f29734845a7 しかない。
    (実のところ、この修正と stackdump が出たのとどちらが先だったのか覚えがない…。)
    しかしこの修正は単純な物でこれで問題が起こるようには思われない。
    実際にこの修正を戻して試してみたが、同様に問題が発生するので、この修正は関係ないとして良いだろう。
    という事はこれは昔から存在していたバグと考えるべきだろう。

    % 取り敢えず nest のシフト範囲がどの様に決定されているのかについてコードを追ってみる事にする。
    % nest のシフトは ble-syntax/parse/shift.nest で行われている。
    % この関数自体が誤っている可能性について先ずは確認してみる。
    % と思ったが、よく見たら壊れているのは nest ではなくて nest の参照元である stat の方だった。

    なので見るべきは stat のシフト範囲の方である。つまり、ble-syntax/parse/shift.stat である。
    stat の他の項目に関しては特に問題も生じていない様なので、恐らくこの関数の呼び出し自体はちゃんと行われている。
    問題は nest 参照 (stat[3]) のシフト方法ではないかと思われる。
    コードを見てみると stat[1] (wlen), stat[3] (nlen), stat[4] (tclen), stat[5] (tprev) が共通のコードでシフトされている。
    これは怪しい。というのも tclen, tprev によって参照されるのは境界で、
    wlen, nlen によって参照されるのは文字であり、両者は異なる性質のものであるはずだからである。

    ? さて wlen に関する問題が発生しなかったのは何故だろう。word が stat に入る機会が少ないからだろうか。
      人為的に単語の途中に構造を導入して (例えば he"l"lo など)、word が破壊されないか確認する。
      うーん word に関しては余り遠くを参照したりしないので nest とは dirty-range との相対位置が異なる様だ。
      振る舞いが違うのはそういう事である。もしかすると特殊な状況では word にも不整合が生じるのかもしれないが、
      wlen で今まで問題が発生しなかった理由がわかったのでこれでよしとして深く追求はしない。
      nlen の修正方法が分かれば wlen の修正方法も同様にすれば良いだろう。

    変だ。ちゃんと動いているべきな気がする。
    何より同じ値なのに正しく動いている shift と動いていない shift がある。
    どうやら shift 量が過剰の様だ。もしかして複数回 shift が実行されている?
    →確認してみたら予想通り複数回の shift が実行されている様だ…。

    % 一方で全然シフトの対象でない部分についても沢山 shift が呼び出されている様な気がするがこれは何だろう?
    % と思ったら改めて実行してみた所何も起こっていない…と、よく考えたら "less ~/a.txt" と入力するのに
    % 使っているシェルがテスト用のコードを埋め込んだ後のシェルになっていて、確認のための入力をしている時に、
    % 変なごみが入力されてしまったというだけの事だった。

    さて、j は j-- としているので複数回同じ j の値で shift が実行されるというのは変である。
    誰かが j を increment しているのだろうか。或いは、j に何か値が代入されているのだろうか。

    + 誰かが j を increment している可能性が怪しい→と思ったがそうでもない。
    + どうやら "((_shift2_j=wbegin)) # skip" という行が怪しい気がする
      (※_shift2_j は j の値を退避している変数である)。
      →と思ったがこれでもない様だ…。
    + あー。なんと _shift2_j に j の値を保存していないコントロールパスがあった。これだ。

    呆気なく直った。


2016-12-21

  * $_ には前回のコマンドの最後の引数が格納されているべきである。 [#D0363]
    しかもシェルによる展開を一頻り実行した後の値である。
    現状では現在実行しようとしているコマンド自体が代入されている。

    先ず最後に実行した時の _ の値を取得する方法と、
    それからその _ を改めて設定する方法について考えなければならない。
    最後に実行した時の _ の値を取得する方法は簡単である。
    問題はどの様に _ を設定するかである。
    これについては : "$_ble_last_command_last_arg" とかいう感じにすれば良いのだろうか。

    % _ の値の取得に関しては ble-edit/exec:gexec/.eval-epilogue の中に追加する事にした。
    % どうやら関数の実行が終了するまではその関数の最後の引数は _ に設定されない様なので。
    % つまり、そのコマンドが終了した時に _ が設定されるという事である。
    %
    % 一方で同じ理由で _ の設定に関しては ble-edit/exec:gexec/.eval-prologue の中に設定しても駄目だ。
    % というのも中で _ を設定したとしても .eval-prologue 関数を出た時に
    % .eval-prologue 関数自体の最後の引数が改めて _ に設定されてしまうからである。

    実際にやってみると動かない。成る程、最後に実行したコマンドの引数が取得されるのではなくて
    最後に実行した eval の引数が評価されている。つまり、eval の内部で _last_exit 云々を取得しなければならない。
    しかしそうすると今度は lastexit 等の再設定が必要になる。いや lastexit も一緒に取得してしまえば良いという事だろうか。
    →少し汚いが $? と $_ を取得する為の関数 .save-params を作成してそれを eval の引数の中で評価する事にした。
    文法エラーになった場合にはそもそも $? と $_ が更新されないという事になるだろうがそれでも仕様がないだろう。
    →やはり $? が更新されないというのは変な気がするので外に伝播する事にする。

2016-12-06

  * プロンプトにジョブ数が表示されてなくなって変だと思っていたら、 [#D0362]
    shopt -s nullglob していると GLOGIGNORE を設定していたとしても、
    何らかのパターンがあった時に全体が消えてしまうという事が判明した。

    これを簡単に回避する方法はあるのだろうか。
    一つの方法は一旦変数の内容を取り出して、
    ?*[() その他のシェル特別文字をを全てエスケープしてしまうという事である。
    しかしエスケープするべき文字は沢山あるのでこの方法は現実的でない様な気がする。

    だとすると nullglob を一時的に解除する様にする必要がある。
    さて、よく考えてみれば分割を行っている箇所はこの一箇所だけではないはずだ。
    と思ったが、文字列の分割を目的としてこれを行っている箇所は全て
    ble/string#split に書き換えたのであった。ならば、ble/string#split だけ対策をすれば問題ない筈だ。

    →取り敢えず ble/string#split に nullglob の対策を施す事にした。

    しかし、もしかすると他にも同様の問題で項目が消滅してしまうという箇所があるかもしれない。
    他に GLOBIGNORE を ble.sh の中で使用している箇所がないという事は、その様な場所は、
    * や ? や [..] が含まれる内容を指定した時にファイル名に展開されてしまう危険がある。
    その様な事にならない様に設計しているはずなので GLOGIGNORE が使われていない場所では問題ないと考えて良い様に思う。
    つまり、論理的にはその様な場所は存在しないはずなのでここでは余り気にしなくても良い。
    その様な場所があるとすれば別のバグである。

2016-11-07

  * [2016-11-05] 半角仮名が入力できないという事に気づいた。コピー&ペーストしても駄目である。 [#D0361]
    ble-detach している時はちゃんと動作する。TAB で補完する時は入力できる。
    半角文字を入力すると変な文字に変換される。

    screen を経由していると変な文字が増える。
    これは screen が不正な文字を受信した時の処理方法の問題だろう。
    今回の問題とは直接に関係は無いはずである。

    他の文字を入力している時には何も問題は生じていないので
    これは utf-8 のデコードの問題ではないかと思われる。
    試してみると半角仮名は 3 byte 文字である。普通の漢字と同じに見える。

    UTF-8 のデコード部分を調べてみたが誤りはない様に見える。
    次に ble-decode-char 65422 を実行してみる。
    正しく処理されている。半角仮名の ﾎ が入力された。
    直接に入力してみる…あれ…入力できる。変だ。
    どうやらローカルの cygwin でやると入力できなくて、padparadscha 上でやると入力できる様だ。
    cygwin 側のロケールの設定だろうか。。
    cygwin 側で ble-decode-char 65422 としてみたら変な文字が入力される様だ。
    cygwin 上の c2s が怪しい。

    →なんと cygwin で printf '\UFF8E\n' をすると文字化けするという事が判明した。
    LC_ALL=C.UTF-8 printf '\uFF8E\n' として見ても駄目だ。version は 4.3.46 である。
    /bin/printf '\uFF8E\n' は正しく動作する。これは bash のバグなのか?
    然し padparadscha 上の bash-4.3.42 ではちゃんと動いている。

    もう少し詳しく見る。printf '\uFF8E\n' | od -t x1 とすると結果は ed 9f bf ed be 8e 0a である。
    これを UTF-8 に従って戻すと U+D7FF U+DF8E になる。サローげとペアにしようとして失敗している。
    https://ja.wikipedia.org/wiki/UTF-16 を見るとサロゲートペアの計算方法は、
      char16_t w1 = 0xD800 | ((uchar >> 32) - 1 & 0xFF) << 6 | uchar >> 10 & 0x3F;
      char16_t w2 = 0xDC00 | uchar & 0x3FF;
    である。この式を多少弄って、以下のようにしてみる。
      char16_t w1 = (0xD800 + (uchar >> 26)) - 0x40;
      char16_t w2 = 0xDC00 | uchar & 0x3FF;
    このコードで本来サロゲートペアにならない U+FF8E をサロゲートペアにしようとすると、U+D7FF U+DF8E になる。
    これは実際サロゲートペアになっていないので UTF-8 にしようとすると上記の様に 6 bytes のデータになる。

    これは誰が悪いのか? bash のソースを見る。
    builtins/printf.def:888:       temp = u32cconv (uvalue, cp);
    この u32cconv が怪しい。定義は lib/sh/unicode.c:239 にある。
    見るとサロゲートペアに変換する関数 u32toutf16 があって怪しい。
    lib/sh/unicode.c:213: u32toutf16 (c, s)
    あー。この関数にバグがある。何故か 0x0d800 未満の文字以外を全てサロゲートペアに変換している。
    bash のバグ報告に投げるべきだろうか。何処かに bash の repo は落ちていないか?

    その前に最新版をチェックしなければなるまい。最新版4.4でも直っていない。
    4.4 の patch は未だ出ていない。

    報告を提出した。accept された。恐らく 4.5 で反映されるのではないかと予想される。
    work around を ble.sh に追加する。

2016-11-05

  * 調子に乗って算術式のバグに関しても報告を行うべきだろうか。 [#D0360]

    $ bash-4.4 -c 'a=0 x="a=1"; ((0?x:0)); echo $a'
    1
    $ bash-4.4 -c 'a=0 x="a=1"; ((0?(x):0)); echo $a'
    0
    $ bash-4.4 -c 'a=0 x="a=1"; ((0?$x:0)); echo $a'
    0

    しかしできるだけソースコードのどの部分が問題であるのかも指摘した方が良い。
    「この様なケースは今まで報告されなかったので滅多にないことで対応する必要はない」等とはぐらかされる気がする。

    先ず算術式は何処で処理されているのだろう。
    builtins/let.def を見ると evalexp という関数を呼び出している。
    evalexp は expr.c:365 に定義されている。引数は文字列である。そのまま subexpr に制御が渡る。
    グローバル変数 expression に引数の文字列をコピーし、それを readtok で読み取る。
    結果は EXP_HIGHEST () で取り出している。readtok は expr.c:1230 にある。中は単に単語を一個ロードするだけの様だ。
    ということは EXP_HIGHEST() が本体という事になる。そしてマクロによって expcomma が呼び出される様だ。
    expcomma は expr.c:442 にある。其処から再帰下降解析を行っている。expassign (expr.c:457) -> expcond (expr.c:572)
    どうも cond? lhs: rhs において cond の値に応じて noeval という変数を inc/dec して評価するかしないかを切り替えている様だ。
    そして再度 EXP_HIGHEST を呼び出している。さて変数参照と noeval の関係が怪しそうだ。EXP_HIGHEST から下降していく。
    expcomma -> expassign -> expcond -> explor うーん。この exp0 というのが怪しい。辿るまでもなくこれが一番下なのでは?
    どうも既にこの時点で値が計算されているらしい? だとすると readtok で変数の中身が評価されているのか?
    調べると次のトークン (peektok) が "=" 以外の時は expr_streval (expr.c:1085) で評価を行っている。
    それで expr_streval を見るとちゃんと noeval を判定している。変だ。だとすればやはり評価されない筈ではないのか。
    変だ。bash-4.3 を見ても同様である。と思って再度 expcond を見てみる。
    おや。noeval を設定する前に readtok しているではないか。これは駄目な筈だ。

    報告を提出した。

2016-09-16

  * ble-core: bug ble/util/upvar を導入してみた所、色が全く着かなくなってしまった。 [#D0359]

    調べてみると upvar の変数名に対して配列要素 arr[index] を渡しているのがいけなかった。
    配列要素を指定した場合にどの様な動作をするのだろうか。調べてみる事にする。

    先ず local arr[1] などとするとそもそも arr という変数が関数内から見えなくなる様だ。
    関数スコープに arr という名前でスロットが作成されるが変数の実体は配置されないなどという事だろうか。
    また local arr[1]=1 などの様に値まで指定すると arr=([1]=1) の様な内容の配列が local に作成される様だ。
    引き続き unset arr[1] 等とすると、その配列要素は削除されるが配列自体は残ってしまう。

    a さて、どの様に定義するべきだろうか。
      例えば変数名が単純な変数名の場合には今まで通りに local "$var" && upvar "$var" "$value" として、
      変数名が arr[index] 等の場合には単に eval $var=\"\$value\" を実行する様にするか。
      然し、それだとローカルに arr という名前で変数が存在すると、
      その変数に新しい要素を追加する事になってしまい、変更が外に達しないという事になる。
      配列名が被ったとしても正しく外に変数を返す事ができる様にする為には、

      local "${var%%\[*\]}" && upvar "$var" "$value"

      として upvar の中でも unset "${var%%\[*\]}" 等の様にしなければならない。

    b 或いは、全く発送変えても良い。例えば export を使うとどの様な動作になるだろう。

      - 試してみた所、外側の関数で local var として内側の関数で export var=value とすると、
        外側の関数でその値を参照できると共に、更に外側の関数を抜けると変数が存在しなかった事になる。
        (少なくとも bash-4.3 ではその様な動作になっている。他の bash の version ではどの様な動作になるだろうか。)

        % ToDo: check bash-3.0, 3.1, 4.0, 4.1, 4.2 での動作確認:
        %   外側の関数で local して内側の関数で export した変数は外側の関数を抜けた時に削除されるか。
        %   もしくは export flag が削除されるか。

      x 更に重要な事は、或る関数の中で declare した変数について、
        export によってその関数の外側にまで寿命を延長させる事ができるかどうかである。
        実際に試してみた所、できない様だ。飽くまで宣言された時の寿命は変わらない様だ。

      - また、もしこの問題を解決できたとしても、他の実行形式に対して環境変数として
        変数の内容が伝播してしまうのは都合が悪い可能性がある。

      - 更に、配列要素などが指定された時の動作についても非自明である。
        結局配列要素などが指定される場合を考慮に入れれば
        upvar を使った場合と較べてコードが簡単になるという事はない様に思われる。

    結局今の所は export するしかない様だ。

2016-09-11

  * isearch: C-g でキャンセルした時に元の位置に戻る。 [#D0358]
    元々の _ble_edit_ind _ble_edit_mark の値を記録して、
    キャンセルした時にそれを復元する様に変更すれば良い。

    と思ったら元々 _ble_edit_ind, _ble_edit_mark の値は、
    一致範囲として記録されるものであった。

  * syntax:bash: $ は単体でもOK [#D0357]

    $ の直後に文字列終端・空白・改行その他の記号があってもエラーではなくて、
    単に $ という文字になるという事。

    はじめは通常文字のリストに追加しようと思ったが、
    設計上、通常文字の連続のチェックの方が先に来ている。
    これは通常文字が登場する確率の方が高いので、
    特殊文字よりも先に通常文字をチェックしたほうが高速だからである。
    従って、この順序を変更したくはないので、check-dollar の内部で処理する事にした。
    どのパターンにも一致しなかった $ は単に一文字の文字として解釈を行う。

  * edit: history の一番下で C-o した時の動作 2016-07-18 [#D0356]

  * accept-and-next: erasedup はどの様に処理されるべきか。 [#D0355]

    もし erasedups が指定されているとすれば、
    履歴に同じ内容のものが二つ以上登録されていることは無いはずである。
    という事は或る履歴項目を実行した事によって
    その次の項目が削除されてしまうという事は無いはずである。

    しかし、実行した履歴項目がその場所から削除されてしまうので、
    履歴番号がずれる事になるという事に注意する。
    これに対する対策を追加する必要性がある。

    同様に ignoredups が指定されている場合にも、
    その項目が一番最後の項目の場合には番号のずれが生じる。
    というか、ignorespace など他の指定に引っかかる事もある。

    これらをどの様に判定すれば良いだろうか。
    自前で全て判定をしなければならないのだろうか。
    或いは、履歴項目の個数を数える等して処理を簡単化できないか。
    例えば ignoredups と ignorespace の場合を考える。
    ignoredups に当たった場合は新しい履歴項目は追加されないが、
    一番最後の履歴項目が同じ内容を持っているので、その履歴項目に移動する事にすれば良い。
    ignorespace や HISTIGNORE に当たった事によって履歴項目に追加されなかった場合にはどうすれば良いか。
    実行したのが昔の履歴項目の場合にはそのまま気にせずに次の項目に移動すれば良い。
    実行したのが一番最後の履歴項目の場合には履歴項目に移動するのではなくて、
    現在の編集内容に前回の編集内容をコピーするという様に対応すれば良い。

    動作についてまとめるとどうなるだろうか。
    動作が簡単な場合から順に考えていくことにすれば良い。

    a 先ず、実行したのが昔の履歴項目だった場合には、
      基本的にその次の履歴番号に進めば問題ない。
      但し例外が erasedups によって項目が削除された場合である。
      それ以外の履歴の設定では過去の履歴が変化する事はないので気にしなくて良い。
      erasedups が設定されている場合に、
      その履歴項目の内容と実行したコマンドの内容が同一の場合には
      erase 操作によって次の履歴項目は実行したのと同じ履歴番号になる。
      (履歴項目の内容と実行したコマンドの内容は、
      過去の履歴項目の内容を編集することができるので違っても良い事に注意する。
      つまり [[ ${_ble_edit_history[index]} != ${_ble_edit_history_edit[index]} ]] かもしれないという事。)

      よく考えたら HISTIGNORE や ignorespace に引っかかってそもそも履歴項目の登録が起こらない場合は、
      erasedups に引っかかっていたとしても履歴項目の削除は起こらない。
      つまり index のずれは起きないので特別な処置は要らない。
      これを確かめる為には HISTIGNORE や ignorespace の判定を自前で行わなければならないのではないか。
      然し、二重に判定を行うのは具合が悪い。あるいは履歴項目の登録部分で履歴が登録されたかどうかの情報を返す様にするか。
      例えば [[ -v histadd_status ]] && histadd_status=$result の様にして。

      もっと良い判定方法があるのではないか。
      実行したのが昔の履歴項目だった場合に登録が起こるのはどの様な時だろう。
      HISTIGNORE に引っかからなかった場合である。
      ignoredups に引っかかる事は基本的にない、と思ったがよく考えて見れば
      同じ内容の文字列が履歴項目の一番上にある場合には普通に ignoredups に引っかかるのではないか。
      つまり、履歴登録試行後に一番上の要素が実行した文字列と同じかどうかを見るだけでは
      実際に新しく履歴項目が登録されたかどうかを正確に判定することは不可能である。

      という事はやはり history/add から結果を返す様にする必要があるか。
      実際に履歴項目の追加が発生したかどうかの判定を返すようにしても良いが、
      結局その情報が得られたとしても accept-and-next 側で、
      accept-line の内部実装に依存する様な処理を実行する必要がある。
      そのような構造になっていると将来的に history/add の処理方法を変更した時に問題が生じる。
      そういうことを考えれば、履歴項目番号の shift も含めて
      history/add の側で処理してしまったほうが良いのではないか。
      という訳で history/add の内部で shift も実行することにする。

    b 実行したのが一番最近の履歴項目だった場合には、
    c 実行したのが最新の編集文字列だった場合には、

      % 何れにしても一番最後に登録された項目に移れば良い。
      % erasedups や ignoredups の場合には、
      % 一番最後に登録された項目というのは丁度一番最後に実行したコマンドになっている筈だからである。
      % しかし、問題点は HISTIGNORE もしくは ignorespace によって、
      % 一番最後に実行したコマンド自体が履歴に登録されなかった場合である。
      % その場合には新しい編集文字列を用意して、そこに実行したコマンドの内容をコピーする事にする。

      よく考えたらこれは一番最近の履歴項目を実行した場合ではなくて、
      履歴項目を編集して実行した場合ではなくて、最新の編集文字列を実行した場合の処理である。
      一番最近の履歴項目を実行した場合には、既に履歴項目として登録されているという事だから、
      もし HISTIGNORE ignorespace によって登録されなかったとしても、単に一番最近の履歴項目に移動すれば良い。
      但し、最近の履歴項目を編集してから実行した場合にはまた異なる処理が必要になる。
      というか、最新の編集文字列を編集した時と同じ処理で良い。

      結局、一番最近の履歴項目だった場合と最新の編集文字列だった場合は処理を統合するのが良いだろう。
      取り敢えず、実行と履歴項目への登録を試行する。
      登録を試行した後に一番上にある履歴項目の内容が実行したものと同じであればそこに移動する。
      (もし内容が異なるのであれば、それは HISTIGNORE/ignorespace によって登録されなかった上に、
      一番最近の履歴項目を編集してから実行したor最新の編集文字列だったという事である。)
      もし内容が異なる場合には、最新の編集文字列に実行したのと同じ文字列を指定すれば良い。

  * [check] 複数のコマンドを一度に入力し場合に、実際の実行を遅延している。 [#D0354]
    この時に履歴番号 (PS1 の \! という指定で表示される物) と
    実際の履歴項目の番号はちゃんと一致したものになっているか。

    懸念として、実行前だから履歴番号が前のコマンドと重複してしまったり、
    或いは履歴項目の登録の際に登録が前後したりして番号がずれる事があるのではないか
    と考えたが特に問題は無いようであった。

  * ble-edit/history/add: bug HISTCONTROL=erasedups:ignorespace が指定されている時に [#D0353]
    ignorespace に当たると履歴項目が消滅する。
    ignorespace ignoredups について確認して引っかからなかった場合にのみ erasedups するべき。
    HISTIGNORE に関しては先にチェックを行っているので問題ない。

  * ble-edit: bug C-r で現在行の内容に一致しない。 2016-09-07 [#D0352]

2016-08-08

  * mintty で xenl 絡みの動作がおかしい [2016-08-07] [#D0351]
    丁度端末の横幅と同じに為る様な履歴項目が登録されている時に項目を辿るとなっている。
    後で動作を調べる必要がある。
    もしかすると mintty と同じタイプの物では全て動作がおかしくなっている可能性がある。

    というか今 screen で試してみてもカーソルの位置が怪しい。
    mintty とは又別の変な振る舞いをしているが、
    どうも ble.sh は次の行にカーソルを移しているつもりにいなっているが、
    実際には次の行にはカーソルが移っていないという事の様である。
    本来は次の行にちゃんとカーソルが移動する様にする必要がある。
    xenl 周りの計算について再度確かめる必要があるだろう。

    xenl 周りの計算は少し見た限りは問題が何処にあるか分からない。
    動作確認もしながら探す必要があるだろう…と思って何となく echo $_ble_term_xenl したら変だ。
    rosaterm (xenl なし) でも screen (xenl あり) でも常に 0 になっている。
    と思って term.sh の中を覗いたら、情けないことに ble/term.sh/tput tput xterm という具合に、
    tput に tput を渡していた。直接の tput 使用から ble/term.sh/tput 経由での使用に切り替えた際に、
    元からあった tput を削除し忘れていたということであろう。

    また他にも類似のミスがないか確認する。他にはないようだ。

    一応 _ble_term_xenl について確認:
    - _ble_term_xenl=1 ... xenl あり。tput xenl; echo $? の結果は 0 (成功)
    - _ble_term_xenl=0 ... xenl なし。tput xenl; echo $? の結果は 1 (失敗)
    echo $? の結果と _ble_term_xenl の内容が逆転していることには注意する。

    > * isearch: 検索中に長い履歴項目があるとカーソル行がずれる。 [2016-07-08]
    >
    >   このずれはカーソルが一番上の行にある場合に起こる様だ。
    >   カーソルが二行目以降にある場合は発生しない。最終行にある時でも発生しない。

    以上の問題もこの修正によって直ったと思われる。


2016-08-07

  * Windows では管理者権限があるかどうかは [#D0350]
    test -w "$(cygpath -u $WINDIR)"
    で判定することができる。

    cygpath に関してはプロセスを起動していると遅いので自前で実装する?
    変な文字が含まれていない限りにおいては簡単に実装できる筈である。


2016-08-06

  * edit: bug 履歴項目に登録されなくなる現象 [#D0349]

    突然、履歴項目に登録されなくなってしまう現象に出会う。
    但し、history -s では登録されている様である。

    調べてみると空白が登録されている様子である。
    というかこのプロセスはいつの version なのだろうか。。

    % % 更に現象の発生したシェルで調べてみると、
    % % _ble_edit_history と同じだけ要素数を持っている筈の
    % % _ble_edit_history_edit 配列の中身が殆ど空になっている。長さが 20 だ。
    % % そもそも何故その様な事態になったのかも不思議であるが、
    % % これが履歴が登録されない原因なのだろうか。
    % % 取り敢えず、問題を確認する為に _ble_edit_history_edit の内容を復元してみる。
    % % →問題は発生しなくなった様に見える。
    % % 従って、_ble_edit_history_edit さえ空にならなければこの問題は発生しないのではないかと思われる。
    % %
    % % さて、ではそもそも何故 _ble_edit_history_edit の中身が空になってしまったのだろう。
    % % 再度 _ble_edit_history_edit に変更が発生しそうな箇所を探す。
    %
    % と思ったが変だ。問題が発生した直後に実行した以下のコードではちゃんと
    % _ble_edit_history_edit の中身は沢山の項目が登録されている。
    %
    %   [murase@padparadscha 1 xgetopt]$ echo ${#_ble_edit_history_edit[@]}
    %   21034
    %
    % 登録されている項目数も前後に実行した history | tail の結果と較べても正しい物の様に見える。
    %
    % これで二つの謎現象が起こっていたという事になる。
    %
    % a 何故か分からないが履歴項目が登録されない状態になる。
    %   history -s には登録されている。
    % b 更に原因を探す為に色々実行していると、
    %   _ble_edit_history_edit の中身が空になってしまった。
    %
    % と思って再度前にテストの為に実行したコマンドを確認してみると、
    %   echo "${#_ble_edit_history_edit[0]}"
    % を実行していた。つまり、配列の要素数ではなくて配列の先頭要素の長さを確認していた。
    % ただの勘違いだった。

    さて上記の勘違いで唯一分かった事は、
    _ble_edit_history_edit=("${_ble_edit_history[@]}")
    を実行したら以上状態から直ったという事である。
    うーん。一応近辺の出力内容を記録しておく。

    | [murase@padparadscha 1 xgetopt]$ history | tail
    | 21020  git submodule --help
    | 21021  g t
    | 21022  pwd
    | 21023  less xgetopt.h
    | 21024  g add remote origin git@gitlab:akinomyoga/libmwg-xgetopt.git
    | 21025  g remote origin git@gitlab.akinomyoga/libmwg-xgetopt.git
    | 21026  false
    | 21027  true
    | 21028  g remote add origin git@gitlab:akinomyoga/libmwg-xgetopt.git
    | 21029  history | tail
    | [murase@padparadscha 1 xgetopt]$
    | [murase@padparadscha 1 xgetopt]$
    | [murase@padparadscha 1 xgetopt]$ echo ${#_ble_history_edit_dirt[@]}
    | 0
    | [murase@padparadscha 1 xgetopt]$ echo ${#_ble_history_edit[@]}
    | 0
    | [murase@padparadscha 1 xgetopt]$ echo ${#_ble_edit_history_dirt[@]}
    | 0
    | [murase@padparadscha 1 xgetopt]$ echo ${#_ble_edit_history_edit[@]}
    | 21034
    | [murase@padparadscha 1 xgetopt]$ echo ${_ble_edit_history_dirt[@]: -10}
    |
    | [murase@padparadscha 1 xgetopt]$ echo ${_ble_edit_history_edit[@]: -10}
    | history | tail echo ${#_ble_history_edit[@]} echo ${#_ble_edit_history_dirt[@]} echo ${_ble_edit_history_edit[@]: -10}

    うーん。どうやら ${#_ble_edit_history_edit[@]} の数が余分になっている様に見える。
    上記のタイミングでは本当は 21034 になっているべきである。
    何かが無駄に登録されてしまっている状態である。
    では何故その様な事になるのか?

    →原因が分かった。現在最新の行を編集してから (何か非空の内容がある状態で) 履歴項目を移動すると、
    その現在最新の行が _ble_edit_history_edit に登録される。
    これはまた最新の行に戻ってきた時に参照する為に必要になる物である。
    また、この編集仕掛の行は検索の対象でもある。
    この時点で _ble_edit_history と要素数が異なってしまう。
    →実際に試してみた所、再現した。
      編集して echo という文字列がある状態で別の履歴項目に移る。
      その後でコマンドを実行する。ずれが生じる。確かに履歴項目に登録されなくなる。

    つまり、_ble_edit_history の要素数と _ble_edit_history_edit の要素数が
    同じ筈だという仮定は成立しない物として取り扱わなければならない。
    多分、_ble_edit_history/_ble_edit_history_edit に同時に項目を登録している箇所で注意しておけば問題ない。

    + 一箇所 _ble_edit_history から項目を削除しているのに、
      _ble_edit_history_edit から項目を削除していない箇所を発見する。
      これについては修正した。
      しかし、この事によって _ble_edit_history_edit の中身が空になるとは思われない。
      寧ろ、_ble_edit_history よりも余分な要素が残留してしまうという逆の現象になるはずだ。
      更に、現在の HISTCONTROL の設定ではこのコードは実行されないはずである。

  * syntax: bug 他の問題を調査中に以下のエラーも発生した。 [#D0348]

    _ble_edit_history_edit が空になる事故を調べる為に配列 _ble_edit_history の内容を
    出力しようとしたりして試行錯誤している時に以下の stackdump が生じた。

    stackdump: unexpected ntype="${ for arithmetic expression
      @ /home/murase/prog/ble/ble.sh:1709 (ble-syntax:bash/ctx-expr)
      @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
      @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
      @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
      @ /home/murase/prog/ble/ble.sh:4598 (ble-highlight-layer/update)
      @ /home/murase/prog/ble/ble.sh:4933 (.ble-line-text/update)
      @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
      @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
      @ /home/murase/prog/ble/ble.sh:1157 (ble-edit/bind/.tail)
      @ /home/murase/prog/ble/ble.sh:-4279 (ble-decode-byte:bind/EPILOGUE)
      @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)

    1. echo ${_ble_edit_history_edit[@]: -10}
    2. echo ${_ble_edit_history_edit[@]: -10}"
    3. echo "${_ble_edit_history_edit[@]: -10}"

    というか直接 3. を入力してもなる。
    何と、以下を入力するだけでなる。

    $ echo "${a: -1}"

    メッセージを見るに、単に ${ に入る時に nest の値として
    " も巻き込んで登録してしまっているというだけの事だろうか。
    調べてみることにする。

    →調べてみると明示的に '"${' を nest-push している様だ。
    これは何の為に使っているのだろうか → "${...}" と ${...} では
    中のエスケープなどの取り扱い方法が異なる。これを区別する為の物である。
    更にこれを nest-push する時点では後ろで算術式 (:offset:length)が来るか
    もっと複雑な物が来るかの判定も出来ない。

    それによく考えてみれば算術式の中であっても "${...}" と ${...} で違いがあるのではないか?
    そもそも "${...}" と ${...} の中の文字列の取り扱いの違いは何だったか。
    function ble-syntax:bash/check-quotes のコメントに書かれていた。

      # "${var ～}" の中では '' $'' $"" は無効 (-u extquote の時は '' が無効) になる。

    この事は ${} の中にある算術式の中でも有効の様に思われる。
    というか良く考えてみると、それだけではなくて "${... ${...}}" の中でも有効でなければならない気がする。
    現在の判定では ${...} が始まった所の文脈が CTX_QUOT かどうかだけで見ているが、
    そうではなくて先祖に CTX_QUOT がないかどうか (但し途中に $() などがあったら其処で探索を止める)
    などのように複雑な判定をしなければならないのではないだろうか。

    取り敢えず現在の所は、算術式の中で判定として '${' だけでなく '"${' も考慮に入れる事にする。
    また、"${var: 算術式}" の算術式に含まれる '' $'' $"" についても正しく処理を行う (quote として解釈しない)。
    更に、正しい '' $'' $"" の判定方法に関しては別項目として立てる事にする。

2016-08-05

  * 実は Windows 10 で試すと /dev/tcp/0.0.0.0/80 [#D0347]
    はエラーメッセージを出力する → これは駄目だ。
    やはり Cygwin では別の方法を用いる必要がある。
    取り敢えずのところは &>/dev/null にして様子を見る事にする。

    →既に 1s 以上の場合には /dev/tcp を使わない方法を使っているので、
    いつでもその /dev/tcp を使わない方法を使用することにした。
    しかしこの方法だと子プロセスが死んだ時に sleep が動かなくなる。

    この問題を解決する為には子プロセスの pid を覚えておき、
    死んでいたら確認して再度設置するなどの処置が考えられる。
    しかし面倒である。

    % それよりは cygwin 専用の builtin sleep を添付してしまっても良い気がする。
    % cygwin/cygwin64 bash-4.1/4.2/4.3 それぞれについてコンパイルして添付する。
    % 一致する version がなければ現在の方法に fall back する様にすれば良い。
    % もし cygwin に binary を添付することを許すのであれば、
    % stty に関しても cygwin 用に builtin として提供してしまって良い。
    %
    % しかし、この事の問題点は binary を添付することを許してしまうと、
    % 今迄スクリプトで実装してきたことの意味は何なのかという事になるという事である。
    % 一応、そのバイナリが使えなくても問題なく動作するという点は有意義であるが。
    % バイナリが使えなくても動作するということを保証するのであれば、
    % 多少性能が劣るとしてもそのままで良いじゃないかという気もする。

2016-07-15

  * [保留] _ble_edit_history_edit の初期化時間について [2016-07-07] [#D0346]

    検索速度の向上の為に配列 _ble_edit_history_edit において、
    配列 _ble_edit_history と同様に完全な履歴を保持する様に変更した。
    その為に、一番最初の初期化時に _ble_edit_history_edit のコピーが必要になる。

    気になるのは初期化にかかる時間が余計にかかる様になることだが実際にやってみた所体感としては余り変わらない。
    (もし気になるのだとしたら初期化についても progress を表示する様に変更する必要がある。
    或いは edit を使用するまでは edit の初期化は遅延するなど。)
    因みに、

    $ time ble-edit/history/.generate-source-to-load-history >/dev/null
    real    0m0.600s
    user    0m0.683s
    sys     0m0.119s

    $ time eval -- "$(ble-edit/history/.generate-source-to-load-history)"
    real    0m1.210s
    user    0m1.273s
    sys     0m0.165s

    $ time _ble_edit_history_edit2=("${_ble_edit_history[@]}")
    real    0m0.320s
    user    0m0.316s
    sys     0m0.004s

    _ble_edit_history 本体の初期化時間に較べれば _ble_edit_history_edit
    の初期化時間は 1/4 程度なのでそれほど問題という訳でもない。
    また、工夫してコピー速度を向上しようにもこれ以上の工夫のしようはないと思われる。

    もし改善するのだとしたらコピー自体の速度向上ではなくて、
    コピーの遅延を行う様に修正した方が賢明である。

    [_ble_edit_history 自体の初期化高速化]

    あるいは、一番時間の掛かっている _ble_edit_history 初期化の方の改善が必要である。
    しかしこれ以上の高速化の方法は思い浮かばないし、
    また、部分的なロードをして残りは遅延にするなどの処置をするとしても、
    結局履歴を登録する際や検索を実行する際に、効率の問題から全部をロードする事を余儀なくされるだろう。

    % 本当に改善するのだとしたら、履歴項目を独自形式で保存するような .bash_history の ble 版を管理する事になる。
    %
    % a その様にすれば mapfile/readarray などを用いて比較的高速に読み込める様にできる…かもしれない。
    %   実際に mapfile/readarray などのコマンドが本当に速いのかどうか (どれだけ速いのか) は確かめる必要がある。
    %   良く考えたら複数行に渡る履歴項目も管理しなければならない。mapfile/readarray だと改行を含む要素を読み込めないので、
    %   読み込んだ後で後処理を行う様な方式にしなくては為らない。しかしこれは時間が掛かる。
    %
    % b それよりは source できる様な形式にしておく方が賢明である。
    %   或いは eval -- "_ble_edit_history=$(< ble_history)"
    %   の様にして eval で評価するか。結局今の方式と大して変わらない。
    %
    %   (今の方式の bottle neck が awk の方にあるのだとしたら
    %   現在の awk の出力をキャッシュする事によって高速化が可能という事になる。
    %   しかし bottle neck が bash の eval の方にあるのだとしたら残念ながら余り効果はないだろう。
    %   それぞれ時間を計測する必要がある。
    %
    %   eval $() にしていると非同期動作はしないので
    %   処理時間は awk の処理時間 + eval 時間という形に上乗せになっている。
    %   さて上記の時間計測を見てみると、awk に 0.6s であり、
    %   eval に 0.610 である。という事は awk の出力内容をキャッシュすることによって初期化時間を半減させる事ができるという事になる。
    %
    %   しかし問題点は awk の出力内容をキャッシュしたとして、.bash_history との整合性をどの様に保つのかという事である。
    %   a 一つの方法は .bash_history の内容は完全に無視して history で別の履歴を読み込んでしまうという事である。
    %     しかし、これは既存の .bash_history を無効にしてしまう事になるのでユーザに混乱を与える。
    %     また、終了時に ble が勝手に追加した内容が .bash_history に追記されないようにするなどの対策も必要である
    %   b もう一つの方法は .bash_history の内容は飽くまで尊重して、
    %     .bash_history に対する変更を検出して ble history cache ファイルの内容も更新する様にする事である。
    %     しかしそれは結構面倒な事の様な気がする。結局その更新には awk などで大量の処理をする必要が生じ、
    %     現在の方法と速度的に変わらなくなる気がする。。
    %
    %   やはりこの履歴項目を独自方式で保存する作戦は余りよくない気がする。

    また別の高速化手法として、起動時に非同期で履歴初期化用プロセス (awk) を起動して
    source 用のファイル (仮に history.src とする) を生成しておき、
    必要になった時に awk が終了しているのを確認して source history.src を行うという方法である。
    - 懸念の一つは起動後・履歴初期化前に追加された履歴項目をどの様に反映するのかという事であるが、
      これは初期化前に追加された履歴項目についてはその都度 history.src に追記するという方法で行ける。
    - もう一つの懸念は履歴初期化用プロセスがジョブ管理から見えてしまうことである。
      これについては disown して、wait する代わりに kill -0 && sleep で待つしかないだろうか。しかし sleep が難しい。
      或いは名前付きパイプで同期を取るという手も考えられるがそうすると初期化用のプロセスがいつまでも残存する事になるので好ましくない。

  * complete: double quotation の中で変数名の補完が起こらない。 [2016-07-09] [#D0345]
    →何でか分かった。ctx==CTX_CMDI 等の中で check/parameter-expansion を呼び出しているからだ。
    しかし、実際には "" の中に $VAR がある場合には ctx==CTX_QUOT になっている。

  * complete: というか ${...} の中でも変数名の補完が起こらない。 [2016-07-09] [#D0344]

  * complete.sh: bug 変数名の補完確定時に = の代わりに ' ' が挿入される。 [2016-07-05] [#D0343]

    実の所、挿入したいのは += かもしれない。
    また、declare の引数などの場合には = でも += でもなく ' ' を挿入したいのかも知れない。
    配列変数の場合には =( 等の様にした方が親切かも知れない。

    しかし取り敢えずは最大公約数的な補完として = を挿入する様にして良いのではないか。
    少なくとも ' ' を挿入するよりはましだし、また、変数代入においては、何も挿入しないよりは分かりやすい。
    ただ、declare の引数などに使用する際に何も挿入しない方が良いかも知れない。
    が、実際に使ってみてその辺りは判断する。

  * 以下、GLOBIGNORE が必要なのではないか。 [2016-07-05] [#D0342]

    ./complete.sh:197:  IFS=$'\n' builtin eval 'arr=($(ble-complete/source/command/gen))'
    ./complete.sh:374:  IFS=$'\n' builtin eval 'arr=($compgen)'
    ./complete.sh:385:  # * arr($(...)) としないのは IFS=$'\n' の影響を $(...) の中に持ち込まないためである。
    ./complete.sh:421:  IFS=: eval 'tmp=($FIGNORE)'
    ./complete.sh:485:        IFS=$'\n' builtin eval 'arr=($(compgen -v -- "$COMPV"))'

    また以前の GLOBIGNORE を使っている箇所も含めて ble/string#split を定義して使い回した方がよいのではないか。
    → ble/string#split を追加する事にした。

  * ble/util/joblist: 実は set -b でジョブ状態の変更が即座に出力される? [2016-07-08] [#D0341]

    →でもこれだと bash の stdout/off にしている時に出力された場合などの処理が面倒である。
    標準出力を監視して何か出力されたらそれがジョブ状態の変更に関する物であるかどうかを判定し、

    更にジョブ状態の変更に関する物であればその部分を切り出して出力しなければならない。
    しかし、切り出すと言ってもジョブ項目が何処で終端するのか分からないので確実な方法は分からない。
    途中で切れた離別の出力が混ざったりしてしまう可能性がある。

    現在の実装で問題なく動いているのだからこの方針を考える必要はないのではないか。

  * ble/util/sleep: sleepenh, usleep への fallback [#D0340]

  * isearch: backward-search で既に一致している部分を部分に持つ新しい一致がなされない。 [2016-07-07] [#D0339]
    例えば履歴に qqq が一件だけ存在する時に、isearch で qqq と入力すると一致しない。
    というのも qq まで入力した段階で qqq の内の後半二文字に一致が為され、
    新たに qqq を検索しようとしてもこの qqq は一致対象とはならないからである。

    この修正は簡単だ。と思ったらそうでもなかった。

    % 適当に検索範囲を変更したら C-r が効かなくなってしまった。
    % 今迄と同じものに一致してしまうからである。
    % 修正するべきは isMod の時の検索であった。

    さて、isMod のときの検索範囲を修正するにしてもどの様に修正したらよいのかは謎である。
    現在は isMod のときには一致開始位置を固定したままその場で文字列を伸張する方向で更新を行う。
    しかし、qqq の時の様に一致終端位置を固定したまま伸張する場合もあれば、
    また、伸張ではなくて少しずれてから一致する様な場合も考えられる。

    その様な場合も含めて考えると実は backward-search ばかりでなく forward-search にも問題がある事になる。
    例えば aba なる連なりが或る一箇所 ababac にのみ含まれていたとする。
    ここで abac を順方向に検索しようとすると一致しないという事になる。
    何故ならば aba まで入力した段階で [aba]bac に一致し、その後に c を入力したとしても、
    [abab]ac という一致と、aba[bac...] という一致しか試みられないからである。

    これを解決する為には一致位置の伸張ばかりでなく、
    多少ずらした一致も許す様にしなければならない。
    実の所、現在の isMod の部分のコードは不要で、
    唯単に検索範囲を isMod に応じて変更するだけで良いのではないだろうか。
    →いや、逆方向の探索の時は入力して行く内に今迄一致していた位置よりも範囲が戻る事がある。
      そもそもその為に isMod の時の範囲が修正されているのだ。
      なので、isMod の時専用のコード (一致範囲延長) はそのままで、
      通常の検索の部分の範囲を isMod に応じて変更する様にすれば良い。

    % ble-edit/isearch/next.fib を修正して次の様な処理を行う様に変更した。
    %
    % 0. 前提として検索中は _ble_edit_ind は一致範囲先端を表し、
    %   _ble_edit_mark は一致範囲後尾を表す事にする。
    %   順方向検索の場合は先端は範囲終端位置であり、後尾は範囲開始位置である。
    %   逆方向検索の場合は先端は範囲開始位置であり、後尾は範囲終端位置である。
    %
    % 1. もし isMod (検索文字の追加) を行う場合には現在位置に於ける一致範囲の拡張を試す。
    %
    %   例えば順方向検索で [abc]de の様に一致している
    %   (文字列が abcde で現在 abc に一致しているという意味である) 場合、
    %   初めに [abcd]e の一致を試みる。
    %   或いは、逆方向検索の場合には例えば a[bcd]e に一致している時は、
    %   初めに a[bcde] の一致を試みる。ここで一致範囲 (後尾) が後退することに注意する。
    %
    % 2. 次に通常の検索に入る。
    %
    %   但し、isMod のときとそうでない時で一致の範囲を変更する。
    %   isMod の時には自己にオーバーラップした一致を許可する。
    %   isMod でない時 (次の一致を探す時) は自己にオーバーラップしない一致を試す。
    %
    %   自己にオーバーラップしない一致を試すのは簡単で検索開始位置を先端 _ble_edit_ind に設定すればよい。
    %   自己にオーバーラップすることを許す場合は順方向検索の場合には _ble_edit_mark+1 から検索を行えばよい。
    %   但し、_ble_edit_mark が既に文字列末端に位置している場合は _ble_edit_ind (== _ble_edit_mark のはず) にする。
    %   逆方向検索の場合は微妙で、基本的には _ble_edit_mark-1 から逆方向に検索をしたいが、それだと、
    %   q[qq] だった所にを [qqq] を入力して 1 文字ずれて一致が起こる様な場合に対応できない。
    %   つまり一致先端が 1 ずれる事によって一致末端がずれないということも可能である。
    %   従って、実は _ble_edit_mark にすれば良い。それだと同じ場所に一致する様にも思われるが、
    %   実際は自己にオーバーラップする事を許すのは isMod の時のみであるので、同じ範囲に一致することはない。

    しかしながら実は上記の 1 と 2 は統一可能なのではないかという気がする。
    →統一した。実際の所現在位置に於ける一致範囲の拡張というのは、
    2. の検索範囲を一つ増やすだけで 2 の動作に含ませることができる。
    意外と簡単にすっきりとした実装にまとまった。

    rename: 今迄 isMod としていた識別子を isAdd に変更する。
      現在の実装に於いて、検索文字列の変更が実質文字の追加しかないこと、および、
      文字の追加しかないということを前提とした実装になっていることから。
      将来的に文字の追加以外の変更に対応した時に問題が生じないために。

2016-07-09

  * history: bash-3.0 で history に履歴が登録されないので、 [#D0338]

    履歴展開などの番号がずれてしまう。
    →良く考えてみたら history -r filename 等を用いて履歴を追加できるのではないか。
      実際に試してみた所期待通りに動作する様である。

    但し、history に登録できたとしても依然として終了時に履歴ファイル (.bash_history) には
    追加されない様である。というのも元からファイルから読み込んだ行なので
    敢えて .bash_history に追記する事はないという事なのだろう。
    これは今迄通りに手動で (その場で) 履歴項目を書き出す必要がある。

  * history: bash-3.0, 3.1 で履歴が登録されないだけでなく、 [#D0337]
    _ble_edit_history などにも追加されない様だ。
    history コマンドで履歴を追加できないのは以前から問題だったが、
    地震の管理する履歴に関してはどの様に処理する事になっていたのだったか。
    再確認が必要である。

    更に、コマンドを実行した直後、履歴内の位置がそのままになっている。
    一番最後に移動するべきである。最後に移動する処理は履歴に登録した後に為された物だった事を重うと、
    履歴に登録する過程で途中で抜けてしまっているという事なのだろう。

    2015-08-19 に関連しそうな議論が残っているが、同様の問題については言及されていない。
    つまりこの時点では特に大きな問題は生じていなかったという事になる。
    現在までの間に何か問題を埋め込んだという事だろう。

    →分かった。[[ -o history ]] のチェックで死んでいる。
    しかし bash のマニュアルを見ても history というのが新機能だと書かれていない。
    bash changes を見ても wiki を見ても新しい機能として history が実装されたという話はない。
    古い MANPATH で bash のマニュアルを見たが何と bash-3.1 でもちゃんと history という項目はある様だ。
    ここで set -o で現在設定されているオプションの一覧を見ることができるというので見てみる。
    何と history off になっている。つまり項目として存在していてしかも off になっているという事である。
    bash-3.0 3.1 では off になっていて、bash-3.2 では on になっている。
    さて、試しに bash --norc で起動してみると何れの version でもちゃんと初めから on になっている。
    どのタイミングで off になってしまうのだろうか。
    - --norc で起動した後に source .bashrc をすると off になってしまう。
    - というか source ble.sh すると off になる。
    - ble-detach すると on になる。
    - ble-attach すると off になる。
    - bind -x '"\C-t":set -o' して C-t をすると ble-detach していても off である。
    - --norc で起動した直後に bind -x '"\C-t":set -o' としても off である。

    つまり bash-3.0, 3.1 では bind -x のハンドラの中では常に history off という訳である。
    bind -x の中で、bind -x 以外の実行で history が on になっているかどうか確かめる方法は無さそうだ。
    それならば interactive かどうかで判断を代用するしかないのではないだろうか。
    interactive かどうかで言えば ble が起動している時点で interactive である。
    なので常に有効になっていると思って良いのではないか。

    > それとは別に気になるのが $- である。$- で表示される文字がそれぞれ何を意味するのかについて…。
    > 調べようとしたがマニュアルの何処に載っているか分からない。オプションフラグを表示するとその説明には書かれているが、
    > そもそもオプションフラグという単語がそこ意外に記述されていない。
    > →と思ったら set 組み込みコマンドの説明の下の方に現在のオプションの集合は $- で知る事ができると書かれている。
    >   明示的に書かれていないが実の所一文字オプションが定義されている項目についてはその文字が $- に含まれるということなのだろう。
    >   それとは別に bash が -i で起動された時には i が $- に含まれるとも別の箇所に書かれている。
    >   さて、実際に $- に含まれている文字で h や H は何だろう。見てみると h は hashall で、H は histexpand である。
    >   history 自体の on/off に関連する文字は割り当てられていない様だ。

2016-07-08

  * bash-3.2 補完確定した時のカーソル位置が変だ。 [#D0336]

    よく見たら shopt: autocd なんて知らない、というエラーが表示されている。
    つまり shopt -q を実行する際には 2>/dev/null にするべきという事である。
    修正した。

    さて、ble-0.1 の方ではどうなっていたかと確かめてみた所、
    なんとちゃんと &>/dev/null になっていた。その他の shopt についてもついている。
    つまり、何処かの時点で不要だと勘違いして除去したという事になる。
    blame で見てみた所 854babfc62a0d7865c5cf53db0a9c42ee8813c56 (2015-12-19)
    の大幅な整理の際に消してしまっていた。

  * prompt: PS1: PROMPT_DIRTRIM を実装する。 [#D0335]

    例えば 2 に設定すると、~/hello/test/world は ~/.../test/world になり、
    /home/foo/bar は .../foo/bar になる。
    これは param_wd の段階で省略してしまえば問題ないだろう。

    この機能は bash-3.2 以降の様だが関係なく実装してしまって問題ないだろう。

  * prompt: PS1 \n 周りの動作? → 勘違い [#D0334]

    % IND のつもりで \n を出力しようとするが \e[B が出力されている気がする。
    % これのせいで端末の最終行に何かを表示しようと言う目論見が失敗する。
    % →調べてみたが \n に対しては NEL = \r\n を出力している。
    % では何故 IND が効いていないのだろうか…。

    →そもそも PS1 に最終行を追加する為に記述したシーケンスが誤っていただけの様だ。
    \e[s, \e[u でカーソル位置を復元するとしても、画面がスクロールされてしまうと意味がない。
    そして IND の積もりで \n やら \eD を出力するとスクロールされてしまうので \e[s, \e[u
    しても画面バッファ上の同じ位置には戻ってこない事になる。
    従って、下に一行追加する為には IND RI するのが良い。

    % 所が、現実の端末では IND を実装しているとは限らないし、
    % 大体の terminfo では (端末が実際に対応しているとしても) IND に対して \n が記述されている。
    % しかし、それは仮想端末の設定で \n が \r\n に変換されない状況でしか意味がない。
    % というのも \r が混入してしまう所為で列の位置が先頭になってしまい、
    % 単に IND RI しただけでは元の位置に戻ってくる事ができないのだ。
    % まあ、元の位置に戻ってくる必要がないのであればこれで問題ない。
    % しかし元の位置に戻ってくる必要がある時にはどうするのだ?

    と思ったがよく見たら ble-edit/draw/trace/process-esc-sequence でちゃんと
    その場合の為の対策もされていた。\eD は変換されて "\n + 列の位置に移動" に変換されていた。
    つまり ble においては単に PS1 に \eD を記述しておけばよいという事になる。

    従って、プロンプトで最終行を追加する方法:
    PS1 の "末端" に以下を追加する。末端でなければならないのは PS1
    が複数行で構成されている場合を考えての事である。

    '\[\eD\eM\e7\e[${LINES}H\e[7m hello \e[m\e8\]'

    しかしこれだとコマンド実行時に最終行がごみとして残って厄介だ。
    削除できないだろうか。あるいは先頭行に表示する方が現実的かも知れない。

    '\[\e7\e[H\e[7m hello \e[m\e8\]'

    しかし、それだと以前に出力された内容を汚す事になってしまう。
    PS1 だけではどうにもならなそうだ。もしこの様な機能を提供するのだとしたら、
    RPS1 と同様に LPS1 だとか HPS1 だとか何かの変数を作って ble 側で特別に処理する必要がありそうだ。

  * prompt: 履歴番号 [#D0333]

    よく考えたら PS1 の \! の番号は履歴展開で使う為にあるのではないか。
    だとすれば、history に登録されている番号と実際の番号が一致している必要がある。
    ところが試してみると 1 ずれている。

    bash の動作をもう少し詳しく見てみる事にする。
    例えば履歴に 3 項目登録されている時に \! で表示される番号は 4 である。
    つまり \! は既に登録されている項目の数ではなくて、
    "現在の行が登録された時に登録される番号" であって、履歴項目の数より1つ多い。

    ${_ble_edit_history[]} の中身も確認してみる。番号がずれている…
    と思ったが、良く考えたら history の結果は 1 base の系列である。
    従って 1 ずれている事は問題ない。

    また isearch で表示される "現在位置" が _ble_edit_history 内の番号になっているが、
    これも履歴番号と一致させた方が分かりやすい。

    1. PS1 \! で表示されるものを現在の履歴番号に置き換える。
    2. isearch で表示される "現在位置" を履歴番号 (配列添字+1) にする。

2016-07-07

  * 2016-06-20 isearch: 検索速度の向上 (Bash 配列の workaround) [#D0332]

    進捗状況を表示する様に変更した。

    しかし検索位置によって速度が著しく異なる。
    もしかしてこれは "Bash のループの中で二つ以上の巨大配列を触ると遅くなる" という奴だろうか。
    と思って触る配列を一つに絞ってみたが違いはない様だ。
    次に検索方向を変えて試してみた…ら、凄まじく検索速度が異なる。
    また触る配列を二つに増やしたら順方向の検索でも遅くなった。

    1. 触る配列を一つに絞る
    2. ループの方向を順方向に変える

    これらの二つを満たした時の検索速度は格段に速い。

    まず実は検索は逆方向に検索する事の方が多い。
    従って 2. は実に都合が悪い。素直な実装方法は存在しないので、
    様々な対策の可能性を考えて最良の物を選択する必要がある。
    しかし、1. に関しては比較的簡単に解決できるのではないかという気がするので
    先にこちらにかたを付けてから考える方が良さそうに思われる。

    ★という訳で、触る配列を一つに絞る方法について考える。

    | a 一つの方法は、現在 _ble_edit_history_edit と _ble_edit_history に分けている配列を
    |   一つの配列にくっつけてしまう方法である。
    |
    |   つまり、現在は _ble_edit_history_edit を sparse な配列として保持し、
    |   そこに登録が為されていなかったら _ble_edit_history を参照するという仕組みにしている。
    |   案としては、代わりに _ble_edit_history_edit に完全な情報を保持するというものである。
    |   勿論、_ble_edit_history は別の場所で必要になるから、
    |   これはこれで独立に完全な情報を持つ物として記録しておく必要がある。
    |   そして、_ble_edit_history の更新に際しては同時に同様に _ble_edit_history_edit にも変更を加える様にする。
    |   実はこの案は最近別の理由で考えた。その時にどの様な理由で現状の実装で良いとしたのかを思い出す必要がある。
    |
    |   →2016-05-21 のログである。ble-edit/history/add で編集仕掛の状態をクリアする必要があるが、
    |     その際に配列を丸ごとコピーする事にしている。
    |     このコピーに時間が掛かってコマンド実行が遅くなってしまうので廃案になった。
    |     しかしこの問題は (aa) 編集仕掛の状態を完全にクリアする事を諦める (bash と同じ動作)
    |     または (ab) 編集仕掛の状態になっている項目の履歴番号を全て覚えて置いて、
    |     それについてだけ更新を実行する。という方法の何れかを取って解決する事ができる筈である。
    |
    | b もう一つの方法は _ble_edit_history (密) の内容に関しては for ent in "${arr[@]}" で取得してしまい、
    |   _ble_edit_history_edit (疎) の内容について配列添字アクセスで回すという方法である。
    |
    |   然し疎な配列のアクセス速度がどれくらいの物か実測してみないと分からない。
    |
    |   sparse_array_read.dense
    |     time 242972.10 usec/eval
    |   sparse_array_read.1
    |     time 234972.10 usec/eval
    |
    |   実測してみたが密な配列の場合と殆ど変わらない。寧ろ多少速い位である。
    |   では逆順に添字を動かしても大丈夫か。
    |
    |   sparse_array_read.1r
    |     time 246972.20 usec/eval
    |
    |   疎な場合には (殆ど) 変わらない速度で回す事ができる様だ。
    |   とここで気付いてしまったが、for arr in "${arr[@]}" だと逆順に回す事が不可能である。
    |   # 所で zsh にはこの様な操作がいかにも実装されていそうである。
    |   # 調べてみたら ${(Oa)array} (zsh-4.1.1) というのがあるそうだ。

    これは a の方針にするのが良さそうである。
    但し、編集しかけの状態になっている履歴番号を全て記録する様な仕組みにする。
    まずは、その様な実装方法によって _ble_edit_history 及び _ble_edit_history_edit
    の両方を完全な配列として maintain する様に変更を行う。

    _ble_edit_history_dirt に編集状態の項目の index を記録することにした。
    また isearch は完全に _ble_edit_history_edit だけを用いて動作する様にした。
    _ble_edit_history は使用しない。初回の動作は良好である。
    これにより順方向の検索は格段に向上した。

    ★逆方向の検索をできるだけ順方向の検索で処理できる様にする方法について考える。

    | a つまり高速な検索を実現する為には、履歴項目を逆順に格納した方が早いのではないか。
    |   と思ったが、逆方向に格納するとすると、履歴項目を追加する時に shift をしなければならず遅い。
    |   とすれば検索を開始する直前に反転した内容の配列を一気に生成すれば良さそうだ、
    |   と思う物のこれも良く考えてみれば外部コマンドを呼び出すなどして工夫しなければ難しい。
    |   内部コマンドで reverse を実現する高速な方法は存在するのだろうか。
    |
    |   reverse について時間の測定を試みた (benchmark-array.sh)
    |   外部コマンドを使用する方法だと高速な方法でも 10万要素あたり 500ms であった。
    |   また内部で処理を実行する場合には 10万要素辺り 2150ms であった。それ程の違いはない。
    |   寧ろ Cygwin で外部コマンド起動が遅くなる事を考えれば内部で処理した方が良さそうだ。
    |   しかし、いずれにしても反転だけで 2150ms かかるというのは遅い。
    |
    | b 別の方法として実際に行う検索は逆順だとしても、
    |   内部では順方向に計算を行ってしまうという手も考えられる。
    |   履歴項目の数が少ない内は愚直に逆順に探索した方が早いとしても、
    |   履歴項目が増えてくると順方向に探索を行って最後に一致した物を
    |   取り出す方が早くなるという反転が起こるはずである。
    |
    |   例えば仮に順方向の探索速度が a [s/entry] とし、
    |   また、逆方向の探索速度が位置 x について bx [s/entry] だとする。
    |   現在検索しようとしている文字列の頻度が c = 1/m [個/entry] だとする。
    |   現在位置 x から逆方向に探索したいとする。
    |   愚直に文字通り逆方向に探索を実行するとし x - m の位置で見付かるとすると、
    |   探索に掛かる時間は (bx + b(x-m))m/2 = bm (x+m/2) になる。
    |   順方向に計算して最後に当たった物を採用するとすれば、
    |   探索に掛かる時間は単に ax になる。
    |
    |   さて実際には探索を開始するまでは m が幾つになるか分からない。
    |   普通は最近実行したコマンドを呼び出す場合が多いはずだから m の期待値は小さいはずである。
    |   しかし、検索が進んで行くに連れて m が大きいという事が段々分かってくる。
    |   今 n 回外れた時の m を見積もる式 m = f(n) が与えられているとする。
    |   検索を逆順で y から始めて n 回外れて x = y - n まで来た時に、
    |   残りの検索を順方向で行うか逆順で行うかを予測処理時間で決定する。
    |
    |     ax < bm (x+m/2)
    |
    |   になっていれば其処で逆順検索はやめて順方向検索に切り替える。
    |
    |   | m (> 0) について解くと
    |   |
    |   |   -x + sqrt(x^2 + 2ax/b) < m = f(y-x)
    |   |
    |   | ここで逆探索が外れる程に右辺は増加し左辺は減少する。
    |   | つまり、どこかで両者が反転する場所が存在する。
    |   | そこで検索方向の切替を行えば良いのだ。
    |   |
    |   | では、n 回連続で外れだった時に m はどの様に見積もる事ができるか。
    |   | m もしくは c = 1/m についての事前確率を指定する必要がある気がする。
    |   | 取り敢えず考えると、二項分布で n 回連続で外れる確率は (1-c)^n である。
    |   | - これを最尤とする c は何かというと明らかに c = 0 であり、m = ∞ である。
    |   |   やはり事前確率が必要になる気がする。
    |   |   しかし実際の所検索文字列がどの様な分布を持っているかとか、
    |   |   更に過去に同じコマンドを実行した事があるかどうかとか、その分布とか、
    |   |   検索文字列についてのタイプミスだとか色々考えるとその様な事前確率を
    |   |   設定するのは困難に思われる。だとすれば、もっと別の方法に頼るしかない。
    |   | - 例えば (1-c)^n = 1/2 に為る様な c を求めたらどうだろう。
    |   |   解は c = 1 - (1/2)^{1/n} となる。
    |   |   ここから 不等式を満たす n を事前に計算するのは大変そうである。
    |   | - 或いはもっと単純に n 回失敗した時 m = n とするのはどうだろう。
    |   |   これならもっと楽に計算できるのではないだろうか。
    |   |   逆に言えばこの時点で求めるのが難しければ
    |   |   より複雑な場合は考えるのはやめた方が良い。
    |   |   一番初めの不等式に戻って x = y-n, m = n を代入すれば、
    |   |
    |   |     a(y-n) < bn (y - n + n/2)
    |   |
    |   |   これを満たす n (0<n<y) の条件は、
    |   |
    |   |     a/b+y - sqrt((a/b+y)^2 - 2ay/b) < n
    |   |     2(a/b)y / [a/b+y + hypot(a/b, y)] < n (分子の有理化)
    |   |
    |   |   さて、a/b は一体どれぐらいの値になるだろうか。
    |   |   実測してみる事にする。実際にはループに掛かる定数時間 d も合わせて、
    |   |   それぞれ (a + d)N, bN^2/2+dN という時間が掛かるはずである。
    |   |
    |   |     N=10k 順 time 223972.40 usec/eval = (a+d)M
    |   |     N=10k 逆 time 476972.40 usec/eval = bMM/2 + dM, where M=10k
    |   |     N=20k 順 time 441972.40 usec/eval = 2(a+d)M
    |   |     N=20k 逆 time 1555972.40 usec/eval = 2(bMM + dM)
    |   |     (a + d)M = 222479.3
    |   |     bMM =  602027.6, bM = 60.20276,
    |   |     dM = 175958.6,
    |   |     aM = 46520.7,
    |   |     a/b = 773.
    |   |
    |   |   今、r = a/by (a/b が y の内どれだけの割合をしめるか) を用いて n/y を表現すると、
    |   |
    |   |     n/y > r + 1 - hypot(r, 1)
    |   |     n/y > 2r / [(r+1) + hypot(r, 1)]
    |   |
    |   |   特に y >> a/b の場合を考えれば、r << 1 であり、
    |   |
    |   |     n/y >~ r, n >~ a/b
    |   |
    |   |   となる。sqrt 等の計算を bash で実行する (taylor 展開 or newton 法) のは面倒なので、
    |   |   これぐらいにしておくのがよい様な気もする。
    |
    |   [まとめ]
    |
    |   履歴位置 y から逆方向に検索を開始するとき、
    |   検索時間期待値が短くなるように途中で順方向の検索に切り替える。
    |   n 回連続で見付からなかった場合 m = f(n) = n として期待値を評価する事にする。
    |   この時 r = a/by として、
    |
    |     n/y >= r + 1 - sqrt(r^2 + 1)
    |
    |   になった時に順方向の検索に切り替えれば良い。特に y >> a/b のときは、
    |
    |     n >= a/b
    |
    |   で評価しても良い。実際に a/b を実測してみると a/b ~ 773 になる。
    |
    |
    |   しかしながらこの方法の欠点は何かというと実装が汚いという事である。
    |   途中で順方向に検索順序を切り替えるとすると、中断時に記録しなければならない項目の数が格段に増える。
    |   1. まず、現在の内部検索方向
    |   2. それから一番最後に一致した位置
    |   3. 検索の開始点(これは m の見積もりに必要)
    |   或いは順方向の検索は十分速いと考えるならば中断しないという手も考えられる。
    |
    |   更に現在の実装では _ble_edit_history_edit と _ble_edit_history の両方を参照しなければならないので、
    |   順方向の検索だったとしても結局検索に時間が掛かる事に違いはない。
    |   というか先に _ble_edit_history_edit と _ble_edit_history の
    |   両方を参照しなければならない現状について解決するべきの様な気がしてきた。
    |   →先に触る配列を一つにする課題を解決することにした。
    |
    | c 中位の大きさの buffer 配列にコピーして順次検索を実行する。
    |
    |   例えば 1000 位ずつ buffer 配列にコピーを行って、
    |   その配列から読み出しながら検索を行う。
    |
    | d あるいは部分的順方向検索にするという手もある。
    |
    |   部分的順方向検索の大きさは 2 の累乗で増加する様に設定し、
    |   但し、中断位置チェックの場所を跨がない様にその都度大きさを弄る。
    |   うーん。この方法が現実的の様に思われる。
    |
    |   この方法と較べると b の様な複雑な計算はまるで無駄なことである。

    d の方向で実装する事にする。

    実装した。良好である。以前と比べると検索速度が格段に異なる。

  * syntax-highlight: 変数の右辺の中で * や ?, @(...) などが着色されている。 [#D0331]
    しかし実際には変数の右辺では glob は無効になっている筈である。

    また bash の動作を観察すると glob pattern としての意味は失う (glob 展開はされない) が、
    文法的には extglob を認識している様子である。つまり hoge=@(1|2) などとできる。

  * 2016-06-23 ジョブ状態の変更 (suspended だとか "[1]+ 終了" とか) が出力されない様だ [#D0330]

    [状況確認]

    % これは標準出力だか標準エラーだかに出力されている筈。
    % これがそのまま捨てられているということだろう。
    %
    % 調べてみたが不思議なことに何処にも何も出力されていない様に見える。
    % 標準エラーで処理されなかった行を出力するようにして出力されたファイルの中身を見たが何もない。
    % また、標準出力の出力先のファイルを見ても何も書かれていない。
    % (中身のクリアは行っていないはずだし、少なくともタイムスタンプが変更されていない。)
    %
    % bleopt_suppress_bash_output を off にして試してみることにする。
    % なんと bleopt_suppress_bash_output にしていても何も出力されない様だ。
    % bind -x した関数の中から実行されたジョブは終了が捕捉されないという事なのだろうか。
    % と思って確かめてみたがそんなことはない様だ。
    %
    % $ bind -x $'"\eM": sleep 5 &'
    %
    % では eval にしているから駄目なのだろうか。
    %
    % $ bind -x $'"\eM": eval "sleep 1 &"'
    %
    % と思ったがそういうこともない様だ。
    % suppress output でも出力されなかった事から、fd の繋ぎ替えだとかは関係ないはずだ。
    % では stty などの設定によるものなのだろうか。と思って以下を試してみたがそれでもちゃんと出力される。
    %
    % $ bind -x $'"\eM": stty/enter; eval "sleep 1 &"; stty/leave'
    % $ function stty/enter { stty -echo -nl -icrnl -icanon kill undef lnext undef werase undef erase undef intr undef quit undef susp undef; }
    % $ function stty/leave { command stty echo -nl kill '^U' lnext '^V' werase '^W' erase '^?' intr '^C' quit '^\' susp '^Z'; }
    %
    % 何が原因でジョブ管理の出力が消えているのだろうか。jobs コマンドの呼び出しが関係しているのだろうか。
    % うーん。jobs をやってみて一つ分かった事がある。ジョブが終了して初回の
    % jobs の際に "[1]+ 終了" という内容が出力されている様だ。
    % そしてプロンプトに \j を入れていると内部で初回の jobs が実行されることになり、
    % ユーザの目には何も見えないという具合に為る様だ。
    %
    % もしかして default で終了時にメッセージが表示されるのも、
    % 実はプロンプトに \j が入っているからなのだろうか。
    % と思って PS1='\$ ' にしてみたが、それでもちゃんとジョブ終了直後にメッセージが表示される。
    % 今迄やったのと同様に stty を弄って eval するようにしたがそれでも変わらない。
    %
    % ble を読み込んでいる時とそうでない時の違いが謎である。。
    %
    % 更に ble-detach をしてみたらちゃんと出力される様になった。
    % つまり、何かが違うとすれば、ble-detach の中で行っている設定に依存している可能性がある。

    % →何と分かってしまった。通常の状態に於いてジョブ状態の変化が出力されるのは、
    % ユーザがコマンドを実行した直後である。しかし、ble を attach している時は、
    % ble の eval によってコマンドを実行しているのであって、
    % シェルの機能でコマンドを実行している訳ではない。
    % それが理由でジョブの状態変化が出力されないのである。
    %
    % 一方で、画面に出力される前に明示的に jobs を呼び出した時には、
    % 状態変化がその jobs で表示されて以降では表示されなくなる様だ。

    →と思ったが色々実行してみるとそういう訳でもないらしい。
    コマンドを空にしたまま RET を沢山押してもジョブの状態変化に
    対応するメッセージは何も表示されないが、
    一方で、何らかのコマンド (何でも良い。echo など) を実行すると
    その場でジョブ状態の変更についてメッセージが出力される様だ。

    また PS1 に \j が含まれている場合は、内部的に jobs が実行されて、
    その時にジョブ状態変更についての結果が出力されると、
    画面には表示されないという事になってしまう。

    ※何故コマンドを実行した時にはちゃんとジョブ状態の変更について出力されるのか調べる必要がある。
    調べると ble-edit/exec:gexec/.eval-prologue の中の、
    ble-stty/leave の中でジョブ状態の変更が出力されている。
    中で呼び出しているのは実質 command stty だけである。
    だとすれば、bash は "stty で状態が変更された瞬間にジョブ状態の変更を確認し出力を行う" という事になる。

    という訳で、コマンドを実行した直後にジョブ状態の変更があれば自動的に出力されることが分かった。
    明示的に対処が必要なのは、実のところ、内部的に明示的に jobs を呼び出した時だけの様に思われる。


    [方針]

    % これを解決する方法の方向性として二通り考えられる。
    %
    % a 一つはコマンドを ble.sh で実行する度に jobs を実行して状態変化のあったコマンドを調べる。
    %   特に "終了" したコマンドを検知するのに使用する。ただし、終了したかどうかを判定するためには、
    %   ロケールが設定されていると厄介である。従って LC_ALL=C jobs の様にしなければならないと思われる。
    %
    %   しかしそうするとロケールに従った状態の表示ができない。が、これは仕方がない。
    %
    %   この方法を取った時にもう一つしなければならないのは、
    %   プロンプトの計算や syntax-highlight の際に jobs を実行した時にも、
    %   状態の変更を追跡しなければならないということである。
    %   これは直接 jobs を呼ぶ様にするのではなく、
    %   jobs を呼び出すと同時にその内容を確認するような ble-edit/jobs 的関数を用意すれば良い。
    %   色々の用途に使う際にはこの関数を通して呼び出すことにする。
    %
    % b もう一つの方法は、コマンドが実行可能な状態にある時には bind を弄って、
    %   コマンド実行を引き起こす様なキーでシェルとしてのコマンド実行が為される様に構成する。
    %   しかしこの方法は基本的に無理である。
    %   というのも唯単にコマンド実行が起こる様に構成するのだとすると、
    %   シェルの標準出力・標準エラー出力などを本来のものに戻さなければ為らず
    %   (そうしないとコマンドを実行した結果が画面に出力されずに失われてしまう)、
    %   その様にするとカラーに着色した表示を無理にするためにちらつくことになる。
    %
    %   他にもコマンドが実際に実行されたかどうかの判定等々色々面倒である。
    %   この方法は駄目である。まるで枠組を一から再考しなければならなくなる。
    %
    %
    % 上記の a の方向で考えることにする。基本的にコマンド実行が終了した時にチェックを行う。
    % これはプロンプトの計算を行って、プロンプトを出力する直前に結果を出すということにする。
    % 或いは、明示的にコマンド実行が終了した時にチェックを行うというのではなくて、
    % 単にプロンプトの描画の部分で jobs を確認して出力を行うという様にすれば良い。
    % 特にプロンプトの再描画 (前回と同じ内容) などではなくて、プロンプトの再計算を行ったタイミングで出力することにしたい。
    %
    % その他の処理で jobs を呼び出してその際にジョブ状態の変更を検知した場合には、
    % 検知したということを何処かの配列にでも覚えて置いて、
    % その次にプロンプトを再計算・再描画しようという時に改めて出力する様にすればよい。

    状況に誤認が多少あった。基本的に上記 a の方針で行くが、
    コマンドの実行が合った場合 (stty で設定が変更された場合) は、
    bash が自動的にジョブ状態の変更について確認を行い出力を行う事が分かったから、
    実際に対処が必要になるのは内部で明示的に jobs を呼び出した時のみである。
    特に PS1 に \j が含まれている時の動作である。


    前準備として (既定の) jobs が一体どのような出力をするのかについて詳しく調べておく必要がある。

    - ジョブのコマンドに改行が含まれている場合は jobs の結果はどうなるのか。
      →複数の行にまたがって出力される。

      現在のジョブ数のカウントではどの様にしているか。
      →ちゃんと対策できていない。余分に表示されてしまう様だ。これは対策が必要だ。

    - "終了" "Done" などの文字列を検出する方針について

      % LC_ALL=C jobs にすると "実行中" の代わりに Running と表示される。
      % しかし "終了" は "終了" のままである。LC_ALL=C; jobs などとしても駄目だ。
      % しかし、LC_ALL=C としてから jobs とするとちゃんと Done と表示される。
      % どの様な動作基準になっているのだろうか。
      % LC_ALL=C jobs → だめ
      % LC_ALL=C; jobs → だめ
      % (LC_ALL=C; jobs) → だめ
      % LC_ALL=C eval jobs → だめ
      % どうも LC_ALL は設定してから反映される迄に時間が掛かるということの気がする。
      % 代わりに LANG を使って同様にしてみたが動作は変わらない。
      % だとすれば、bash-3.0 で C-d を捕捉する為に ignoreeof-message.txt でやっている様に、
      % Done に対応する文字列の一覧表を作る必要がある。
      %
      % 過去の記録に基づくと ignoreeof-message.txt は generate.sh で生成している。
      %
      % また修了の仕方によって様々なメッセージが考えられる。
      % 単に kill すると Terminated と表示される。
      % 他にも色々の修了の仕方に応じてメッセージが異なるのかもしれない。
      %
      % 或いは単純に jobs を二回実行して状態が変化したジョブについてのみ
      % 出力を行うという風にしても良いのではないだろうか。
      % というかもし jobs に状態変化があるのだとすれば、
      % 結局二回 jobs を実行する必要がある様な気がする。
      % こちらの方法のほうが合理的な気がする。
      %
      % 知りたいのは特にジョブが "終了" したとか "強制停止" されたとかではなく、
      % 単にジョブの実行状態の変化が知りたいというわけである。
      % だとすれば jobs によって出力される結果の変化と等価なものを提供したい。
      % これを調べるためには単に jobs の状態変化を追えば良いという訳である。

      固定文字列を使用する方法だと不安定に思われるので、
      jobs を二回実行して比較する方針で実装する事にした。
      また、ジョブの状態変化に対応するために前回の jobs の呼び出しについても記録を行っておく。

    - jobs %1 などの様に指定を行ったとしても状態変化したジョブの情報は出力されるのか?

      →なんと番号を指定していたとしても状態変化したジョブの情報が一緒に出力されてしまう様である。
      →もしかすると標準エラー出力などに出力されている可能性?
        確認してみたが普通に標準出力に混ざって出力されている様だ。

      bash の既定の動作は不思議な動作なのでこれについては模倣する必要はないように思われる。

    [実装]

    1 取り敢えず jobs の出力を解析する関数を作成する必要があるだろう。

      実装してみた → ble/util/joblist

      同時に jobs に状態変化したジョブの内容が
      報告されている可能性があるのでそれを毎回調べる必要がある。
      毎回調べる必要があるのだから、毎回二回解析を実行して差分を調べる様にしてしまっても問題ないだろう。
      終了したジョブなどに関して言えば一回目の jobs で出力されていて、
      二回目の jobs で出力されていなければそうであると判断できる。

      しかし、実行状態から停止状態に移ったジョブや、
      その逆のジョブに関してはこの方法では検知できないのではないかという気がする。
      ここで確認して置かなければならないのは通常の bash の時に、
      その様な状態変化が標準出力に報告されるのかそうでないのかという事である。
      調べてみたところ、実行状態から停止状態に移った時には報告が為されるが、
      停止状態から実行状態に映った時には何も報告が為されない。

      さて速度は気になる。

      $ ble-measure ble/util/joblist
      time 2410.60 usec/eval
      $ ble-measure 'ble/util/assign jobs jobs; GLOBIGNORE=\* IFS=$'\''\n'\'' builtin eval "jobs=(\$jobs)"'
      time 357.60 usec/eval
      $ ble-measure 'ble/util/assign jobs jobs'
      time 305.60 usec/eval
      $ ble-measure jobs
      time  11.10 usec/eval

      単なる jobs の実行とは比ぶべくもない (220倍)。
      しかし比較対象はその出力を変数に格納するときの場合である。
      単なる ble/util/assign jobs jobs と比較すると 8 倍程遅い。
      行分割も考えれば 7 倍程度の遅さである。
      うーん。まあ 2ms 程度であれば許容範囲内ではあるが、
      7倍というのは余りに大きい。まだ高速化の余地はある様な気がする。
      もし使ってみて遅い様に感じたらその時にまた高速化を考える方向で良いとする。

      ジョブを 10 個にして試してみた。
      $ ble-measure ble/util/joblist
      time 13170.60 usec/eval
      $ ble-measure 'ble/util/assign jobs jobs; GLOBIGNORE=\* IFS=$'\''\n'\'' builtin eval "jobs=(\$jobs)"'
      time 2020.60 usec/eval
      $ ble-measure 'ble/util/assign jobs jobs'
      time 729.60 usec/eval

      % 13ms というのは結構遅い気がする。何とかならないものか。やはり正規表現による一致に時間がかかるのか。
      % そう思って以下のように正規表現を使わないように書き換えた。
      %
      %   - [[ $line =~ $rex_ijob ]] && ijob="${BASH_REMATCH[1]}"
      %   + local n=${line%%']'*}; [[ $line == '['[0-9]*']'* && ${n//[0-9]} == '[' ]] && ijob=${n:1}
      %
      % それで計測してみたところ、
      %
      % $ ble-measure ble/util/joblist
      % time 12570.60 usec/eval
      %
      % 微妙に早くなった。違いは有意である。しかし絶対量としては大して変わらない。
      % わざわざこの様な分かりにくい方法を選択する程の利点はない。

      % 或いは直に正規表現を記述しておけば precompile されるだろうか。
      %
      % [[ $line =~ ^\[([0-9]+)\] ]] && ijob="${BASH_REMATCH[1]}"
      %
      % $ ble-measure ble/util/joblist
      % time 13170.60 usec/eval
      %
      % まったく変化しない。駄目だ。

      遅さの原因は for ループにある様に思われる。
      for ループ無しにジョブの分割などを実装する方法はあるだろうか。
      つまり /\n\[[0-9]+\]/ の箇所で分割を実行する。
      その時に [0-9]+ の番号の部分を保持したい。
      或いは、/\n/ で分割した後に /\[[0-9]+\]/ 以外で始まる行を潰す。

      →遅いので 1回目の jobs の時点で前回からの変化がない場合には以降の処理を省略することにする。


      遅い第一の原因が分かった。[[ $a == $b ]] の比較において二つ目の引数を quote していなかった。
      bash が二つ目の引数の中身を glob pattern として parse している事が原因だったようだ。
      これを修正したら、ジョブが 10 件ある状態でも以下の様な速度に落ち着いた。3.5倍程度である。

      $ ble-measure ble/util/joblist
      time 7220.40 usec/eval

      更に一回目の jobs の結果が前回の結果と全く同一の場合にはそもそも処理を完全にスキップできる。
      結果として以下の様になった。今まで (jobs) と殆ど変わらない速度である。
      というより今迄 (毎回 jobs + 改行で分割) より高速になっている。OK

      $ ble-measure ble/util/joblist
      time 383.90 usec/eval

      取り敢えず ble/util/joblist 完成という事でここで commit しておく事にする。

    2 ble/util/joblist で状態変化をチェックする様にしたが、
      先頭の "-+" の有無の変化も検知してしまっている。これらを無視した比較が必要である。
      →対策した。

      色々試した結果、あるジョブが終了した後に別のジョブが同じ番号に入った時、
      (同じジョブの状態が変化したというように) 誤検知してしまう。
      その様な誤検知が起こるのはコマンド実行の stty 時にジョブの変化が bash によって出力され、
      その事が ble/util/joblist のキャッシュに反映されないという場合である。

      これを防ぐためには stty 実行時にキャッシュをクリアするか、
      stty 実行直前に明示的に ble/util/joblist.check を呼び出すかする必要がある。
      stty 実行時に確実にジョブの状態変化が bash によって出力されるというのであれば、
      ble/util/joblist.clear してしまって良いだろう。

    3 検知した状態変化を何処かのタイミングで出力する必要がある。

      これは新しくコマンドを実行する直前と、コマンドを実行した直後にしたい。

      コマンドを実行する直前 (もしくはプロンプトの再計算を要求する箇所) を探してみる。
      先ず、コマンドを実行したりする為に newline を呼び出す。
      ここでは _ble_edit_LINENO を increment する。
      _ble_edit_LINENO が変化しているとプロンプトの再計算が実行され、
      次にプロンプトを表示する際に一から表示されることになる。
      さて、よく見ると _ble_edit_LINENO を更新する直前で、
      プロンプト・コマンドライン行の末端で改行を出力している。
      この直後で jobline.flush を実行すれば良いだろう。

      一方でコマンドを実行した直後ではどうだろう。
      これについては、そもそもコマンドを実行している最中に内部関数
      ble/util/joblist を呼び出すことは想定していないので、
      そもそも何らのジョブ変更イベントも記録されない様に思われる。
      従って、わざわざ出力させる必要はないと考える。

      →通常の bash はどの様な動作であったか。試してみる。
        どうやら "外部コマンド" が終了する度に確認を行っている様である。

        一方で、複数のコマンドの間に挟まれてジョブ情報が出力されると見にくいので、
        ble ではコマンド実行の前とコマンド実行の後にまとめて出力するのが良さそうである。

      現状では、コマンド実行を開始する直前の command stty でジョブ情報が出力される。
      (というか実は command stty でジョブ情報が出力されるのも、
      別に stty が呼び出されたからジョブ情報が出力される、というのではなくて、
      単に外部コマンドが呼び出されて終了したからジョブ情報を出力しているという動作に過ぎないのではないか。)
      従って、コマンド終了後にまとめてジョブ情報を出力する仕組みにしているとジョブ情報の順序が前後することになり分かりにくい。
      よって、コマンド実行をする前に joblist.flush はしておきたい。

      一方で、長いコマンドを実行して終了した時に既にジョブ状態が変更されている場合、
      その出力を次のコマンドを入力して実行した時まで遅延するというのはまた分かりにくい。
      それならばいっその事コマンド実行が終了した時にも同様にチェックをしたい所である。
      コマンド実行が終了する箇所というのを探すのは簡単である。
      行末位置調整などを行っている場所で一緒に実行してしまえばよい。

    4 動作確認

      bug: events が二回ずつ登録されている。これはどういう事か。

        →調べてみたら、実行中から終了に変化し、終了から空に変化し、
        という所で両方に引っ掛かってなっていた様である。
        どちらか片方だけで良い。

      bug: それと joblist の表示が一足遅い気がする。何故か。

        →これはプロンプトの再計算が on demand で行われている為で、
        joblist.check, joblist.flush をしてからプロンプトを計算して、
        その時にジョブ状態の変更が検出されるためではないだろうか。
        結果として次のコマンド実行まで検出されたジョブ状態変更が出力されない。

        しかしそれは変だ。それならば何故初めの joblist.check で検出されないのだろうか。

        →理由が分かった。そもそも joblist.check, joblist.flush をしていない。
        現在はコマンドを実行した後に joblist.check, joblist.flush をしているが、
        よく考えてみたら空コマンドで newline した時はそもそもコマンド実行に到らないので、
        joblist.check, joblist.flush には到らないのだ。
        従って、newline をした時でも joblist.check 及び joblist.flush
        を実行する様に変更しなければならない。それも明示的に。
        うーん。でも変だ。newline をした時に flush はしている筈なのに…。
        と、よく考えたら flush しているだけで check をしていなかった。

        うーん。設計を眺めてみるに flush の直前には必ず check をする事になっている。
        考えてみればそれもそうだ。そうでなければならない。
        なので、flush の内部で check を呼び出してしまう事にする。

      現在の所動作良好である。反応も遅くなっていない。

2016-07-04

  * ble-detach して ble-attach すると、BS が効かない。 [#D0329]

    bind -p | less で確認すると以下の項目について unbind できていない。
    "\C-u": self-insert
    "\C-v": self-insert
    "\C-w": self-insert
    "\C-?": self-insert

    しかし不思議だ detach してみると上記のキーは self-insert
    ではない物に bind されている。だとすると、何処かで変な bind をしているのか?

    うーん。変だ。この状態で

    $ builtin bind -x '"\177":ble-decode-byte:bind 127; builtin eval "$_ble_decode_bind_hook"'

    を手動で実行してみる。するとちゃんと BS が効く様になる。
    ということは ble-attach の方の問題なのだろうか。

    ble-attach を少しずつ実行してみることにする。
    ble-decode-attach の source "$_ble_base_cache/ble-decode-bind.$_ble_bash.bind" を実行すれば直る。

    うーｎ。何か、これ、前にも似た様なことをして対策した様な気がする…と思ったら、
    関数 ble-decode-bind/uvw である。ここでは変数 _ble_decode_bind__uvwflag を使って、
    未だ設定が行われていなければ bind をやり直すということをしている。
    そしてこの関数は ble-decode-byte:bind/PROLOGUE で呼び出されている。
    つまり、毎回ちゃんと呼び出されると考えて良いだろう。
    そうすると問題は _ble_decode_bind__uvwflag の値の設定ということになる。
    これを検索してみると、ble-decode-bind/uvw を定義した一箇所しか存在しない。
    つまり、最初の ble-attach でしか uvw に対する特別な bind が動作しないということである。
    これでは駄目だ。という訳で ble-attach の際に _ble_decode_bind__uvwflag= を設定すれば良い。
    →これで解決した。

2016-06-27

  * $_ble_base/cache ユーザの分離ができていない。 [#D0328]

    これも $_ble_base/tmp と同様に chmod a+rwxt
    してその下に $UID でデータを置く様にする必要がある。
    あと UID 変数は信用できるのだろうか→man bash によれば読み取り専用である。OK.

    既に cache というディレクトリを作ってしまっているので、
    g pull 等で更新した時には問題になる。
    cache.d という名前のディレクトリに変更して処理するべきである。
    また、その際に既に存在しているファイル達を移動する仕組みも提供するか。

  * [2016-06-22] sleep の実装方法 → ble/util/sleep として実装した [#D0327]

    $ mkfifo tmp/sleep
    $ exec 3<> tmp/sleep
    $ function sleep { local v; ! read -t 0.1 v <&3; }

    自分で作った fifo なら自分で書き込まない限りはブロックされる事が保証できる。

    # これで cygwin でも高精度な sleep ができる! と思ったらそんな事は無い。
    # "bash: read: 読み込みエラー: 0: Communication error on send"
    # というエラーを出力して終わってしまう。
    #
    # うーん。仕方がない。cygwin では /dev/tcp/0.0.0.0/80 に頼るか…。
    # (少なくとも cygwin では bash /dev/tcp が有効でビルドされている事は知っている。)
    # しかし、/dev/tcp/0.0.0.0/80 が完全に永劫にブロックする物なのかは謎である。
    # これについては長時間放置したテストが必要になる。
    # →と思ったら高々 20 秒で接続を諦めて止まる様子だ。
    # しかし接続を諦めたとしてももう一回実行すればまたブロックされる。
    # さて、この方法の問題点は何かというと普通に外に向かって通信を開始してしまう事である。
    #
    # うーん。また mkfifo に戻ってくる。cygwin はやはり駄目なのか。
    # http://cygwin.1069669.n5.nabble.com/Bug-Named-Pipes-FIFO-Bash-td10925.html
    # と思ったらどうも cygwin では真面目に mkfifo の blocking な振る舞いを実装する気はなさそうだ。
    # 色々な人が文句を言っていると言う事は work around はないという事ではないか。
    #
    # あるいは cygwin ではこうする?
    #
    #   exec 3< <( while :; do sleep 1d; done &> /dev/null )
    #
    # できた! と思ったが…そもそも
    #
    #   time read -t 0.1 <&3
    #
    # がきっかり 0.1 にならずに 0.109 か 0.125 になる…。うーん。何故だ。
    # 因みに /dev/tcp/0.0.0.0/80 は 0.094 か 0.109 になる。こちらはそんなに変ではない。
    # もう一つの問題点は C-c をするとそれが while :; ... に伝達して終了してしまう事。
    # プロセス置換が延々と生きていて欲しいのだが…。
    # <(while do done &) としてみたがすると今度は <&3 で読み取ろうとしても何も読み取れない。
    # うーん、C-c だけならば trap -- '' INT とかすれば良い。
    # しかし今度は C-\ を押した時にやはり消えていなくなる。QUIT を追加した。
    # しかし、うーん、INT と QUIT だけ無視しておけば OK なのかどうかは不明である。

    [cygwin の場合、まとめ]

    cygwin の場合には mkfifo でブロックされない。
    /dev/tcp/ は外部に変なアクセスをするので timer には向かない。
    というか socket を作りまくって接続数の上限に抵触する可能性すらある。
    更に、時々固まるので時間計測にも支障を来す。

      exec 3< <( trap -- '' INT QUIT; while :; do sleep 1d; done &> /dev/null )

    で頑張るしかない。しかしこれによる sleep は多少遅延がある。

    →実際にやってみたら read -t 0.001 <&3 するだけで 12ms の時間を消費することが分かった。
      read -t 0.001 -u 3 でも時間は全く変わらない様だ。
      一方で read -t 0.001 </dev/tcp/0.0.0.0/80 は遅延が 1.5ms 程度と短い。
      どうも繋がっている先によって遅延時間が異なる様である。

      もっと他の繋ぎ方も試してみる事にする。

      $ mkfifo tmp1
      $ (exec 3> tmp1; sleep 65535) &
      $ exec 8< tmp1
      $ read -t 0.001 -u 8
      → やはり同じ時間掛かる。

      うーん。/dev/tcp がごく短い時間しかかからないというのが不思議だ。
      実は通信を始める前に処理を中断しているのだという可能性もある。
      →うーん。実際に while :; do read -t 0.01 </dev/tcp/0.0.0.0/80; done を試してみたが、
        外部に対して通信を行っている気配はない。
        ということはネットワークに対する負荷はないのではないか。
      →今度は実在する IP アドレスに対して同じ事を行ってみた。
        外部に対して通信を大量にしまくっている様だ。これはいけない。
        ということはやはり 0.0.0.0 の場合には通信が内部で閉じているという事である。
        しかしこれは Windows だけの話かも知れないので他の OS では事情が異なるかもしれない。
        やはり mkfifo が期待通りに働かず pipe が遅い Windows ならではの措置である。

    Cygwin 上で系統的に速度の計測を行ってみる

    $ exec 9< <(
    >   [[ $- == *i* ]] && trap -- '' INT QUIT
    >   while :; do command sleep 65535; done
    > )
    $ (exec 3> tmp1; sleep 65535) & exec 8< tmp1
    $ exec 7<> tmp1

    | コマンド                                | 実行時間 (Cygwin)  | 環境2
    |-----------------------------------------|--------------------|--------------------
    | sleep 0.001                             | 1819.10 usec/eval  | 1214.50 usec/eval
    | read -t 0.001 < /dev/tcp/0.0.0.0/80     | 1967.50 usec/eval  | 1410.60 usec/eval
    | read -t 0.001 < /dev/tcp/127.0.0.1/80   | 1967.50 usec/eval  | 1410.60 usec/eval
    | read -t 0.001 < /dev/tcp/███.███.6.2/80 | 23337.50 usec/eval | 14070.60 usec/eval
    | read -t 0.001 < /dev/udp/0.0.0.0/80     | 3067.50 usec/eval  | 1310.60 usec/eval
    | read -t 0.001 <&9                       | 12437.50 usec/eval | 1210.60 usec/eval
    | read -t 0.001 -u 9                      | 12437.50 usec/eval | 1220.60 usec/eval
    | read -t 0.001 -u 8                      | 12437.50 usec/eval | 1210.60 usec/eval
    | read -t 0.001 -u 7                      | ※1                | 1200.60 usec/eval

    ※1 bash: read: read error: 6: Communication error on send

    | コマンド                                | 環境1 Cygwin | 環境2 GNU/Linux |
    |-----------------------------------------|----------|---------|
    | `read -t 0.001 < /dev/tcp/0.0.0.0/80`   | 2.0 ms   | 1.41 ms |
    | `read -t 0.001 < /dev/tcp/127.0.0.1/80` | 2.0 ms   | 1.41 ms |
    | `read -t 0.001 < /dev/tcp/██.██.6.2/80` | 23 ms    | 14.1 ms |
    | `read -t 0.001 < /dev/udp/0.0.0.0/80`   | 3.1 ms   | 1.31 ms |
    | `read -t 0.001 <&9`                     | 12 ms    | 1.21 ms |
    | `read -t 0.001 -u 9`                    | 12 ms    | 1.22 ms |
    | `read -t 0.001 -u 8`                    | 12 ms    | 1.21 ms |
    | `read -t 0.001 -u 7`                    | エラー   | 1.20 ms |

2016-06-20

  * isearch: 検索に時間が掛かっている時に進捗状況を表示する。 [#D0326]

    isearch_suspend で進捗状況を表示しようと考えたが、どうも動かない。
    よく考えてみたら isearch_suspend は次の文字が標準入力に来ている時にだけしか起こらない。
    なので、次の文字が来ているかどうかに拘わらず更新をしなければならない。
    最初は一定の数以上処理を行ったら中断を行う様に変更しようかとも考えたが、
    次の文字が来ていないのに中断を実行してしまうと続きの検索が処理されなくなってしまう。
    従って、中断を行うのではなくてその場で更新を行う必要がある。

    →実装した。検索の進捗状況が表示されている。

  * isearch: history 検索に時間が掛かっている時に次の入力が来たら中断できないか? [#D0325]

    % 単に中断するのだと問題がある。abc と入力したのに b
    % が入力されなかった事になってしまうという事があるからである。
    % 検索に時間が掛かっている状態で次の入力が来た時の振る舞いについて整理する必要がある。
    %
    % a back 等で検索状態を一つ戻すキーが来た場合には処理を中断する。
    %   直前の状態に戻りキーの入力を待つ。
    %
    % b RET やその他のキーで等で確定する場合には、
    %   一旦 RET を受領してから検索の続きを実行し、
    %   当たったら其処で確定を行う。
    %
    %   引き続きその他のキーについて処理を実行する必要がある時には
    %   それを自分で呼び出す必要がある。
    %
    % c 続きの文字を入力した場合は、
    %   やはり一旦キーを受領してから検索の続きを実行し、
    %   それが終わったらまた次のキーを処理し、
    %   という事をしなければならない。
    %
    %   単に検索文字列を更新するだけでは駄目なのは、検索の進行をスタックに記録しなければならないからである。
    %   つまり、abc と入力したら a まで入力した時の一致位置、b まで入力した時の一致位置も記録しておかなければならない。
    %   - そうしないと abc まで打ってから back をして ab に戻した時に適切な位置にまで戻ることができないからである。
    %     勿論、abc が一致しているのだから ab が同じ位置で一致していたということは明かだろうが、
    %     例えば ab までは一致して abc について一致する項目がない場合には、
    %     ab に戻るためには ab の位置がやはり記録されていなければならない。
    %   - 何より、a → ab → abc という様に検索を行っても、abc を一発で検索しても検索のコストが変わらない。
    %     従って、わざわざ検索文字列をすりかえて処理を一回の検索で済ませる様にする利点がない。
    %
    %   検索を再開する場合には前回の検索位置からの続きとして実行をしたい。
    %   初めから検索をやりなおすのではどんどん時間が掛かる様になってしまうからである。
    %   その為には現在の検索位置の変数をグローバル変数にする、
    %   または、検索位置の変数を対応するグローバル変数に保存するようにする必要がある。
    %
    % 結局、現在検索中かどうかと言う情報を保持する様にすればよいように思う。

    結局考察の結果として少し違った実装になったので、上記の当初の案はそのままは採用されなかった。


    さて、検索中に次の文字が来た時にどの様に検索方法を修正するかなどについては
    いきなり考えると訳が分からなくなってしまうので、
    取り敢えずは検索を単に中断して再開する方向で実装を考えてみる。

    取り敢えず ble/widget/isearch/next-history を中断可能に書き換える。
    と思ったけれどももっと全体を見てから書き換えた方がよい様な気もする。
    どの様に実装すれば良いか。取り敢えず現在の方法はすっかり止めて、
    [タスクを登録] → [タスクを実行] という形に変更しなければならない。
    そしてタスクを実行している途中で中断があればタスクを再開する
    というタスクを先頭に挿入する必要がある。
    もしくは先頭に挿入するというよりは完全に新しくタスク列を設定し直すという考え方でも良い。
    もし現在待ち状態になっているタスクがない場合には、その時に限って直接実行を行っても良い?


    中断を実行できる様に設計を変更した。以下の問題点・課題がある。

    - isearch: is-stdin-ready で中断するとき、既に一致したコマンドラインの描画が為されない
      →別項目 2016-06-20
    - isearch: 検索中の accept は実行しない。
      →別項目 2016-06-20
    - isearch: 検索に時間が掛かっている時に進捗状況を表示する。
      →別項目 2016-06-20

  * isearch: is-stdin-ready で中断するとき、既に一致したコマンドラインの描画が為されない [#D0324]

    is-stdin-ready が true になっている限りコマンドラインの描画がされないので、
    全ての検索が終了するまで、途中の一致が表示されない。
    これは恐らく今迄の実装でもそうなっていたのではないかと思われる。

    →これについては is-stdin-ready の時に描画をスキップする様になっている箇所で、
    何らかの変数を参照して描画を実行する必要がある場合はスキップしない様にすれば良い。
    描画を実行するかどうかを決定づけているのは、ble-decode-byte:bind/EPILOGUE である。

    しかし、ここでは is-stdin-ready の際には描画をスキップするだけでなく、
    ユーザによって実行を要求されたコマンドの実行もスキップされる。
    今回の用途の場合にはコマンドの実行もスキップする必要はあるのだろうか。
    そもそも今回の場合 (isearch) には検索中にコマンドの実行が要求される事がない。
    なので、もっと異なる状況で考えなければならない。
    例えば、複雑なキー操作と思い処理によって順次実行するコマンドの内容を決定していく場合を考える。
    この様な場合に確定したコマンドを実行するタイミングはどうであるべきか。
    うーん。現在の処理だと中途半端な状態でコマンドを実行すると、
    編集行の下に表示されているパネルなどの上にコマンドの実行結果が上書きされたりして変な事になる。
    本来は、コマンドを実行する前にその様なパネルなどの表示を消去しておくべきなのである。
    現状の方向性としては、

    a. 描画する時はコマンド実行をスキップしない。パネルなどの表示はコマンド実行時に消去する様にする。
    b. is-stdin-ready の場合には描画をスキップしないとしてもコマンド実行をスキップするか、

    の二通りが考えられる。どちらもそれなりに理に適った実装の様に思われる。
    但し、コマンドをスキップするかスキップしないかに拘わらず、
    コマンドの実行時には一時的に表示しているパネルなどは消去するべきなのは確かである。
    現在の所は実装が楽な b. の様に処理をすることにして後で問題になったら a. にするのが良さそうである。
    パネルの一時消去に関しては新しく項目を作って保留とする。

    → 変数名は _ble_edit_bind_force_draw とする。


    変数に描画が必要である事を設定する箇所の候補は二つ考えられる。

    a. ble-edit/isearch/.goto-match
    b. ble-edit/history/goto

    そもそも描画をスキップしない様にする必要が生じるのは、
    時間の掛かる処理を実行している途中に、入力に応答できる様に中断する時である。
    ということはスキップしない様に値を設定するのは、
    その様な中断を行う枠組の方であるべきである。
    ble-edit/history/goto はその様な時間の掛かる処理以外でも使われる。
    つまり、ble-edit/isearch/.goto-match の側で設定を行うべきである。

  * isearch: 検索中は accept をしないように変更したい。 [#D0323]
    今迄の実装だと現在実行中の検索が終わってから accept をしていた。
    しかし、これだと思いがけず変なコマンドが検索に当たって実行されてしまうかも知れないので。
    また、現在表示されている (現在までに一致した) コマンドを実行するという仕組みにするのも危険である。
    というのも現在実行中の検索がある場合、ユーザが accept をしようとした瞬間に
    表示されているコマンドが切り替わる可能性があるからである。

    しかし accept しないと言っても検索の中断はすぐさま行われる訳ではないので、
    多少の検索が実行されて新しく一致した後にそのコマンドが実行される可能性もある。
    しかし、"基本的に accept しない" 設計にしておけば、
    ユーザからすれば検索中に accept することの意味が殆ど失われるので、
    ユーザがその様な操作を実行する可能性が少なくなる。
    従ってその心配はしなくても良いのではないか。

2016-05-21

  * 出た 2016-04-23 [#D0322]

    [状況]

    | stackdump: 0 <= beg=23 <= end=24 <= len=1; beg=23, end=23, ins(1)=c
    | @ /home/murase/prog/ble/ble.sh:5079 (_ble_edit_str.replace)
    | @ /home/murase/prog/ble/ble.sh:-1789 (ble/widget/self-insert)
    | @ /home/murase/prog/ble/ble.sh:33 (ble-decode-key/.invoke-command)
    | @ /home/murase/prog/ble/ble.sh:22 (ble-decode-key/.invoke-partial-match)
    | @ /home/murase/prog/ble/ble.sh:37 (ble-decode-key)
    | @ /home/murase/prog/ble/ble.sh:92 (ble-decode-char/.send-modified-key)
    | @ /home/murase/prog/ble/ble.sh:50 (ble-decode-char)
    | @ /home/murase/prog/ble/ble.sh:-966 (ble-decode-byte+UTF-8)
    | @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |
    | 改めて探してみるが不整合が出る様な場所は存在しない。
    | _ble_edit_str に値を設定している場所は _ble_edit_str.replace, _ble_edit_str.reset だけである。
    | _ble_edit_str.reset-and-check-dirty は現在の設定では使用していない筈である。
    | _ble_edit_dirty_syntax_{beg,end} に関しても値を設定している箇所は
    | _ble_edit_str/update-dirty-range だけだし、
    | _ble_edit_str/update-dirty-range を呼び出している箇所は、
    | 上記の _ble_edit_str.{replace,reset} だけである。
    |
    | と思ったが…良く考えたら挿入位置が範囲外になっているという事だろうか。
    | self-insert で起こっているという事は、
    | _ble_edit_ind の値が範囲外になっているという事である。
    | そして今迄の経験から言ってこの現象が起こるのは履歴の操作をした後であるから、
    | 履歴の移動を行った際に _ble_edit_ind の更新を忘れている、または、更新に失敗しているというのが怪しい。
    |
    | ble-edit/history/goto を確かめてみたがちゃんと _ble_edit_ind _ble_edit_mark は設定されている。
    | 怪しいのは、ble-edit/history/goto の直後に ble-edit/isearch/.set-region を実行している箇所である。
    | ここで格納されている・或いは関数外から指定されている beg end はちゃんと範囲内になっているのだろうか。
    | 結局また迷宮入りの様な雰囲気がしている。
    | しかし前よりは進歩があった。_ble_edit_ind, _ble_edit_mark の設定が怪しい。

    → _ble_edit_ind, _ble_edit_mark が異常な値 (範囲外) になっている。

    [原因]

    | 怪しい所を発見した。
    | ble/widget/isearch/next-history において、_ble_edit_history における一致箇所を取得している。
    | その次に ble-edit/isearch/.goto-match で一致した箇所に移動を行っている。
    | しかし、ble-edit/isearch/.goto-match から呼び出された ble-edit/history/goto では
    | _ble_edit_history_edit または _ble_edit_history から文字列をロードしている。
    | もし _ble_edit_history_edit が設定されているのに _ble_edit_history の中に一致が見付かった場合、
    | _ble_edit_str には _ble_edit_history_edit からの文字列が設定され、
    | _ble_edit_ind には _ble_edit_history の中の文字列における位置が設定される。
    | _ble_edit_history_edit の文字列が _ble_edit_history の文字列よりも短く、
    | 更に検索で _ble_edit_history の末尾付近 (_ble_edit_history_edit の文字列の長さよりも後尾) で一致が発生した場合、
    | そこで _ble_edit_ind に対する不整合が生じることになる。

    →ble/widget/isearch/next-history において _ble_edit_history の中を検索している。
      しかし、実際に ble-edit/history/goto で設定される文字列は _ble_edit_history_edit から優先して取得される。
      両者の文字列の内容に違いがある場合不整合が生じる。
      更に、長さが異なり _ble_edit_ind が範囲外になった時にエラーが発生する。

    [再現方法]

    | 実際に再現するかどうかを試験する。
    | →カーソルの位置がずれるというバグを発見した。しかしながら、
    |   以前から出ているエラーは再現しない。
    |
    | うーん。_ble_edit_ind が不正な状態の時に self-insert が発生する為には、
    | 或る時点で検索が中断されなければならない。矢印キーで検索を中断しようとすると、
    | カーソルの移動が起こって、その際に正しい位置に _ble_edit_ind が設定され直す様だ。
    | (本当か?) → 確かに関数 .ble-edit.forward-char において範囲外になった時のチェック・補正が行われている。
    | という事は、矢印キー以外で検索を中断する手段があるという事になる。再度キー割り当てを確認する。
    |
    | C-d にすると補正が行われずに検索状態から抜けられそうである。
    | 実際にやってみた。確かに初めの self-insert で変な状態になっている様に見えるが、
    | しかしエラーは発生しない様である。うーん。と思ったが、検索した文字がいけない?
    |
    | 1. "echo hello" RET として入力・実行
    | 2. up back*5 down として hello を削除
    | 3. C-r "h" C-d で検索を行い中断
    |
    | としたが "h" で検索を行ったので "echo " の末尾にカーソルが設置された状態になっていて
    | 何も問題が発生していないという事ではないだろうか。という事で o で検索を行ってみる事にする。
    | 出た! 再現方法が分かった! 以下に再現方法の最小操作を書く

    再現方法 → "aa" RET up C-u down C-r "a" C-d "a"

    [解決方法]

    ad hoc には検索時に _ble_edit_history だけでなく _ble_edit_history_edit も参照する様にすれば良い。
    しかし、やはり実際に履歴を遡った時に表示する内容を _ble_edit_history に格納した方が良いのではないかという気がする。
    つまり、現在は実際の履歴を _ble_edit_history に格納し、履歴の編集仕掛の状態を _ble_edit_history_edit に格納しているが、
    そうではなくて、編集したものも含めて _ble_edit_history に格納しておいて、
    編集前の状態を _ble_edit_history_edit に格納するという様に変更するべきかもしれない。

    しかし、一方で現在の編集状態が _ble_edit_history に入っていると不都合という場合もあるかもしれない。
    _ble_edit_history か _ble_edit_history_edit かどちらの値が入っている方が扱いやすいかについて、
    それぞれの配列が使用されている各箇所で確認を行う必要がある。

    * ble-edit/history/add の erasedups のチェックで使用する _ble_edit_history は編集前の内容であるべきである。
    * ble-edit/history/goto で読み出しているのは編集後の内容であるべきだ。現在は既にその様な実装になっている。
    * ble/widget/isearch/next-history で使用するのはやはり編集後の内容であるべきだ。
      そしてここではループなどで読み取りを実行する為、_ble_edit_history_edit,
      _ble_edit_history の両方をチェックする様な実装にはしたくない。

    両者ともループでチェックする部分を含んでいる事から、編集前の状態と編集後の状態を完全に保持するという手もある。

    * redo undo との関係

      | また、今後 redo undo を実装することも考えて実装を選択する必要もあるだろう。
      | redo undo を前提にするとどの様な実装が良いだろうか。
      |
      | a 一つの方法は現在の編集後の状態を _ble_edit_history に記録しておいて、
      |   編集の履歴は一つの配列に edit[編集番号]="履歴番号 文字列" の形で積み重ねて記録する方法である。
      | b もう一つの方法は、配列の履歴番号に対応する要素に edit[履歴番号]="文字列0 文字列1 ..." と格納する方法である。
      |   この方法だと格納する文字列に適切な escape を施す必要がある。
      |   例えば空白類を別の文字で置き換えるか、或いは、%q で格納しておいて使用する時に eval で取り出す。
      | c 或いは編集前の状態を _ble_edit_history に記録して、編集の履歴を a と同様に格納する方法、
      | d また、編集前の状態を _ble_edit_history に記録して、編集の履歴を b と同様に格納する方法が考えられる。
      |
      | 何れの方法を選ぶとしても erasedup check もしくは next-history で、
      | 編集前の状態、編集後の状態の両方を高速に処理することはできない。
      | という事は結局、やはり、編集前の状態・編集後の状態・編集過程の情報
      | の三種類を独立に管理するという事になる。
      | この内の "編集過程の情報" の管理に関しては redo undo で完全に閉じている話で、
      | 実際に redo undo を実装する段階になってから考察すればよい。
      | そして、編集前の状態・編集後の状態に関しては redo undo の方法に依らずに実装できる。
      | つまり、redo undo と履歴データの保持は直交的である。或いは、直交的な実装にするのが見通しがよい。

      [結論]

      "編集前の状態"・"編集後の状態" は redo undo とは関係なく実装する。
      更に redo undo については "編集過程の情報" を保持する何らかの形式の配列を用いる。

    % 現在は、編集前の状態を _ble_edit_history に格納し、
    % 編集がある場合には編集後の状態を _ble_edit_history_edit に格納している。
    % その儘 _ble_edit_history_edit が完全な情報を持つ様に拡張を行うのが自然に思われる。
    % しかし、その為の管理は大変ではないかどうか確かめる必要がある。
    %
    % 基本的に _ble_edit_history に値を設定している箇所で
    % 同様に _ble_edit_history_edit にも値を設定する様にすればよい。
    % 調べてみた所 _ble_edit_history に値を設定しているのは、
    % ble-edit/history/load と ble-edit/history/add だけである。
    % また _ble_edit_history_edit に値を設定しているのは、
    % ble-edit/history/add で _ble_edit_history_edit の中身をクリアしている所と、
    % ble-edit/history/goto で移動前に値を格納している所だけである。
    % 以外と変更範囲が少ないので拡張の見通しは良い。
    %
    % [実行]
    % _ble_edit_history_edit の拡張を実行する。
    % 更に改名: _ble_edit_history -> _ble_edit_history0,
    % _ble_edit_history_edit -> _ble_edit_history
    %
    % [問題]
    % 変更してみるとバグは発生しなくなった。しかし今度は別の問題点が生じる。
    % コマンドの実行が遅い。コマンドを実行する際に履歴に実行するコマンドを登録する。
    % その時に _ble_edit_history0 の内容を丸ごと _ble_edit_history にコピーする。
    % そのコピーに時間が掛かっている様だ。実際に、
    %
    %   time alpha=("${_ble_edit_history[@]}")
    %
    % を実行してみると、0.374s かかっている。ble-edit/history/add ではこれを2回実行している。
    % つまり、毎回 0.7s 以上の遅延が生じるという事になる。
    %
    % やはり丸ごと同じ物を管理するというのは非現実的なのだろうか。
    % 或いは、_ble_edit_history の内容をクリアするのに丸まるデータをコピーするのではなく、
    % 変更のあった物だけクリアするという方法でも良い。
    % この方針の場合には、変更のあった履歴番号を記録に残しておく必要がある。
    %
    % 或いは、実際に _ble_edit_history を使おうとするまでは
    % _ble_edit_history0 -> _ble_edit_history のコピーは遅延させるか。
    % しかし何れにしても history の検索に無駄な時間が掛かることに違いはない。

    速度が遅いということが判明したので、
    _ble_edit_history_edit にも完全な情報を持たせるという方法は棄却することにした。
    代わりに、(多少検索に時間が掛かる様になるかもしれないが) 編集後の値が必要な箇所では

      ${_ble_edit_history_edit[i]-${_ble_edit_history[i]}}

    の形式でアクセスする様に変更した。

    何れにしても現在の時点で既に検索には時間が掛かる傾向があって、
    その対策として検索中に入力がないかチェックすることを考えていた。
    検索中に入力がないかチェックする機能が完成すれば、
    この形式のアクセスによるオーバーヘッドは気にならなくなるだろう。
    (実測はしていないが元々そんなに重くはないだろうと予想されるので)。

    以下にある過去の報告はこの修正で直った物と思われる。
    もし依然として問題が残っているのだとしても、それはその時に考える事にする。

    | 2016-01-12
    |
    | * 履歴検索を起動しただけで×になった。比較的最新版である。
    |   最近の構文解析のバグは全て潰した後である。
    |
    |   | stackdump: X1 0 <= beg:11 <= end:12 <= iN:1, beg:11 <= end0:11 (shift=1 text=s)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4 (_ble_edit_str.update-syntax)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4441 (ble-highlight-layer/update)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:4884 (.ble-line-text/update)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (.ble-edit-draw.update)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:966 (ble-edit/bind/.tail)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-4230 (ble-decode-byte:bind/EPILOGUE)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1 (ble-decode-byte:bind)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 0 <= 11 <= 12 <= 1 <= 1
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   |   ※以降のエラーは全て ble-syntax/parse 以下で起きている。
    |   |     上記と同じなので詳細な stackdump は以降は省略する。
    |   | stackdump: X1 0 <= beg:12 <= end:13 <= iN:2, beg:12 <= end0:12 (shift=1 text=ss)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 1 <= 12 <= 13 <= 2 <= 2
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | stackdump: X1 0 <= beg:13 <= end:14 <= iN:3, beg:13 <= end0:13 (shift=1 text=ssh)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 2 <= 13 <= 14 <= 3 <= 3
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | stackdump: X1 0 <= beg:14 <= end:15 <= iN:4, beg:14 <= end0:14 (shift=1 text=ssh )
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 3 <= 14 <= 15 <= 4 <= 4
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | stackdump: X1 0 <= beg:15 <= end:16 <= iN:5, beg:15 <= end0:15 (shift=1 text=ssh l)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 4 <= 15 <= 16 <= 5 <= 5
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | stackdump: X1 0 <= beg:16 <= end:17 <= iN:6, beg:16 <= end0:16 (shift=1 text=ssh la)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | -bash: beg: 読み取り専用の変数です
    |   | stackdump: X2 0 <= 5 <= 16 <= 17 <= 6 <= 6
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |   | assertion failure: ((nofs<${#node[@]}))
    |   | ble-syntax/tree-enumerate/.impl(i=4,iN=6,nofs=0,node=,command=ble-syntax/parse/shift.impl2/.proc1)/FATAL1
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:7612 (ble-assert)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:108 (ble-syntax/tree-enumerate/.impl)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:22 (ble-syntax/tree-enumerate)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:1901 (ble-syntax/parse/shift)
    |   |   @ /home/murase/.mwg/src/ble.sh/out/ble.sh:-16 (ble-syntax/parse)
    |
    |   三つの問題点が生じている。再現性はない (正確には、再現方法は未だ不明)。
    |
    |   1. dirty range がおかしい (文字列の長さの外にある)。
    |     これはここではなく dirty range を更新している部分でチェックを行うべきではないか。
    |   2. dirty range がおかしい時の対策として beg, end を再設定している。
    |     しかしここで "-bash: beg: 読み取り専用の変数です" のエラーが発生している。
    |   3. 以下のエラーが発生している。node が空である。
    |     assertion failure: ((nofs<${#node[@]}))
    |     ble-syntax/tree-enumerate/.impl(i=4,iN=6,nofs=0,node=,command=ble-syntax/parse/shift.impl2/.proc1)/FATAL1
    |
    |   どうも今迄の経験から 1. の範囲の異常は履歴の移動に関係している気がする。
    |   取り敢えず 2. "beg: 読み取り専用の変数です" のエラーメッセージの部分だけは修正する。
    |   3. に関してはこのエラーに関係しているのかどうか分からないが、
    |   一見すると独立なエラーのようにも思われる。
    |   しかし発生したタイミング的には明らかに相関している。
    |   そうだとするとどの様にしてこのエラーが発生するのか確認する必要がある。
    |
    |   先ずは改めて dirty range の計算について調べる。
    |   _ble_edit_str が直接変更されているのは、初期化時を除けば、
    |   function _ble_edit_str.{replace,reset,reset-and-check-dirty} のみである。
    |   現在の所 reset-and-check-dirty は使用されていない。
    |
    |   →トラップをしかけたら直ぐに引っかかった。
    |   _ble_edit_replace である。履歴検索をして中断した後になる。
    |
    | 2015-11-30
    |
    | * 構文解析部分更新の bug
    |
    |   + bug (2015-11-28a)
    |
    |     $ seq2gif -f 0 -b 254 < demo.tty > out/img/demo.gif
    |     カーソルを先頭に移動した時?? 再現しない。
    |
    |   + stackdump: X1 0 <= 48 <= 49 <= 1, 48 <= 48
    |       @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |       @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |       @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |       @ /home/murase/prog/ble/ble.sh:4327 (ble-highlight-layer/update)
    |       @ /home/murase/prog/ble/ble.sh:4818 (.ble-line-text/update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |       @ /home/murase/prog/ble/ble.sh:1001 (.ble-decode-byte:bind/tail)
    |       @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |     stackdump: X2 0 <= 0 <= 48 <= 49 <= 1 <= 1
    |       @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |       @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |       @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |       @ /home/murase/prog/ble/ble.sh:4327 (ble-highlight-layer/update)
    |       @ /home/murase/prog/ble/ble.sh:4818 (.ble-line-text/update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |       @ /home/murase/prog/ble/ble.sh:1001 (.ble-decode-byte:bind/tail)
    |       @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |
    |     また出た。一旦 C-u した後に RET して貼付をしたら出た。2015-12-03
    |     でもまた同じようにしても再現しない??
    |
    |     stackdump: X1 0 <= beg:66 <= end:96 <= iN:30, beg:66 <= end0:66 (shift=30 text=function () () { echo hello; })
    |       @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |       @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |       @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |       @ /home/murase/prog/ble/ble.sh:4353 (ble-highlight-layer/update)
    |       @ /home/murase/prog/ble/ble.sh:4844 (.ble-line-text/update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |       @ /home/murase/prog/ble/ble.sh:1140 (.ble-decode-byte:bind/tail)
    |       @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |     stackdump: X2 0 <= 0 <= 66 <= 96 <= 30 <= 30
    |       @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |       @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |       @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |       @ /home/murase/prog/ble/ble.sh:4353 (ble-highlight-layer/update)
    |       @ /home/murase/prog/ble/ble.sh:4844 (.ble-line-text/update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |       @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |       @ /home/murase/prog/ble/ble.sh:1140 (.ble-decode-byte:bind/tail)
    |       @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |
    |   見た感じ dirty-range の更新に失敗している様である。

2016-04-07

  * バグが出た。再現性がある。 [2016-04-05 提起] [#D0321]

    今迄に出ていたバグとはまた種類が異なる様に見える。

    | $ CXXKEY=g454 cxx -I$HOME/opt/libmwg-201509 20160318.idea.sfinae-overload.cpp ← 最後の引数の先頭で C-w C-y C-y する
    | $ CXXKEY=g454 cxx -I$HOME/opt/libmwg-201509  -I$HOME/opt/libmwg-201509 20160318.idea.sfinae-overload.cpp
    | $ CXXKEY=g454 cxx -I$HOME/opt/libmwg-201509 -I$HOME/opt/libmwg-201509 20160318.idea.sfinae-overload.cpp
    | $ CXXKEY=g454 cxx -I$HOME/opt/libmwg-201509 -I$HOME/opt/libmwg-201509/i 20160318.idea.sfinae-overload.cpp
    |
    | assertion failure: ((nofs<${#node[@]}))
    | ble-syntax/tree-enumerate/.impl(i=40,iN=106,nofs=0,node=,command=ble-syntax/parse/shift.impl2/.proc1)/FATAL1
    |   @ /home/murase/prog/ble/ble.sh:7630 (ble-assert)
    |   @ /home/murase/prog/ble/ble.sh:108 (ble-syntax/tree-enumerate/.impl)
    |   @ /home/murase/prog/ble/ble.sh:22 (ble-syntax/tree-enumerate)
    |   @ /home/murase/prog/ble/ble.sh:2127 (ble-syntax/parse/shift)
    |   @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
    |   @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
    |   @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/prog/ble/ble.sh:4388 (ble-highlight-layer/update)
    |   @ /home/murase/prog/ble/ble.sh:4902 (.ble-line-text/update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   @ /home/murase/prog/ble/ble.sh:966 (ble-edit/bind/.tail)
    |   @ /home/murase/prog/ble/ble.sh:-4248 (ble-decode-byte:bind/EPILOGUE)
    |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)

    単純化する。何と以下の操作だけでバグが出る。

    $ echo  $B+
    $ echo $B+
    $ echo $B+12

    上から二行目の時点で何か以上になっていると見るべきであろう。
    空白を消したりせずに、先頭から順に入力した時には何もエラーには為らないので、それと比較すればよい。

    +-------------------------------------------------------------+-------------------------------------------------------------+
    | エラーが発生する直前                                        | 正常時 (順に入力した時)                                     |
    +-------------------------------------------------------------+-------------------------------------------------------------+
    | [murase@padparadscha 0 ~]$ echo $B+                         | [murase@padparadscha 0 ~]$ echo $B+                         |
    | A?                                                          | A?                                                          |
    |  2 aw   000 'e' | stat=(1 w=- n=- t=-1:-1)                  |  2*aw   000 'e' | stat=(1 w=- n=- t=-1:-1)                  |
    |  | aw   001 'c' |                                           |  |*aw   001 'c' |                                           |
    |  | aw   002 'h' |                                           |  |*aw   002 'h' |                                           |
    |  | aw   003 'o' + word=2:0-4                                |  |*aw   003 'o' + word=2:0-4                                |
    |  3 a    004 ' '                                             |  3*a    004 ' '                                             |
    | 14 a  s 005 '$' | stat=(3 w=- n=- t=1:-1)                   | 14*a    005 '$' | stat=(3 w=- n=- t=1:-1)                   |
    |  7 a    006 'B' |                                           |  7*a    006 'B' |                                           |
    |  4 a    007 '+' + word=4:@3>5-8 stat=(4 w=4:5- n=- t=-1:4)  |  4*a    007 '+' + word=4:@3>5-8 stat=(4 w=4:5- n=- t=-1:3)  | !
    | \_ 'echo'                                                   | \_ 'echo'                                                   |
    | \_ '$B+'                                                    | \_ '$B+'                                                    |
    +-------------------------------------------------------------+-------------------------------------------------------------+

    早速違いがある。記録されている stat だ。木構造に於ける兄の位置がずれている。
    具体的に表示されているのは t=tclen:tplen の様だ。
    実際には tplen = _ble_syntax_stat[index][5] に記録されている。

    正常値 tplen=3 は 3 文字前の 境界4 で単語が終了している事を表している。
    そして、それは実際には単語情報が セル3 に格納されている事を表す。
    一方で異常値 tplen=4 は境界3 で単語が終了して セル2 にデータが格納されている事を期待する。
    ところが其処には何も格納されていない為にエラーが発生するのである。

    と言う事はスペースを削除する瞬間に _ble_syntax_stat[index][5] の shift に失敗している事になる。
    shift を実行しているのは function ble-syntax/parse/shift.stat である。
    実際に shift の際に呼び出されている所を確認する。j=9 及び j=6 で呼び出されている。
    これは実際に stat が設置されている場合にのみ shift を行うという事なのだろう…?
    しかし良く分からないのが、この時点で設置されているのは j=6 及び j=8 なのではないかという事である。
    うーん呼出元を確認してみる事にする。現在は ble_shift_method は 2 に設定されているので、
    function ble-syntax/parse/shift.impl2/.proc1 が実効的に処理をしている事になる。
    これに実装中という文字が書かれているのが気になるが、よく動作を見てみる事にする。

      ここで気付いたのだが、shift が起こったかどうかは _ble_syntax_shift という配列に記録して、
      それを上記の dump で表示している事に気付いた。s という文字がある場所でだけ実際に shift が起こったという事を表す。
      確かにそれを見ると 境界7 に設定されている stat で shift が起こらなかったという事が見て取れる。
      つまり、このバグの問題点は shift するべき対象の列挙に失敗しているという事である。

      やりにくいので末尾 (iN 番目) に設置されている stat も ble_debug=1 で表示する事にする。

    改めて ble-syntax/parse/shift.impl2/.proc1 に戻る。
    ble-syntax/parse/shift.impl2/.proc1 の呼び出しの時点では j = 9 ... 6 について処理を行う様に呼び出しがある様だ。
    という事は問題は skip にあるという事だろうか。というか i だとか j2 だとか j の値は誰が決めているのだろうか。。

    - 先ず、i については ble-syntax/tree-enumerate/.impl が設定している値の様である。
      現在処理を行っている word (tree node) の終端境界の番号である。
      具体的に word の情報は _ble_syntax_tree[i-1] に格納されている。
      さて、ここでの疑問は shift.impl2 で参照している変数 i が果たして
      本当に tree-enumerate の内部変数を意図しているのかという事である。
      shift.impl2 の呼出元を辿ってみるが意図して i を設定しているという箇所はないようなので、
      これは確かに tree-enumerate の内部変数 i を意図しているのだろうと推測・仮定する。

    - 次に j, j2 に関しては ble-syntax/tree-enumerate/.impl では特に設定を行っていない様である。
      というか寧ろ shift.impl2/.proc の呼出元 (ble-syntax/parse/shift) で意図的に iN 及び j を設定している。
      この変数名は本当は変えるべきである。tree-enumerate の実装を変更して内部で j を使う様に変えてしまうと事故が起こる。
      いや、iN に関しては変更する必要はない、というか、iN は tree-enumerate に対する入力(tree 起点)なので変数名は変えては行けない。

      うーん。変数名を変えようと思ったが tree-enumerate を跨いで共有されている変数が実は他にも沢山ある様だ。
      しかも広範な関数でこれらが共有されている。

      beg,end,end0,shift は勿論の事、ble-syntax/parse のローカル変数である i1,i2,j2,iN も共有されている。
      そして j に関しても、shift.stat, shift.nest, shift.tree, shift.tree/1 等の
      諸々の関数で使用されているので変数名を変える訳には行かない。
      しかし j という変数名は余りに衝突が起きやすそうであり危険である。
      これは後で処理する事にした。

    変数の役割については大体分かったので、実際に .proc1 を呼び出した時の変数の様子について見てみる。

      shift.impl2/.proc1: current word: 6-9, end0=6 tprev=4 tchild=-1
      shift.impl2/.proc1: loop will be j = 9 (_shift2_j) ... 6 (j2)

    という事のようだ。この時 tchild が存在していないので内部に対する探索は行われない。
    そのままその単語についてだけ処理が行われて中に設置されているデータに対する shift は実施されないのである。
    つまり "$B+" という単語については内部構造がないので内部の shift を省略するというのである。
    しかしながら実際には内部に解析再開点が存在している。これらの shift が飛ばされてしまうのである。

    うーん。これはこの shift 対象列挙の strategy 自体に欠陥があるという事になる。
    内部の解析再開点に関しては一つ一つ配列の中身を確認して shift を試みるという手もあるが、
    それだと元々の strategy 1 と違いがない。寧ろ strategy 1 の様に単純に shift を全部試みるのがよい。
    或いは、

    結局何が問題なのかというと内部の解析再開点については単語の内部にしか参照を持っていないと仮定したからではないかという気がする。

    > 一つの方法は tree nest は木構造を反映した方法によって更新を行い、stat はそれとは別に更新を行うという方法である。
    > そして、stat を保持するに当たって直前の stat の位置を一緒に記録する事にするのである。
    > 直前の stat の位置の情報を保持するとなると
    >
    > - ble-syntax/parse の変数が一つ増える。
    > - shift の際にその直前の stat の位置もずらさなければならない。
    > - 直前の stat の位置も一致していないと同一状態になったと判定できないので、中断が起こりにくくなる。
    >
    >   > しかしながら直前の stat の位置というのは実は解析に使用されていないので、
    >   > それが一致していなくても解析中断を実行しても良いという気がする。
    >   > というか、今迄が直前の stat の位置に依存せずに中断を起こしていたのでこれは問題にならない。
    >   > 単純に前回の解析中断位置をその場で更新して終了するだけで済む話である。
    >   > 更に、len (負のoffset) で記録しておけば shift も実は行わなくて良い様な気がする。
    >   > len を shift する必要がある場合というのは、
    >   > 直前の解析中断位置と現在位置の間に dirty range が被っている場合で、
    >   > しかし、その様な場合に関しては何れにしても再解析が実行される事になるのでその時に結局上書きされるのである。
    >
    >   結論: 直前の stat の位置は解析中断判定には使わない。直前の stat の位置は stat 更新時に設定すればよい。
    >
    > しかし、shift だけを実行して、実際の解析を最後までやりきらなかった場合には一体どうなるのだろうか。
    > 現状ではその様な動作はしない事になっているが将来的には解析を途中で中断して、それから
    > 解析を後で再開するというような機能を実装したいと考えている。というか、現在の構造はそれを意図しての構造である。
    > しかし、解析を後で再開しようという時に直前 stat 位置の shift が中途半端な状態になっていると
    > 再度の shift を実行する事が不可能になってしまう。
    >
    > →えーと。でもそれは現在の tree-enumerate による実装でも同様なのではないだろうか。
    >   途中で解析を中断して後で解析を始めよう…という時に tree 構造が中途半端になっていると、
    >   そもそも tree 構造を辿って shift 位置を楽しようと言う事ができなくなる。
    >   つまり、現在の実装だと結局全探索を余儀なくされるという事になるのではないだろうか。
    >
    > ちょっと現在の手法について再度一から考え直した方が良いような気がする。
    >
    > 一応直前 stat 位置を記録する、という方法は何とか manage する事ができる。
    > 解析途中で一時停止をする際に辻褄が合うように直前 stat 位置を更新すればよいのである。
    > しかし tree 構造に関して解析一時停止をする時になんとか辻褄が合うような形にするというのは無理である。
    > できるとしても可成り複雑になりプログラムを書くのが面倒になる事請け合いである。
    >
    > 従って tree, nest に関してもそれぞれに直前の非空白要素の位置を管理する様にすれば良い気がする。
    > そもそもは、既にある tree の仕組みを利用すれば additional な情報を管理せずに
    > 高速に shift 対象を列挙できるのではないかと考えた事にあった。
    > この様に直前の非空白要素の位置を管理するようにしてしまうと管理コストが増えてしまう。
    > しかし、これも将来的にはしょうがないという気もする。

    結論:

    現状の方法では、解析一時中断を行った時に shift 対象の高速な列挙が出来なくなる。
    唯一の現実的な高速化手法は "直前非空白要素の位置" を管理するように変更する事である。
    これは解析自体の動作とは全く関係なく、_ble_syntax_tree/stat/nest の配列としてのデータ構造を拡張するという事である。
    解析自体の実装とは直交して実装する事が可能と思われるが、新規情報の管理コストが増えるという問題点が残る。

    > 解析一時中断を考えない現状での解決方法についても考えてみる。
    > 解析一時中断を考えない事にすれば、現状の方法でも解決する方法があるかもしれない。
    > 何が問題だったかというと、その単語が dirty range に被っていないのであれば、
    > 内部に存在している stat nest の何れも dirty range 及びそれを跨いだ参照は持たないと仮定した事にある。
    > しかし乍らその単語自体が dirty range に被るような参照を持っている場合は、
    > 内部に設置された stat も dirty range に被るような参照を持っているという事を意味する。
    > 何故ならばその単語が dirty range に被るような参照を持つ事が出来るのは、
    > 内部の stat を通じてその参照が継承されたからなのである。
    > 従って *少なくとも* その単語自体が dirty range に被るような参照を持っている場合には、
    > 内部の shift を実行する必要があるという事になる。
    > 問題はその単語自体が dirty range に被るような参照を持たない場合に、
    > 実は内部の stat が dirty range に被るような参照をもっているかもしれないという事である。
    > 外部に対する参照として可能なのは基本的に tprev inest のみである。
    > 単語内部では既に wbegin が設定された状態にあり、それを跨ぐ事が出来るのは tprev (tplen) inest (nlen) だけだからである。
    > tchild (tclen) に関しては wbegin 以降でなければならない。wlen については wbegin その物を参照する。
    > その他の種類の参照は多分存在していない様に思う。

    結論: 単語外部に対する参照として可能なのは tprev inest のみである。
      tplen 及び nlen について dirty-range に被らないという事が保証できる時に
      単語内部の探索のスキップが可能である。

    tprev に関してチェックを追加しようと思ったら既にチェックが入っていた。
    というかコメントに正にその様に書かれている。
    それなのに今回その事が問題になった。では、一体何が悪いのか。
    何か ble-syntax/parse/shift.impl2/.proc1 の構造が変である。
    →結局大幅に直した。バグが出なくなった。skip も適切に行われている。
      結局、問題点については shift.impl2/.proc1 の実装当初認識していたが実装が甘かったという事だ。

    % 後で余裕があれば shift.stat, shift.nest, shift.tree, shift.tree/1 は引数で j を受け取る様に変更する。
    %
    %   shift.stat, shift.nest の呼出元は何れも 3 箇所である。意味的にも j を引数で受け取って変な事はない。
    %   shift.tree の呼出元は二箇所である。しかし実は既に引数として nofs を受け取る仕組みになっている。
    %   j を新しく受け取れるような仕組みにはなっていない…?
    %   然し意味を考えれば nofs というのは _ble_syntax_tree[j]
    %   の要素の中の更に nofs 番目のフィールドという意味であるから、
    %   本来は nofs を受け取るのであればそれが属している所の j も受け取るのが自然である。
    %   なのでこれも書き換えて問題ないと考える。
    %   shift.tree/1 に関しては様々なローカル変数を受け取っている中で j だけ引数で受け取るようにするのは変である。
    %   幸いにして呼び出しているのは shift.tree だけなので、
    %   shift.tree/1 は親の shift.tree のローカル変数を共有していると考えて、
    %   ローカル変数 j を直截さ割って良い事にする。関数名が shift.tree/1 であるのはそういう事である。
    %
    %   もう一つ確認しておくべき事は各関数が j を内部で書き換えていないかという事である。
    %   内部で書き換えた値が外部に伝播する事を意図しているのだとしたら、
    %   単純に引数で受け取るように変更してしまうと問題が生じる。
    %   これに関しては関数内部を観察してみた所 j を書き換えている様子はないし、
    %   関数の役割的にも j を書き換えるのは不自然に思われたので、多分大丈夫だろう。
    %   多分だとアレなので再度確認する。特に別の関数を呼び出しているという事もないようなので、
    %   更に子関数で書き換えられているという危険性もない。
    %   唯一呼び出されている関数が touch-updated-word であるが、この関数も内部で j には触っていない。
    %
    %   よって以下のように変更を行う → OK
    %   - shift.stat, shift.nest, shift.tree は引数を介して j を受け取る様にする。
    %   - 特に shift.tree に関しては第一引数に j を受け取り、第二引数に nofs を optional で受け取る様にする。

    変数名の変更については、そもそもそんなに綺麗な実装でもないのでどうでも良くなった。
    というか j を紛らわしくない変数名にすると言っても余り良い変数名も思い付かないし、
    _shift2_j の様な不自然に長い変数名だと関数を書いていて何か変な感じがする。
    結局 tree-enumerate を跨ぐ部分でだけ _shift2_j という変数に値を待避する事にした。

    tree-enumerate による skip の実装と解析一時中断の不整合に関しては別項目で残す事にする。


2015-12-24

  * (ble-syntax:bash): time -p 対応 [#D0320]

    > [2015-02-16] (ble-syntax:bash): time -p

    parse_suppressNextStat を用いて無理矢理対応した。
    問題があるかもしれないので注視する。

    + parse_suppressNextStat は常に設置する事にする。

      当初条件を満たせば parse_suppressNextStat を設置せずに
      -p を解析済とする様にしていたがそれでも問題が起こる様だった。

      例えば time -p<(echo hello) の様に入力する事を考える。
      time -p< まで入力した時点で time -p で確定し、再開点が < に設置される。
      しかし <( まで入力した時点で、実は '<' はリダイレクトではなくて単語の一部だったという事になり、
      そこで単語が終わるという仮定の下での time -p での確定が誤りだったという事になる。

      他にも似たような罠があるかもしれないので、
      複雑な条件で parse_suppressNextStat 設置を省略するのは止めて、
      常に parse_suppressNextStat は設置する様にする事にする。

    + -p を確定した場合は単語を設置する事にする。

      この様にしないとコマンドとして解釈していた時の単語着色が残ってしまう。
      (これは現在の単語着色の仕組みの問題点に起因する物であるが、
      -p を単語として登録しても別に損する事は無いし寧ろ好ましい)。

  * (ble-syntax:bash): a=([...]=value), a+=([...]+=delta) に対応。 [#D0319]

    > [2015-02-16] (ble-syntax:bash): a=([key]=value) b=([x]=123 [y]=321)

  * bug: extglob の所為で var+= が正しく読み取られない。 [#D0318]

    どうも var+ まで入力した時点で |var|+ の二箇所に解析再開点が設置される様である。
    この状態で var+= を入力しても解析は += から再開されるので、
    正規表現の var+= に引っかかる事がないという事になる。

    これを何とかする為には、+( 以外の + については解析再開点を設置せずに
    前の解析に取り込んで処理する必要がある。

    parse_suppressNextStat という変数を新しく追加してみる事にした。
    この変数に値を設定すると次の stat 記録が保留される。
    これによって不都合が起こるかもしれないので暫く様子を見る。

  * (ble-syntax:bash): \new 文脈 CTX_CASE [#D0317]

    > ;& ;; ;;& の次に来るのは CTX_CMDX ではなくて CTX_CASE? 的な物では?
    > ;& ;; ;;& の場合には CTX_ARGX CTX_CMDXV に加え CTX_CMDX でも ERR ではない。

    case word in 直後、;; ;;& ;& 直後 の状態。
    次に esac が来れば esac をコマンドとして受け入れる。
    次に ( が来ればそれをパターンの開始と解釈する。
    他の場合にはそのままパターンが開始すると解釈する。

    未だ case コマンドの方で対応していないので、
    現状では case a in ...) は正しく解釈されない。

  * ble-syntax.sh: CTX_VAL{X,I} から CTX_COND{X,I} を分離。 [#D0316]

    > 値リストと条件コマンドの文法は、 &<>() 等の文字に対して結構違う。
    > 分離した方が良いのではないか?

  * ble-edit.sh: bug: 履歴展開が効かない [#D0315]

  * ble-syntax:bash extglob 対応 [#D0314]

    > [2015-02-16] (ble-syntax:bash): extglob

    extglob が有効なのはどの箇所か。
    - case pattern 内部
    - パラメータ展開内部
    - [[ == globpat ]]
    - シェル単語
    特に色付けなどをしなくても良くて入れ子状態だけ正しく処理できれば良いのであれば、
    シェル単語の箇所と case pattern 内部だけ処理すれば良い。
    色も付けようとなると面倒である。


    [入れ子構造の解析について]

    パラメータ展開内部に関しては extglob の括弧の中にあるかどうかに拘わらず
    '}' が来ればパラメータ展開は終了する様である。
    extglob としての解釈はパラメータ展開を切り出してからの様である。

    シェル単語などの様に裸で extglob の括弧が登場する場合に関しては
    文法的に特別な扱いをして括弧を考慮に入れなければ正しく構文解析する事ができない。
    (現状では構文解析が滅茶苦茶になるという事は無くて、
    単に括弧の開始部分と内部でエラーが発生するというだけであるが。)

    1 パラメータ展開内部・[[ ]] の == 右辺に関しては特別な扱いを考える必要はない。
    2 シェル単語及び case のパターン部分を解析する際には extglob
      を考えて入れ子構造を追う必要がある。
    3 実は現状でも突如として出て来る () の解釈をコマンド置換としてではなく、
      配列処理と同様のリストとして解釈する様にすれば見た目上の動作として充分かも知れない。
      もっとつめるとすれば !( @( などの組合せを正しく認識して、
      認識できない組合せになっている時にエラーを表示するという事である。

    配列のリストと同じようにしてみたがやはり動作としては異なる様な気がする。
    配列のリスト処理では単語分割まで実行するが、extglob の括弧の場合は、
    内部に単語などの構造はない。スペースがあったとしてもそのままスペースの文字として解釈される。
    更に <, > や ;, & 等のコマンド区切の文字も extglob 内部では通常文字として取り扱われる様だ。
    但し | は "または" の意味を持つ。
    (逆に言えば @() で quote できるという事にもなる?)

  * (ble-syntax:bash): bugfix: redirect 直後に redirect/delimiter があった時に解析データ書き込み違反。 [#D0313]
    具体的には echo <>& と入力した時にエラーになる (そもそも <>& というリダイレクトは存在しない)。
    解析に際し echo <> までは問題なく終了し、その後で & を読もうとした時にエラーになる。
    直前の redirect に対してエラー設置及び nest-pop を実行していた為であった。
    直前の redirect は既に解析が終わっているので、これに対して変更を行う事は出来ない。

    redirect を設置した時点で次に redirect/delimiter がないかチェックする様にしてみた。
    →問題なく動いている。しかし、エラーの設置位置にやはり違和感がある。
      エラーが設置されるべきは echo <>& の <> の方ではなくて、& の方ではないのか。
    →やはり & の方にエラーを設置する様に変更してみる。
      動いている…と思ったら何か変だ。カーソルの位置がジャンプする。
      変数がリークしているか?
      と思ったら単に正規表現テストの左辺を間違えている所為で
      インデックスの計算がおかしくなっていただけだった。
    →OK 動いている。

  * ble-syntax.sh: 正規表現の整理: rex_delimiters [#D0312]
    一回変数に入れてから適用しているがその必要はないのでは?

  整理 (自然解消した項目)

  * [2015-02-18] 履歴展開の微妙な所 [#D0311]

    例えば echo "!a" は !a の部分が履歴展開される。
    しかし echo !a" は !a" の部分が履歴展開される。
    これらの規則は一体どうなっているのだろう。man には大して何も書かれていない。

2015-12-23

  * ble-syntax:bash declare 配列初期化構文対応 [#D0310]

    > * [2015-02-16] ble-syntax.sh: local a=(arr) a+=
    >   これは declare や local typeset readonly 等を文法的に特別扱いしなければ対応できない

    色々試してみた所、以下のコマンドの引数で =() を特別扱いする様である。
      declare readonly typeset local export alias
    alias に関しては他のコマンドと全然性質が違う様な気がするし、
    export に関しては配列の初めの要素しか export されない気がするが、
    文法的には両者とも =() の形式を許容する様である。
    或いは、他にも同様の形式の引数を許容する組コマンドが存在するかもしれない。

    (少なくとも echo などの組み込みコマンドや、外部コマンドに関しては
    引数に =() 等という物が含まれていると失敗する。)

    [書き換え]

    > 取り敢えず、CTX_ARGX, CTX_ARGI という文脈を複製して、
      CTX_ARGVX, CTX_ARGVI という文脈を作成した。

    > [[:alpha:]_][[:alnum:]_]*\+?=() の形式の引数を許容する
      これは CTX_CMDX の辺りを真似すればよい。

    > 補完候補生成の種類を指定

    > その他ちゃんと動いているかのチェック。

  * ble-syntax:bash: assignment a=(1 2 3) 直後の文脈の変更 [#D0309]

    今迄、配列の代入文 a=(1 2 3) において、
    括弧を抜けた直後に次の単語に移る様に構成していた。
    (具体的には "(" を nest-push する直前に一旦単語を抜けてしまって、
    更に、ctx (nest-pop 時の文脈) として CTX_CMDXV を設定していた。)

    しかしながら実際の bash で試してみると、代入文の () の直後は
    やはり未だ代入文の右辺の続きとして取り扱われる様である。
    即ち、a=(1 2)b=123 と記述すると、
    a=(1 2) b=123 と解釈されるのではなくて、
    a='(1 2)b=123' と解釈される様である。

    bash の動作に合わせて "(" を nest-push する際は、
    単語をキャンセルしないし、また、nest-pop 時の文脈も敢えて変更はしない、
    という様に動作を変更する。

2015-12-21

  * ble-syntax:bash [#D0308]
    > a[算術式] の終了条件 (() pairs ではなくて [] pairs を数える)
    >   $((...)) ((...)) は () pairs で終了判定する。
    >   ${a[...]} a[...]= $[...] は [] pairs で終了判定する。
    >   ${v:...:...} は } が来たら無条件で終了する。

  * bash-3.0 で C-d が効かなくなっている。 [#D0307]

  * /dev/null に色が着いていない → つけた [#D0306]

  整理 (自然解消した項目)

  * [2015-02-16] ble-syntax:bash: 関数定義 function ... [#D0305]

  * [2015-02-16] ble-syntax:bash: Here string [#D0304]

  * [2015-02-16] ble-syntax:bash: aaa=(hoge), 他に aaa+=(hoge) というパターンもある。 [#D0303]

  * [2015-11-23] ble-detach 後の stty sane [#D0302]
    現在はユーザに stty sane を実行して貰っている。もっと綺麗な方法はないか?
    →保留する。これは今のままでも余り気にならないのでそのままで良い。

2015-12-20

  * ble-synta.sh: bug: 配列添字の書き換え時に syntax error [#D0301]

    以下の編集でエラーになる。
    $ a['']=
    $ a['a']=

    | assertion failure: ((nofs<${#node[@]}))
    | ble-syntax/tree-enumerate/.impl(i=5,iN=7,nofs=0,node=,command=ble-highlight-layer:syntax/word/.proc-childnode)/FATAL1
    |   @ /home/murase/prog/ble/ble.sh:10 (ble-assert)
    |   @ /home/murase/prog/ble/ble.sh:4 (ble-syntax/tree-enumerate/.impl)
    |   @ /home/murase/prog/ble/ble.sh:164 (ble-syntax/tree-enumerate-children)
    |   @ /home/murase/prog/ble/ble.sh:472 (ble-highlight-layer:syntax/update-word-table)
    |   @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/prog/ble/ble.sh:4380 (ble-highlight-layer/update)
    |   @ /home/murase/prog/ble/ble.sh:4884 (.ble-line-text/update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   @ /home/murase/prog/ble/ble.sh:966 (ble-edit/bind/.tail)
    |   @ /home/murase/prog/ble/ble.sh:-4230 (ble-decode-byte:bind/EPILOGUE)
    |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    | assertion failure: ((nofs<${#node[@]}))te_mode_buff='()'$
    | ble-syntax/tree-enumerate/.impl(i=5,iN=7,nofs=0,node=,command=ble-syntax/print-status/.dump-tree/proc1)/FATAL1
    |   @ /home/murase/prog/ble/ble.sh:10 (ble-assert)
    |   @ /home/murase/prog/ble/ble.sh:4 (ble-syntax/tree-enumerate/.impl)
    |   @ /home/murase/prog/ble/ble.sh:2 (ble-syntax/tree-enumerate-children)
    |   @ /home/murase/prog/ble/ble.sh:7614 (ble-syntax/print-status/.dump-tree/proc1)
    |   @ /home/murase/prog/ble/ble.sh:108 (ble-syntax/tree-enumerate/.impl)
    |   @ /home/murase/prog/ble/ble.sh:5 (ble-syntax/tree-enumerate)
    |   @ /home/murase/prog/ble/ble.sh:8005 (ble-syntax/print-status/.dump-tree)
    |   @ /home/murase/prog/ble/ble.sh:-24 (ble-syntax/print-status)
    |   @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/prog/ble/ble.sh:4380 (ble-highlight-layer/update)
    |   @ /home/murase/prog/ble/ble.sh:4884 (.ble-line-text/update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   @ /home/murase/prog/ble/ble.sh:966 (ble-edit/bind/.tail)
    |   @ /home/murase/prog/ble/ble.sh:-4230 (ble-decode-byte:bind/EPILOGUE)
    |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)
    |
    | 異常
    | A?
    |  7 a    000 'a' | stat=(1 w=- n=- t=-1:-1)
    |  8 a    001 '[' | nest=(11 w=7:0- n=- t=-1:-1)
    |  9*a    002 ''' | stat=(8 w=- n=@1 t=-1:-1)
    |  5*a    003 'a' |
    |  9*a    004 ''' |
    |  8 a  s 005 ']' | stat=(8 w=- n=@1 t=-1:-1)
    |  | a  s 006 '=' + word=7:0-7>@4
    | \_ 'a['a']='
    |
    | 正常
    | A?
    |  7*a    000 'a' |  stat=(1 w=- n=- t=-1:-1)
    |  8*a    001 '[' || nest=(11 w=7:0- n=- t=-1:-1)
    |  9*a    002 ''' || stat=(8 w=- n=@1 t=-1:-1)
    |  5*a    003 'a' ||
    |  9*a    004 ''' |+ word=na[:1-5
    |  8*a    005 ']' |  stat=(8 w=- n=@1 t=-1:-1)
    |  |*a    006 '=' +  word=7:0-7>@4
    | \_ 'a['a']='
    |     \_ '['a''


    設置されている筈の単語が存在しないという所にある。
    というかそもそも単語の設置位置が変な気もする。
    単語は終了が判明した時点でその前の点に設置する物だったろうか?
    良く分からなくなってきた。配列の添字の終了点での処理について再度確認する。

    どうやら nest-pop をする時に i を進めた後に nest-pop するか、
    i を進める前に nest-pop するかの違いのようだ。
    調べてみると、a[...]= の時以外の nest-pop に関しては全て i を増加させた後に nest-pop を指定している。
    nest-pop は更に tree-append を呼び出している。tree-append は [i-1] に情報を格納している。
    つまり、tree-append 自体 i を進めた後にしか呼び出してはいけない物になっている。
    この辺りの注意書きは何処にも書かれていない。

    [tree-append/nest-pop/word-pop 呼出条件確認]

    実際に _ble_syntax_tree 等の使用時の条件と、tree-append の内部動作を見るに、
    tree-append/nest-pop/word-pop の呼出条件は以下のようになる:

      解析開始点を p1 とする。現在の位置を i とする。tree-append/nest-pop は i >= p1+1 の時にだけ呼び出して良い。

    この注意点を _ble_syntax_tree の制限の部分に書き加える。
    また、tree-append/nest-pop/word-pop のそれぞれの関数の注意書き (要件) にも記す。
    更に tree-append 内部にチェック用のコードを導入する事にした。

    [既存コードの check]
    さて似たような誤りを他の箇所でも犯していないか確認する必要がある。

    基本的には check-word-end の中では必ず i が進んでいる筈なので tree-append を呼び出しても nest-pop を呼び出しても問題ない。
    一方で、実際の解析部分では tree-append もしくは nest-pop は注意して呼び出す必要がある。
    nest-pop に関しては類似の呼出箇所で問題がないか確認した。
    tree-append を確認した所 word-pop と nest-pop だけからしか呼び出されていない。
    word-pop に関しても調べてみたが全ての箇所で i を進めてからの呼出になっていた。

  * ble-edit: [[ ! -o history ]] の時は履歴に登録しない。 [#D0300]

  * ble-syntax.sh: rex_redirect を何処かに共有する。 [#D0299]

    rex_redirect -> _ble_syntax_bash_rex_redirect.

  * ble-syntax.sh (ble-syntax:bash): < check [#D0298]

  * ble-syntax.sh (ble-syntax:bash): <>| や &>| はどうなっているのか? [#D0297]
    →試してみたが <>| や &>| は存在しない様だ。
      set -C の時に上書きできるのは >| だけという事になる。

    一方で <> は set -C でも普通に実行できている様な気がする。何故だ。
    多分 < として開かれるという事で書き込みはできないが読み取りはできるという事なのだろう。

  * [2015-06-28] complete: HOGE= の直後の編集でファイル名などを補完候補として出して欲しい [#D0296]

    →これが出てこない理由は二つあった。
    1 一つは HOGE= 直後の状態 CTX_VRHS について check-here でのチェックを行っていなかった事。
    2 もう一つの理由は check-prefix で候補が存在した場合には check-here を行っていない事。
      HOGE= の直後にカーソルがある時、候補生成として HOGE= を用いたコマンド補完も試みられる。
      その為に既に check-prefix で候補生成が設定されているという事になりその場での補完が有効にならないのだ。

      もともとこの仕組みは単語中で単語開始の補完が実行されない様にする為の物であった。
      例えば CTX_CMDI の場合には既にコマンドや単語の中にいるという事が分かっているので
      必ず check-prefix で実行しなければならないという事が分かるが、
      CTX_CMDX CTX_ARGX 等の場合には、その場で単語を開始するべきか一旦スペースを挟むべきか分からない。
      →本当か? 直後に単語を構成する文字が存在するかどうかで判定できるのではないか?
      a 例えば単語を構成する文字がない場合にはそので直前の単語が終了して次の単語を希望する状態であるから、
        そこからいきなり次の単語を挿入するというのはおかしい。直前の単語の続きとするべきである。
      b 一方で、直後に単語を構成する文字が存在するのであれば…そこで丁度単語が開始しているという事なので、
        新しい単語を其処に挿入するのは問題ないだろう。
      c もし直後に文字が何も存在しない場合は、そこに何か空白などを追加するべきなのか、
        それとも新しい単語をその箇所で初めて良いのか分からない。

      結局の所、その箇所から新しい単語が始まるかどうかを判定するには prefix を調べて、
      その続きとして挿入できそうならばそうするし、そうでなければ新しい単語の開始として処理するしかない。
      まさに現在の構造はそうなっている。
      そして単語の途中で節がある場合には、そこから新しい補完候補の生成が必要になるが、
      現在の実装ではそういう状況は check-prefix の中で処理されている。
      例えば単語中に = があった場合などにその続きから候補生成が実行されている。
      やはりそれがどういう節なのかという事は prefix を見ているから分かるのである。

    →check-prefix に書き加える事で VAR= の続きの候補生成を実装する事にした。
      丁度 VA から変数名 VAR に補完する部分があったので其処に追加・修正する形にする。

    また同時に RDRF や RDRS の時にも候補が生成できる様にする。

  * [2015-08-11] complete: コマンドの補完で現在のディレクトリにあるサブディレクトリも候補に入れる。 [#D0295]

  * [2015-11-25] complete: bug 単語と単語の間で補完が効かない。 [#D0294]

    →単語と単語の間の空白の位置で TAB を押しても補完候補が生成されなかった。
      これは前の単語の終端位置から次の単語が始まっていると認識されて、
      空白で始まるファイル名を検索していたからであった。

2015-12-19

  * [2015-12-12] complete FIGNORE に対応 [#D0293]

  * ble-syntax.sh: 現在の実装ではリダイレクトの直後に改行が来る事を許している。 [#D0292]

  * ble-syntax.sh: リダイレクト先 ディレクトリチェック・上書きチェック [#D0291]

    →この着色は単語の着色時に行うのが良い。それより前に着色を行ったとしても、
    工夫をしないと単語の着色時に上書きされてしまうからである。
    しかし単語の着色時にはリダイレクトに使用した演算子の情報が消失している。

    リダイレクトに使用した演算子を取得する為には、
    木情報を辿るか、或いは、自分で直前部分を読み取って抽出するかである。
    自分で直前部分を読み取る方法は ad hoc には良いが、
    実際に構築された木と独立な解析なので齟齬が生じるかも知れないし、
    またデバグという観点からも独立な解析が二つ存在するのは好ましくない。
    なので、取り敢えずは木情報を辿る方針で考えてみる事にする。

    木情報がどうなっているかは改めて ble_debug=1 等で確認する。
    →確認してみると親 word の wtype に "n..." という形で格納されている。
      現在着色は tree-enumerate-in-range を用いて行われている。
      子ノードから親ノードの情報を取得するのは面倒そうである。
      そもそも _ble_syntax_word のデータ構造からして子には親の情報が含まれていない。
      tree-enumerate-in-range は木を辿って列挙している訳ではないので、
      呼出の過程で適当に情報を記録して、という方法も使えない。

    しかし乍ら、リダイレクトの場合にはファイル名の終端と同じ位置に
    親ノードが設置されている (同じ位置でリダイレクトのネストが閉じる) と期待できる。
    リダイレクトのファイル名とリダイレクトが同じ位置で終了するという
    仮定の下に実装してしまって良いのではないだろうか。

  * ble-edit.sh (ble/widget/command-help): less は POSIX ではないが、チェックを行っていない。 [#D0290]

    →less がない場合は more または cat を使う様に変更。

  * [2015-12-19] ble-syntax.sh: <<< を順に入力すると文法エラーになる。 [#D0289]

    これは見てみた所 << と入力した時点で駄目になっている。
    << に対応する文法要素がない (ヒアドキュメントは未実装) 為に、
    < + < と解釈されて解析再開点が二箇所設定されている為である。
    しかしながら <<< に対応する以上、
    << が二回来た段階では一つ目の < で解析結果を確定させては成らない。

    << も受け付ける様にして、単語を受け取ることができる様にする。

  * POSIX コマンドについて全て必ず用意されている物かどうか確認する。 [#D0288]
    POSIX の utilities に載っていたとしても optional だったり deprecated だったりするかもしれないので。
    →tput は UP option だった。しかし ble.sh の動作に必ず必要という訳でもないのでチェックから外す。

  * date の使い方が POSIX じゃない。 [#D0287]

    %N に対応しているとは限らない。
    -r filename に対応しているとは限らない。
    特に -r filename に関しては問題である。
    調べてみると date ではなく stat を用いた方法が紹介されている。

    →stat を使った date に対応する。
    →%N に関しては対応していない場合は単に '%N' がそのまま出力されるだけなので気にしない。

  * [2015-12-16] パラメータ展開の中で '' single quote が効かない。 [#D0286]

    パラメータ展開の中で '' や $'', $"" 等の quote をどの様に解釈するかは
    そのパラメータ展開自体がどの様な環境にあるかに依存している。
    パラメータ展開の親が何かの情報を取得してそれを元にして動作を変更する必要がある。

    [動作確定]

    動作に関して:
      '' に関してはパラメータ展開の親が "" の中であればそのまま "''" という文字列として解釈される。
      パラメータ展開の親がコマンドの文脈である時は quote として扱われ、除去の対象となる。

    extquote -s の時 (既定) は、
      パラメータ展開の親が "" の中にあったとしても、
      $'' や $"" を quote として解釈し quote 除去が行われる。

    "" に関しては extquote に関係なく、また、
    パラメータ展開が "" の中にあるか外にあるかに拘わらず
    常に quote として取り扱われる様です。

    何か良く分からなくなってきたので表にする。

          "" の外   "" の中(-s extqoute)  "" の中(-u extqoute)
    ----  --------  --------------------  --------------------
    ''    有効      無効                  無効
    ""    有効      有効                  有効
    $''   有効      有効                  無効
    $""   有効      有効                  無効 (空白になる?)


    [実装方法]

    a 先ずはパラメータ展開の文脈の際に親の文脈を取得する所から始まる。
      ネスト構造を辿れば現在のパラメータ展開がどの様な文脈の下にあるのかという情報を取得できる筈である。
      但し、毎回ネスト構造を遡るというのも効率などの観点からどうだろうという事もある。
      とはいいつつも、' や $' $" に当たった時にだけネスト構造を辿れば良いのだからそんなに重くもならないだろう。

    b 或いはパラメータ展開が開始する時点で異なる文脈として扱うという方法でも良い。
      現在文脈は CTX_PARAM, CTX_PWORD である。動作が異なるのは CTX_PWORD の方である。
      パラメータ展開が開始する時点で文脈を指定しようと思ったら
      CTX_PARAM2, CTX_PWORD2 の二種類を用意する必要があり、管理が面倒である。

    c もう一つの方法はパラメータ展開のネストを開始する時の、<ネストの種類の文字列> を使って区別する方法である。
      現在は '${' を用いているが、例えばそれに加えて '"${' を用いるなど。
      ネストの種類の文字列は ble-syntax/parse/nest-type -v type でいつでも取得できる。
      またパラメータ展開の開始は ble-syntax:bash/check-dollar の中で以下の様にして実行される。
      ble-syntax/parse/nest-push "$CTX_PARAM" '${'
      従って (1) この部分の '${' を現在いる文脈に応じて変更する様に書き換えて、
      (2) check-qoutes において ble-syntax/parse/nest-type を用いてこの文字列を取得して
      quote が有効かどうかを判定するという形になるだろう。

    ここでは c の方法を採用する事にする。

  * [2015-12-12] ble-syntax.sh: extquote off に対応 [#D0285]

  整理 (過去の修正によって解決済の物)

  * [2015-06-28] complete: <bug> HOGE=aa| の状態で TAB を押すと滅茶苦茶沢山のコマンドが表示される [#D0284]

  * [2013-06-06] complete: 空白文字や " や ' などをエスケープしている時も正しく単語分割する [#D0283]

2015-12-12

  * 起動チェック: bash の現在の設定を取得する方法に関して [#D0282]

    起動チェック: set -o posix を確かめる方法?
    → POSIXLY_CORRECT=y か空欄かで判定する事ができる。
    → [[ -o posix ]] で OK. ただ、POSIX の時に [[ -o optname ]] が有効なのかは不明。
      試すと動くから POSIX でも bash 固有の機能は相変わらず使えるのだろう。

    a 既存の物については速度測定をして速い方法に移行する。

      [[ $- == *H* ]] は [[ -o histexpand ]] の方が早いようだ。しかも分かり易い。

      % shopt -q は $BASHOPTS を用いた物の方が早い方である。
      % しかし読みにくいのは問題だ。$BASHOPTS を使用して判定する為の関数を定義してしまっても良い気がする。
      shopt は >/dev/null にリダイレクトする必要はない。リダイレクトしなければ速い。

    b set -o に関しては?

      % set -o posix    -> [[ $POSIXLY_CORRECT ]]
      %   Note: set -o posix の時は POSIXLY_CORRECT=y になっている。
      %   set +o posix の時は POSIXLY_CORRECT は unset になっている。
      %
      % set -o ignoreeof -> [[ $IGNOREEOF == 10 ]]
      %   これは実行すると実際に IGNOREEOF=10 が設定されるので問題ない。
      %
      % set -o pipefail -> false | :
      %   これは false | : で判断できるが fork が入るので遅いかも。
      %
      % set -o emacs
      % set -o vi
      % bash --noediting
      % EMACS=t bash
      %   → EMACS=t に関しては環境変数を介して判定できるが、
      %   それ以外の方法による行編集機能の有効・無効・デフォルトキーマップは判断不能?
      %
      %
      %   候補 bind
      %     一応行編集機能が有効になっているかどうかは bind がエラーメッセージを出すかどうかで判断できる?
      %     しかし bind の返却値は常に 0 の様だ (エラーメッセージを出力するだけ)。
      %
      %   候補 set +o emacs && set -o emacs
      %   候補 set +o vi && set -o vi
      %     これら (set +o emacs, vi) は訳に立たない。
      %     既にその設定になっているかどうかに拘わらず常に成功する様だ。
      %
      % set -o history
      %   これの判定方法は全く不明だ。
      %
      %   候補 history
      %     常に成功する。動作も変わらない様だ。

      と思ったら set に関しては全て [[ -o option-name ]] で判定できるのであった。

      起動オプション → [[ -o name ]] または [[ $- == *X* ]]
      set → [[ -o option-name ]]
      shopt → shopt -q optname

  * LANG だけでいいのか? LC_ALL は? [#D0281]

    LANG=... を使っているのは read -t 0 のチェック部分と、
    初期化の command awk の呼出の部分だけである。

    結局以下の bash-4.0 未満のコードは使われていない上に、
    仮に動いてしまったとしても問題点もある(?)ので削除する事にする。
    何れにしても bash-4.0 未満ではこの方法では、
    入力が溜まっている事を検知することはできないので削除するのが良い。

    | # x 以下は bind '"\e[":"\xC0\x9B["' による
    | #   byte の受信順序が乱れるので使えない。
    | # x bash-4.0 未満では結局以下では何も起こらない。
    | #   read -t 0 としても必ず失敗する様である。
    | local byte=0
    | while IFS= LC_ALL=C read -t 0 -s -r -d '' -n 1 byte; do
    |   LC_ALL=C ble-text.s2c -v byte "$byte" 0
    |   "ble-decode-byte+$bleopt_input_encoding" "$byte"
    | done

  [過去の ToDo の整理]

  * ble-bind の説明を追加 [#D0280]

  * cat 置き換え [#D0279]

  * [2015-11-06] isearch-forward/backward で現在の一致範囲をハイライトする。 [#D0278]

  * [2015-03-06] complete の古いコード [#D0277]

    →これは誰からも使われていない古い関数達を削除した。please, see commit log.

  * [2015-03-06] binder-source 周辺 [#D0276]

  * [2015-02-27] complete: 既存の bash complete に対応する。 [#D0275]

  * [2015-02-25] isearch-forward/backward の動作 [#D0274]

    気付いたのだが bash では isearch-forward/backward は各ヒストリ項目に対して一致しているのではなく、
    ヒストリ項目の中にある文字列に対して一致している様だ。
    つまり、複数の一致が一つのコマンドラインの中にあれば、
    その中を C-r C-s で移動していく事になる。
    そればかりか現在編集している文字列の中で一致する物についてもちゃんと移動できる。。

  * [2013-06-06] complete: complete -F に対する対応 [#D0273]

  * [2013-06-06] complete: コマンド先頭位置の検出 (複合文の途中からコマンドが始まっている場合など) [#D0272]

  * [2013-06-05] ^U ^V ^W ^? bind 関連 [#D0271]
    + 説明書にその事を書いておく。
    + ^U ^V ^W ^? を bind するより良い方法があれば考える
    + bashrc の中でも同様に問題が起こるのか?

    + 一旦 bind '"":"hogehoge"' 等として変換したら受信できる可能性?

    2015-12-12 →これは現在何も問題が起こっていない気がするので完了済と解釈する。

  * [2013-06-04] vbell .time の置き場所を変更? [#D0270]

    2015-12-12 →一時ファイルは現在は $_ble_base_tmp を介して統一的に取り扱う事になっている。
      もし置き場所を整理するとすれば $_ble_base_tmp 自体を変更する事になるが、
      現在の実装で満足しているので、現在の所変更の予定はない。

  * [2013-06-01 以前] 編集文字列の表示 [#D0269]
    + スタイル指定文字列
    + color fall backs
    + forward-char
    + goto-char
    + insert-string
    + insert-char

    2015-12-12 → これらの ToDo 項目が元々何を意図していたのか良く分からないが、
      スタイル指定文字列は gspec として実装してあるし、
      編集関数 goto-char, forward-char, insert-string, insert-char は実装済である。
      編集関数と編集文字列の「表示」にどの様な関係があるのかは不明。

2015-12-05

  * ble-bind -L, ble-bind --list-edit-functions [#D0268]
    declare -f | sed -n -r 's/^ble-edit\+([[:alpha:]][^[:space:]();&|]+) \(\)[[:space:]]*$/\1/p'

  * v0.1-master: release=1 で更新、release 登録する [#D0267]

  * download/git clone 順序入れ替え [#D0266]

  * 日本語 README.md [#D0265]

2015-12-03

  * また遅くなってきたので初期化の速度について再確認する? [#D0264]

                    時間      行数  最適化後  以前の記録
    ble-core.sh     0m0.023s   605  0m0.013s  0.002s
    ble-decode.sh   0m0.010s  1632  0m0.010s  0.008s
    ble-color.sh    0m0.006s  1034  0m0.002s  0.003s
    ble-edit.sh     0m0.009s  4204  0m0.009s  0.007s
    ble-syntax.sh   0m0.031s  2944  0m0.006s  0.019s
    ble-initialize  0m0.015s        0m0.014s
    合計            0m0.094s        0m0.054s

    ble.sh parse                    0m0.105s
    ble-attach                      0m0.088s

    行数から考えるに ble-syntax.sh は ble-edit.sh に較べて load に時間が掛かりすぎる。
    ble-core.sh についても意外に時間が掛かっている。

    ble-core.sh については _ble_base_tmp.wipe を弄ると 3ms になるので、
    悪いのは各ファイルについてプロセス生死判定を行っている事にある。
    → kill -0 を消しても 25ms のままだった。
    より詳細に _ble_base_tmp.wipe の中を調べる。

    - ファイル列挙        = 4ms (7ms)
    - ファイル名存在確認  = 0ms (7ms)
    - ファイル名形式検査  = 15ms (22ms)
    - プロセス生死判定    = 3ms (25ms)

    どうも正規表現の判定に結構時間が掛かっている様子だった。
    正規表現はそんなに重くないのだと思っていたがやはり重いのか。
    (最初のコンパイルに時間が掛かるが、それ以降は内部で再利用される?)
    何れにしても正規表現を止めてパラメータ展開を用いて pid を抽出する様に変更したら
    全体で 23ms かかっていたのが 12ms 程度まで減少した。
    ble-core.sh の他の箇所は 3ms 程度しか掛かっていないので気にしても仕方がない。

    ble-syntax.sh についても見る事にする。
    殆ど関数定義と変数・配列への代入しかないのにと思ってみると
    関数 _ble_syntax_attr2iface.define, ble-color-defface を大量に呼び出している箇所がある。
    この部分を削除してみると 5ms にまで縮まる。
    特に ble-color-defface で 25ms 程度使っている様で、
    _ble_syntax_attr2iface.define に関しては 2ms しか使っていない様子である。

    どのタイミングで色が必要とされるかに依るかも知れないが、
    例えば色の初期化について遅延を行うとどうだろうか。
    調べてみると幸いに _ble_faces 系統の変数を直接操作しているはごくごく一部である。
    →遅延初期化にしてみた…が、結局最後にプロンプトを表示する時に初期化が必要??
    →調べてみた所 ble-highlight-layer:syntax/update-error-table において
      中身がなくても g (syntax_error) の初期化を行っていた。これを省略すれば良い。

    と思ったら一番時間が掛かっているのは ble-attach だった。
    しかしながら ble とは関係ない部分でもっと時間が掛かっている様にも見える。
    .bashrc の方を調べた。全体で 0.513 かかっている。内訳は:
    - ble.sh        160ms
    - ble-attach     88ms
    - .mwg/bashrc    95ms
    - /etc/bashrc   155ms
    - 残り           15ms

    あれ。変だ。ble.sh が結局 160+88 = 248ms も使っている。
    ble.sh 自身の計測だと 54+88ms しか使わないはずなのに。
    →どうやら parse に時間が掛かっている様だ。
      bash は先にファイル全体を parse して、その後で実行をしているのではないか。
      短いファイルの場合は 100ms も待たされないのでファイルを開くだけでそんなに時間が掛かるとは考えがたい。
      また、ble.sh の先頭で非自明な return を実行する場合でも 100ms 待たされるので、
      実際に実行しようが実行しまいがファイルの長さに依存した解析を実行するという事になる。
      (return の位置で 100ms 待たされなかったりする。
        もしかすると {} で囲まれた単位で parse を実行しているという事だろうか。
        そうだとするとスクリプト実行中にファイルを書き換えた時に変な事になるのも合点が行く。)
      そう考えると ({} が登場する毎に散発的に為される) parse に合計で 105ms かかっている。
      つまり 100 行あたり 1ms つかっている計算になる。

    うーん。これは仕様がない。
    遅延ロードするばかりでなく遅延部分を外部に分離すれば parse 時間も短くなるかもしれないが、
    そもそも遅延部分でそんなに行数を食っている物は少ない。
    あるとすれば ble-edit の編集関数を遅延ロードにするぐらいだろうか。
    と思ったが ble-edit のプロンプト構築や座標計算部分は省略できないし、
    やはり頑張ってもそんなに初期化時間を稼ぐ事は出来ない気がする。
    調べてみるとやはり編集関数は2000行程度である。その他の部分は基本的な部分である。
    これでは 20ms 程度しか稼げない。

    後、コメントが 2000 行程度あった。しかしコメント 2000 行程度にそんなに解析時間が掛かるとも思えない。
    →と思って計測したら 25ms もかかる。そもそもコメントには日本語も多くデータ量が元から多い。その事が原因か?
    しかしながら 25ms でも全体 250ms の 10% に過ぎない。そんなに体感は変わらないだろう。

    まあ、取り敢えずこれはこれで良しとする。

  * ble-syntax/parse/nest-equals bug [#D0263]

    + bug (2015-12-03) まただ

      C-d で以下の様に書き換えを行おうとしたらなる。
      $ function () () { echo hello; }
      $ function () { echo hello; }

      stackdump: invalid nest
        @ /home/murase/prog/ble/ble.sh:1480 (ble-syntax/parse/nest-equals)
        @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
        @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
        @ /home/murase/prog/ble/ble.sh:2583 (ble-highlight-layer:syntax/update)
        @ /home/murase/prog/ble/ble.sh:4292 (ble-highlight-layer/update)
        @ /home/murase/prog/ble/ble.sh:4844 (.ble-line-text/update)
        @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
        @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
        @ /home/murase/prog/ble/ble.sh:1140 (.ble-decode-byte:bind/tail)
        @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)

    これは今丁度直した所の直し方が甘かった所為で余計に変な事になっていただけだった。
    すぐに直した。そんなに問題はない。

  * 構文解析部分更新の bug [#D0262]

    + bug (2015-12-02)

      また出た。今度は

      $ echo a "$(echo b "$(echo c "$(echo d "$(echo e "$(echo f)")")")")"

      を

      $ echo "a $(echo "b $(echo c "$(echo d "$(echo e "$(echo f)")")")")"

      に書き換える過程で起きた。これは 11-28 のケースと状況が似ている。


    + bug (2015-11-28b)

      ble-assert

        "$f" --date="$(date +'%F %T %Z' -r "$f")"
        "${f}" --date="$(date +'%F %T %Z' -r "$f")"

      の過程でエラー。最小化:

        echo "$f" "$(B 'D' "$f")"
        echo "${f" "$(B 'D' "$f")" <- この時点でエラーになっている。(ble_debug= だと次の入力で明らかになるが。)
        echo "${f}" "$(B 'D' "$f")"

    先ず第一に ble_debug=1 が設定されているかされていないかでエラーが表示されるタイミングが異なる。
    しかしこれは単にチェックのタイミングの問題である事は以前のバグ取りの時に分かっている。
    ble_debug=1 が設定されていると現在の状態を表示する為に、その場で構文木の構造を辿る。
    その際にエラーが存在している事が即座に検知されるという訳である。
    一方で ble_debug= になっている場合にはその場で構文木を辿らないので後になってエラーが発生している事が分かる。
    従って ble_debug=1 の時のエラーを先ず見るのが自然である。

    エラーメッセージ

    | ble-syntax/tree-enumerate/.impl(i=10,iN=26,nofs=0,node=,command=ble-syntax/print-status/.dump-tree/proc1)/FATAL1
    |   @ /home/murase/prog/ble/ble.sh:7685 (ble-assert)
    |   @ /home/murase/prog/ble/ble.sh:108 (ble-syntax/tree-enumerate/.impl)
    |   @ /home/murase/prog/ble/ble.sh:5 (ble-syntax/tree-enumerate)
    |   @ /home/murase/prog/ble/ble.sh:8034 (ble-syntax/print-status/.dump-tree)
    |   @ /home/murase/prog/ble/ble.sh:8264 (ble-syntax/print-status)
    |   @ /home/murase/prog/ble/ble.sh:-135 (ble-highlight-layer:syntax/update)
    |   @ /home/murase/prog/ble/ble.sh:4290 (ble-highlight-layer/update)
    |   @ /home/murase/prog/ble/ble.sh:4842 (.ble-line-text/update)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)=(5 w=- n=@5 t=-1:-1)
    |   @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
    |   @ /home/murase/prog/ble/ble.sh:1130 (.ble-decode-byte:bind/tail)t=1:-1)
    |   @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)t=(5 w=- n=@10 t=-1:-1)

    +-------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+
    | エラー状態                                                                                | 正常状態                                                                               |
    +-------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+
    | A?                                                                                        | A?                                                                                     |
    |  2 aw   000 'e' |     stat=(1 w=- n=- t=-1:-1)                                            |  2 aw   000 'e' |   stat=(1 w=- n=- t=-1:-1)                                           |
    |  | aw   001 'c' |                                                                         |  | aw   001 'c' |                                                                      |
    |  | aw   002 'h' |                                                                         |  | aw   002 'h' |                                                                      |
    |  | aw   003 'o' +     word=2:0-4                                                          |  | aw   003 'o' +   word=2:0-4                                                         |
    |  3 a    004 ' '                                                                           |  3 a    004 ' '                                                                        |
    |  9 a    005 '"'       nest=(4 w=4:5- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)                  |  9 a e  005 '"'     nest=(4 w=4:5- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)                 |
    | 14*a    006 '$'       nest=(5 w=- n='${':5- t=-1:-1) stat=(5 w=- n=@5 t=-1:-1)            | 14 a e  006 '$'     nest=(5 w=- n='${':5- t=-1:-1) stat=(5 w=- n=@5 t=-1:-1)           |
    |  |*a    007 '{'                                                                           |  | a e  007 '{'                                                                        |
    |  7*a    008 'f'                                                                           |  7 a    008 'f'                                                                        |
    |  9*a    009 '"'       stat=(14 w=- n=@6 t=-1:-1)                                          |  9 a    009 '"'     stat=(14 w=- n=@6 t=-1:-1)                                         |
    |  5*a  s 010 ' '                                                                           |  5 a    010 ' '                                                                        |
    |  9*a  s 011 '"' ||                                                                        |  9 a    011 '"'                                                                        |
    | 14*a    012 '$' |||   nest=(15 w=- n='$(':6- t=-1:-1) stat=(15 w=- n=@6 t=-1:-1)          | 14 a    012 '$' |   nest=(15 w=- n='$(':6- t=-1:-1) stat=(15 w=- n=@6 t=-1:-1)         |
    |  |*a    013 '(' |||                                                                       |  | a    013 '(' |                                                                      |
    |  2*aw   014 'B' |||+  word=2:14-15 stat=(1 w=- n=@12 t=-1:-1)                             |  2 aw   014 'B' |+  word=2:14-15 stat=(1 w=- n=@12 t=-1:-1)                            |
    |  3*a    015 ' ' |||                                                                       |  3 a    015 ' ' |                                                                      |
    |  9*a    016 ''' ||||  stat=(3 w=- n=@12 t=1:-1)                                           |  9 a    016 ''' ||  stat=(3 w=- n=@12 t=1:-1)                                          |
    |  5*a    017 'D' ||||                                                                      |  5 a    017 'D' ||                                                                     |
    |  9*a    018 ''' |||+  word=4:@14>16-19                                                    |  9 a    018 ''' |+  word=4:@14>16-19                                                   |
    |  3*a    019 ' ' |||   stat=(3 w=- n=@12 t=0:-1)                                           |  3 a    019 ' ' |   stat=(3 w=- n=@12 t=0:-1)                                          |
    |  9*a    020 '"' ||||| nest=(4 w=4:20- n='none':12- t=-1:1) stat=(3 w=- n=@12 t=1:-1)      |  9 a    020 '"' ||| nest=(4 w=4:20- n='none':12- t=-1:1) stat=(3 w=- n=@12 t=1:-1)     |
    | 14 a    021 '$' ||||| stat=(5 w=- n=@20 t=-1:-1)                                          | 14 a    021 '$' ||| stat=(5 w=- n=@20 t=-1:-1)                                         |
    |  7 a    022 'f' |||||                                                                     |  7 a    022 'f' |||                                                                    |
    |  9 a    023 '"' |||++ word=4:@18>20-24>@23 word=nnone:20-24 stat=(5 w=- n=@20 t=-1:-1)    |  9 a    023 '"' |++ word=4:@18>20-24>@23 word=nnone:20-24 stat=(5 w=- n=@20 t=-1:-1)   |
    | 14 a    024 ')' ||+   word=n$(:12-25>@23 stat=(3 w=- n=@12 t=0:-1)                        | 14 a    024 ')' +   word=n$(:12-25>@23 stat=(3 w=- n=@12 t=0:-1)                       |
    |  9 a    025 '"' ++    word=4:@9>11-26>@25 word=nnone:11-26>@24 stat=(5 w=- n=@11 t=0:-1)  |  6 a e  025 '"'     nest=(15 w=- n='none':6- t=0:-1) stat=(15 w=- n=@6 t=0:-1)         |
    | \_ '"$(B 'D' "$f")"'                                                                      | \_ 'echo'                                                                              |
    |     \_ '"$(B 'D' "$f")"'                                                                  | \_ '"${f" "$(B 'D' "$f")"'                                                             |
    |         \_ '$(B 'D' "$f")'                                                                |     \_ '"${f" "$(B 'D' "$f")"'                                                         |
    |             \_ 'B'                                                                        |         \_ '${f" "$(B 'D' "$f")"'                                                      |
    |             \_ ''D''                                                                      |             \_ '$(B 'D' "$f")'                                                         |
    |             \_ '"$f"'                                                                     |             |   \_ 'B'                                                                 |
    |                 \_ '"$f"'                                                                 |             |   \_ ''D''                                                               |
    |                                                                                           |             |   \_ '"$f"'                                                              |
    |                                                                                           |             |       \_ '"$f"'                                                          |
    |                                                                                           |             \_ '"'                                                                     |
    +-------------------------------------------------------------------------------------------+----------------------------------------------------------------------------------------+

    状態の差分

    | --- a.txt       2015-12-03 05:12:49.627927314 +0900
    | +++ b.txt       2015-12-03 05:12:55.499708773 +0900
    | @@ -1,4 +1,4 @@
    | -正常状態
    | +エラー状態
    |  000 'e' stat=(1 w=- n=- t=-1:-1)
    |  001 'c'
    |  002 'h'
    | @@ -24,4 +24,4 @@
    |  022 'f'
    |  023 '"' word=4:@18>20-24>@23 word=nnone:20-24 stat=(5 w=- n=@20 t=-1:-1)
    |  024 ')' word=n$(:12-25>@23 stat=(3 w=- n=@12 t=0:-1)
    | -025 '"' nest=(15 w=- n='none':6- t=0:-1) stat=(15 w=- n=@6 t=0:-1)
    | +025 '"' word=4:@9>11-26>@25 word=nnone:11-26>@24 stat=(5 w=- n=@11 t=0:-1)

    これを見ると最後の状態が異なるだけの様である。
    解析中断点は 020 にあるが 020 までの状態は完全に同じである。
    %%という事は解析の状態は完全に一致している筈なのでその後の解析も同じでなければならない?%%
    と思ったが、解析状態の際に比較するのは (現在の状態 vs 正しいと想定される状態) ではなくて、
    (現在の状態 vs 前回までに解析した状態) であるのでここでは関係ないはずである。
    この結果から言える事は、

    a shift に失敗している
    b 解析の中断の判定に失敗している
    c または解析途中状態が同じで以降の文字列が同じだったとしても最終的な解析結果に違いが出る可能性がある

    のどちらかという事になる。今迄の経験から行くと初めに a, b を疑った方が良い。
    その為に前回までの解析状態を確認しておく必要がある。

    +-------------------------------------------------------------------------------------------+
    | 直前の状態                                                                                |
    +-------------------------------------------------------------------------------------------+
    | A?                                                                                        |
    |  2*aw   000 'e' |     stat=(1 w=- n=- t=-1:-1)                                            |
    |  |*aw   001 'c' |                                                                         |
    |  |*aw   002 'h' |                                                                         |
    |  |*aw   003 'o' +     word=2:0-4                                                          |
    |  3*a    004 ' '                                                                           |
    |  9*a    005 '"' ||    nest=(4 w=4:5- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)                  |
    | 14*a    006 '$' ||    stat=(5 w=- n=@5 t=-1:-1)                                           |
    |  7*a    007 'f' ||                                                                        |
    |  9*a    008 '"' ++    word=4:@3>5-9>@8 word=nnone:5-9 stat=(5 w=- n=@5 t=-1:-1)           |
    |  3*a    009 ' '       stat=(3 w=- n=- t=0:-1)                                             |
    |  9*a    010 '"' ||    nest=(4 w=4:10- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)                 |
    | 14*a    011 '$' |||   nest=(5 w=- n='$(':10- t=-1:-1) stat=(5 w=- n=@10 t=-1:-1)          |
    |  |*a    012 '(' |||                                                                       |
    |  2*aw   013 'B' |||+  word=2:13-14 stat=(1 w=- n=@11 t=-1:-1)                             |
    |  3*a    014 ' ' |||                                                                       |
    |  9*a    015 ''' ||||  stat=(3 w=- n=@11 t=1:-1)                                           |
    |  5*a    016 'D' ||||                                                                      |
    |  9*a    017 ''' |||+  word=4:@13>15-18                                                    |
    |  3*a    018 ' ' |||   stat=(3 w=- n=@11 t=0:-1)                                           |
    |  9*a    019 '"' ||||| nest=(4 w=4:19- n='none':11- t=-1:1) stat=(3 w=- n=@11 t=1:-1)      |
    | 14*a    020 '$' ||||| stat=(5 w=- n=@19 t=-1:-1)                                          |
    |  7*a    021 'f' |||||                                                                     |
    |  9*a    022 '"' |||++ word=4:@17>19-23>@22 word=nnone:19-23 stat=(5 w=- n=@19 t=-1:-1)    |
    | 14*a    023 ')' ||+   word=n$(:11-24>@22 stat=(3 w=- n=@11 t=0:-1)                        |
    |  9*a    024 '"' ++    word=4:@8>10-25>@24 word=nnone:10-25>@23 stat=(5 w=- n=@10 t=0:-1)  |
    | \_ 'echo'                                                                                 |
    | \_ '"$f"'                                                                                 |
    | |   \_ '"$f"'                                                                             |
    | \_ '"$(B 'D' "$f")"'                                                                      |
    |     \_ '"$(B 'D' "$f")"'                                                                  |
    |         \_ '$(B 'D' "$f")'                                                                |
    |             \_ 'B'                                                                        |
    |             \_ ''D''                                                                      |
    |             \_ '"$f"'                                                                     |
    |                 \_ '"$f"'                                                                 |
    +-------------------------------------------------------------------------------------------+

    やはりどうも腑に落ちない。shift に失敗しているのだとしても文法的な入れ子構造が全く違うのだから、
    解析の中断が起こるはずがないのである。という事は、少なくとも解析の中断の判定部分に問題があるのであり、
    先にそちらを解決する方が先になるであろう。という訳で例によって ble-syntax/parse/nest-equals を確認する。
    以下が最後の ble-syntax/parse/nest-equals 呼出時の動作の流れである。

    | ble-syntax/parse/nest-equals
    | declare -- parent_inest="20" i1="6" i2="8"
    | A0
    | declare -- _onest="4 0 4 8 -1 1 none" _nnest="4 0 4 8 -1 1 none"
    | A1
    | A2
    | A3
    | declare -- parent_inest="8" i1="6" i2="8"
    | A0
    | declare -- _onest="" _nnest=""
    | A1
    | A2
    | A3
    | declare -- parent_inest="" i1="6" i2="8"
    | A0

    おかしい、途中で _onest _nnest が空白になっている。そんな事があるだろうか。
    直前の状態ではエラーが生じていなかったはずなので直前の状態で nest を辿って空白になるという事は考えにくい。
    それなのに _onest についてすら空白になっている。_onest を格納している配列の中身の構築に失敗している?

    と思ったが…あれ parent_inest=8 とはどういう事だろう。8 には勿論何もない。
    parent_inest の更新部分を見てみると onest[3] の中身を直接読み取っている。
    確かにこれでは動作しない onest[3] の中に入っているのは現在位置からみた時の parent_inest の相対位置なので、
    直接代入するのではなくて現在の位置からのずれとして計算しなければならない。
    つまり、正しくは parent_inest=$((parent_inest-onest[3]))=20-8 として計算するべきなのだ。
    しかしそうだとしても変である。20-8 = 12 にはやはり何も nest は設置されていないからである。
    →と思ってよく見てみたら設置されている。なので相対位置で計算する様に修正した。
    →修正した。エラーは出なくなった。OK
      2015-12-02 のエラーも出なくなった。OK。

    しかしこれは 2015-11-28 のエラーとは関係ないようである。取り敢えず一旦整理する。

  * alias 対策 [#D0261]

  * fgrep に依存している [#D0260]

  * bash-3 で C-d を捕獲する為のメッセージについて [#D0259]

    これは各言語・各 version で異なるので統一的に取り扱える様にしたい。

    これらのメッセージは

    [u@h bash-4.3/po]$ sed -nr '/msgid "Use \\"%s\\" to leave the shell\.\\n"/{n;p;}' *.po

    とすれば各言語版でどの様なメッセージが使用されているか調べられる。更に、

    % [u@h bash-4.3/po]$ sed -nr '/msgid "Use \\"%s\\" to leave the shell\.\\n"/{n;s/^msgstr/printf/;s/$/ exit/;p;}' *.po | bash
    %
    % とすれば具体的なメッセージを出力する事ができる。
    % と思ったがエスケープしなければならない文字が shell と po では違うので駄目だ。
    % 例えば "" 中の ` をエスケープしないとシェルではコマンド置換と勘違いされる。
    % なのでもう少し慎重になる必要がある。

    % [u@h bash-4.3/po]$ sed -nr '/msgid "Use \\"%s\\" to leave the shell\.\\n"/{n;s/^msgstr/printf/;s/$/ exit/;p;}' *.po | bash

    この結果を何処かにファイルに放り込んでおいて readarray なり何なりで読み込むようにすれば良いのでは?

    → generate.sh に生成用のスクリプトを書いて、生成結果を ignoreeof-messages.txt に出力することにした。
      C-d の検出時にはこの ignoreeof-messages.txt を使用する事にした。

2015-12-01

  * bugfix: 引数に対する補完で complete -D が登録されていない場合に何も起こらなかった。 [#D0258]

    以下のバグはこれに関連する物である:

    > * bug: tab 補完が効かない @ laguerre
    > * bug cygwin 環境で補完が効かない

  * bug: isearch/forward incremental にできない。 [#D0257]

2015-11-30

  * release の登録 on GitHub [#D0256]

2015-11-29

  * input_encoding=C full support as 'UTF-8' [#D0255]

  * bug [#D0254]

    選択している状態で history を移動すると座標がずれる。
    特に長いコマンドの一部を選択している時にずれる。
    ずれの量は選択範囲の長さや位置に依存しない。

    どうやら ble-syntax-layer:region が悪い様だ。
    _ble_highlight_layer__list から region を外したら直った。

  * ライセンスファイルの追加 [#D0253]

  * ble-bind -xf [#D0252]
    ble-bind -x 未実装状態になっている
    →これは単純に ble-edit+... を実装してそれを ble-bind -c で登録すれば良いだけなのでは?

2015-11-25

  * 公開までに特に必要な物 [2015-03-01] [#D0251]

    > 1 背景が暗い環境での色の設定
    >   これは確認してみたがそんなに問題にならないのではないかという気がした。
    >   何れにしても自由に配色を設定できるようにする仕組みは提供する必要がある。
    >   →解説を加えれば良い。
    > 2 complete の設定の取り込み
    3 bind 等の設定の取り込み
      readline 関数の完全対応
      bind -x は対応しなくて良い
      inputrc は対応しない。簡単に翻訳できるから。
    > 4 正しい PS1 の解釈

    取り敢えず大体の所は終わった。
    readline 関数の完全対応には時間が掛かると思われるので、一旦保留として別項目にする。

2015-11-23

  * magic-space [#D0250]

    特定の文字列がある時にカーソルが末端に移動する。

  * プログラム補完: ディレクトリ名の直後の "/" 挿入 [#D0249]

    プログラム補完でディレクトリ名を列挙されると、
    それがディレクトリ名であるにも関わらず直後に " " が挿入されて中のファイルを列挙できなくなる。
    仕方がないのでプログラム補完で生成される候補については action/file で登録する事にする。
    つまり、ディレクトリ名に一致すれば "/" を末尾に挿入するしそれ以外ならば " " を挿入する。

  * complete/compopt -o の対応 [#D0248]

    + compopt -o nospace 等の情報を取り出す事ができない?
      これは complete -p の解析時に先ず抽出し、
      更に、プログラム補完時に compopt 関数を上書きすればよい。
      →実装した。動いている様に見える。

    + compopt -o filenames/dirnames/default/bashdefault
      現状だとこれらは全く使われない様だ。
      これは compgen に失敗した時にどの様に動作するかを指定する物であって、
      compgen 自体の動作には影響を与えない様である。

    + compopt -o plusdirs については compgen の方で処理してくれる様なので気にする必要はない。

  * bug: ble-detach による stty 破壊 [#D0247]

    ble-detach した後に rm file RET yes RET とすると反応がなくなる。
    改行が正しく伝わっていない? stty で調べてみる。

    ble$ bash-4.0 --norc
    ble$ stty -a
    speed 38400 baud; rows 73; columns 210; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig -icanon iexten echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

    ble$ stty -a
    speed 38400 baud; rows 73; columns 210; line = 0;
    intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
    -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig -icanon iexten echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

    ble$ ble-detach
    ble$ stty -a
    speed 38400 baud; rows 73; columns 210; line = 0;
    intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = <undef>; start = ^Q; stop = ^S; susp = <undef>; rprnt = ^R; werase = <undef>; lnext = <undef>;
    flush = ^O; min = 1; time = 0;
    -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
    -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
    opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    isig -icanon iexten echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke

    どうも色々な設定が消滅している様子である。
    状態の復元は ble-decode-detach -> .ble-stty.finalize -> stty で実行している筈である。
    やはり bind -x の中で実行した stty の反映には制限が伴うという事か。
    一応最後に stty sane を実行すれば直る。

    取り敢えずの暫定処置として stty sane を ble-detach 後にユーザに実行して貰う事にする。

  * complete -p による補完を動作する様に修正。 [#D0246]

    下らないバグだった。extract-command 内で、出力変数の筈の
    comp_words comp_line comp_point comp_cword に対して local を指定したままだった。
    (実装中にテスト用として local 宣言していたのが残っていた。)

  * complete -F 対応 [#D0245]

    if complete -p コマンド名 &>/dev/null; then
      IFS=$'\n'
      local arr=$(
        1 ble-getopt $(complete -p コマンド名) で解析
        2 -F, -C オプションに指定されたコマンドを ble の用意した物に置き換え
          ble の関数で COMP_ 変数を用意し、
          その後で -F -C オプションに指定されていたコマンドを呼び出す。
          呼出方などは -F -C の仕様に準じる。
        3 compgen 解析したオプション -- "$COMPV" を呼び出し候補を列挙する
      )
    fi

    既存のシェル関数による補完候補生成 (complete -F) の仕様について確認する。

    | complete -F による補完を実行する際にどの様な変数を設定する事になっていたか、
    | どの様にして補完単語及び補完単語を指定する事になっていたかについても確認する必要がある。
    | それらの仕様によってどの様にコマンドラインの情報を構築するかが変わってくるからである。
    |
    | 基本的に complete -F 呼出元では COMP_ シェル変数を設定すれば良いと考えられる。
    | COMP_* シェル変数には以下のような物がある。
    | - COMP_LINE   コマンドライン全体
    | - COMP_POINT  コマンドライン全体の内の位置
    | - COMP_WORDS  コマンドラインを構成する単語たち
    | - COMP_CWORD  COMP_WORDS 内のどの単語に現在カーソルがあるか
    | - COMP_KEY
    | - COMP_TYPE
    | - COMP_WORDBREAKS ← これはユーザ側が comp の動作を制御する為に使用する変数であって、comp 側で設定する変数ではない。
    |
    | 疑問: 補完関数はどの様にして COMP_WORDS[COMP_CWORD] 内におけるカーソルの位置を知るのか?
    | a 例えばカーソル位置で必ず単語が切断されるのか、
    | b 或いは、COMP_WORDS[COMP_CWORD] にはカーソルよりも前の部分しか格納されないのか、
    | c COMP_WORDS 自体がカーソルよりも前の部分だけしか含まないのか、
    | d それともカーソル位置を知る方法はないのか。
    |
    | →d の様である。COMP_WORDS COMP_CWORD は素直に生成される。
    |   従って単語の途中で TAB を押している可能性もあるので、
    |   シェル関数側では「COMP_WORDS[COMP_CWORD] から始まる単語だけを生成する」
    |   という訳には行かないようである。ちゃんと COMP_LINE, COMP_POINT を用いて、
    |   現在のカーソルの位置が何処にあるのかを確認して候補を列挙する必要がある。
    |
    | 疑問: COMP_POINT の説明が気になる。コマンドの先頭からの offset というのは、
    |   コマンドラインの先頭からの位置とは違うのだろうか。例えば複数のコマンドがコマンドラインに含まれている場合にどうなるか。
    |   特に、複数のコマンドが含まれている場合には、他のシェル変数 COMP_CWORD, COMP_WORDS, COMP_LINE 等もどうなるか気になる。
    |
    | →何と! ちゃんとコマンドライン中の、現在のコマンドに対応する部分を切り出して
    |   COMP_LINE, COMP_WORDS, COMP_CWORD を設定してくれる様だ。
    |   COMP_LINE が現在のコマンドラインだという説明が誤っていたという事になる。
    |
    |   所で $(echo $(echo $(...)) 等としてみたが、... の場所に書かれているコマンドについては
    |   complete で設定された補完は実行されないようである。
    |   一番外側のコマンドについて complete が呼び出されるだけである。
    |   一番外側のコマンドについての補完では $(...) はちゃんとひとまとまりとして
    |   (途中の空白で単語分割されたりせずに) 扱われる様である。
    |
    | 疑問: compgen は COMP_* に対して透過的か?
    |   つまり、先ず compgen -F でシェル関数は呼び出されるのか? という事と、更に、
    |   COMP_* だけ自分で適当に設定すれば compgen -F を介して呼び出される関数は期待通りに動くのか?
    |
    | →試してみた所、透過的ではなかった。関数内で見ると COMP_LINE= COMP_POINT=0 COMP_CWORD=-1 の状態になる。
    |   そればかりか、関数呼出元の変数の内容も変更されてしまう様である。
    |   もし compgen を利用するとなると -F の内容は一旦関数でくるんで実行する事になるだろう。
    |
    | 従来の bash 向けの補完関数の能力を最大限に引き出す為には ble 側で、
    | 現在のコマンドの部分を切り出して仮想的に再現した COMP_LINE, COMP_POINT を用意する必要がある。

    結論 (origiinal complete の仕様)

    (1) COMP_LINE, COMP_POINT, COMP_WORDS, COMP_CWORD は現在のカーソル位置にあるコマンドから作られる。
    (2) COMP_WORDS, COMP_CWORD はカーソルが現在の単語の中のどの位置にあるかは教えてくれない。
    (3) compgen -F を実行すると COMP_* の内容がクリアされてしまう。

    結論 (方針)

    (1) 基本的には complete -p の結果を元に compgen を用いて候補の生成を行う。
    (2) complete -F のシェル関数は COMP_* を設定する関数を一旦挟んでから呼び出す様に介入する。
    (3) 補完対象は現在カーソルがある位置のコマンド全体を特定して決める。
      そこから仮想 COMP_LINE COMP_POINT を構築する。

    先ずはコマンド全体を抽出する所から始まる。

    | [コマンド全体を抽出する手法の選択]
    |
    | というよりそもそも現在の実装で単語のどの様に抽出していたか?
    | →ble-edit+complete 関数から ble-syntax/completion-context 関数を呼び出している。
    |   更にそこから ble-syntax/completion-context/check-prefix 関数を呼び出している。
    |   この中で現在位置が属している単語の切り出しを行っている筈である。
    |   実際に見てみると現在位置から先頭に向かって順に _ble_syntax_stat を見ていって、
    |   現在位置より前にある最後の解析再開点の情報を読む。
    |   解析再開点には現在の解析における単語開始位置などの情報が格納されている。
    |   この情報を利用すれば確かに現在位置にある単語の情報を抽出する事ができる。
    |
    | では更に現在位置の属している単語だけではなくコマンドまで抽出するにはどうしたら良いか。
    | 取り敢えず現在の単語とそれより前にある単語を順に辿って行って、
    | 初めにコマンド単語に当たったら其処で停止するという方法を取れば現在のコマンドを抽出できる。
    | その過程でコマンド・最初の引数から現在の引数までを取得する事は可能である。
    | しかし、以降の単語を抽出するにはどの様にしたら良いのだろうか。
    | 一文字ずつ進んで確かめていく方法だとそのコマンドがとても長いコマンドであった場合に時間が掛かる。
    | すると木構造を辿るしかないのだろうか。現在の実装だと中身から木構造を根本に辿る方法は提供されない。
    | ここで二つの選択肢がある。
    |
    | a tree-enumerate を利用して根本から順に辿っていく方法
    |
    |   現状 ble_debug=1 としてデバグ用情報を表示している時でもそんなに重くは無いようだから、
    |   根本から情報を辿る方式でもそんなに問題は無いように思われる。
    |
    | b tree-enumerate の情報をキャッシュして葉から根本の方向へ辿る事のできるデータ構造を構築する方法
    |
    |   % しかしながら、今後色付けなどの更新の方の需要から、
    |   % 葉から根本の方向へ辿る事のできるデータ構造を構築するかもしれない。
    |   % もしその様な仕組みが整うのだとしたら初めからその事を意識した実装にする必要がある。
    |   % 或いはもうこの complete の実装の為にその仕組みの大枠を作ってしまう方が良いかも知れない。
    |   %
    |   % 例えば葉から根本の方向へ辿る事のできるデータ構造を取り敢えず作り、
    |   % その更新は愚直に全体に対して行う事にする。
    |   % 部分更新などの細かい最適化の可能性については後で考える事にする。
    |   %
    |   % しかし、昔の考察だと部分更新は(整合性を保つようにするのが)かなり難しいと思われる。
    |   % そうすると結局最終的にも完全に全体を毎回再構築する事になるかもしれない。
    |   % それだと結局キャッシュする事の意味も余りないという事になる。
    |   % 色付けの更新の際にもその様な調子であれば結局この仕組みは遺棄される事になる。
    |   % それならば無駄なデータ構造を作らない方が良いとも考えられる。
    |   %
    |   % 結局の所具体的な需要がはっきりしないうちに仕組みを中途半端に揃えても、
    |   % 結局想定していた需要に対しては利用できない・実現不可能という事になって、
    |   % 無駄になるかもしれない。それならば今の段階では余り具体的な行動は動かさない方が良い様に思われる。
    |
    |   色付け更新の方から来る需要にも対応して入れ子構造のデータを構築するのは後回しにする。
    |
    |   そもそもその様な入れ子構造のデータを管理して色付けを効率化できるか不明である事、
    |   "complete で必要としているのは現在のコマンドに於ける最後の引数の位置" という単純な物であるから、
    |   その様な入れ子構造のデータを実装してからでも対応は難しくない事からである。
    |
    | 結局、「最後の引数の位置を特定する」機能を実装して、更に其処からコマンドを抽出するという事にする。
    | この最後の引数の位置は a/b のどちらでも実装できるが取り敢えずの所は a による実装で進める。
    |
    | 現在の単語抽出の枠組を流用しようかと思ったが、どうも現在の実装は不完全の様な気がする。
    | 現在の位置が "～" で囲まれた場所だったりした時に補完が働かない。
    | 一方で現在の位置が ${～} で囲まれた場所だった場合は補完が働かなくて正解なので
    | やはり現状の実装の様にする必要もあるかも知れない。
    | どの様な時にコマンド単語としての補完を実行して、どの様な時にしないのかをはっきりとさせておく必要がある。
    |
    | もう少し体系的な取り扱いをしたいが、これは現状の実装でも同じ様に体系的な扱いをしたいので、
    | 別に新しく作るという事はせずに、現在の枠組の延長としてコマンド抽出を実装し、
    | もし体系的な取り扱いをしたければ現状の実装の部分を拡張する方針で行く。

    結論
    (1) コマンドの抽出部分はモジュール性が高く簡単に再実装できるので、
      現状の枠組 (tree-enumerate) による抽出コードを取り敢えず書いて使う。
    (2) もし今後最適化の機会があれば再度書き直す。

    先に補完対象 (file, command, argument, etc.) を列挙し、
    その後で argument による補完候補列挙が必要になった時にコマンドの抽出を行う。

    | [コマンド部分の抽出の実装]
    |
    | コマンドの抽出はまた別の関数として実装する事にする。
    | 取り敢えず入れ子構造を走るプログラムを書いてみる事にする。
    |
    | そのノードが現在地を含む一番小さな word である条件は?
    |
    | 1.そのノードが word であるという事。
    |
    |   nest による構造ではなくて word であるという意味である。
    |   これは wtype が整数 (CTX_*) か文字列化で判定できる筈。
    |
    |   →本当か? nest で整数を使っている箇所はないのか?
    |     各場所の nest-push 調べてみた所、
    |     数字をしている箇所は存在しないようである。
    |     一箇所だけ何も指定していない場所があるが、
    |     nest-push 関数の中を見ると何も指定しない場合は type は "none" になる様である。
    |   →或いは、nest による node 登録は別の方法で区別できるようになっていたかも知れないのでそれも確認する。
    |     調べてみたが ntype をそのまま tree-append に渡しているので、
    |     区別する為にはやはり ntype, wtype を使用する必要がある。
    |     現在は ntype の値は使用していない様に思われるので、
    |     実は tree-append 時に type を "n$ntype" にしてしまえば良いのではないだろうか?
    |   →また既に ${node[0]} =~ ^[0-9]+$ で判定を行っている箇所を発見した。
    |
    |   保険の為 nest の場合は tree-append 時に n$ntype とする事にした。
    |
    | 2. 内側に word を含まない事
    |
    |   これは先に tree-enumerate-children して内部の構造を調べてから自分の処理を実行するという風にすれば良い。
    |   自分が word で内部に word を含まないと判定できれば isword=1 を設定する事にすれば良い。
    |   内部に word を含まないという事は isword= である事によって確認できる。
    |
    | > 現在のカーソル位置に未だ単語が出来ていない場合はどうするのか?
    | > つまり単語を其処に入力しようとしているが未だ 1 文字も入力していない状態の場合である。
    | > この様な場合を検出する為には単語ではなくて寧ろコマンドの context で検出するべきなのではという気がする。
    | >
    | > 或いは、現在地を含む単語によって検出するのではなくて、現在地より前にある単語を用いて検出するか?
    | > 現在地より前にある単語でかつ親ノードの内側に現在地を含む物が見付かれば良い。
    | > これについては後で対策する。-> Done.
    |
    | コマンドに属する単語の抽出は大体完了した様子である。
    | 更に comp_line や comp_point comp_cword にも対応する必要がある。
    | →対応した。

    取り敢えず実装したので commit する事にする。
    何故か動いていないが後でデバグする。

2015-11-19

  * bleopt コマンド [#D0244]

  * PROMPT_COMMAND [#D0243]

    普通の bash (ble のない bash) では、
    bind -x によって設定したコマンドを実行後に prompt を再描画するが、
    その時には PROMPT_COMMAND の中身は実行されない様だ。
    あくまで通常コマンドを実行した後にプロンプトの内容を
    再計算する時にコマンドが実行される様である。

    つまり PROMPT_COMMAND はプロンプトを計算する際に実行すれば良い。
    プロンプトの計算は .ble-line-prompt/update の中で、
    _ble_edit_LINENO と _ble_line_prompt[0] (前回のプロンプトの計算をした時の LINENO) が
    不一致だった時に実行される。

    PROMPT_COMMAND の内容を何処で実行するかは問題になる。
    関数の内側で実行すると declare した変数が見えないし、
    また関数の内側で定義された変数に干渉する事ができてしまう。

    一番外側で実行しようと思うと色々面倒なことになる気がするので
    取り敢えずは .ble-line-prompt/update の中で
    eval "$PROMPT_COMMAND" を実行する事にする。

    2017-10-26 変更を眺めていて思ったが、これは直しきれていない。改めて修正した。

  * histexpand: "～" 中の histexpand, extglob の際の histexpand 開始 [#D0242]

    > - 文字列 "～" 中の history-expansion は " を含まない。
    > - '!(' not histexpansion when shopt -s extglob 対応

  * histexpand: histchars 対応 [#D0241]

    histchars が設定されている時の正規表現の修正。
    > - _ble_syntax_bashc (旧 _BLE_SYNTAX_CSPECIAL)
    > - _ble_syntax_rex_simple_word
    > - _ble_syntax_rex_simple_word_element

2015-11-16

  * bug: 解析エラー [#D0240]

    解析のバグがようやく直ったと思っていたらまたエラーになった。
    今度は以下の様な状況でエラーが起こる:

    1. echo "${a[*]}" と入力する。
    2. echo ""${a[*]}"
    3. echo ""${a[*]}"" ←これでエラーになる。更に続けて何回かエラーが出る。

    しかもエラー状態のまま色々操作しているとついに CPU 100% でハングする。

    | [murase@padparadscha 0 ~]$ ""${a[*]}"
    | A?
    |  9*a    000 '"'      stat=(1 w=- n=- t=-1:-1)
    |  9*a    001 '"' ||
    | 14*a    002 '$' |||  nest=(2 w=2:0- n=- t=-1:-1) stat=(2 w=2:0- n=- t=-1:-1)
    |  |*a    003 '{' |||
    |  7*a    004 'a' |||
    |  8*a    005 '[' |||| nest=(14 w=- n='v[':2- t=-1:-1)
    |  8 a    006 '*' |||| stat=(8 w=- n=@5 t=-1:-1)
    |  8 a    007 ']' |||+ word=v[:5-8 stat=(8 w=- n=@5 t=-1:-1)
    | 14 a  s 008 '}' ||+  word=${:2-9>@7 stat=(14 w=- n=@2 t=0:-1)
    |  9 a  s 009 '"' ++   word=2:1-10>@9 word=none:1-10>@8 stat=(5 w=- n=@1 t=0:-1)

    何が起こっているかはすぐに分かった。一つ目の " を挿入した時に、
    解析が ${a[ までで中断している。本来は入れ子の構造が異なるので中断してはならない筈である。
    さて最近の修正の所為で中断されなくなったのか、それとも昔からあったバグなのか。

    先ず初めの可能性は更新された領域が誤った解析結果になっていないかという事である。
    上の状態で言えば 000, 002, 005 に設置されている情報に当たる。
    これはなさそうであるが念のため確認しておく。
    →挿入をせずに初めから順番に入力していった場合 (エラーは起こらない) と比較する。
      000, 002, 005 は完全に一致している。
      更にいうならば 006 に設置されている stat も一致している。

    000, 002, 005 が一致しているのは正しく解析が行われているという事なのでOKである。
    ところが 006 も一致しているというのは何かおかしい。
    これだけの情報だと確かにこの場所で解析が中断されてしまう。

    何故前回の解析で全く同じ stat が再現されているのだろうか??
    →いや局所的に見れば stat が一致するのは不思議な事ではない。
    たとえ全く同じ stat になったとしてもその参照先の nest が異なるのでここで中断はないはずなのだ。
    念のため直前の nest の状態についても調べておく:

    | [murase@padparadscha 0 ~]$ "${a[*]}"
    | A?
    |  9 a    000 '"' ||   nest=(2 w=2:0- n=- t=-1:-1) stat=(1 w=- n=- t=-1:-1)
    | 14 a    001 '$' |||  nest=(5 w=- n='${':0- t=-1:-1) stat=(5 w=- n=@0 t=-1:-1)
    |  | a    002 '{' |||
    |  7 a    003 'a' |||
    |  8 a    004 '[' |||| nest=(14 w=- n='v[':1- t=-1:-1)
    |  8 a    005 '*' |||| stat=(8 w=- n=@4 t=-1:-1)
    |  8 a    006 ']' |||+ word=v[:4-7 stat=(8 w=- n=@4 t=-1:-1)
    | 14*a    007 '}' ||+  word=${:1-8>@6 stat=(14 w=- n=@1 t=0:-1)
    |  9*a    008 '"' ++   word=2:0-9>@8 word=none:0-9>@7 stat=(5 w=- n=@0 t=0:-1)

    やはり "nest" が違うようだ。一つ上の nest @ 004/005 は一致している。
    更にもう一つ上の nest @ 001/002 は内容が異なる。
    '"' 挿入前は更にもう一つ上の nest @ 000 を参照しているのに対して、
    '"' 挿入後はもう一つ上の nest は - となっていて無効になっている。

    原因として考えられるのは:

    a. nest を遡った比較に失敗している?
    c. nest を遡って比較する為のデータを誤って参照している?
      またはデータを移動する時に失敗して新しいデータが混入している?
    b. shift に失敗している? (shift の際にデータが化けている?)

    一つずつ確かめていくしかない。確認の簡単そうな物&怪しそうな物から順に。
    先ずは a を疑う。function ble-syntax/parse/nest-equals の制御パスを調べる。
    →おかしい。ループが終わるはずのない場所で終わっている…。
      変だ…と思ったらこれはデバグ用コードの return が悪さをしている??
    →ああ、これだ。bash の && と || の優先順位は同じで左結合である。

    試してみた所、
    * [[ ～ ]] の && と || は期待通りの優先順位である。
      [[ a || '' && '' ]]         -> 0
      [[ ( a || '' ) && '' ]]     -> 1
    * (( ～ )) の && と || の優先順位も期待通りである。
      ((1||0&&0))                 -> 0
      (((1||0)&&0))               -> 1
    * command || command && command の優先順位は注意しなければならない。
      true || false && false      -> 1
      true || { false && false; } -> 0

    一応他にも同じ間違いをしている箇所がないか以下のコマンドで調べる:

    $ grc '\&\&' | grep -E '\|\|' | grep --color -E '\&\&|\|\|'

    他には同じ間違いをおかしている箇所は無いようである。
    元々コマンドを三つ以上 && や || で繋ぐ場合が少ない上に、
    使っている場合でも先に && があってその後に || があるパターンばかりの様である。
    左結合なので、この場合は期待通りに && が内側にあると解釈してくれる。

    (以前同じ様な事で嵌って修正を行ったような気がするが、
    その時に && と || を入れ替えたのだったか…。余り覚えていないが… 恐らく、
    A || B && C となっているのを ! A && B && C にしたのだろう。)

    何れにしても今後は && と || の優先順位に騙されないように注意深く実装を行う。

2015-11-08

  * 補完候補列挙に時間がかかっている時に入力があった場合、中止する? [#D0239]

    そもそも補完候補列挙のどの部分に時間がかかっているのか調べる必要がある。
    列挙・フィルタ部分なのか、それとも描画レイアウト決定部分なのか、描画部分なのか。

    特に時間が掛かるのは何も入力されていない状態で TAB を押した時である。
    complete がどの様な手順で処理されているかについて初めに調べる。
    ble-edit+complete (ble-edit.sh ble-autoload)
    -> ble-edit+complete (complete.sh)
        この関数内で殆ど分岐の処理をしている。
        先ず初めに候補を列挙して (ble-complete/source/command)、
        候補をスキャンして共通部分を計算する。
        候補が複数あったら描画を実行する。
    一番時間が掛かっているのは候補の列挙であり、
    そして次に時間が掛かっているのは共通部分の絞り込みである。
    今迄描画に時間が掛かっているのかと思っていたが、
    描画は本当に一瞬で終わっている。

    もっと ble-complete/source/command を詳しく見てみると、
    どうやら各候補についての情報を生成する所 ble-complete/yield-candidate で時間が掛かっている様だ。
    うーんこれを最適化するのは難しい…と思ったが、
    この部分はシェルによるループになっているので read -t 0 をチェックして中断するのは容易である。

    read -t 0 の performance をチェックする:

    > | $ time for ((i=0;i<100000;i++)); do read -t 0 && echo "$i"; done
    > |
    > | real    0m2.139s
    > | user    0m1.998s
    > | sys     0m0.139s
    > | [ble: exit 1]
    > | $ time for ((i=0;i<100000;i++)); do ((i%10==0)) && read -t 0 && echo "$i"; done
    > |
    > | real    0m1.673s
    > | user    0m1.664s
    > | sys     0m0.009s
    >
    > read -t 0 の呼出回数を 1/10 にしても対して変わらない様だ。
    > つまりループのコストか、或いは算術式による i%10==0 の実行の方も同じ位の実行コストがあるという事である。
    > これならば下手に read -t 0 の判定を間引く必要もないだろう。
    >
    > | $ function ble-util/check-input { IFS= read -t 0 -n 1; }
    > | $ time for ((i=0;i<100000;i++)); do ble-util/check-input && echo "$i"; done
    > |
    > | real    0m9.482s
    > | user    0m9.260s
    > | sys     0m0.213s
    > |
    > | $ function ble-util/check-input { IFS= LANG=C read -t 0 -s -r -d '' -n 1; }
    > | $ time for ((i=0;i<100000;i++)); do ble-util/check-input && echo "$i"; done
    > |
    > | real    0m16.039s
    > | user    0m15.809s
    > | sys     0m0.215s
    > |
    > | $ function ble-util/check-input { IFS= LANG=C read -t 0; }
    > | $ time for ((i=0;i<100000;i++)); do ble-util/check-input && echo "$i" && break; done
    > |
    > | real    0m11.199s
    > | user    0m10.965s
    > | sys     0m0.226s
    > |
    > | $ function ble-util/check-input { read -t 0; }
    > | $ time for ((i=0;i<100000;i++)); do ble-util/check-input && echo "$i"; done
    > |
    > | real    0m3.687s
    > | user    0m3.518s
    > | sys     0m0.166s
    > |
    > |
    > | $ IFS= LANG=C; time !!
    > |
    > | real    0m3.219s
    > | user    0m3.048s
    > | sys     0m0.168s
    >
    > 分かった事は read -t 0 の引数を増やすとそれだけ処理時間が増えるという事、
    > それ以上に IFS= LANG=C によって変数を書き換えるのに時間が掛かるという事。
    > 所で read -t 0 の引数を削除しても振る舞いには影響がないように見える。
    > 唯単に速度が遅くなるだけなのでループ中断の判定の歳には引数は無駄に指定しない事にする。
    >
    > | $ time for ((i=0;i<100000;i++)); do ((_ble_bash>=40000)) && read -t 0 && echo "$i"; done
    > |
    > | real    0m2.909s
    > | user    0m2.775s
    > | sys     0m0.131s
    > |
    > | $ time for ((i=0;i<100000;i++)); do ((check)) && read -t 0 && echo "$i"; done
    > |
    > | real    0m2.712s
    > | user    0m2.646s
    > | sys     0m0.064s
    > |
    > | $ check=1
    > | $ time for ((i=0;i<100000;i++)); do [[ $check ]] && read -t 0 && echo "$i"; done
    > |
    > | real    0m2.614s
    > | user    0m2.419s
    > | sys     0m0.193s
    >
    > 更に、関数呼出はそれほどには重くはないが多少時間は掛かるという事。
    > それでも算術式展開と殆ど同じである。一番早いのは [[ ]] による長さ判定である。
    > 関数呼出が絡むのであれば算術式 ((i%100==0)) でも挟んだ方が結局の所は有効なのかも知れない。
    >
    > | $ time for ((i=0;i<100000;i++)); do ((i%100==0)) && IFS= LANG=C ble-util/check-input && echo "$i"; done
    > |
    > | real    0m1.681s
    > | user    0m1.679s
    > | sys     0m0.001s
    > |
    > | $ time for ((i=0;i<100000;i++)); do ((i%10==0)) && IFS= LANG=C ble-util/check-input && echo "$i"; done
    > |
    > | real    0m2.475s
    > | user    0m2.458s
    > | sys     0m0.014s
    > |
    > | $ time for ((i=0;i<100000;i++)); do false && IFS= LANG=C ble-util/check-input && echo "$i"; done
    > |
    > | real    0m1.586s
    > | user    0m1.585s
    > | sys     0m0.000s
    > |
    > | $ time for ((i=0;i<100000;i++)); do :; done
    > |
    > | real    0m1.399s
    > | user    0m1.398s
    > | sys     0m0.000s
    >
    > そもそもループのコストが一番大きくて、算術式や [[ ]] による判定は殆どノーコストな様だ。
    > read -t 0 による判定は 10 に 1 でも良いかも知れない。

    read -t 0 の performance は大体分かったので適当に complete.sh に中断を実装した。
    関数 ble/util/is-stdin-ready (ble-core.sh) に実装して、それをループ内で間引きつつ呼び出す事にする。

    今の所は使い勝手はそんなに問題ない。誤って TAB を押しても固まるという事は無い。

    ただし、初めのコマンドを compgen で列挙する phase は環境によって滅茶苦茶時間が掛かるかも知れない。
    以下に速度を計測してみる事にする。

    | @gauge Cygwin (Intel(R) Core(TM)2 CPU 6300 @ 1.86GHz)
    |
    | $ time compgen -A command '' > /dev/null
    |
    | real    0m24.248s
    | user    0m0.953s
    | sys     0m5.875s
    |
    | $ time compgen -A command '' > /dev/null
    |
    | real    0m6.578s
    | user    0m1.063s
    | sys     0m5.375s
    |
    | $ time compgen -A command '' | wc
    |    6472    6494   65984
    |
    | real    0m6.734s
    | user    0m1.296s
    | sys     0m5.420s
    |
    | @padparadscha GNU/Linux (Intel(R) Core(TM) Duo CPU T2300 @ 1.66GHz)
    |
    | $ time compgen -A command '' | wc
    |    5274    5274   68019
    |
    | real    0m0.119s
    | user    0m0.038s
    | sys     0m0.092s
    |
    | @hankel GNU/Linux (Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz)
    |
    | $ time compgen -A command '' | wc
    |    4112    4112   57267
    |
    | real    0m0.051s
    | user    0m0.019s
    | sys     0m0.038s
    |
    | @laguerre GNU/Linux (Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz)
    |
    | $ time compgen -A command '' | wc
    |    7639    7639   87603
    |
    | real    0m0.094s
    | user    0m0.021s
    | sys     0m0.079s

    やはり cygwin では桁違いの遅さである。
    cygwin では command prefix が空の時は何も列挙しないなどの対策が必要かも知れない。
    →しかしながらこれは ble.sh を使っていなくても同じ事である。
      遅いのが嫌であれば shopt -s no_empty_cmd_completion を設定している筈なのだから、
      この設定を参照して補完の有効・無効を切り替えるべきである。

2015-11-07

  * M-\ delete-horizontal-space [#D0238]

2015-11-06

  * <bug> 編集中に偶にエラーが起こる。起こる条件は不明 [提起: 2015-09-24] [#D0237]

    [状況確認]

    起こった時のメッセージを記録する。
    "${i}" → "${i" → "${i))" → "$((i))" とする過程で起きた。
    詳細: &kbd{'echo "${i}"' left left DEL "))" left left left DEL}: これで起こる。
    入れ子の境界を backspace で消した時に起きた?
    或いは別の入れ子の終了を挿入した時?

    assertion failure: [[ ${_ble_syntax_nest[inest]} ]]
    ble-syntax/tree-enumerate/.initialize/FATAL1
      @ /home/murase/prog/ble/ble.sh:7397 (ble-assert)
      @ /home/murase/prog/ble/ble.sh:2 (ble-syntax/tree-enumerate/.initialize)
      @ /home/murase/prog/ble/ble.sh:22 (ble-syntax/tree-enumerate)
      @ /home/murase/prog/ble/ble.sh:236 (ble-syntax/parse/shift)
      @ /home/murase/prog/ble/ble.sh:-16 (ble-syntax/parse)
      @ /home/murase/prog/ble/ble.sh:4 (_ble_edit_str.update-syntax)
      @ /home/murase/prog/ble/ble.sh:2479 (ble-highlight-layer:syntax/update)
      @ /home/murase/prog/ble/ble.sh:4223 (ble-highlight-layer/update)
      @ /home/murase/prog/ble/ble.sh:4762 (.ble-line-text/update)
      @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update)
      @ /home/murase/prog/ble/ble.sh:1 (.ble-edit-draw.update-adjusted)
      @ /home/murase/prog/ble/ble.sh:975 (.ble-decode-byte:bind/tail)
      @ /home/murase/prog/ble/ble.sh:1 (ble-decode-byte:bind)

    異常状態
    [murase@padparadscha 0 ~]$ echo "${i))"
    A?
     2 aw   000 'e' | stat=(1 w=- n=- t=-1:-1)
     | aw   001 'c' |
     | aw   002 'h' |
     | aw   003 'o' + word=2:0-4
     3 a    004 ' '
     9 a e  005 '"'   nest=(4 w=4:5- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)
    14 a e  006 '$'   nest=(5 w=- n='${':5- t=-1:-1) stat=(5 w=- n=@5 t=-1:-1)
     | a e  007 '{'
     7 a    008 'i'
    15 a    009 ')'   stat=(14 w=- n=@6 t=-1:-1)
     | a    010 ')'
     6 a es 011 '"'   nest=(15 w=- n='none':7- t=-1:-1) stat=(15 w=- n=@6 t=-1:-1)
    \_ '"' (← ※エラーの結果としてこうなっている。原因ではない。)

    正常状態
    [murase@padparadscha 0 ~]$ echo "${i))"
    A?
     2 aw   000 'e' | stat=(1 w=- n=- t=-1:-1)
     | aw   001 'c' |
     | aw   002 'h' |
     | aw   003 'o' + word=2:0-4
     3 a    004 ' '
     9 a e  005 '"'   nest=(4 w=4:5- n=- t=-1:1) stat=(3 w=- n=- t=1:-1)
    14 a e  006 '$'   nest=(5 w=- n='${':5- t=-1:-1) stat=(5 w=- n=@5 t=-1:-1)
     | a e  007 '{'
     7 a    008 'i'
    15*a    009 ')'   stat=(14 w=- n=@6 t=-1:-1)
     |*a    010 ')'
     6*a e  011 '"'   nest=(15 w=- n='none':6- t=-1:-1) stat=(15 w=- n=@6 t=-1:-1)
    \_ 'echo'
    \_ '"${i))"'
        \_ '"${i))"'
            \_ '${i))"'
                \_ '"'

    011 文字目の nest の値に誤りがある。正しく shift されていない?
    どうやら "${i)" から "${i))" にした時にずれる様だ。
    更に色々調べていると "${i " から "${i a" にしても問題になる。
    "${i" を "${iaa" としても問題は起こらない。

    [原因特定]

    違いを見てみると最後の " の部分についても再更新を行っているかどうかに依存している様である。
    何も問題が生じない時には最後の " についても再更新が行われている。
    しかし問題が起こる場合には最後の " についての再更新が行われず、
    そこで状態が一致したと解釈されて解析が終了してしまう。

    最後の " について shift が実行されていないという事から見ると、
    本来は最後の " に関しては必ず再更新を行うという想定なのだろう。
    それが何かの具合で " の位置で状態 (stat) が一致すればそこで中断可能という事になっている。
    (或いは、逆で、状態が一致すればそこで中断可能の筈なのに、shift が省略されているのかもしれない。)

    最後の " (つまり、挿入部分の直後の文字) について状態が一致した時に
    そこで中断可能とするべきなのかどうなのかについて再度考察する必要がある。
    以前に、再開を可能とする為の条件についてまとめた様な気がするのでそれを参照する。
    →"[memo] の解析の際の原則" に書いたものだったはず。
      ここには解析データ配列に対する操作の原則を書いている。
      この原則から中断が可能かどうかについて導出ができるはず。
    →この原則が厳密に守られているのであれば解析は中断可能な気がする。
      % いや。解析データに関しては問題はないが、編集文字列本体に関してはどうだろうか。
      % 解析の際にどこに解析再開点を設置するかを決定するために、解析点よりも先の文字を使用している。
      % →でも一旦解析状態 stat (及び nest 構造) が同じになって、その点以降の文字列が同じであれば
      % 解析の結果は完全に同じになるほかはない。従ってその場所で解析の中断が可能なはずである。
      やはり解析は挿入範囲の直後で中断可能である。

    % もう一つの疑問点は "${i" を "${iaa" とする過程で、何故解析の中断が行われないのかという点である。
    % stat は一致する筈のように思われるし、解析中断可能範囲は "${i a" とする時と同じはずである。
    % % →本当に stat は一致するのだろうか。もしその位置の stat も shift をしないのだとすれば
    % % 解析状態 stat は一致しないのでそこで解析が中断する事は無い。
    % % でも、そうすると今度は "${i a" の時に何故解析状態が一致してしまうのかという話になる。
    % % うーん。謎だ。というか確認してみた所 stat はちゃんと shift されている様である。
    % stat はやはり shift されている。従って一致しても良いように思われる。
    %
    % とすると残るのは解析中断範囲の計算方法の問題だろうか。。
    % (つまり、挿入範囲直後の文字を含んだり含まなかったりまちまちになっている可能性?)
    % →実際に調べてみると解析中断範囲 (-i1 i2-)は問題が出ている時も出ていない時も、
    % 挿入範囲直後の文字の位置に i2 がある。つまり、解析中断範囲の指定によると解析中断可能の筈である。
    % それが中断不可能と判定される理由は何であろうか…。
    % % 唯一の違いは '${' から解析を再開しているかその中身から解析を再開しているかに依存すると思われた。
    % % しかし、中身から解析を再開した場合でも問題が起きない場合には起きない様だ。
    % % →気のせい??→どうやら ble_debug を入れている時と入れていない時でエラーが出るタイミングが違うようだ。
    % %   ble_debug を入れている時の方が即座にエラーを検知していると思われる。今後その仮定の下で調べる。
    % やはり '${' から解析を再開しているかどうかである。
    % '${' から解析を再開する場合、それに対応する nest
    % への参照を含む stat が全て削除されてしまうのが中断が起こらない原因と思われる。
    % さて、ここで改めて考えるに '${' から再解析をして再び全く同じ状態になった場合、
    % 新しく作成される nest は元々あった nest とは違うインスタンスではあるが、
    % やはりそれより後の解析状態は同じになるのではないだろうか。
    % そうだとすると nest が新しく作成された物であったとしても、
    % そこで中断して良いはずなのではないだろうか。
    % →取り敢えずは挿入範囲で削除された要素に対する参照が復元された場合でも中断可能として考える事にする★
    %
    % もし「新しい nest インスタンスであっても同じ状態になれば中断可能」とするならば
    % shift の部分を弄ってその nest に対する参照がある stat/nest etc. を削除しない様に修正する。
    % (削除する代わりに適当なshiftを実行する。特に、内容が変わらないという仮定の下での shift で良かろう。)
    %
    % % - 挿入範囲にあって削除される単語・ネストを参照する解析要素でも削除せず
    % %   適当な shift を実行する事にする。
    % →確認してみた所初めからその様になっている様である。おかしい
    →解析の中断が終わらないのは nest の shift 自体にバグがあって nest が変な状態になっていたからであった?
      でも変である。解析の中断の判定は stat 及び stat の参照している nest だけしか参照しない。
      現在の位置に設定されている nest は解析を続行する事によって設定されるはずの物だから、
      解析の中断の判定には使わないはずだし実際に確認してみた所そうなっている様に見える。

    未だ残っている問題というか、確認していない事項は shift 対象の範囲である。
    なぜ nest の情報が shift の対象になっていないのだろうか。
    nest の格納方法について再度確認を行う。別に特別な格納の方法はしていない様だ。
    原則に則った格納方法になっている。

    各項目の shift 方法の判定についても確認してみたが問題ないようである。
    と思ったらバグを発見した。klen = nest[k] の値を見て nest[k] の shift 方法を判定するべき所を、
    nest[1] を見て nest[k] の shift 方法を判定していたようだ。
    →修正した。これで当初のエラーは発生しなくなった。

    ToDo: 残る事はこの修正によって解析の中断がちゃんと起こる事を確認する事である。
    →おかしい。やはり解析の中断は起こっていない。
      確認してみたが stat の状態は同じ様である。という事は nest か。
      やはりそうだった nest の判定で棄却されている。ではどの様に?
    原因が分かったこれは別項目として独立させる (2015-11-06)。

2015-08-25

  * ble-edit.sh (function .ble-edit/history/generate-source-to-load-history): bash-3.0, [#D0236]
    history が load されているか確認する時 history '!1' でエラーメッセージが表示される。

  * ble-edit.sh: PS1 の中に含まれる ! が \! に化ける。 [#D0235]

    → eval 'a="!m"' となっていても特に履歴展開は起こらない様だ。
    また、PS1 中の ` は特別な意味を持つのでエスケープしない。

  * ble-edit.sh: PS1 の \w の $HOME を ~ に置換する部分で、 [#D0234]
    或るユーザ名が自分のユーザ名を先頭に含んでいる場合、
    そのユーザのホームディレクトリが部分的に ~ に置換されてしまう。

2015-08-19

  * <bug> bash-3.0 で上 (prev-history) をすると今迄に実行したコマンドの履歴が消える。 [#D0233]

    bash-3.0 で消える。bash-3.1 ではちゃんと期待通りの動作になっている。

    そもそも history に登録されていないという可能性もある??
    →しかし一回履歴を見てから実行したコマンドについてはちゃんと履歴に残っている様である。
      でも、それは history コマンドから拾った事に依る物ではなくて、
      自前で記録しているからに過ぎないのでは?

    実際に history コマンドでどの様な物が登録されているかを確認してみればよい。
    と思って確認してみた所最近拾ったコマンドですら登録されていない。
    というか、history に項目を登録するたびに実際には
    history の末端の項目が削除されて行っている様である。
    これは history コマンドの呼出周辺に問題がありそうである。

    少し触ってみて分かった事。
    bash-3.0 では history -s -- で登録したコマンドは末尾に追加されるのではなくて、
    一番最近のコマンドを置き換える形で実行される様である。この動作は bash-3.1 の時と異なる。
    history -s 'echo hello' としても同じであった。
    しかしこれだけならば何故コマンドを実行する度に数が減るのかを説明できない。

    もう少し試してみる。bind -x に history ... を指定したらどうなるだろうか。

      bind -x '"\C-t":history -s echo "$RANDOM"; echo ok'

    として C-t を何回か押してみたが history が寧ろ減少するという状況は再現しない。

    他に history に対して操作をしている箇所と言えば history -p ... のみである。
    それとも history -p を実行する度に history の中身が減少するのだろうか。。。

      bind -x '"\C-t":history -p "echo $RANDOM"; echo ok'

    →何とこれだった! bash-3.0 では history -p する度に history の中身が減少するのだ。
    しかも一回 history -p する度に 2 個ずつ項目が削除される様だ。

    a history -sp としてやってみると何も問題は起こらないようだ。
      しかしこれだと評価結果が出力されないので history から読み出す必要がある。
      更に問題なのは history -sp を用いるとそれまでに history の一番上にあった項目が置換されてしまうという事である。
      これに対応する為には一番上にあった項目を一旦別の変数に覚えておいて、
      history -sp ...; history 1; の後に再度覚えて置いた項目を history -s で設定する必要がある。
      しかも history 1 で出力される内容は行番号 (と変更があれば * も) なので、自分で解析して正しい履歴内容にする必要がある。
    b 上の方法は大変に面倒である。面倒な事をするぐらいならば、
      実は (history -p ...) の様に subshell の中で history -p を実行してしまうのが一番楽である。
      subshell 内での履歴リストに対する変更は親シェルには影響がないので。
      fork のコストはあるものの、どうせ古い bash の対応であるのでこれで良いだろう。

    しかし、history -p で履歴が削除されるのを防ぐ事が出来たとしても問題は依然として残る。
    実際にコマンドを履歴に登録する history -s が使えない事である。
    history -s を用いても最近の項目が置換されるばかりで新しい項目としての登録が出来ない。
    これは、複数回のコマンドを実行しても一番最近の一つのコマンドの履歴しか保持できないという事を意味する。
    これに対処する為には、bash の history に頼らずに初めから全て ble.sh の側で処理してしまうしかない?

    →結局 history -s には頼らずに全部 ble 内で処理することにした。
    起動時に既に .bash_history を読み込んでしまい、
    そして、history -s には頼らずに直接 .bash_history に append を行う。

2015-08-18

  * <bug> bash-3.0 で less <<< と入力した時点で assertion failure が出る [#D0232]

    更に echo $(echo) と入力しただけでも assertion failure になる。

    - FATAL1 が出て無限ループになる → 無限ループになっていたのは
      ble-assert || break による停止が働いていなかった為。
      ble-assert の実装を新しくして上記の使い方が出来る様にしたつもりで居たが、
      実際には古い ble-assert が使われていた為。

    - さて assertion-failure になるのは children で参照した先が空欄である為。
      print-status で構築されている木の形を見てみようとしたが何か出力が変である。
      と思ったら local arr=() の形を使っていた為に bash-3.0 で arr='(...)' が代入されていた。
      これを local -a arr; arr=() の形に修正したらすぐに print-status は直った。

    さて漸く print-status による出力を確認してみる。しかし assertion failure になる直前の形に問題はない。
    (正しく動いている bash-4.3 の出力と全く同じ物が出力されている。)
    逆に assertion-failure 直後の print-status の状態を確認してみると一箇所だけ間違っている。

    | --- a.txt       2015-08-18 23:27:44.399485443 +0900
    | +++ b.txt       2015-08-18 23:28:20.860151961 +0900
    | @@ -11,7 +11,7 @@
    |   | aw   008 'c' |||
    |   | aw   009 'h' |||
    |   | aw   010 'o' ||+ word=2:7-11
    | -14 a    011 ')' ++  word=4:@3>5-12>@11 word=$(:5-12>@10 stat=(3 w=- n=@5 t=0:-1)
    | +14 a    011 ')' ++  word=4:@3>5-12>@11 word=$(:@4>5-12>@10 stat=(3 w=- n=@5 t=0:6)
    |  \_ 'echo'
    |  \_ '$(echo)'
    |      \_ '$(echo)'

    何故か存在しない単語を親単語としている様である ("@4>" の部分)。
    しかしこれは寧ろ ble-assert による中断で shift に失敗しているという事の様な気もする。
    しかしそもそも ble-assert が発生するのは存在しないノードへの参照がある為であり、これがその原因とも解釈できる。
    もう少し動作を見て判断する必要がある。

    全体を探す前に念のため local arr=() の形式の誤りをしていないか確認を行っておく。
    他に2箇所その様な問題のある記述をしている箇所が見付かった。それを修正する。
    それを修正したら今迄出ていた assertion failure も出なくなった。
    echo $(echo) をしても何も起こらないし、また、cat <<< hello 等としても何も起こらない。良かった。

2015-08-16

  * [2015-02-21] <bug> [#D0231]

    word の属性が解除されてもそれが表示に反映されない。
    これはレイヤーの機能を使って実装した方が良いだろう。

    付記: 以下の問題もこの問題によるものだった。

    % * color: <bug> \ arg → \rm arg という編集をすると間の空白が構文再計算の対象から抜ける??
    %   →問題点は構文解析部分ではなくて単語に対する着色を削除する部分にある。
    %     構文解析や属性・単語の更新範囲の計算には問題がない事が分かった。
    %

    % echo file とした後 echo を C-d で消すとその直後の空白がエラー状態になる。
    % そのまま新しいコマンドを入力してもエラーの儘?
    % →再現しない?

    そればかりか…。前に存在していた word が消えた時 (word 以外の意味になった時)
    にそれを検知する術がない…。前回の word 配列を覚えておいてそれと比較する必要がある?
    二つの方向性がある。

    a parse で消えた word についての情報も提供する

      実は消滅した単語というのは、(1) DMIN DMAX0 の間にあったものと
      (2) _tail_syntax_word で使われなかった部分の2種類しかないのでは?
      代入する事によって上書きして消している word は存在しない。
      常にまっさらな所を i が走り、その i の箇所で word に代入しているから。

      (1) はどうせ削除されるから関係なさそうとも思ったが、
      DMIN DMAX0 の間にあった単語に関しても蔑ろにはできない。
      というのも DMIN DMAX0 の間に終端があって開始点は
      それよりも前にあるかも知れず、これらの単語が消える可能性もあるから。

      さて、parse の側でこれらの消滅について通知する事も出来るが、
      これは parse のするべき事なのかというと疑問である。
      もう少し別の方法…補足的情報を外部で取得する事によって、
      外部で消滅した単語の情報を取得する方法はないだろうか。

      (1) に関しては外部で既に計算する事が可能である。
      (2) に関しては…外部で計算前の _word のコピーを持っていれば、
      最後に処理した i さえ分かれば分かる。
      そして (将来的に変わるかも知れないが) _ble_syntax_attr_uend がそれに対応する。

    |
    | b 或いは、呼出側で前回の _word の内容を覚えて置いて消えた物がないか確認する。
    |
    |   これだと比較する為には呼出側で覚えて置いた物について shift したりしなければならない。
    |   というか覚えて置いたとしても同一性を確認するのは骨である。
    |   範囲と種類が同じであったとしても内容が同じとは限らないし、
    |   内容までも覚えておくのは面倒である。
    |   それに内容が完全に一致したとしても本当に同一と言えるのか??? (同一として良い気がするが)
    |
    | c 更に別の方法としては呼出側で単語と描画属性の組を覚えておくというのもある。
    |   (これは独立したレイヤーとして扱うという事に近い)。
    |
    |   これを用いて毎回全ての単語に対して属性の適用を行う。
    |   但し、単語の描画属性が何になるかだとか引数の解析だとかは省略する。
    |
    |   然し乍らこれは結構なコストである。属性の適用についてキャッシュしていないから。
    |   それに消滅する単語に対する処理は結局考えなければならないので変わりない。


    改めて考え直す。parse 呼出元で呼出前の _ble_syntax_tree を保持しておいて、
    消滅した単語を検知するというのは面倒である。もっと良い方法がないか。

    呼出元で呼出前の状態を保持する場合にしなければならないのは以下の事である。
    1. 先ず初めに、parse による更新範囲を取得する。
    2. 1 で得た更新範囲に登録されている単語を列挙し、
      その単語が存在していた範囲を特定する。更新による shift に注意する事。
    3. 2 で得た範囲に含まれる文字について着色を再計算する。

    実際には消滅した単語の更新範囲 (上記 2.) さえ分かればよいのだから、
    それを parse の中で計算してしまうと言う手もない事はない。

    また、3. を実行するという事は、任意に与えられた範囲に対して
    入れ子構造を考慮に入れた着色を実行するという事になる。

    これは何れ対応しなければならなかったので難点とはならない。

    ∵現状では新規生成された単語の範囲内のみで入れ子構造を考えていたが、
      実はこの実装は不十分である。新規生成された単語に着色が為されない場合、
      本来その親節の着色を適用するべきであるが、現在の入れ子構造の処理方法だと、
      任意に与えられた単語の親を取得する事が困難である。
      仕様がないので現状では着色無し、という事にしている。
      更に、単語と単語の間の空隙に関しても親節の着色を適用すべき所であるが、
      % これについては現在の実装では何もしていない (前回の状態が残る)。
      これについては着色の更新範囲内に入った場合には属性を完全に削除する様に変更した。

    つまり、色々な小細工を考えても仕方がない。現状で既に問題があるのだから、
    入れ子構造を用いた再着色の実装は必須である。

    「任意に与えられた範囲に対して入れ子構造を考慮に入れた着色を実行する」のは結構骨である。
    後ろから入れ子構造を辿っていかなければ完全な木を構築する事が出来ないからである。
    実は、似た操作を shift の時にも行っている。一回木の構造 (というか親節へのポインタ) を生成してしまえば
    後はそれを使い回せばよいので、木の構造を何処かにキャッシュする仕組みがあると良いだろう。

    % 1 取り敢えず消滅単語の範囲を計算するコードを書く。
    % 1.1 更新によって消滅する部分については、parse 呼出前に確認する。
    % 1.2 再解析によって捨てられる部分に関しては、何とか parse から結果を借りる方法を考える。
    %   適当なフラグに従って tail_* に対して local を宣言しないようにすれば良いだけでは?

    parse をできるだけ弄らないように実装しようとしていたがどうも困難な様なので
    結局 parse 内に消滅単語呼出の追跡の為の関数呼出を書き込む事にした。
    取り敢えず実装した。以下の変数に範囲を記録する:
      _ble_syntax_vanishing_word_umin _ble_syntax_vanishing_word_umax

    2 入れ子構造に対して計算を実行するコードを書く

    現状で十分動いているので、一旦切る事にする。
    効率が悪くなったら再度考え直す。

  * color: <bug> echo hello world と入力してから echo を消去すると、 [#D0230]
    hello に適用されるはずの色が "hello world" 全体に適用されてしまう。
    内部の _ble_highlight_layer_syntax?_table 系統の配列の内容は正しい物になっているが、
    _ble_highlight_layer_syntax_buff の内容はずれている。

    ble-syntax.sh (ble-highlight-layer:syntax/update-attribute-table) の実装で、
    _ble_syntax_attr_uend とするべき所 _ble_syntax_attr_umax としている部分を見つけた。
    取り敢えずこれを修正する→直った。。。原因を探索することなく、案外呆気なく直った。

  * <BUG> 表示されている文字列と内容の文字列がずれている。 [#D0229]

    まとめ: これは ble-edit/dirty-range/update 実装中の2種のタイプミスによる物だった。
      今迄影響が出ていなかった(影響に気付かなかった)のが不思議な位に致命的なバグであった。

    C-d を連続で入力した時などに発生している。
    どうも描画用の配列に対する shift が正しく処理されていない様に見える。
    _ble_highlight_layer_syntax_buff の内容を見てみたが変な事はないようだ。
    →異常がないように見えた物のよく見たらちゃんと shift できていない様だ。
      実際の文字数よりも長い配列になってしまっている。

    もう少し詳しく見てみる事にする。これらの *_buff 配列は、
      function ble-highlight-layer/update/shift
    を呼び出す事によって shift している。そしてこの関数では DMIN, DMAX, DMAX0
    を用いて shift を実行している。一方で、ble-syntax/parse ではどの様に
    shift を行っていただろうか (もしかするとこれ自体も間違いを含んでいるかもしれない)。
      ble-syntax/parse text beg end end0
    の引数を参照している様だ。そしてこの関数は ble-edit.sh (_ble_edit_str.update-syntax)
    から参照されている。ここでは _ble_edit_dirty_syntax_* に格納されている情報を渡している様だ。

    一方で *_buff の shift に用いている DMIN, DMAX, DMAX0 の出所は何処だろうか。
      ble-highlight-layer/update
    において DMIN, DMAX, DMAX0 が設定されている。この関数では配列 BLELINE_RANGE_UPDATE に
    格納された情報をそのままコピーしている。配列 BLELINE_RANGE_UPDATE は、
      ble-edit.sh (.ble-edit-draw.update)
    関数で、_ble_edit_dirty_draw_* から読み出している。これらの、
    _ble_edit_dirty_draw_*, 及び _ble_edit_dirty_syntax_* の更新は、
      ble-edit.sh (_ble_edit_str/update-dirty-range)
    にて実行されている。同時に実行されているので両者の内容に変化が生じるとは思えない。

    という事は syntax の方も不当な shift/解析になっている可能性もある。
    但し、元の文字列を参照して解析を行っているので目立った問題が見えていないと言うだけと思われる。
    これについてもチェックする。ble-assert を試しに埋め込んで見る。
    やはり _ble_edit_dirty_draw_*, 及び _ble_edit_dirty_syntax_* の内容は常に同じになっている。

    すると問題点は dirty 領域の合成自体にあると思われる。試しに、

      $ ble-edit/dirty-range/clear --prefix=hello
      $ echo $hellobeg:$helloend:$helloend0
      -1:-1:-1
      $ ble-edit/dirty-range/update --prefix=hello 2 2 3
      $ echo $hellobeg:$helloend:$helloend0
      2:2:3
      $ ble-edit/dirty-range/update --prefix=hello 2 2 3
      $ echo $hellobeg:$helloend:$helloend0
      2:2:2

    もうこれだけで間違った合成になっている。全然駄目だ。ble-edit/dirty-range/update の実装を見直す。
    ちょっと見ても分からないので過去のログを見る事にする。ble-edit/dirty-range/update の実装の詳細については、
    2015-02-16 の実装ログに記録が残っていた。論理についてよく見てみたが誤りは内容に思われる。
    結局、結果の式に値を代入しても正しい結果になると言う事を確認した。
    再度、コードの方を見てみると…何と変数名を間違えている。delta とするべき所が del になっていた。

    直した。然し良く分からないのは、このミスだけだったら最終的な結果は 2:2:2 ではなくて、
    2:2:3 という謝り方をしていた筈なのではないかという事である。
    2:2:2 になるという事は未だ別の箇所で何かミスをしているという事ではないだろうか。。
    取り敢えず再度実行してみる…。

      -1:-1:-1
      2:2:3
      2:2:3

    今度は 2:2:3 がもう一度表示されるという結果になった。本当は 2:2:4 になるべきだ。
    手で計算しても 2:2:4 になる気がする。再度数式を追って何で 2:2:4 にならないのか確認する。
    と思ったら…endA0 読み出しの時点で beg を読み出していた…。

      -1:-1:-1
      2:2:3
      2:2:4

    今度は正しい合成になっている。

  * eval は builtin eval に書き換え。test は [[ ]] に書き換え。 [#D0228]
    builtin の上書きを阻止。他にも複数のコマンドの上書きを阻止する。

  * <bug> コマンドを編集中にカーソルの位置がずれて表示されている文字列と内部の文字列に齟齬が生じる。 [#D0227]

    これはどうやら read -t 0 で読み取ったキーシーケンスが不当に解釈されて、
    結果として不正な文字が編集文字列に挿入されるためのようである。
    どの様な文字が挿入されているかを調べてから対策を考える事にする。

    1 本来は不正な文字が挿入されたとしても正しく表示されるべきである。
      →不正な文字 (というか 0x80-0x9F) が挿入された時に M-^? と表示される様に変更を行った。
      (元の bash readline ではこれに対する対策は行っていない。従って表示がずれる。)

    2 また、不正な文字が挿入される過程についても調べる。

      挿入されている文字を確認した所 "M-^[" であった。
      つまりこれは ESC [ を受け取る為にこれを CSI の utf-8 表現に変換しているのが原因である。
      変換の際に bind '"\e[":"\xC0\x9B["' としているが、この "\xC0\x9B[" という列は
      bind を通じてしか読み取る事ができず read で読み取れる文字とは別である。
      bind で 1 byte 目を受け取った時点で read を実行すると 2 byte 目ではなく、
      "\e[" の更に次に来た文字を読み取ってしまう。
      "\e[" の 2/3 byte 目は全ての read が実行された後にようやく処理される事になる。
      つまり受信される文字の順序が変化してしまうのである。

      (実際に確かめてみた所、その通りだった。しかし、この場合だけでなく複数の文字に対して
      bind -x または bind している物の場合に同様の問題が発生しうる?
      →複数文字から1コマンドへのmappingの際には問題にならない。複数文字が来て初めて
      コマンドが実行される為、複数文字の順序が交換されたりする事はない。)

      解決方法は色々考え得る。

      | a read -t 0 を使う以外の方法を考える。
      |
      |   bind -s と相性の良い読み取り手段が有れば良い。
      |   例えば、bind -s で待機されている文字をコマンドから取り出す方法が有れば良い…
      |   がそのような方法があるとは思えない。
      |   或いは、bind を用いて次の文字を直ぐに受信できるかどうかを判定する方法さえあればよい?
      |
      | a' read -t 0 で次の文字が来ていれば再描画を行わずに bind を抜ける
      |
      |   実は read -t 0 を用いて次の文字がすぐに来る事が確認できれば、
      |   表示を省略して bind を抜けても良いのではないだろうか。
      |   再描画は次の文字を処理する為の bind で実行されるであろう。
      |
      |   問題は accept-line の処理中に、
      |   再描画が完全に終わっている事を前提として処理が行われているかも知れないという事である。
      |   (exec:exec の場合にはそうではなかったのでちゃんと再描画していたはずだが、
      |   exec:gexec の場合にどうなっているかは調べないと分からない。)
      |   →どうも exec:gexec の場合には
      |
      |     ".ble-edit+accept-line/process+$bleopt_exec_type" && return 0
      |
      |   によって bind を取り敢えず抜けてから exec:gexec の設定した trap の内部で
      |   再描画処理を実行するので、再描画を省略しても問題はない。というか、
      |   元々 bind 内部では再描画されない。
      |
      |
      | b "ESC [" を受け取る別の方法を考える。
      |
      |   bind '"\e[":"\C0\9B["' が悪い、という事ならば別の方法で受け取る方法を考えればよい。
      |   しかしこれは可成り苦しんだ事なので他に解決方法を見つけるのは難しい。
      |
      | c utf-8 decoder の内部状態を見て bind-s の処理中かどうかを確認し、
      |   bind-s の処理中であれば read -t 0 で次の文字を読み取るのを抑制する。
      |
      |   例えば現状だと "\e[":"\xC0\x9B[" としているが、代わりに
      |   "\e":"\xC0\9B" という事にすれば、最後の文字として \xC0 が来た場合には、
      |   次の read -t 0 を抑制するという風にするだけで問題は発生しなくなる。
      |
      |   実は内部状態を見なくても、その :bind の中で最後に処理された byte が
      |   C0 かどうかだけ見れば良いのではないかという気がする。
      |   但し "\e[" の代わりに "\e" に対して bind を行った場合。
      |
      |   % x しかし \xC0 で始まる文字は結構ある (u80-u7FF) ので、
      |   %   それらの文字の read -t 0 ができなくなるという問題点がある。
      |   % と思ったが、\xC0 は u80-u7FF では決して使われないのでこれは気にする事は無い。
      |   % \xC0 はいわば非正規化表現でしか使われないのでそれ程気にしなくても良い。
      |
      |   x この方法だと実際に次の文字が来ているのに、
      |     \e[ の回数 (bind-s を介した読み取りの回数) だけ
      |     再描画処理が実行されてしまうという問題もある。
      |
      |     というか、実は "\e[" の組合せだと utf-8 の内部状態を見ても bind -s の処理途中なのか
      |     どうなのかという事を判定できない (utf-8 decoder を弄れば出来ない事もないが) ので、
      |     "\e" に bind -s するのが現実的となる。しかし、そうすると "\e" を含むシーケンスは全て
      |     read -t 0 の抑制の対象になってしまい、入力の高速化には繋がらない。
      |
      |     とも思ったが "\e" の読み取り過程では実際のキー入力は発生せず、
      |     ble-decode-key または ble-decode-byte の内部状態を変更するだけで、
      |     再描画も何も処理されないので、read -t 0 で急いで読み取らなくても問題ないのでは?
      |     という気もする。とも思ったが、確かに byte 毎の処理は実行されないが、
      |     例えば矢印キーによる移動などを考えると key 毎の矢印キーの移動・更新は実行される事になる。
      |     その過程で syntax も更新されるだろう。key 毎に syntax を更新するという事なので、
      |     やはり入力には従来通りの時間が掛かってしまうと言う事と思って良い。
      |
      | c' utf-8 で来るはずのない byte \xFF を用いるという手もある。
      |
      |   % c において、多くの文字で read -t 0 ができないのを防ぐ為に、
      |   % →この問題は気にしなくても良いという事が分かった。
      |   % つまり、この方法は c と比べて何らの利点もない。
      |
      |   "\e":"\xFF\9B" 等としておいて byte \xFF が来たら次の文字では read -t 0 をしないという具合に。
      |   x この方法を用いる場合 utf-8 decoder に手を加える必要がある。
      |     或いは、ble-decode-byte:bind 側で \xFF のみを特別扱いして
      |     ble-decode-byte に実際には文字が渡らない様にするなどの対処が必要である。
      |   x この方法は utf-8 以外の文字符号化方式では使えない。
      |     或いは文字符号化方式毎に調整が必要である。
      |   x 更に、c でもう一つ問題だった \e[ の入力の際に処理を抑制できない
      |     という問題も解決されていない。
      |
      |   この方法は可成り実装が面倒なのと場当たり的なので、余り考えたくない。

      → a' の方針で行く事にした。簡単な実装だがちゃんと動いている様だ。

  * read -t 0 を用いて貼付などの際に入力をまとめて処理するという事。 [#D0226]

    実は read の timeout を 0 にして呼び出せば、これまでに入力されたバイトを全て読み出せるのでは?
    →意外と簡単に実装できた? と思ったが色々と問題がある様だ。

    1. bash-4.0 未満では文字を既に入力していても何故か read -t 0 に失敗する。

      (何も入力がない時には単に失敗するだけなので、bash-4.0 未満では単に動作しないだけである。)

      bind -x 内部で実行している為に環境が違って read -t 0 が動作しないのかとも思ったが、
      実際に通常のスクリプト (test/readbyte.sh) として実行してみてもやはり動作しない。

      改めてマニュアルを見てみると read -t 0 について言及があるのは bash-4.0 以降の様だ。


    2. 日本語の文字を入力した時に変な事になる。

      bind -x で受信しているのはバイトである。一方で read で受信できるのは、
      bash-4.0 以降では文字である。日本語を入力すると、日本語の 1 byte 目は bind で受信され、
      2 byte 目以降は read で読み取る事になる。この時に、

      - read で読み取られた不完全なバイトをどの様に処理するか
      - byte 単位で読み取られた文字と文字単位で読み取られた文字をどの様に区別するか
      - 現状不完全な byte の内容取り出しに失敗している (printf %d '文字 は常に 0 を返す様だ)。
        →否、負の数を返してる様だ?

      が問題になる、解決の方法としては、

      a byte/char を区別する方法を考える。

        byte の場合、read の結果に不完全な文字が入っているという事なので、
        原理的に区別はできる筈だが…。また、区別できたとして、
        不完全な byte の内容を取得できる必要がある。

      b read でバイト単位で読み取る方法を考える。

        試しに LANG=C を read につけて読み取るなどしてみたが効果は無かった。

        →どうやら LANG=C をつければちゃんと byte 単位で読み取られる様だ。
        しかし、その直後の s2c で LANG=C を付けていなかった為に
        変な結果になっていたという事の様だ。

2015-08-15

  * ble-syntax.sh: `function ...' 対応 [#D0225]

    先ず関数名に使用する事の出来る文字について確認しておく必要がある。

    使える物: [][:%=~^{}@+-*:,.?/_]
    使えない物: [	 "$&'();<>\`|]
    条件付き:
      !    shopt -H して置かないと履歴展開されてしまう。
      #    単語の先頭には使えない (コメントになる)
      \001 使えるが実際に定義される関数名は何故か \001\001 になる。
      \177 使えるが実際に定義される関数名は何故か \001\177 になる。

    $'[^#\t\n "$&\'();<>\\`|][^\t\n "$&\'();<>\\`|]*'

  * ble-syntax.sh: `hoge ()', `function hoge ()' 直後のコマンドに制限をかける。 [#D0224]


2015-08-14

  * ble-syntax/parse/shift.impl2: <bug>: echo $(echo hello) hello で1つ目のhelloをBSで削除すると無限ループになる。 [#D0223]

    取り敢えず今は、古い実装を使う事にする。

    ble-syntax/tree-enumerate ble-syntax/parse/shift.impl2/.proc1

    の内部で無限ループになっている様である。
    どうやら一箇所に複数の節が登録されている時に
    一番外側の節に出会った時に一気に shift を実行してから、
    内側の節に対する処理を続けるという形にしていた為に不整合を生じていたようだ。
    一気に shift をするのではなく自分に対応している所だけ shift をする様に変更したら問題は発生しなくなった。
    取り敢えず、これで一旦解決とする。


  * [2015-03-08] <bug> $() を閉じると中身に色が着かない。 [#D0222]

    $( だけ書いて中身を記述している時は正しく着色されている。
    $( の中の引数も、コマンド名についても同様に着色の対象になっていない様だ。
    ( ) の中については正しく処理されている様に見える。

    原因は分かった。$() 全体が一つの単語となっている為に
    $() 全体としての着色が施され、内部にある個々の単語の着色が消されているという事だ。
    これをどの様に処理するのが良いかは考える必要がある。
    例えば zdepth 的な物を使って被覆されない様にするとか?
    しかし、それだと単語が消滅した時に困る。
    より上の階層にある単語の色を使いたいが
    その情報は失われているので単語の色を再計算しなければならない。

    一応適用順序を範囲の広い物が先に行われる様に修正したが、
    それでも部分更新に際しては完全ではない。
    やはり部分更新と単語毎の着色は親和性が低いのだろうか。

    これに完全に対応する為には現在存在している全ての単語について
    どの様に着色をしているかの情報を保持する必要がある。
    その為には必然的に単語の生死を完全に追跡する必要がある。

    実は単語の生死を追跡するのは簡単なのではないか?
    単語の生成に関してはわざわざ述べる迄もない。
    単語の消滅に関しても beg-end0 に存在していた単語と、
    shift 後に j2-i に存在していた単語が消滅する単語と分かっている。

    ただし、問題は単語が消滅した事が分かったとしてどの様に着色を修正するのかという事である。
    親単語が変更された時に全ての子単語について再度着色をするのは大変であるが、
    各単語の着色については _ble_syntax_tree に記録してしまうという手もある。

    入れ子構造が変化した時の着色の変化をどの様に適用するかについて二通りの方法を考え得る。

    a 着色の変化を考慮に入れるべき範囲を先に計算し、その範囲内の各点について色を計算する。
      この方法を用いるとどの部分を再度着色し直さなければならないのかという事を計算しやすい。
      一方で、各点がどの色になるのかという計算が難しい。
      愚直にやると各点についてその点に存在する word を列挙しなければならず現実的でない。

      実は末端から順番に着色を進めていけばそんなに複雑な操作をしなくても着色ができるのでは?

    b 生成・変更のあった各単語について着色を実行する。

      単語に overlap がある場合に複数回着色されて非効率に思われるかもしれないが、
      親単語から順に着色を実行する様にすれば他の単語の事は考えずに自然に着色が出来る。
      問題点は親単語の一部でも変更があると、その親単語に含まれる全ての子要素について再度着色を実行する必要が生じることである。

      特にこの問題はトップレベルの単語が消滅した場合にも拡張される。
      トップレベルの単語が消滅した場合、その部分の着色は解除されて既定の色になるべきである。
      しかし、単語に対して着色を実行するだけで、既定の色を適用するという操作をしなければそこに色が残ってしまう。
      結局トップレベルの文脈で既定の色を適用するという操作が必要になるのである。
      しかし、トップレベルで既定の色を適用すると全ての単語について再度着色を実行しなければならなくなる。

    c もっと効率的な実装はないだろうか?

      例えば CG で複数の物体が重なり合っている場合にどの様に処理を行うか?
      CG の場合には毎回全てのオブジェクトを描画し直すという事をする気がする。
      その場合には z-depth を用いてどのオブジェクトが前に来るかの判断を行う。

      今回の場合には単語の入れ子構造の情報を持っているので z-depth を考える必要はなくて、
      単純に親のノードから順に着色を実行していけばよいだけの事である。
      従って z-depth だとかの手法は今回の場合には訳に立たない。

      今回特に考えたいのは "部分更新" である。
      部分更新の対象は、生成された単語に対する着色、消滅した単語についての着色解除を含む。
      更に、コマンドに応じた着色を行っている際には、単語自体に変化が無くても着色が変化する事もあるだろう。
      これらを効率的に処理するにはどうしたら良いだろうか。
      特に最終的に "その点の配色" を格納した配列を更新・取得できればそれで良い。

      % 例えば単語の depth 毎に配列を用意してそこに値を記録するという方式は?
      % →単語のレベルがまとめて上がったり下がったりする時に大移動が起こる。非効率である。
      %   更に、depth が深くなれば成る程より遅くなる。

      % 各点についてそこに存在する単語へのリスト構造を保持する方式は?
      % この様にすれば或る単語が削除された時に、その位置に次に存在する色を直ぐに取り出す事ができる。
      % →リストを管理するのが大変である。
      %   単語の生成・消滅に際してリストへの登録・解除を行う必要がある。
      %   単語自体はその範囲情報を伴っているので、どの範囲に登録・解除をするべきかという情報を追加で持つ必要はない。
      %   逆にリストの各項目がどの単語に対応しているかという情報が必要である。
      %   shift が起こった場合などには更に面倒な事になる。
      %   余り考えたくない方法である。単語が削除された時にその下にある色を取得する方法としては大袈裟すぎる。

    色々考えたが a の方法が現実的な気がする。もう少し案を具体化する。

    先ず、単語自体の着色と結果の着色は独立に扱う。

    単語自体の着色情報は _ble_syntax_tree に補足情報として追加する事にする。

    > 1 _ble_syntax_tree に色情報を記録できる様にする。
    > 1.1 4と即値で指定している所を修正する。
    > 1.2 _ble_syntax_tree の幅を5に増やす。未設定の状態では - を置く。
    >   終端していない単語の場合には - の代わりに -- を置く事にした。
    > 1.3 長さや内容の変化した node についての色も - に戻す。
    >   _ble_syntax_word_umin 等に登録を行う。
    >
    > 2 更新された単語について色情報を再計算する。
    >   同時に色情報の変化のあった範囲を記録する。
    >
    > 3 色の変化のあった範囲に関して色配列を更新する。

    取り敢えず実装した。$() の中も期待通りに着色されている。
    一旦此処でこの項目は解決とする。

    削除して消滅した単語について着色が除去されない、
    速度について検証していない、等の問題点はあるが、
    これらは後で問題になってから考えればよい。

  * leak variables [#D0221]

    > cs ps1out                             # local 宣言忘れ
    > rex=$'^([ \t]*)(\\([ \t]*(\\))?)?'    # local rex 宣言忘れ
    > rmax=-1 rmin=-1                       # local rmax rmin 宣言忘れ
    > type='$('                             # parse/nest-type -v type 前に local type 忘れ
    > tchild=11 tprev=-1 wbegin=-1 wtype=-1 # parse/nest-pop を parse の外側で呼び出していたのが原因

    現在 g が leak している事が分かっているが、使用箇所が分散している為に見つけるのが面倒。
    → g も処理した。

  * ble-syntax/parse: shift チェックのループが遅い。 [#D0220]

    [現状]

    % これはどんなに後ろの方であっても挿入位置に wbegin や inest の参照があるかもしれない
    % という可能性が否定できない所に問題点がある。取り敢えず、この可能性があるかないか
    % 判定する簡便な方法について考えてみる。
    %
    % 1 削除領域内に word 開始点や nest 開始点がなければこのチェックは免れられる。
    % 2 word 終了点や nest 終了点は一つの開始点に対して一つまでしかない

    と思ったが、stat の有効性のチェックは上記の様に工夫すれば省略を考えられるが、
    shift に関しては結局全てチェックしなければならないので意味がない様に思う。
    ただ、stat や word を相対位置で覚えておくようにすれば、
    編集領域に跨る word や nest 以外についての shift をしなくても済む様になる。

    % どの様にすればスキップを行う事ができるだろうか。
    % 先ずは stat から考えてみる事にする。
    % inest の可能性について。
    %
    % 1 編集領域の終了点でトップレベルならば中で始まった inest が外で閉じる事は無い
    %
    %   編集領域の前と後で nest level が同じ場合、新しい inest が中で始まっている可能性はあるだろうか。
    %   と思ったが、ある。xxxx の中で一旦括弧が閉じて再び括弧が始まる可能性などを考えなければならない。
    %   但し、xxxx が top の nest level にある場合には中で括弧が閉じる事は出来ないので inest が中にあるとは考えにくい。
    %   (ただ、inest の境界などで何が起こるかは慎重に考えなければならない。)
    %
    %   まとめ: 編集領域の開始点と終了点でトップレベルならば中で始まった inest が外で閉じる事はない
    %   と思ったが、別に開始点はトップレベルでなくても関係ない。終了点でトップレベルならば関係ないのだ。
    %
    % 2 編集領域の終了点での inest が編集領域の開始点よりも前を指しているのならば、
    %   中で始まった nest が外で閉じる事はない。
    %
    %   というかつまり編集領域の終了点で inest が編集領域の内部を指していなければ OK という事である。
    %
    % 3 編集領域の終了点から順に見ていって、一度でも inest が編集領域よりも前を指したならば、
    %   それ以降に編集領域の内部を指す inest が現れる事はない。
    %
    % 3 は 1,2 の一般化になっているので 3 だけチェックすれば OK である。
    % もっと条件を課す事が出来ないかとも考えたが、長いネスト領域の開始点を編集した時に
    % 多少処理に時間が掛かるという事は不自然な事ではない。
    % 長さ(相対位置)を補正するのに時間が掛かっているのだなという事は想像できるだろう。
    %
    % 次に stat に格納されている wbegin について。基本的に wbegin についても同じである。
    % wbegin は通常 inest よりも更に下の構造である。つまり inest < wbegin の筈である。
    % この事が使えるかは分からない。
    % 少なくとも言える事は wbegin も inest と同じ様な判定方法ができるという事である。
    % ここで更に考えたいのは inest と wbegin を組み合わせてより効率的に中断をできないかという事。
    % もう少し考える inest < wbegin であるのならば、
    % wbegin < dbeg になった時には inest も wbegin も更新を中断して良い。
    % しかし inest < dbeg となった段階では未だ wbegin が dbeg より手前にあるかもしれない。
    % でも少なくとも word は同じネストレベルの中で構造は作らないはずだから、
    % 一旦 dend0 < wbegin となったならばそのネストレベルでは二度と wbegin が編集領域内に現れる事は無いだろう。
    % 但し、一つネストレベルを抜けた時にまた wbegin が編集領域内に現れる可能性はある。
    % 一つネストレベルを抜けた時にまた wbegin が現れない為の条件は何か?
    % これは何とも言えない。抜けたネストレベルの inest が編集領域内にある限りは
    % 常に wbegin が編集領域内に新しく現れる可能性を排除できない。
    % 逆に inest < dbeg なネストを抜けたら OK という事になる。
    %
    % wbegin も考慮に入れた時の中断の条件を更新する:
    %
    % 4 編集領域の終了点から順に見ていって始めに以下の条件を満たした時に中断できる
    %   inest < dbeg かつ ( wbeg < dbeg または dend0 < wbeg )
    %   この時に inest が再び編集領域内部に現れる事は無いし、
    %   また wbeg も編集領域内部に現れる事は無い
    %
    %   仮定: word は或るネストレベルの中で構造を作る事はない
    %     (これは現在の解析の仕組み上保証されている様に思うので特別に意識する必要はない)

    此処まで書いて気付いたが、上は編集領域内に inest や wbegin がない事の条件であって、
    inest や wbegin の相対位置を補正しなくても良い条件ではない。
    相対位置で記録した場合に inest や wbegin の補正が必要になるのは、
    編集領域の長さが変化し、かつ、inest や wbegin が編集領域よりも前を参照している場合である。

    一方で編集領域の長さが変化しなかった場合でも、
    word の invalidate が必要になるのでループを回す必要は残る。
    いっその事 word の invalidate は別のループで処理した方が良いのかも知れない。
    word の invalidate に関しては上記の方法でループを回すのを中断して問題ない。

    思うに、尻からで良いからネストの構造を掘り出す事ができる様なデータを記録するべきだという気がする。
    特に、直前のネスト構造ノードへの nest の offset を保持する様な。
    全ての点について一々ネストノードだとか stat だとかが設定されているかどうかをチェックするのは大変である。
    考えなければならないのはその様なデータ構造自身も shift の対象としなければならない事、
    それから文脈値 (stat) が同じになった時に解析の中断をしてデータ構造が壊れないかどうか考える事。

    少し考えてみる。その様な掘り出すのに必要なデータは何かというと…。
    先ず、途中から解析を再開できる様にする為にはその点よりも後の情報を含んでいる様なデータは保持できない。
    従って、必然的にノードはデータ構造の末尾に置く事になる。
    1 兄(末尾)のoffset 2 親(先頭)のoffset 3 末子(末尾)のoffset である。
    親の offset に関しては兄を辿っていけば早晩に辿り着くので記録しなくても良い。
    というか、親の offset は stat の inest に記録されているのでわざわざ此処で記録する必要はないし、
    そもそも親の末尾の offset さえ知っていれば問題なく、
    これは掘り出す過程で知っているはずなので各ノードのデータに含める事は考えない。

    更に良く考えてみたら自身の情報についても格納しなければならない。自身の先頭の offset も含める。
    データの内容について改める。
      data="${自身の先頭のoffset} ${兄(末尾)のoffset} ${末子(末尾)のoffset(子がなければ -1)}"

    [2015-08-11] 取り敢えず _ble_syntax_* に含まれるポインタを offset (長さ) で表現する様に書き換えた。

    [2015-08-13] _ble_syntax_tree (旧 _ble_syntax_word): 入れ子構造を記録する様に変更

    入れ子構造の情報を利用して shift を実行するコードを書いてみた。
    しかしそれ程高速化はしていないようである。もっと積極的に shift の skip を行うべきか?
    しかし、取り敢えずはこれで良いという事にする。

  * [2015-08-13] _ble_syntax_tree (旧 _ble_syntax_word): 入れ子構造を記録する様に変更 [#D0219]

    shift の際に入れ子構造を考慮に入れたスキップをする為に、
    入れ子構造を記録・構築する様に改良を行う。

    % 整理2015-08-12
    %
    % 改めて _ble_syntax_* の形式についてまとめる:
    %
    % | _ble_syntax_text    解析結果の対象の文字列を記録
    % | _ble_syntax_stat[]  文字 #i を解釈する直前の解析状態
    % |   ctx     現在の解析の文脈
    % |   wlen    現在のシェル単語の継続長さ
    % |   wtype   現在のシェル単語の種類
    % |   nlen    現在の入れ子段階の継続長さ
    % | _ble_syntax_nest[]  入れ子の情報
    % |   ctx     入れ子を抜けた時の復帰状態
    % |   wlen    同上
    % |   wtype   同上
    % |   nlen    同上
    % |   type    入れ子の種類を表す文字列
    % | _ble_syntax_word[]  境界 #(i+1) で終わる単語の情報を記録
    % |                     (つまり単語の最後の文字の位置に記録されると思えば良い)
    % |   wtype   シェル単語の種類
    % |   wlen    シェル単語の長さ
    % |
    % |   ※境界#(i+1) (または境界#i が word[i-1] に対応する) の様に1つずらして格納しているのは、
    % |     部分更新の際の配列の切り貼りを他の配列と同様に行える様にする為である。
    % |     基本的に配列の切り貼りは、添字 data[i] に対応している情報はその境界の右にある文字に附属していると見做して実施される。
    % |     従って単語の情報は単語を構成する最後の文字、つまり添字 i-1、に附属しなければならない。

    [計画]

    - 入れ子構造を利用して効率的に shift を実行するためには、
      入れ子構造の情報を残して置かなければならない。
      現状の実装では入れ子構造の情報の一部は _ble_syntax_nest 等に残存しているが、
      解析終了後に再び構造を調べるのに十分な情報は記録されていない。

    - 入れ子構造を構築するに当って、word に関する入れ子構造の管理は不要である。
      というのも、word が入れ子になっている場合には
      必ず nest を通して入れ子になっているはずだからである。

      ただし、word を効率的に列挙して処理を実行するためには
      "前のword" に対するポインタを word 情報に含めておくのが良い。
      →しかしそうすると prev_word ポインタについても
        shift を考えなければならないという面倒な事に…。

      nest に関しては自分の親、自分の兄、自分の末子に対するポインタを保持する。

    - どこにどの様な形式で情報を格納しておくかというのも考える必要がある。
      既存の _ble_syntax_* のどこかに入れ子構造を記録するという形にするという手と、
      新しく _ble_syntax_tree などの配列を作成してそこに記録するという二種類の方法がある。

      既存の _ble_syntax_* のどこかに記録するとしたら _ble_syntax_word が適切であろう。
      ちょうど _ble_syntax_word は解析の動作自体に影響は与えず「出力」としての効果を持つ。
      また、word と nest の入れ子構造を統合して統一的に記述できる可能性がある。
      この変更にあたって _ble_syntax_word の中身の形式を大幅に変更してしまっても良い。

      新しく _ble_syntax_tree などの配列を作成して管理する事にすると、
      x 切り貼りをしなければならない配列が増える。
        元々 sparse な配列なので無駄に切り貼りの作業を増やしても損した気分になる。
      x word/nest の両方について入れ子構造を辿るのも面倒かも。

      _ble_syntax_word を改造して形式を一新する方向で考える。
      まず、現在 _ble_syntax_word が使用されている箇所について確認を行う。
      - 単語の登録・shift
      - 色付け (syntax/update-word-table)
      - debug 用コード (print-status など)
      現在の形式は "wtype wlen" である。此処にどの様な情報を付加するべきか?
      - word と nest は同じ箇所で終了する可能性がある。
        したがって両方登録できる様にするべきである。
        同じ箇所で終了する場合、word の内部に nest があるという構造になっている。
      - word の親と nest の親は必然的に同じである。
      - word の親はなしまたは nest である。nest の親はなしまたは word である。
        word が word の親になっていたり nest が nest の親になっている事はない。

      a 案 "wtype wlen parent prev child ..." というのはどうだろうか。
        [[ $wtype == ^[0-9]+$ ]] の時に word でありそれ以外の時に nest である。
        child > 0 の時は末子はその offset の位置に存在する。
        child == 0 の時は末子は同じ位置で終了し ... に末子の情報が記録される。
        既に登録されている場合には "wtype wlen parent prev 0 既存内容" などとすれば良い。

        % ? 疑問点: 前回の解析までに存在していた内容を消去しなくても良いのか?
        %   前回の内容はいつ消去されるのだろうか。
        %   何処かで削除を実施しないと、前回の解析の結果が混ざってしまう。
        % - これは今迄の実装でも注意しなければならなかったはずだ。
        %   前回の解析で単語の終端だった部分が新しい解析で単語の途中になった場合、
        %   前回の解析で生成された単語が消去される機会が失われてしまう。
        % →前回の解析で存在していた内容を気にする必要はない。
        %   これらは配列の切り貼りの時点で削除され _tail_syntax_word に移動される。
        %   途中で解析状態が同一になった時にのみ _tail_syntax_word から再度コピーされる。
        %   つまり、解析する時には _ble_syntax_word は空文字列になっているので
        %   前回の内容の残存については気にしなくて良い。

        この方法ならば同じ位置で複数のレベルの word が終端する場合にも対応できる。
        今現在ではそのような単語の区切り方は存在し得ないが、柔軟な構造にしておいた方が見通しが良いだろう。

        ? nest-push の type として [0-9]+ の様な物が存在していると word と区別が付かない。
          そのような物が存在していないことを確認する必要がある。
          → grc --exclude=out nest-push で確認した。その様なものは今のところない。OK

    [実装]

    上記 a 案で行くことにする。

    1 先ず初めに word に登録する関数を準備する。これで word を登録する様に変更する。動作を確認する。
    2 word に別の情報も登録できる様に word 読み取り部分の変更を行う
    3 nest 情報も pop 時に登録する様に変更する。print-status の改良

    4 兄情報・子情報も登録する。入れ子になっている部分も shift する

    > (a) 兄情報・子情報をその場で計算して登録するという可能性?
    >
    >   兄情報・子情報も登録するためには stat に兄情報・子情報を記録する必要がある?
    >   もし兄情報・子情報をその場で計算して求めることができるのであれば、
    >   わざわざ現在の解析状態に含める必要はないのではないかということ。
    >
    >   ? stat に記録を行わなくても _ble_syntax_word, _ble_syntax_nest 等を用いて
    >     兄情報・子情報を構築することは可能だろうか?
    >
    >     兄は max { 終端 | 親の開始位置 < 終端 <= 自身の開始位置 } の筈である。
    >     また、子は max { 終端 | 自身の開始位置 <= 終端 <= 自身の終端位置 } の筈である。
    >     親の開始位置は、
    >       wbegin が設定されている場合は wbegin が、
    >       inest が設定されている場合は inest が、
    >       それ以外ならば初期位置 0 が該当する。
    >     自身の開始位置・終端位置は知っている。
    >
    >     これらの情報を用いれば兄情報・子情報を必要になった時に構築する事は可能である。
    >
    >   ? 解析時は兄情報・子情報はローカル変数に保持しながら解析して、
    >     ただし、stat から復元する時には兄情報・子情報を再構築するという方法はどうか?
    >     nest-pop の際にも同様に構築する必要が生じるのでは?
    >     これだとコストがかかってしまうので、nest-push の際にまとめて兄情報・子情報も push して良い。
    >     しかし、その様にするのであれば stat にも同様に保存してしまえば良いのではという事になる。
    >     但し面倒なのは、兄情報・子情報を stat/nest に記録する様にしてしまうと、
    >     兄情報・子情報に対する shift も実装しなければならないという事である。
    >
    >   取り敢えずの方針としては、shift の実装が面倒なので兄情報・子情報は stat/nest には含めない。
    >   代わりに word に登録する際に毎回自分で兄情報・子情報を計算する、という事にする。
    >
    >   問題点
    >
    >   ? 兄情報・子情報は shift だけで良いのか?
    >     stat に登録していない為に兄情報・子情報がずれていても
    >     解析状態が同じになったと判定されてしまう可能性がある。
    >
    >     →削除された領域にあるノードを参照している stat は削除すればよい。
    >       stat で現在参照しているのは wbegin, inest である。
    >
    >     % 但しチェックする範囲が広がるのが難点かも知れない。
    >     % →stat に兄情報・子情報を記録する場合でも stat の更新範囲が広くなるので
    >     %   結局どのようにしても同程度チェックする範囲が広がる。気にしなくて良い。
    >
    >     →削除された領域にあるノードを参照している弟ノードはどうするのか?
    >       それも削除すると更にその弟も再構築の対象になり…を繰り返して結局すべて解析し直す事になる?
    >       更に、削除された領域にあるノードでなくても、
    >       解析状態が一致しないことによって再解析が行われて失われる word も存在している。
    >       それらを兄情報・子情報として参照しているノードはどの様に取り扱うべきか。
    >
    >     結局 _ble_syntax_* に記録された昔の情報を参照して構築する方式だと、
    >     部分更新した際に不整合が生じてしまう。
    >     昔の情報を参照して構築した部分をすべて再計算しなければならなくなるが、
    >     どの部分がどの部分の昔の情報まで使って構築したかの情報がないので、
    >     すべて再計算しなければならなくなる。
    >     (一応各ノードを調べれば再計算が必要かどうかを得ることができるが、
    >     いずれにしてもすべてのノードについてそのチェックを実行しなければならない。)
    >
    >     因みに _ble_syntax_nest に関しては過去の情報を使用して解析が実行されるが、
    >     解析状態一致の確認の際にはちゃんと _ble_syntax_nest の一致まで確認されている。
    >
    > (b) 兄情報・子情報に対応する情報も stat に含めて計算を実行する
    >
    >   word/nest が混合しているのでどの様に取り扱うかが微妙である。
    >   兄にしろ子にしろ (ある条件を満たすノードで) 最後に登録したノードへのポインタになる。
    >
    >   何れにしても wbegin/inest 設置の瞬間に兄・子の情報も更新する必要があるような気がする。
    >   inest 設置の瞬間の処理については nest-push で行えば良い。
    >   wbegin 設置については新しく wbegin 設置用の関数を置くことにするか?
    >   先ず初めに wbegin 設置位置について確認を行う。
    >   →主に3箇所の wbegin 設置箇所があったので新しく関数を用意してそれに置き換えた。
    >
    >   更に解析状態を表す tprev, tchild という変数を追加した。
    >   tchild は現在の level で一番最後に設置された節の位置を表す。
    >   tprev は一つ上の level で一番最後に設置された節の位置を表す。
    >   child/prev というのは現在の節からの視点であって、
    >   現在の位置に新しく設置する節からの視点ではないことに注意する。
    >
    >   ? stat に tprev/tchild を記録する必要は実はないのではないか?
    >     というのも解析再開時に状態を復元する際は、
    >     過去のデータ配列の内容を参照して良いはずだから、
    >     わざわざ記録しなくても計算で tprev/tchild を再構築できるからである。
    >
    >     →やはり記録する必要はある。stat には2つの役割がある。
    >       一つは解析再開時に解析途中の状態を復元する役割であり、
    >       もう一つは解析状態が一致したかどうかを判定して、
    >       解析を中断するための参照状態となる役割である。
    >
    >     前者の役割を果たす為には tprev/tchild は再構築できるので不要であるが、
    >     後者の役割を果たす為には参照用の tprev/tchild を保持している必要がある。
    >     (後者の場合でも、一応 "古いデータ配列を全て覚えておいて、かつ解析状態の比較の際に
    >     毎回古いデータ配列から tprev/tchild を再構築して一致するか確かめる" という力技もあるが、
    >     それはさすがに遅くなるのでやはり記録をする。)
    >
    >     結論: stat に tprev/tchild も記録する。
    >
    >   ? nest に tchild を記録する必要は実はないのでは?
    >     nest は pop した時に状態を復元するためにある。
    >     ところで pop した時に新しい節が作成されて tchild は上書きされて消える。
    >     どうせ直後に上書きされて消えるのであれば記録する意味は無いのでは?
    >
    >     解析状態の一致の際にもチェックする必要はないように思われる。
    >     というのも結局使われない情報であるため、
    >     もしチェックをせずに違いを看過したとしても最終的な結果には何の違いも出ないからである。
    >
    >     % また記録するとその分また shift のコストが上がるという事を意味する。
    >     % 取り敢えず nest には tchild を記録しない方針で行くことにする。
    >
    >     実は nest の tchild は必要のようだ。
    >     nest の下に word を構築する際、word に入って word から抜けた時に tprev を復元しなければならない。
    >     それが実は nest-push した時の tchild に対応している。
    >
    >   ? word-pop 後の tprev について現在のデータ形式で自然に再構築できるか?
    >
    >     word-pop 後は nest の level (または top level) に必ずいる。
    >     というのも word の下に word は直接来ないからである。
    >     word-pop 後の tprev は何を意味するかというと、現在の nest-level の前の nest-level である。
    >     これは nest-push する直前の tchild を意味する。
    >
    > 取り敢えず (a) で実装したが (b) に方針転換する事にする。

    4.1 word-pop の際の tprev の再構築?
    4.2 ble_syntax_stat の形式変更
    4.3 check
    4.4 新しく追加した項目の shift

    > shift は再度整理して書き直す事にする。
    >
    >   不可解な実装になっている部分についても再考察を行う。
    >
    >   ? stat 無効化に於いて wbegin/inest の判定範囲が
    >     更新領域 beg-end0 ではなく再計算領域 i1-j2 になっているが、
    >     無効化は更新領域に被る時にだけ行えば問題ないのでは?
    >
    >     或いは実は原則を破っている箇所があった為にこの様になっていた?
    >     例えば var[]= の部分に関しては、元々原則を破った実装になっていた。
    >     (現在は、この部分に関しては保留中である。
    >     最終的には word 着色で var[] としての着色を上書きしてしまうなどすれば良い。)
    >
    >   ? stat の shift に於ける無効化チェックは必要なのだろうか?
    >
    >     原則さえ守っていれば stat/nest の解析状態チェックだけでOKなのでは?
    >
    >     元々この様にした理由は、無効化がないと不正確な stat が残ってしまうという事である。
    >     % この不正確な stat の状態で解析を続行しても続きのデータを再現できない可能性がある。
    >     % つまり、この事により予期しない解析中断が生じる可能性がある。従って無効化は必要である。
    >
    >     →本当だろうか? 不正確な stat (その様な stat が生成される機会はなかった) としても
    >     stat が一致している以上は後続のデータも全く同様の物が生成されるのではないだろうか?
    >     つまり、stat を無効化するかどうかの判定は「前回の解析の shift だけで同じ stat が生成されるかどうか」
    >     ではなく、もっと許容的な「後続のデータを再現することができる stat」という条件にするべきという事である。
    >
    >     逆に stat が壊れた状態になったとしても、
    >     後続のデータと整合する様に修正する事ができれば無効化する必要はないという事になる。
    >     stat の wbegin/inest が指し示している部分が消滅した時の wbegin の変更の仕方を一つ決めればよい。

    5 check: チェックの為に print-status に構文木の結果を表示する。

    5.1 未だ終端していない入れ子構造についても正しく処理する必要がある。

    > 例えば shift を計算する範囲を決定する際に愁嘆していない入れ子構造の部分を跳ばす事はできない。
    > 終端していない入れ子構造についてどの様に処理を実行するべきかは、print-status の実装で試せばよい。
    > 他の shift 等に対しても同様の処理を実行する際には print-status の実装を真似すれば良い。
    >
    > 一つの方法は無理矢理終端させた時のデータ配列を作成して、
    > その配列に対して処理を実行する方法である。
    > この様にすればデータ配列の形式に従ってそのまま処理を実行する事が出来る。
    > 終端していない節と終端した節 (データ配列に格納された節) が混合したままだと、
    > それに対する処理を上手に書くのが面倒なように思われる。
    >
    > 何れにしても print-status の実装を終端していない節に対応する過程で再考察を行う。
    >
    > 何だか良く分からなくなったので、結局終端していない入れ子構造についての情報を変数 tree に集計した後で、
    > ("${_ble_syntax_tree[@]}" "$tree") に対して処理を実行するという形にする事にした。
    > 関数 ble-syntax/tree-enumerate proc, ble-syntax/tree-enumerate-children proc を使う。
    > proc には各節を処理する関数名を指定する。
    > これを用いて print-status も実装した。多分動作している。

2015-08-11

  * _ble_syntax_* の単語・入れ子開始位置の記録方法を変更 (絶対位置 wbegin → 相対位置 wlen) [#D0218]
    記録点からの負のoffset(単語長・入れ子継続長)で指定する事にした。

    % 整理2015-08-11
    %
    % 何やらよく分からなくなってきたので改めて現在の状況についてまとめることにする。
    % まず、現在の _ble_syntax_* のデータは以下のような形式になっている。
    %
    % _ble_syntax_text    解析結果の対象の文字列を記録
    % _ble_syntax_stat[]  文字 #i を解釈する直前の解析状態
    %   ctx     現在の解析の文脈
    %   wbegin* 現在のシェル単語の開始位置
    %   wtype   現在のシェル単語の種類
    %   inest*  現在の入れ子の開始点
    % _ble_syntax_nest[]  入れ子の情報
    %   ctx     入れ子を抜けた時の復帰状態
    %   wbegin* 同上
    %   wtype   同上
    %   inest*  同上
    %   type    入れ子の種類を表す文字列
    % _ble_syntax_word[]  境界 #(i+1) で終わる単語の情報を記録
    %                     (つまり単語の最後の文字の位置に記録されると思えば良い)
    %   wtype   シェル単語の種類
    %   wbegin* シェル単語の開始位置
    %
    %   ※境界#(i+1) (または境界#i が word[i-1] に対応する) の様に1つずらして格納しているのは、
    %     部分更新の際の配列の切り貼りを他の配列と同様に行える様にする為である。
    %     基本的に配列の切り貼りは、添字 data[i] に対応している情報はその境界の右にある文字に附属していると見做して実施される。
    %     従って単語の情報は単語を構成する最後の文字、つまり添字 i-1、に附属しなければならない。
    %
    % shift の対象となるのは * で示した項目である。
    % 現在、内部構造を表現する情報に nest と word の2種類がある。
    %
    % A word&nest を統合する可能性について:
    %
    %   word と nest を別々に管理していることによって、
    %   shift 対象の管理がより面倒になっている様に思われる。
    %   nest は解析のために必要な入れ子の情報であり、
    %   word は解析には必要がないが解析の結果として呼び出し元に提供する情報である。
    %   どちらも似た様な入れ子構造を構築することには変わりないが使い方が多少異なる。
    %
    %   x どちらも同じ位置で二段階の入れ子を作ったり抜けたりする事はない、
    %     という前提で実装されている気がする。
    %     統合するとしたらこの前提が成立しなくなるので注意する必要がある。
    %     例えば echo $(command),$(command) となっている場合、
    %     echo の第一引数の単語は、開始点で2段階の入れ子を作成し、
    %     また、最終点で2段階の入れ子を抜ける事になっている。
    %     (ところで、単語と解析の入れ子が交錯する様な事態は起こらないので、
    %     多段階の入れ子作成・解除にさえ対応すればそれで問題はなくなる。)
    %
    %   x word/nest は微妙に異なる構造の構築になっている気がする。
    %     word は word の終了時にその性質が決定され、末端に情報を格納する。
    %     word が開始した時点では word 情報は確定していないので、
    %     配列には記録せずにむしろ解析状態 stat に現在の word を直接記録している。
    %     一方で nest は入れ子が開始した時点で、
    %     それがどの様な入れ子なのかが確定するので、開始点に全ての情報を格納できる。
    %
    %   x 何より完全に解析部分を再実装することになりそうなので統合したくない。
    %     現在の実装では、解析の制御に最低限必要な部分を nest に格納している形になっていて、
    %     解析の制御に関係のない word の部分は分離している、という体である。
    %     Shift 時の複雑さには目を瞑ってこのままで良い気がする。
    %
    %   →上記の色々な理由から word&nest の統合は取りあえず断念する
    %
    % shift 時は単純に該当する項目の補正を行うだけではなく、
    % 無効になった word, nest を参照している stat を削除するという事もする。
    %
    % B 単語の開始位置を offset で管理している場合:
    %
    %   単語が完全に更新領域の外側にある時は書き換えの必要性はない。
    %   単語の開始点が更新領域に含まれている場合、
    %     単語は消滅する。この単語を参照している stat (解析状態) も同時に削除しなければならない。
    %     削除しておかないと、再解析の結果として偶々同じ stat になった時に解析が停止してしまう。
    %     # 或いは、解析が停止するのならばそれで良いのではないだろうか?
    %     # 全く同じ状態になったのであれば以後の計算をしても同じ結果になるはず。
    %     # もし同じ結果にならないのであれば shift/状態復元 に失敗しているという事だから、
    %     # そちらを修正するべきということである。
    %     # これは shift を正しく実行できないのだとしたら削除するべきということでもある。
    %     # 今、単語の開始位置の表現を変更した為に、前と状況が変わっているかもしれない。
    %     # この辺りの stat を削除するかしないかについては再度慎重に検討するべきである。
    %     この単語を参照している nest は、使用されることがないので放置で良い。
    %     何故ならば解析再開点は nest が記録された位置よりも前になり、
    %     また…(本当か???)
    %   単語の内部に更新領域が含まれている場合
    %     その単語の長さの修正を行う。
    %   単語の終端だけが更新領域に含まれている場合
    %     単語は word には記録されていない。
    %     stat にある相対位置だけ修正を行えば問題ない。
    %
    %   →考えるのが面倒になったので実際に実装してしまう事にした。意外と簡単に済んだ。
    %     _ble_syntax_{stat,word,nest} に対して内容の形式を変更した。
    %     先ず単語の終端が更新領域よりも後にある場合にしか単語の shift は必要ない。
    %     (というのも、単語の終端が更新領域よりも前にある場合は勿論 shift は不要だし、
    %     単語の終端が更新領域の内部にある場合は単語自体が無効になるからである。)
    %     そして更に単語の長さが変更になるのは単語の開始が更新領域よりも前にある場合である。
    %     (というのも、単語の開始が更新領域の内部にある場合には単語自体が消滅するからである。)

  * <bug> 履歴が正しく初期化されない [#D0217]

    何かコマンドを実行した後に history-prev を実行すると、
    直前に実行されたコマンドが表示されず、少し昔のコマンドが表示される。
    幾つか遡っていくと直前に実行されたコマンドが表示される。

    history で表示されるコマンドは正しいコマンド順になっている。
    また、遡っていって直前に実行されたコマンドに行き着けば、
    それより前は正しいコマンド順になっている様である。
    余分コマンド (直前に実行したコマンドと履歴リストの末端の間にあるコマンド)
    に対応した抜けがある訳でもなく、余分コマンドと同じコマンドが幾つか繰り返している。
    どうやらコマンド順が変になっているのではなくて、
    履歴のリストの末端に余分にコマンドが追加されているという事のようだ。

    どうやら .bash_history に空行があると駄目な様だ。
    .bash_history の空行は初期化の際に読み取られないので行番号がずれる。
    行番号がずれていると history -n で追加読み取りした部分がずれる。
    →.bash_history の空行を削除したら問題は発生しなくなった。

    と思ったが、それでも ble.sh を起動してからコマンドが追加されたりして、
    その後で初めて履歴を使う、という事をするとまた履歴が末尾に追加されて分かりにくい。

    % 無条件で履歴を読み取るのではなくて、履歴エントリが空の時にだけ読み取る様に変更するべきでは?
    % →履歴エントリが空の時にだけ読み取る様にすると、
    %   一回でもコマンドを実行すると過去の履歴が辿れなくなる。
    %   履歴の初期化をせずにコマンドを実行したときの履歴の処理はどうしているのか。

    再度履歴情報の取り扱いについて整理する:

      履歴情報は2段階ある。shell が持っている history 情報と、
      ble で取り扱えるようにシェル変数に格納した履歴情報である。
      ble の履歴情報の初期化には時間がかかるのでできるだけ遅延したい。
      bashrc 処理時には shell の history にまだ履歴が読み込まれていない。
      bashrc の処理が終了して対話状態になった時には shell の history は初期化されている。
      しかし、ble の履歴情報はまだ初期化されていない状態である。
      ble でコマンドを実行したときには shell の history に情報を追加する。
      ble の history 情報が既に初期化されていればそちらの更新も行う。

    結局、shell の history が空の時にだけ読み取る様に変更することにした。

2015-08-09

  * complete: <bug> リダイレクトのファイル名でファイル名補完が効かない。 [#D0216]
    →対応した。
  * complete: <bug> .# で始まるファイルを扱うために .\# などとして tab をしても補完が効かない。 [#D0215]
    →再現しない。再度改めて試してみたが、補完は問題なく動いている様である。

  * complete に関連する過去の修正 [#D0214]
    - 変数= の補間でファイル名を取り扱える様にする
    - > の直後のファイル名の補間が働かないのを修正
    - (command) ディレクトリ名の直後に / を挿入する

2015-04-25
  * complete: 補間挿入: 既に直後に '/' または ' ' がある場合にはこれらの文字を挿入せずに次に文字を進める。 [#D0213]
  * complete: option hoge=, hoge: の続きにファイル名を指定できる様にする [#D0212]

2015-03-22

  * ble-decode.sh: bugfix, bash-4.1 でも ESC * に登録しないと駄目 [#D0211]

    一回でも ESC z 等を bind -x で登録して解除すれば OK になる。
    しかし、一回も bind -x をしていない状態だと
    ESC 単体で登録しても何も起こらない。
    どの bash の version でも ESC * に対して張る事にする。

    今度は ESC [ を捕まえられなくなった。
    bash_execute_unix_command: cannot find keymap for command のエラーになる。
    bash-4.3 と同じ症状である。結局 bash-4.3 と同様に ESC [ を変換する事にする。

2015-03-11

  * ble-syntax.sh: <bug> 単語の先頭に空白を挿入すると空白が単語の一部とされる [#D0210]

    % 単語の先頭に文字列を挿入した時に単語情報 _ble_syntax_word が更新されない。
    % 結果として単語の先頭位置が更新されず、空白も単語の一部と解釈される。
    %
    % 本来であれば wbegin の位置が変化しているのだから _ble_syntax_stat が一致せず、
    % 単語の終端まで行って漸く _ble_syntax_stat が一致する筈である。
    % 単語の終端まで行くのであるから word の情報も再設定されるはずという算段である。

    これは単に単語の shift が実行されていない事が原因であった。
    元々は、単語の登録は必ず stat の設定を行った箇所でしか起こらないと決めていた。
    従って shift 判定の時は stat に値が設定されている時にだけ単語の shift の確認を行っていた。
    所が、shift の判定を stat に値が設定されているかどうかに拘わらず実行する様にしたら、問題が発生しなくなった。
    これはつまり stat の設定が行われた箇所とは異なる場所で word が設定されているという事を意味する。

    - よく考えてみれば for の直後などでも空白を飛ばしているので for に対する word の箇所では stat が起きない。
      つまり、この場合にも stat が設定されている事を前提とした word の shift は動かない事になる。
      と思ったが改めてみてみると for の直後には stat が設定されている。
      改めて考えてみれば for の直後の状態は CTX_CMDXF で表現する様に変更したのであった。

    - 問題の発生していた例 "echo hello" の場合には word の位置に必ず stat が設定される様に思ったが、
      これで問題が起きていたという事は echo の終端位置に stat が設定されていないという事を意味する。
      実際に echo hello を解析した後に stat の内容を吐き出してみたが、stat が設定されているのは、
      (echo の直前、hello の直前、終端) の三箇所だけになっている。
      改めて ctx-command/check-wrod-end を見てみると、
      関数定義に対応した時にコマンドの後の空白を読みとばす様に変更したのであった。

  * <bug> i-word[1]: substring expression < 0 [#D0209]

    time : $(echo | echo | echo) を time : $(: | : | :) に書き換えている最中に
    bash-4.0: i-word[1]: substring expression < 0 というエラーが出た。
    bash-4.0 と bash-4.1 で再現したが、再度起こそうとしても起きない。
    起きる条件が良く分からない。

    エラーメッセージに現れる式は ble-syntax.sh の
    ble-highlight-layer:syntax/update-word-table
    にしか現れない式である。wbegin の shift に失敗しているのだろうか。

    再び起こった。今度はもう少し違ったパターンだが共通点はある。
    $() の中で | の直後の単語の一部を削除している時に起こったというのが共通点である。
    しかし似たような編集を再度実行しても問題が再現しないようである点も同様である。

    多少 shift の部分に手を加えた。これで解決したかは分からない。

    追記:

    "単語の先頭に空白を挿入した時に空白が単語の一部になる" バグの修正の際に、
    word は必ずしも stat の設定された場所だけに設定される訳ではない、
    という事が判明しそれに対する修正を行った。
    この修正の前は shift するべきなのに shift されていない単語があった事になる。
    この substring expression < 0 の問題もこれに関連していた可能性が高い。
    再度 $() 等を入力して色々してみても問題は再現しないようなので、
    取り敢えずこの bug に関しても解決したと解釈する事にする。
    実際には解決されていないとしても、再び問題が発生した時に考える事にする。

2015-03-08

  * cygwin 上で prompt の色がついていない。 [#D0208]

    _ble_line_prompt の内容を覗いてみると、
    何と ps1out に CSI 99s や CSI 99u が残っている。
    また、\e[32m も本来ならば \e[0;32m 等に翻訳されている筈なのにそれがない。
    要するに ps1esc がそのまま出力されている様に見える。
    出力幅が22桁余分である事から CSI sequence を認識していない様に思われる。
    先頭の CSI の部分だけ無視して残りを普通に出力している。

    試しに以下を cygwin 上で実行してみた所、失敗する。(linux の上では成功する。)
    rex_csi=$'^\e\\[[ -?]*[@-~]' && [[ $'\e[99s' =~ $rex_csi ]] && echo hello
    何故だろう。locale の問題かも知れない。と思って LANG=C としたら成功した…。
    更にプロンプトにも色が着くようになった…。

    然し、LANG=C にしていると今度は日本語があった場合の動作が怪しいのではという気がする。
    →実際に日本語を入力してみると大変な事になる。なので一時的にだけ LANG=C にしたい。
    実装した。テストは未だしていない。→テストした動くようになった。

  * <bug> bash-4.1 以下でカーソルの表示位置がずれている。 [#D0207]
    現在のカーソル位置の追跡自体は誤っていない様に思われる。
    という事は、移動先の cx cy の算出を誤っているという事か?

    bash-4.1, 4.0, 3.2 で起きる。bash-3.0, 3.1, 4.2, 4.3 では起きない。
    調べてみると getxy.cur の返す値が変である。
    変な値を返している時に _ble_line_text_cache_pos の中身を確認したが問題ない。
    と思ったら ((_eoc[2]&&(_pos[0]=0,_pos[1]++))) が駄目であった。
    bash のバグで条件分岐内で配列要素を参照できないのであった
    (参照するとその branch が必ず実行される)。

  * <bug> bash-4.2, 4.0, 3.2, 不完全な編集内容に対してエラーが出る。 [#D0206]

    i=${ で駄目。
    bash-4.3 では起きない。bash-4.1 でも何故か起きない?

    どうも正規表現が正しく動いていない様な気がする。
    →これは正規表現中の "'" を無駄に多く escape していたのが原因であった。
    '[^']*' で済む所を \'[^\']*\' としていた事による。
    然し \' になっていた時の解釈が謎である。例えば以下が一致する。

    rex="^([^\$]|\\'[^\\']*\\')+\$" && [[ 'i$' =~ $rex ]] && echo hello

    上で 'i$' を '$' にすると一致しない(正常)。
    上をこれ以上単純化する事は出来なかった。

    何だか良く分からないが \' を ' に修正したら問題は起きなくなったのでこれで解決とする。

  * <bug> bash-4.0, 4.1 でプロンプトが表示されない [#D0205]
    これは declare DRAW_BUFF としただけの時に、
    ${#DRAW_BUFF[*]} が 1 になっている事が原因であった。

  * <bug> bash-4.1 以下でプロンプトの色が着かない。。 [#D0204]
    何と、_ret="${specs[++i]%%:*}" を実行すると i が 2 増える…。
    つまり配列の添字を複数回評価しているという事になる。

    色々試してみた。
    i=1; _ret="${a[++i]%%:*}"
    - a が配列でない場合には起こらない。
    - %%:* がない場合には起こらない。
    - %%:* の代わりに #a 等でも起こる。${a{++i]#a} では起こらない。

2015-03-07

  * ble-decode.sh: CSI Function Key Sequence を特別扱いする? (2015-02-28) [#D0203]

    現在の登録作業は些か無駄な事をしている様な気がする。
    ble-bind の出力も exaustive になっているし、
    テーブルも巨大な物になっていて declare や set の時に見苦しい。

    - .ble-decode-char 再実装した。
    - それに伴って .ble-decode-char/csi/* も追加し、
      CSI シーケンスを特別に読み取る様に変更した。
    - また、cmap/default.sh も大幅に変更した。
    - 修飾の機能は sendkey の方で一括で行う様に変更する。
      C-x @ S 等に対して ESC と同様の修飾の機能を与える。

2015-03-06

  * ToDoの整理 [#D0202]

    > 2015-02-17
    > * for 等の末端が赤くならない
    >   →コマンドとしての着色によってエラー色が上書きされていた。
    >   着色の "レイヤー" に対応できる様にしたい。その後で再度考える。

    これは改めて確認してみた所、赤くなっている。
    単語の色付けよりも後にエラーの着色を行っている為であろう。
    エラーに関しては又後で仕組みを整えるつもりであるが、
    特にこの問題に関しては解決済という事にする。

    > 2013-06-10
    > * <lbug> complete: ~ で始まるパス名の場合、
    >   ディレクトリ名の末端に / を追加したり、
    >   ファイル名の末端に SP を追加したりする機能が機能しない。
    >   これは test -e "$hoge" としてファイル名がどうかを判定している時に、
    >   hoge の中に含まれている ~ が展開されない為である。
    >   同様に ~user で始まる形式のパスについても期待通りに働かない。

    これは新しい complete の仕組みの元では問題なく動作している。
    単語を eval で評価してから候補を生成している事により見た目の表現には関係なく動作する。

  * overwrite-mode に対応 [#D0201]

    | 2013-06-06
    | * overwrite mode
    |   + 開始時は insert
    |   + self-insert, delete-backward-char で対応するだけで OK
    |   + 現在のカーソル位置を反転して表示する

    ble-edit+overwrite-mode 実装、self-insert, delete-backward-char の対応。テスト。
    test (overwrite-mode): OK, accept-line 後のリセットOK
    test (self-insert): 半角を半角で上書き、全角を半角で上書き、半角を全角で上書き、全角で全角を上書き。
    test (self-insert): 行末での半角挿入、行末での全角挿入、改行の挿入
    test (delete-backward-char): 編集文字列終端での削除、文字列中途での削除、行末での削除、行頭での削除

    TAB や改行が関係する場合の emacs の動作について調べる。
    - 改行とタブを挿入する場合は次にある文字を削除する事はしない様だ
    - 改行を上書きする事は無い。タブを上書きする時はタブの終端に達する場合にはタブを削除する。
      終端に達しない場合にはタブをそのまま保持する。
      面倒なので ble では取り敢えずはタブを常に保持する事にする。

    →xterm の場合は元からカーソル位置を反転して表示する様になっている。
      この状態でカーソル位置の属性を反転させると二重に反転して、カーソルが見えなくなってしまう。
      カーソル位置の別の表現方法を考える必要がある。
      或いはカーソルの大きさを制御するシーケンスを出す? カーソルを隠すシーケンスを出しても良い。
      $'\e[?25l' $'\e[?25h' を発射してカーソルを隠す。

    カーソルの反転は layer で行うか、それとも描画部分に対して完全にハードコードするか。
    ハードコードする前回書き込んだカーソル位置の情報を再び回復しなければならない。
    別に layer として実装した時と比べて実装が楽になる訳でも無い様に思われる。
    layer として実装した。無駄に複雑になったように思うが取り敢えずテスト。
    - insert を toggle しても即座に反映されてない
      →これは .ble-line-draw.update の更新判定に登録するのを忘れていただけ。
    - 前の文字の反転が解除されない
      前回の buffer の内容を流用しているのが行けないのかと思ったが、
      どうやら PREV_UMIN PREV_UMAX の方の問題の様である。
      とも思ったがそうでもない。どうも変な動きをすると思ったら、
      そもそも上のレイヤーでの更新に失敗している様だ。/update/getg を弄った事が原因だろうか。
      確認してみると ble-highlight-layer:syntax/update で
      ble-highlight-layer/update/getg を呼び出すべき所で、
      ble-highlight-layer/getg を呼び出していた。つまり layer:syntax 側でのバグであった。

      ble-highlight-layer/update/getg を呼び出す様に変更してみた物の、それでも何か変だ。
      良く考えたら /update/getg でも駄目だ。自分自身を含めないと行けない。
      ble-highlight-layer:syntax/getg を呼び出して空だったら ble-highlight-layer/update/getg を呼び出す様に変更した。
    - bugfix: PREV_UMAX の計算
      insert mode の時に途中を編集するとカーソルの位置が狂う。
      C-u を押した時のカーソルの位置が変。
      C-u 等、overwrite と関係なく見える物でも起こっているので、別の箇所のバグかと思いきや、
      layer:overwrite_mode を外すと上記の現象は起こらなくなる。
      色々試した結果 oindex の shift を間違っている所為で PREV_UMAX が変に大きな値になり、
      その所為で座標位置が 0 0 にあると勘違いされてずれるという事が分かった。

2015-03-05

  * ble-edit.sh (ble-edit/draw/trace): 描画属性も詳しく。 [#D0200]

    描画属性の追跡も実装した。
    これに伴って、プロンプトの最後の文字の属性も(限定的ではあるが)取得できる様になった。

    | 2015-02-23
    | * bleopt_suppress_bash_output 制限
    |   - プロンプト最後の文字の SGR が消える。これに対応するにはプロンプト中の SGR を解析しなければならず大変。

    完璧な対応という訳ではないが、これで上の問題は解決された。

2015-03-04

  * 修正: 環境での行末での動作 [#D0199]

    編集の行が減った時に削除される行が間違っている気がする。
    長い行を編集してその行が短くなった時の動作に問題がある。
    というか行が減った後のカーソルの表示位置が変だ。
    内部的なカーソルの位置(挿入位置)は正しいようだ。

    どうも丁度ぴったり columns に収まる時の座標計算の問題?
    →カーソルを動かしてみると座標計算自体は問題ないようだ。
    やはり前の行の最後の位置にいるにも拘わらず次の行の先頭にいると勘違いしている様に見える。
    問題は何故前の行の最後の位置に移動してしまうのかという事である。

    % 分かったような気がする。座標計算と部分更新に問題がある。問題点は結構複雑な気がする。
    % 現在、update-positions で計算されるのは「次の文字が表示される位置」という事になっている。
    % これは指定した位置へカーソルを移動させるのに使う。カーソルの移動先は、
    % そこに存在する文字の先頭にあるべきである。
    %
    % 一方で、部分更新をした後にカーソルが存在している位置、というのは xenl cap のある端末では
    % 実は次の文字が表示される位置とは異なっている。
    % 行末の文字を出力した時にカーソルはその行の末端に留まっている。
    % 所が、update-position に格納されているのは、次の文字の開始位置である次の行の先頭である。
    % この時に勘違いが起こる。これを解決するには update-positions に格納されている情報の意味を考え直すか、
    % 或いは、update-position とは独立に文字を出力し終わった後の位置の情報も管理するという事である。
    % 後者は余り考えたくない。殆どの場合で文字出力後の位置と次の文字の開始位置は同じである。
    %
    % どの様な場合にずれが生じるかというと、
    % 1 行末=次の行頭
    % 2 行末近くに wide 文字が存在して入りきらずに次の行へ送られている場合
    %   現在の計算だと次の表へ送られる場合は先頭に行末を埋める padding をつける事になっている。
    %   例えば " あ" 等としている。この時カーソルの位置は "あ" の位置ではなく行末の空白の位置になっている。
    %   これはどちらに表示するべきか改めて考えた方が良いかも知れない。この状態で例えば "a" 等と入力すると
    %   行末に文字が挿入される事になる。カーソルは依然として "あ" の位置ではなくて行末にあるべきなのかもしれない。
    %   しかしながら、例えば↑キーで更に次の行の行頭から移動してきた時に、カーソルが二つ上の行の行末に来るのは変である。
    %   そういう意味から言うとあの先頭にやはり文字を置くべきなのかも知れない。
    %
    % 少なくとも三種類の位置が存在する
    % - 部分更新出力後の位置:
    %   これは部分更新をした後の座標計算に必要である。
    % - 部分更新開始の位置:
    %   これはカーソルの表示位置とは異なる。例えば行末の " あ" の場合には、
    %   カーソルの表示位置は "あ" の直前に来るが、
    %   部分更新の開始位置は " " の直前になければならない。
    %   しかし出力後の位置とも限らない。例えば出力後に行末にカーソルがある場合、
    %   そこから部分更新の出力を開始しようと思っても、そもそも其処にカーソルを移動させる手段がない。
    %   (xenl の厄介な所は文字を出力した時にだけ行末にカーソルが来る可能性があるという所である。)
    %   そこ場合は移動先を次の行頭に変更しなければならない。
    % - カーソルの表示位置:
    %   これは次に来る文字が何かに依存する。
    %   positions の部分更新なども考えるとこれは記録せず、出力後の位置から計算する方が良い。
    %   例えば次に改行が来るのであれば行末だし(でも行末にカーソルを移動させる方法はない■)、
    %   それ以外の文字が来るのであれば次の行頭である。
    %
    % どの箇所で getxy が呼ばれているかについて確認する
    % 意外と呼び出している場所は少ない様である。
    % (改めて考えてみればそんな物だろう、というのは
    % 元々は update-positions は x y endx endy cx cy 等のシェル変数を通して
    % 直接計算した値を返していたからである。つまり、結果は呼出元の関数でしか使っていなかったという事である。)
    %
    % - 先ず、カーソル位置へ移動する時の cx cy と、
    %   bleopt_suppress_bash_output= の時にその左の文字 lc を取得する時。
    % - 後、描画領域を確保する為の begx begy endx endy
    % - それから部分更新の為の umin umax → uminx uminy umaxx umaxy
    % - また、矢印キーによる移動の際の移動先の計算
    %
    % 取り敢えず、_ble_line_text_cache_pos に格納するのは
    % その文字の開始位置ではなくて、前の文字の終了位置という事にする。
    % その文字の開始位置は前の文字の終了位置から計算する事が出来る。

    + bugfix: ascii printable characters の行末で \n を付加した時 ichg に登録していなかった。
      と思って update/position を変更しようとしたら新しい事実が発覚した…。
      そもそも xenl の場合、行末に来た文字の末尾には \n を付けて、
      文字を出力した際に必ず次の行頭に進むように調整をしていた。
      しかしながら、ASCII 文字が連なっている場合の最適化として
      位置を設定しているループの部分で、「変更文字」ichg のマークをつけていなかった。
      これの所為で実際の出力には \n が反映されておらず期待した位置とは異なる位置に
      文字が出力されるという事態になっていた。

      取り敢えずこれで問題点の一つは解決される事になる。
      そしてまた、上の考察で区別しなければならないとしていた部分更新後のカーソル位置と、
      部分更新開始時のカーソルの位置の違いがなくなった。
      更に、行末にカーソルが来ない事を保証しているので、
      部分更新開始時の位置として行末が来た場合に其処にカーソルを移動できないという問題にも引っかからない。
      (結局、\n を末尾に追加するというのは特に重い処理でもなく、
      また実装も面倒ではなく、そもそも実装されていたというのが考察の上での穴であった。)

    上記の部分を修正してテストしてみた所、表示がずれるという問題は解消された。
    しかし問題(といえるかどうかは分からないが)は未だ残っている。
    行末に入りきらなかった wide character の先頭に移動した時のカーソルの表示位置である。

    + bugfix: _ble_util_string_prototype の長さ指定に 0 を指定していた
      試してみたらかなり微妙な事になっている…。空白が挿入されていない! と思ったら
      x=cols を設定した後に空白を挿入していた。修正した。このバグはこの前全く同じ物を潰したような気がするが…。
      →検索してみたら結構色々な所に似たようなコードがある様だ。(余り良い事とは言えない…)

      また、これに伴って意図的に terminal の幅を縮めた時の折返しの処理も正しくされる様に、
      xenl の時に (本当の端末の端にいる時には敢えて付加しなくても良かった) \n を付加する様に変更した。

      更に、^? や ^A 等の特殊な制御文字の場合についても追い出しを実行する事にする。
      (bash の readline ではこれらの特殊文字の表現に関してはわざわざ追い出しはしないようだが。)

      また、行末付近での tab の取り扱いについても変更を行った。
      特に一番右端にいる場合には " " + 改行を入れる。
      (所で ble-edit/draw/trace の方の tab の取り扱いも同様の問題があるのでは、
      と思って確認してみた所こちらについてはちゃんと実装されていた…。)

    先ず _ble_line_text_cache_pos の形式を変更した。今迄は "x y" だったが、
    更に、入りきらない文字が追い出しされたかどうかを判定する為に "x y wrapping" とした。
    wrapping=0 が通常の文字 (出力開始位置とカーソルの位置が同じ) で、
    wrapping=1 が行頭に押し出された文字 (出力開始位置は前の行の最後、
    カーソルの表示位置は行頭) を表す物とする。
    カーソルの位置を取得する場合には wrapping を見て、((x=0,y++)) 等とする。

    更に、出力位置の制御に用いる getxy とは別に
    カーソルの表示位置を制御する getxy.cur を用意した。
    カーソル移動などの際に参照するのは専ら getxy.cur である。
    また get-index-at 関数も getxy.cur を参照する様に変更した。

    テスト: と、実装してからテストしてみたがずれている…。
    % 改めてみてみると wrapping の格納位置がずれている。
    その文字が wrapping の対象となるかどうかは、その文字を処理してからでないと分からない。
    従って、その文字の終端の境界に wrapping の情報を格納する現在の実装は正しい物である。
    寧ろ、参照する時に「現在の文字の位置」ではなく「次の文字の位置」の wrapping を参照するべきである。
    →この修正で自然な動作をする様になった。

  * ble-edit.sh: プロンプト内の job count 等の情報が更新されない。 [#D0198]
    →新実装で取得したデータのキャッシュを local に設定するのを忘れていた。

  * ble-decode.sh (stty): -icanon の設定。 [#D0197]

    何故か bless を起動してその儘抜けると入力しても反応しなくなる
    →無限ループに陥っているのかと思ったらそうではない様だ。
    →どうも入力が buffering されている様で C-d を押した時に初めて入力が読み取られ、
      それまでに入力した内容が一気に書き込まれていく。
    →stty で bless 前後を比較してみると stty -icanon が stty icanon に変わっている。
      stty -icanon を設定し直したら正常に表示される様になった。
      stty.enter で -icanon も設定する事にする。

2015-03-03

  * ble-edit.sh: prompt 再実装 [#D0196]

    | 2013-06-06
    | * <bug> PS1 に $() などが含まれているとプロンプト位置を正確に計算する事が出来ない。
    |   _ps1txt の方を eval してから再度位置の計算をする?
    |   →それだと _ps1txt, _ps1esc の両方について $() の展開をしなければならない。
    |     つまり、$() が2回実行される。これは意図しない動作になるかもしれない。
    |
    |   例えば \[ ... \] を [ - ] などに変換して出力し、
    |   その後で [ ... ] を除いた物を用いて位置の計算をする?

    この問題が未だ解決されていなかったので。
    bash の PS1 に対する振る舞いも確認して再実装した。
    bash 内部では先に \? の部分だけ展開して、
    その後で "" に全体を入れて eval している様な振る舞いをする様だった。
    それに従って再実装を行った。幅の計算は eval の後に行う事にした。
    \? の解決と幅の計算を独立させた事により、実装は却ってすっきりとした物になった。

    | 2015-02-23
    |
    | * <最適化> プロンプト構築
    |
    |   改行を押し続けた時の反応が遅い
    |   プロンプトの更新を停止すると動きが速くなる。
    |   これはプロンプトの生成に時間が掛かっているという事。
    |   見てみるに高速化できる余地はそんなに無い様な気がする。
    |   jobcount を実行するのに subshell 実行が必要なのは気にはなるが。

    新実装に移行した後に再度確認してみたが、それ程気にならないのでこの問題は破棄する。
    新実装になった事で速くなったのかも知れないし、
    あるいは変わっていないが気分の問題で気にならなくなっただけかも知れないが。


  * ble-edit.sh, ble-edit.color: discard-line の際に着色 [#D0195]

    | 2013-06-02
    | * ble-edit+discard-line: 灰色にする

  * ble-edit.sh: bugfix, 複数行で上に行けない [#D0194]
    →_ble_line_begx _ble_line_begy に編集内容の開始点を格納する様に変更。

  * ble-edit.sh: bugfix, 複数行なのに空行の accept-line でのずれ量が1行になっている [#D0193]
    →行を更新した後に _ble_line_x=0 _ble_line_y=0 を設定する必要。

2015-02-28

  * <bug> 履歴項目を移動中色が更新されない例を発見 [#D0192]

    "[[ ; == \; ]]" から "arr=(a b<a c)" に移動した時、初めの 2 文字の色がそのままだ。
    これは良く考えたら word による着色を消していない事と関係がある。
    特に上の二つの文字列は長さが一致しているので、shift を呼び出しても
    shift の実行が省略される為に中身がクリアされない。
    これは word 着色のバグ解決の時に解決されるはず。

    長さが一致していても shift を実行する事にする。
    shift によって途中の編集部分がクリアされる方が動作として自然だからである。
    或いは、途中の編集部分に何が入っているか未定義、という事にしていると、
    一々使う側でクリアしなければならないからである。
    編集部分で前の属性などを保持するのは不自然であるし、
    使う側でクリアするよりは shift の内部で行っている様な繋ぎ替えの方がコストが小さい。

    →結局 shift 長さが変わらない場合でも shift を実行するように変更した。

  * 初期化最適化: ble-bind が遅い [#D0191]

    どうも ble-bind の遅さが、後続の bashrc をも遅くしている様である。
    手軽に ble-bind を呼び出す事ができないのは致命的なので performance の悪さについて調べる。
    どうも調べてみると ble-getopt が遅い様に思われる。
    手で解析を書いて試してみる…(面倒だ。似たようなコードを何度も書かなければならない。
    確かに ble-getopt の様な仕組みを作りたくなる物である。)

    ble-bind を ble-getopt なしで書き直してみる。
    今回は ~/.mwg/bashrc にある 7 つの binding について試してみる。
    1 ble-bind (old, using ble-getopt) 122ms - 100ms = 22ms
    2 ble-bind (new) 87ms - 78ms = 9ms
    新実装の方が半分以下の時間で実行できる様になった。
    これで現在 87ms で bashrc がロードされる様になった。

    所で ble-bind が全体でどれぐらいの割合を占めているかについても概算しておく。
    ble-bind が 9/22 の速さで実行できる事によって全体で 122 - 87 = 35ms 短縮している。
    (ble-bind old 時間) * 13/22 = 35ms なのだから、(ble-bind old 時間) = 59ms という事になる。
    実に半分を ble-bind が占めていた事になる。残りの 63ms が他の処理である。
    現在は全体で 87ms に迄減った。63ms (他) + 24ms (ble-bind) という形である。

    また、新しい実装についてより分かり易く実装できないかと、各オプションを関数に分けてみた。
    結果、94ms - 83ms = 11ms であった。それ程遅くはなっていない。
    他のコマンドのオプションを作る時にはこれを参考にしても良いだろう。

    さてこれで ble-bind の速度は割合改善したがそれでも定数倍である。
    本当はもっと速くなって欲しい。改めて現在時間の掛かっている部分の特定をする。
    引数の解析部分を飛ばして直接呼び出して速度を確認すると、
    83ms - 76ms = 7ms であった。という事は引数の解析は 2ms しか費やしていない。
    今度は実際の登録部分について最適化を試みるべきであろう。

    特に気になっているのは ble-decode-kbd の部分である。
    試しに ble-decode-kbd を再実装してみたがそんなに時間は変わらない。
    全体で 83ms である。元々 85ms であったから 2ms しか変わっていない。
    特にテストに使っている部分 (7ms) に限って言えば大体 2/3ms 程度しか速くなっていないという事。
    別の部分で時間が掛かっているという事だろうか。
    試しに ble-decode-kbd 単体の速度を測ってみる事にする。
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd C-,; done → 292ms
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd M-down; done → 295ms
    | 7 * 0.294ms = 2ms なので、全体の内 2/7 がこの ble-decode-kbd であると分かる。
    バグがあった。修正したらかなり変わった。
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd C-,; done → 230ms
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd M-down; done → 375ms
    正規表現によるマッチは結構重い??
    →正規表現ではなく ${key//[...]/} を用いて試したら 375 → 257ms 迄速くなった。
      所で、長さが 1 である事を確かめるならば、
      算術式で長さを求めてから比較するよりは glob の pattern で一致させた方が速い様だ。
    所で、旧実装を削除する前に改めて速度を測っておく。
    →C-, に対しては 346ms,  M-down に対しては 670ms である。
      全体の内 3.070ms / 7ms である。またこの事からこれ以外の部分に 4ms かかるという事が分かる。
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd C-,; done → 231ms
    | time for ((i=0;i<1000;i++)); do ble-decode-kbd M-down; done → 257ms
    | → bashrc の 7 bindings に対し大体 1.667ms / (4+1.6)ms。大体 5/17 を占める。

    その他の部分で怪しいのは .ble-decode-key.bind である。
    押されるキーの数×2 の eval を実行している。
    しかしこれはどうしようもないので取り敢えず諦める。

  * ble-edit.sh: bugfix, .ble-line-info.clear で位置がずれる [#D0190]

    描画後の座標値の設定時に存在しない変数 x y を参照していた。これらは 0 であるべき。

  * 初期化の最適化 [#D0189]

    現在の初期化のボトルネックは圧倒的に history である (2015-02-09)
    →.ble-edit.history-load を多少最適化した。読み取り時間が約半分になった。
      それでも未だ全体の半分が history 読み取りである
      (しかし history を 16k も溜めている場合は少ないから、実際は無視できるかも)。

    | 改めて初期化の時間を調べる:
    | 多少なりとも時間が掛かっているのは以下の phase
    | - ble-core.sh                     58ms
    | - ble-edit.sh                    629ms (554ms が history, 75ms が他)
    | - ble-decode-bind.cmap            52ms
    | - ble-decode-bind                105ms
    | - .ble-edit.default-key-bindings 229ms
    | - .ble-edit-draw.redraw           35ms
    |
    | default-key-bindings を見るに ble-bind に平均 229/75 ms かかっている様だ。
    | これを考えると ble-edit.sh の中の 33ms も ble-bind の遅さに起因する。

    改めて初期化の時間を計る (2015-02-28)
    前回から、初期化と attach の分離、history 遅延ロードの実装など、
    初期化の順序・構成が変化した。

    1 ファイルの読込                 |  39ms
    2 ble-initialize
      ble-decode-initialize          |  53ms
      .ble-edit.default-key-bindings | 309ms -> 4ms
      ble-edit-initialize            |   4ms
    3 ble-attach
      ble-decode-attach              | 201ms -> 55ms
      ble-edit-attach                |   0ms
      .ble-edit-draw.redraw          |  36ms

    ble-decode-initialize は ble-decode-bind.cmap の現在の名前と思って良い。
    これのロード時間は大して変わっていない。
    この部分は基本的にファイルにキャッシュした配列を読み取っているだけである。
    しかしその容量が大きい為にこれだけの時間が掛かっている。
    CSI Function Key が大半を占めているので、これらを特別扱いする様にすれば多少は解消するかも。

    .ble-edit.default-key-bindings は前回よりも大幅に増えている。
    これは多少の bindings の追加を行った事もあるが、
    keymap isearch などの初期化を .default-key-bindings に統合した事もある。
    →これもファイルに dump を出力する様にした。これは 4ms と嘘のように軽くなった。
      ble-bind 自体に問題があるのかもしれない…。

    ble-decode-attach は前回に比べて大幅に増えている。
    これは bash-4.3 で ESC [ ... に bind する為に、
    全ての可能性に対して bind を実行している為であろう。
    (しかしそれでも元々 100ms 程度かかっていたのでここを直しても劇的に速くなるという事はない)。
    更に詳しく調べる。既存の bind の保存と削除は 31ms で済んでいる。
    全組合せに対する bind は 77ms 掛かっている。メインの bind に 91ms かかっている。
    実はこの部分をこそ最適化するべきなのかも知れない。
    →既存の bind の保存と削除の部分は awk の呼出が2回に渡っているのを1回にくっつけた。
      この部分は時間を計測してみたが 31ms の儘で変化しなかった。
    →結局全組合せに対する bind はしないで代わりに ESC [ を utf-8 で翻訳する方向にした。
    →また、メインの bind はコマンドを生成するのに時間が掛かっている様に思われたので、
      先にコマンドを生成してファイルにキャッシュする様に変更した。
      その為に新しく bind のコマンドを生成する為のファイル ble/bind.sh を作成した。
    結果として元々の 201ms から 55ms に迄ロード時間を減らす事ができた。

    これで一通り重い場所は解決したように思うので解決とする。

  * ble-decode.sh (.ble-decode-bind/generate-source-to-unbind-default): awk 呼出を一回に統合。 [#D0188]

    | * 既に bind -x してある物を削除するという事?
    |   bash-4.3 では bind -X が実装されたので bind -x した物を列挙できる。
    |   (但し、bind -r しても bind -X のリストには残ってしまう様だ @bash-4.3.33
    |   リストには残っているが実際には削除されている。)

    同時に上記の項目 (2015-02-09) も実装した。

  * ble-core.sh, ble-color.sh: .ble-shopt-extglob-push/pop/pop-all 廃止 [#D0187]

    ble-color.sh で、extglob を使った部分のコードの管理が
    好い加減面倒なので正規表現による実装に切り替えた。
    (そもそもこの部分は現在は使われていない部分ではあるが。)

    さて、.ble-shopt-extglob-push/pop/pop-all 関数は
    この部分でしか使われていなかったので削除してしまう事にする。
    別にそう大した実装でもないので。

  * history 遅延ロードについて [#D0186]

    これから本格的に常用する為にはできるだけ速くロードできる様にしたい。
    特にボトルネックになっているのは history である。
    history の遅延ロードの可能性について考える。

    現在の実装では history がロードされている事を前提にして書かれているので、
    できるだけ history の項目に触る前に history がロードされる事を
    保証する様に書き換えなければならない。
    特に history の interface を絞る事によって移行しやすくする事を考える。

    現在の所どの様な場所で history が参照されているかを確認する。
    先ず現在の history 項目の数を幾つかの場所で参照している。
    実はこれは HISTCMD 変数を用いて参照する事ができるのではないか?

    HISTCMD は代入してもその効果がなくずっと history に登録されている項目の数を指している様に見える。
    と思って実際に ble.sh を起動して確認してみると常に 1 という値になっている。これは困った。
    しかし何故明示的に unset している訳でもないのに HISTCMD=1 なのだろうか。
    これは rcfile で読み取っている事にも関係しているのだろうか。。
    →判明した bind -x の内部で HISTCMD を参照すると 0 になっていると言う事の様だ。

    という事は HISTCMD を参照する事によって history 項目の数を取得するというのはできないという事だ。
    別の方法を考える…。どうやら count=($(history 1)) で取得した値が、
    実際に history からロードした時のエントリの個数と一致する様である。
    という事は count=($(history 1)) を必要になった時に一回呼び出して、
    後はそれを maintain (increment するなど) すれば問題ないという事になる。

    更に history-add の時にもロードを遅延させる事は出来ないかと考える。
    その為に history -s の動作について確認しておく。
    - history -s を使っても HISTCONTROL は考慮に入れられる様だ
      従って、ble.sh の側で HISTCONTROL の処理をしなくても済む。
      逆に現在の history 項目の数は分からなくなる。
      history が追加されたのかされていないのか分からないから。
      返却値も確かめてみたが、重複によって登録されなかった場合でも 0 (正常終了) する様である。

    対応できそうなので遅延ロードに対応する事にした。実際の修正は意外と小規模で済んだ。
    未だ、何処かに取りこぼしがあるかも知れないがそれは問題になってから対処する事にする。

2015-02-27

  * <bug> bash-3.0, bash-3.1 [#D0185]

    何故かパス名展開がされない: echo * としても * がそのまま表示される。
    echo $- としても f はついていない。
    何故か分からないが unset GLOBIGNORE したら直った。
    (GLOBIGNORE には何も設定されていない様に見えるのに)

    →ble-decode-kbd の local GLOBIGNORE を削除したら直った。

  * bash-3.0 対応 [#D0184]

    bash-3.0 では += 演算子が使えない。また、${#param} が文字数ではない。

    これらの事から対応を諦めていたが、
    += 演算子については調べてみたらそんなに使っていない様だ。

    grc '\+=[("'\'']' --exclude=test --exclude=out --exclude=ble.sh

    term.sh (varnames),
    ble-syntax.sh (completion-context context, _ble_highlight_layer_syntax3_list),
    ble-core.sh (ble-stackdump message),
    ble-decode.sh (.ble-decode/keymap/push, ble-decode-kbd keymods)
    ble-edit.sh (_ble_edit_accept_line, _ble_line_text_cache_ichg, _ble_edit_isearch_arr)

    面倒になったので ble/util/array-push という関数を作って、
    速度に関係なさそうな所ではそれに置き換えた。
    (注意しなければいけないのは、array-push を使う時は、
    配列要素が 0 から順に割り振られている必要があるという事。
    専ら push のみを用いて要素を追加する場合には問題はない。)

    さて bash-4.3 で問題なく動いているか確かめてみると、TAB を打った時に表示がずれる。
    →これはまた別のバグであった。別項目として独立して解決。

    今度は bash-3.0 で起動してみる。すると、沢山のエラーが発生している。
    何より unknown ble edit function と表示されてそもそも関数が登録されていない様だ。
    ble/util/isfunction が悪いのかと思って調べたがちゃんと動いている。
    改めてエラーメッセージと ble-bind を照らし合わせると…そもそも ble-getopt が駄目なのかも。

    →何と…。
      local a=($command)
      上の実行結果が a="($command)" というのと同じになっていた。以下の様に -a を指定する必要がある:
      local -a a=($command)

    さてこの様な使い方をしている所は正直沢山ある。以下で列挙できる。
      grc '(local|declare) [a-zA-Z_][a-zA-Z_0-9]*=\(' --exclude=out --exclude=test --exclude=ble.sh
    特に ble-decode.sh の中にあるのは致命的なので、取り敢えずそれだけは直しておく。
    また ble-core.sh や ble-getopt.sh に関しても起動に致命的な影響を与えるので修正する。

    さてそれでも ble-decode が動いていない様に見える。
    noattach の状態でもエラーが出ているのでそれを手がかりに原因を探る。
    どうも .ble-edit.default-key-bindings の中でエラーになっている。
    しかも其処で死んでいて、続きの初期化が実行されていない??
    この中でやっているのは ble-bind の呼出だけである。
    という事は ble-bind に未だ問題点があるという事だろう。
    何と初回の ble-bind で既に死んでいる。。
    →ble-decode-kbd の中の同様の配列の初期化が悪かった様だ。先程 grep した正規表現では不十分だった。
      grc '(local|declare|readonly|typeset)[^-]* [a-zA-Z_][a-zA-Z_0-9]*=\(' --exclude=out --exclude=test --exclude=ble.sh

    この修正で取り敢えず起動はする様になった。
    しかし、少し弄るだけで簡単に無限ループになる。やはり上記の配列の初期化を全部修正しないと駄目なのだろうか。
    →仕様がないので配列の初期化を全部修正してみたら意外とすんなりと起動した。
      普通に色も着いているし問題は起こっていない様に見える。
      但し、.ble-line-info.draw の表示が少し狂っている様に見える。

      後ファイル名の補完候補を列挙できていない。

    何と…初期化内容に括弧があると local/declare -a に失敗する。
      a="1(2"
      declare -a b=("$a") → エラー
      b=("$a") → これはOK
    local/declare は文法的に特別な処置を受けて折らず唯単に文字列の引数を受け取っているという事だろうか。
    再び大幅な書き換えが必要になりそう…。→結局全部書き換えた。

    改めて bash-4.3 で起動してみると補完候補の表示が狂っている。
    今迄の書き換えで何処かミスしたという事だろう。。
    .ble-line-info.draw を潰すと何も問題はない様なので、
    .ble-line-info.draw の中か関連した所が怪しい。
    そもそも .ble-line-info.draw が表示されている箇所がおかしい。
    .ble-line-info.draw が表示されている箇所に対する相対位置としては最終的なカーソルの位置は正しい。
    という事は何処かで座標計算がずれているという事。

    多分分かった…bash-3.0 の declare で吐き出した term.sh のキャッシュが間違っている。
    →当たりだった…。bash-3.0 は _ble_term_ind (内容は $'\n') について、
    | _ble_term_ind="\
    | "
    という風に出力していて、成る程そういう扱い方もあるのか、等と思っていたが、
    上記のコードは "" となる(改行は消える)。試しにやってみると…やはりそうだ。
    | $ echo "a\
    | $ b"
    | ab
    つまり bash-3.0 の declare -p は信用できないという事である。修正した。

  * <bug> TAB 等の変更文字があった場合に文字列が表示されなくなる [#D0183]

    bash-3.0 対応の時に _ble_line_text_cache_ichg 関係を書き換えテストした時に発見したバグ。
    色々試してみるとこれは今回の変更とは関係ない様に見える。今迄のコードに直しても再現する。
    また、_ble_line_text_cache_ichg の登録を止めるとまた異なるずれ方になるので、
    これは _ble_line_text_cache_ichg の登録に失敗しているのではなく、
    _ble_line_text_cache_ichg を使用している側で失敗しているのではないかと思う。
    →確認してみたが、置き換えに失敗しているという事は無い様だ。
      という事は、座標計算を間違っている可能性の方が高い。
      改めて ichg を設定している側に戻って座標について確認してみる。
      良く分からないので、やはり適用している側に行きそこで _ble_line_text_cache_pos を出力する。
      この部分についても何も問題はない様に見える。
    →もしかして出力している物が間違っている?
      と思ったら空文字列を出力していた…。
      元々 .ble-line-text/update で HIGHLIGHT_BUFF に指定された物を使って出力していて、
      .ble-line-text/update の後で slice によって出力内容を取得する様に変更したのが原因だった。
      変更文字があった場合には HIGHLIGHT_BUFF の示す先をローカル変数 buff に置き換えて
      その場で出力させていた。当然ローカル変数は他の関数 /slice を呼び出した時には
      残っていないので空文字列 (或いは、呼出元で buff が定義されていればその内容) が出力される事になる。
      変更文字があった場合にローカル変数に書き込むのは止めて、グローバルに変数を用意して其処に書き込む事にした。

  * <bug> bash-3.1 日本語の色付け・描画が変だ [#D0182]

    何と日本語が含まれている時の BASH_REMATCH が変だ…。
    一致を試みる際には文字数でカウントして、しかし結果は
    バイトオフセットで切り出しているという具合に見える。

    と思って色々試したらどうも自分で指定している SGR 指定ですら変な事になっている。
    もしかして BASH_REMATCH 等の問題ではなく、単に自分の新しいコードの問題か?
    と思ったが 4.0 4.3 では問題は起きていない。3.2 でも問題は起きていない。
    これはやはり 3.1 固有の問題である様だ。

    よく考えたら SGR 指定で変な事になっているのは、SGR の出力に問題があるというよりは
    その前後に変な文字 (UTF-8 の不完全なシーケンス) がある所為で、
    SGR の先頭の ESC 等が食われてしまっている事による物と推察される。
    さて、描画に用いている文字は基本的に _ble_line_text_cache_cs から来ている。
    そして、_ble_line_text_cache_cs に格納されている文字は
    ${text:i:1} によって取り出した物である。問題があるとすればこの辺りだろうか。

    試しに a='ああ' として見て色々試したが問題がある様には見えない。${a:ofs:len} は勿論の事、
    ${#a} も正しい値を返している。取り敢えずは保留という事にする。
    念のため、最後に新しく実装した.ble-line-text.construct が悪さをしている訳ではない
    事を確かめる為に古い関数に戻して試してみる。やはり古い関数でも同様に変な風になっている。
    従って、新しい実装が悪さをしているという訳ではない。

    →何と ${#BASH_REMATCH[n]} がバイト数になる様だ…。
      以下を実行すると、通常時は正しく日本語の文字数で数えているが、
      BASH_REMATCH の中ではバイト数になっている。

      local text='あいう'
      [[ $text =~ ^.+$ ]]
      echo "#${text} = ${#text}, #${BASH_REMATCH[0]} = ${#BASH_REMATCH[0]}"

      | ${BASH_REMATCH[0]:ofs:len} 等は問題なく動いている様なので謎だ。
      | 別の変数に再代入しても問題は続く。
      | 一旦 ${BASH_REMATCH[0]:0} 等として別の変数に移せば問題ない様だ。
      と思ったら関係ない様だ。

      % if ((_ble_bash>=30200)); then
      %   function ble/util/modify-bash31-rematch {
      %     :
      %   }
      % else
      %   # In bash-3.1, BASH_REMATCH returns corrupted string
      %   # when multibyte characters are matched.
      %   function ble/util/modify-bash31-rematch {
      %     local i iN="${#BASH_REMATCH[*]}"
      %     for((i=0;i<iN;i++)); do
      %       BASH_REMATCH[i]="${BASH_REMATCH[i]:0}"
      %     done
      %   }
      % fi

    →色々試して、漸く問題点が分かった。これは BASH_REMATCH だけの問題ではなく、
      ${#配列[n]} 全般で起こる問題である。この形式で要素の長さを取得すると
      文字数ではなくバイト数が取得される。
      ${#配列} の様にして第一要素の長さを取得する場合は問題にはならない。
      (結構重大な問題だと思うが bash の ChangeLog には fixed された等とは書いていない様だ。
      一応 3.0 → 3.1 で ${#param} の場合にバイト数ではなく文字数を返すように修正された様ではある。)

      取り敢えず以下で問題のありそうな部分を列挙する
      grc '#[a-zA-Z_][a-zA-Z_0-9]*\[[^@*]' --exclude=test --exclude=out --exclude=ble.sh

      一番多いのは ${#BASH_REMATCH[0]} なのでこれは単に ${#BASH_REMATCH} と書き換えれば良い。
      次に多いのは、その場所に一致したかしていないかの判定 ((${#BASH_REMATCH[n]})) である。
      これは [[ ${BASH_REMATCH[n]} ]] 等に書き換えてしまえば問題ない。
      こういった物を除いていったら本当に ${#BASH_REMATCH[n]} を使っている場所は 11 箇所のみであった。
      これならば何とか対応できる。対応した。

      これで着色の問題に関しては解決した。しかし、今度はカーソルの移動の度に C だとか D だとかの、
      カーソルの移動方向に対応した文字が出力される。term.sh のキャッシュの読み取りに失敗しているという事だろうか。
      →分かったような気がする %d の置換に失敗しているのではないか?
      →やはりそうだった
        $ aa=123%d4
        $ echo "${aa//%d/@}"
        $ echo "${aa//'%d'/@}"
        123%d4
        123@4

        下のように %d を '' で括っておけば問題ない様なのでこれで行く事にする。
        しかしそうすると、visible-message も壊れているのでは…。
        以下で問題の有りそうな所を列挙して修正する。修正した。

        grc '//%' --exclude=test --exclude=out --exclude=ble.sh

  * 文脈に応じた complete [#D0181]

    syntax の update はいつ行うか

    | これに対応する為には描画時以外にも syntax の update を実行できる様にしなければならない。
    | その為には
    | 1. ble-syntax/parse を独立に実行できる様にする
    | 2. update-positions や描画なども含めて文脈補完時に実行する
    | 3. 実は ble-syntax/parse は up to date になっている筈?
    |
    | もし 2. の描画が無駄にならないのであれば実装でしても良いが、
    | 補完時には確定部分を挿入するので再度後で解析し直しが必要になる。
    | 3. は補完関数を直接 bind している時には正しいが、
    | 実際には内容を変更してから補完を呼び出すという使い方をシェル関数でするかもしれない。
    |
    | 更新の必要がなければ更新しないだけなので、余分に更新を試みるのは悪い事ではない。

    やはり当初の考え通り 1 の方向性で行く事にする。

    次に補完を行う文脈をどの様に判断するかについて

    文脈に応じた補完と言っても、どの様に文脈を判断するのかが問題になる。
    できるだけ補完点の後の情報に依存しないようにするのが望ましい。
    例えば arr=hoge となっている時に ar の点で補完を開始しようとしたとする。
    もし現在居る単語の種類を元にして補完を行おうとすると、
    現在の単語は変数の代入であるから変数の代入に出てきそうな単語しか補完候補に現れない。
    もし ar で始まるコマンド名に補完したいと考えている場合にはこれは不便である。

    実際に挿入をしながら補完を行う場合については、
    普通カーソルより後の部分は現在入力している物と関係ないと考えるのが自然である。
    というのも挿入を続ける事によって、挿入点以降の文字列の文法的意味は次々に変わっていくからである
    現在の入力状態で挿入点の次にある文字列が補完対象と同じ単語の中に含まれている様に見えても、
    挿入が其処で終わるとは限らないのでどんどんと挿入を続けていけば軈て別の単語になるなど。
    何れにしても、挿入点より後の情報を用いて補完するのは直観的でないという事である。
    なのでルールとして以下を設ける
    @ 挿入点より後の文字列は補完内容の決定に使用してはならない。

    次に現在の attr を使用して補完方法を決める事について。
    結論から言うとこれは使えないのではないかと思う。
    先ず、エラーがある場合には attr にはエラーが設定される。
    エラーが発生した時には別の配列にエラー情報を記録するように設計を変更したとしても、
    attr は未だ0文字も入力していない場合 (例えば ${ の直後) などでは文脈の判断に使えない。
    ${ の直後には変数名が来る事は明らかであるので、例え何も入力していなくても補完候補が出せた方が良い。
    @ attr は補完の文脈の決定を行うのには使わない。

    とすれば残るのはやはり直近の stat の状態である。
    stat は解析の再開に用いられる物であるから、
    次にどの様な文法的要素が来るのかを規定するのに充分な情報を持つ。
    但し、問題点は stat は解析結果ではなく解析を行う為の情報に過ぎない事である。
    この事から、stat を用いて補完を実行する為には、
    解析に極めて近い所まで処理する必要が出て来るという事である。

    complete 側でこれを処理するのは面倒だし、
    また、ble-syntax/parse で用いている stat の形式に大きく依存するので、
    これは ble-syntax 側で実装する方が適当である。
    つまり ble-syntax 側で指定した位置が文法的にどの様な物を期待する物なのかを決める。
    実際の補完候補の決定などは ble-edit 側で行えばよい。


    実装1 取り敢えず実装してみる

      取り敢えず簡単の実装の為に、プログラム補完は考えない事にする。
      補完をする為に必要な情報は何か。。
      補完の際に行う事が何かを考えそれを元に必要最低限の情報について考える。

      - 補完候補を表示する → 表示される文字列
        この為には補完候補の一覧が取得できれば良い。
        但し注意しなければならないのは、
        表示される補完候補と実際に補完される単語が一致しているとは限らないという事である。
        例えば、 a/b/c/ ディレクトリの下にあるファイルを保管しようとしている時、
        全ての補完候補に a/b/c/... とディレクトリ名が付いているのは煩い。
        普通は a/b/c/ 以下のファイル名の部分しか表示しない物である。

      - 一意確定部分を求める → 追加挿入される文字列
        共通一致部分。これの為にはこれから挿入しようとしている内容が必要。

        文脈によっては何らかの方法で共通一致以外の確定方法があるかもしれない。
        この時にはこれから挿入しようとしている物の内容は不明である…。
        というか様々な種類の確定方法が混在していた時に、それらをまとめて
        一つの答えを出すという操作は慎重に考える必要がある。
        どんな候補の場合にも確定できる方法と言えば
        やはりこれから挿入しようとする文字列を各候補に生成させる事である。

        特に意識したいのは曖昧一致による確定である。この場合には決定した時に
        既に入力した部分も含めて置き換えが行われる。
        これに対応するには、挿入される文字列などではなくて、
        既に出力されている部分も含めての置き換えを提出させるのでも良いかも知れない。
        その様にすればより自由度は向上する。しかし、問題は、
        異なる補完開始点を持つ候補が混在している場合である。
        その様な場合に共通一致部分を計算したり曖昧一致を計算したりするのは可能か?

        所で、曖昧一致と先頭一致では区別して、先頭一致の方を優先させる等の処理をしたい。
        例えば、先頭一致だけを見ると確定しているが、曖昧一致の候補まで含めると色々ある、
        という場合には先頭一致で確定させてしまって良い。
        (一方で、先頭一致の共通一致部分に関しては確定しない方が良い?
        或いは曖昧一致探索と先頭一致探索はそもそも混ざり合わない様に異なるキーに
        割り当てるべきなのかも知れない。)
        それぞれの候補についてそれが曖昧一致なのか先頭一致なのかで形式を変えても良いかも。
        しかしそれぞれの候補をどう取り扱うかは受け取った側で設定できるようにしたくもある。
        それに候補生成の方法を複雑にすると言うのもなんである。
        そう考えるとやはり候補の生成の際には両者を区別しない形で列挙して、
        それを使う側で先頭一致とそれ以外に分けるという方法の方が良いようにも思う。

      - 挿入する → 挿入関数名
        ただ挿入するだけではなく、様々な追加操作を行う可能性がある。
        例えば、一意確定の際にスペースまたは / を挿入するという事。
        或いはお節介な機能として確定した単語について
        様々な装飾・エスケープなどを施したいという需要があるかもしれない。
        これは色々と自由度が高い様な気がするので関数で実装する事にする。
        各候補についてどの関数を用いて挿入を行うかを取得できる様にする。

      他に問題になるのは、上記に示した情報をどの段階で生成するのかという事である。
      必要最低限と言えば、補完候補の文字列とその取り扱いを定義する関数さえ持っていれば、
      後は関数を呼び出す事によって、補完候補の表示文字列も生成できるし、
      追加挿入される部分について生成する事もできるし、候補表示の時の着色やら、
      メニュー表示にした時の説明文まで何でもできる。
      ただ、候補生成の時にしか分からない情報もあるかもしれないから、
      後でそれらの関数が利用できる様に各項目に data 等というフィールドが使える様にする。
      (これらはそれらの補完関数に形式・使用方法を任せる。)

      取り敢えずその形式で行く事にする。
      候補生成関数が用意するのは、
      1 補完候補
      2 補完関数群 (これは名前の形式を定めておき prefix 等を呈示する)
      3 2 で使用する内部データ (あれば)
      という事にする。
      補完の表示文字列については高確率で必要になるので、これも生成時に用意させる。
      4 表示文字列
      また、候補毎に挿入位置や元にしている文字列が異なるかもしれないので、
      これについても用意した方が良い様に思う。
      5 補完開始点・補完終了点・対象の単語
      補完対象の単語、というのはクォート除去・パラメータ展開などを行った後の値である。

      補完候補、表示文字列、対象の単語に関しては内部に任意の文字列を含みうるので、
      独立した変数に入れる様にした方が管理しやすい。
      一応、固定形式の末端に入れれば何とか抽出できない事もないが面倒なので止める。
      補完関数群の prefix 補完開始点・補完終了点などの情報は空白を含まないので、
      これらは一つに纏める事ができる。
      補完関数群で使用できる内部データは補完関数群の内部で簡単に使える様にする為に、
      やはり一つの独立したデータであるべきである。
      従って候補のデータは以下の様な物に改める:

      cand_word 単語
      cand_show 表示文字列
      cand_head 対象の単語
      cand_prop 関数群接頭辞 開始点 終了点
      cand_data 自由データ

      特に簡単な候補生成の為に cand_word さえ渡せば他を fill できる様にするべきである。

    実装2:

      実装1の方針で実装してみたが問題がある。
      上記の方針では異なる補完開始点や関数群に従った候補を混在させる事ができる様になっている。
      しかし、候補を一意に絞れない時の動作はどの関数群に従ったらよいか判断できない。

      但し、以下に挙げる様な特定の候補に関する操作に関しては、候補語との関数の指定で問題ない
      - 一意確定時の動作 (挿入した時に後に " " や "/" を追加するなど)
      - 各候補に対する説明の取得や色つきの表示文字列の取得など

      問題になるのは以下の動作である。
      - 共通部分確定時の挿入

        単純に挿入するだけであれば共通の動作であるので別に関数群に頼る事は無い。
        しかし、文脈によっては挿入によって文法構造が壊れてしまう事もある。
        その様な場合には色々な修飾が必要になってくる。

        例えば myfile-$ind の末端の様に変数名補完と
        ファイル名補完が混在している時を考える。
        変数名補完としては myfile-$index になる事を考え、
        ファイル名補完としては myfile-${ind}ex になる事を考えている場合、
        両者の補完は共に ex となるので共通一致で ex を挿入しようと言う事になるが、
        実際に挿入する場合にはどちらか一方のやり方で挿入する訳には行かない。
        結局の所、共通一致しそうに見えて一致しないというのが答えである。

        この判断をどの様にすれば良いのかについて慎重に考えなければならない。
        というかそもそも両者は異なる補完結果を与えるのだから、
        異なる候補として区別すればよいだけの事かも知れない。

        つまり、挿入の仕方は挿入関数を定義する事によって実現するのではなくて、
        そもそも候補列挙の時点で挿入文字列・挿入方法を完全に確定してしまって、
        その後で共通部分一致などを試す必要があるのではないかという事。
        逆に挿入時には共通の処理しか挟まない様にする。

      今後他にも共通操作に関して問題になる事があるかもしれないが、
      取り敢えず今回の共通部分確定時の挿入に関しては、
      事前に何が挿入されるか迄候補として生成して、
      共通部分探索時にそれを考慮に入れて絞る。

      今度の実装では候補生成を以下の様に行う:
      1 補完範囲の開始点と終了点を得る。
        更にその間にある部分の評価結果を文字列として取得する。
        (これは補完の種類によっては不要であるかもしれない)
        COMP1 = 補完範囲の開始点
        COMP2 = 補完範囲の終了点
        COMPS = 補完範囲の文字列
        COMPV = 補完範囲評価結果

        この次に具体的な候補を複数列挙する事になるが、
        ここまでの処理はそれらの候補の間で共通である。

      2 候補を生成する

        CAND = 候補の文字列
        ACTION = 関数群接頭辞
        DATA = 何か追加情報があれば。ACTION への引数的な物。

        此処までは候補に依存して完全に異なる物である
        エスケープなどの共通の修飾などについては後段に任せる。

      3 各候補に対する処理

        これ以降は既に指定した ACTION による関数で処理を行う。
        候補の違いは全て ACTION の違いで処理する。

        $ACTION/init で処理を行う

        SHOW = 表示文字列
        INSERT = 挿入文字列 ← CAND から生成する
        DATA に対する加工も。

      4 候補の情報の格納

        cand_word+=("INSERT")
        cand_show+=("SHOW")
        cand_prop+=("ACTION COMP1 COMP2")
        cand_data+=("DATA")

        その他の情報については後で使う事は無いと思う。
        何か特別に必要な物があれば DATA に入れる。
        一般的に使う機会が多そうな物があれば配列を増やす。

    新しく共通部分の探索も加えて取り敢えず実装を行った。
    今の所は仕組みとしては問題なく動いている。
    後はこの仕組みに従って少しずつ拡張していけば良い。


    | * <bug> complete
    |   引用符に囲まれた場合などに挿入位置がずれる。

    この問題は新しく実装し直した事によって解消した。

2015-02-25

  * <bug> accept-single-line-or-newline が二回目以降常に accept [#D0180]
  * <bug> 複数行の編集時に履歴移動をすると表示が乱れる [#D0179]

    他にも編集してから実行をすると実行後にずれるとか、
    複数行の場合には accept-line ではなくて newline の筈なのに accept されるとか。

    これには二つの別の問題が関係していた
    1. 表示を消す時の座標の間違い
    2. stty -nl で icrnl が設定される事により CR が LF に変更されていた

    accept の件は、本来は、行末が次の行に移動しているかどうかではなく
    $'\n' がコマンドラインに含まれているかどうかで判断するのが良い。
    唯単に端末が狭くて折り返しているだけで単一行の時もあるから。
    しかしそうだとしても accept されるのは不思議である。
    accept-single-line する前に一旦表示している筈だから _ble_line_endy
    は更新されている筈であるのに。

    % やはり _ble_line_endy の更新に失敗しているという事であろう。
    % と思ったらいつの間にかに accept が正しく動くようになっている。謎だ。

    それでも表示が乱れるのは変わっていない。
    色々試した結果、_ble_line_endx _ble_line_endy は正しい値になっている。
    よく見てみると、単純に表示を削除する時の座標を間違えていただけであった。
    これで問題なく動くようになった。

    accept の方の問題に関しては再現する条件がある様だ。
    良く分からないが echo hello の様に単純なコマンドを一回実行してからだと
    常に accept される様に変わってしまう。
    表示の部分で _ble_line_x 等の動作を確認してみたが問題は内容に見える。

    と思って ble-edit+accept-single-line-or-newline の内部で
    出力を行う様にしてみた所、何故か初めの一回だけしか呼び出されていない。。
    ble-bind で確認してみても何か別の物に置き換わっているという様子もないようだ。
    すると何が起きているのだろうか…。
    実行されているという事は accept-line は呼び出されていると思われる。
    →実際に accept-line で stackdump すると ble-decode-key/invoke-command
    から直接 accept-line が呼び出される様になる様だ。
    もう少し詳しく調べる事にする。
    →どうやら ble-decode-char の時点で 13 ではなく 10 を受信しているようだ。
      もっと遡ると ble-decode-byte でも 10 を受け取っているし、
      そもそも ble-decode-byte:bind でも 10 を受け取っている。
      (何故始めの1回だけ正しい物を受け取っているのか謎である。)

    - bind -X で確認してみたが異常はない。
    - 因みにコマンドを一回も実行しない限りはずっと 13 が受信できる。
      何か stty の設定と関係があるのだろうか。
    - M-c で ble-bind -cf のコマンドを実行した場合も同様である。

    判明した function .ble-stty.enter の中の stty -nl が駄目だった。
    stty nl としてみたら動くようになった。然しそうすると表示が滅茶苦茶になる。
    今迄の描画ルーチンでは全然駄目という事になる。

    | 解決方法は二つある。
    | stty のモードをもう一つ付け加えて、入力を受け付ける時にだけ stty nl にする。
    | 或いは、 stty nl でも正しく描画できる様に描画ルーチンを変更する。
    |
    | a 何とかして stty を使わずに端末の設定を切り替える方法はあるか?
    |
    |   現在の所 stty のモードの変更はコマンドを実行する瞬間だけで済んでいる。
    |   もし描画する時と表示する時で毎回 stty を呼び出して切り替えなければならないのだとすると、
    |   かなりコストが高い。
    |
    |   - できるならば stty を呼び出さずに端末を制御する方法が有れば良いのだが…。
    |   - 或いは、stty を裏で起動しっぱなしにしてリアルタイムで変更させるなんて言う事ができたら…。
    |     しかしそんな機能はない。
    |   - それとも新しく仮想端末を作ってしまって設定に応じて出力先を変更する、
    |     等という事も出来たりするのだろうか。。
    |
    |   mknod とか?? 試しに
    |   $ mknod testtty c 4 100
    |   等としてみる…。許可されていない操作ですと怒られて終わる。これでは駄目だ。
    |   $ mknod a c 136 10
    |   としても駄目だ。今度は
    |   $ mknod /dev/pts/10 c 136 10
    |   等としてみる。エラーメッセージが変わった。"許可がありません" になった。
    |   良く考えてみればこれは "許可されていない操作です" 以前の問題なので、
    |   寧ろ遠ざかったのではないかと思う。
    |   さて、システムが落ちても嫌なので無理矢理 sudo で作るのは止めておこう。
    |   使い方も良く分からない事であるし。
    |
    |   関係有りそうな質問が出ている:
    |     [[Create new /dev/pts/&lt;n&gt; device using bash script?>https://forums.opensuse.org/showthread.php/494468-Create-new-dev-pts-lt-n-gt-device-using-bash-script]]
    |   しかし解決法は呈示されていない。
    |
    |   [[screenの”Cannot open your terminal ‘/dev/pts/0′”対策 | Siguniang's Blog>https://siguniang.wordpress.com/2012/08/11/screen-and-pseudo-terminal/]]
    |   によると script コマンドを起動すると新しい pts が開かれる様である。
    |   例えば、script コマンドを無理矢理開いて、その後でその script コマンドが作成した端末に書き込んだりするとどうなるのだろう。
    |   script を & で開いて新しく作成された pts に何か書き込んでみたが何も起きない。
    |   プロセスを見てみたが script コマンドが新しく pts/8 な bash を中で開いている様だ。
    |   要するに bash が何か出力したら script がそれを読み出す、という事なのだろう。
    |   bash は -i で起動し入力待ち状態になる。この時に pts/8 に書き込んでも何も起きない。
    |   うーん。良く分からない。もう少し試してみる。
    |
    |   $ script $(tty) &
    |
    |   何とも微妙な事になる。先ず & で起動しても script は停止してしまう。
    |   仕様がないので fg に持ってくると今度は出力が二重化されている。
    |   うーん。
    |
    |   $ script $(tty) -c cat &
    |   としてみる。cat は起動されていない様だ。
    |   この状態で /dev/pts/8 に書き込んでも何も起こらない。
    |   といって fg で中にはいると C-z 等で抜ける事ができない。どうした物か。
    |   % どうも /dev/pts/8 に書き込むというのは cat に書き込むという事のようである?
    |   とも思ったがそういう訳ではないようだ。やはりちゃんと $(tty) の方に書き込まれている。
    |
    | b もし -nl で描画を設計しなければならないとすると結構骨である。
    |   echo 等で適当に出力する事ができないという事になる訳だから。
    |   何を出力するにしても .ble-line-* を通して描画するか、
    |   或いは stty を自分で設定して出力するかをしなければならない。
    |
    |   例えばログアウトや戻り値が 0 以外の時に [ble: hoge] 等と表示しているが、
    |   これらも全て適当な出力としてではなく "描画" として取り扱う様に注意をしなければならなくなる。
    |
    | c 実は stty をもっと細かく設定できるのではないか?
    |   というか入力と出力で別々に設定が出来た様な気がする。と思って stty --help を見てみたら、
    |
    |   入力設定:
    |      [-]icrnl      復帰 (CR) を改行 (LF) に翻訳
    |      [-]igncr      復帰 (CR) を無視
    |      [-]inlcr      改行 (LF) を復帰 (CR) に翻訳
    |
    |   出力設定:
    |    * [-]ocrnl      復帰 (CR) を改行 (LF) に翻訳
    |    * [-]ofdel      ヌル文字の代わりに埋める文字として削除文字を使用
    |    * [-]ofill      遅延のタイミングの代わりに埋める文字を使用
    |    * [-]olcuc      小文字を大文字に翻訳
    |    * [-]onlcr      改行 (LF) を復帰改行 (CR-LF) に翻訳
    |    * [-]onlret     改行 (LF) が復帰 (CR) として振舞う
    |    * [-]onocr      1桁目の復帰 (CR) を表示しない
    |
    |    nl            -icrnl -onlcr と同じ
    |    -nl           icrnl -inlcr -igncr onlcr -ocrnl -onlret と同じ
    |
    |   と書かれていた…。基本的に -nl で、問題のありそうな物を nl と同じ設定にする、
    |   という事にすれば良いのではないだろうか。
    |
    |   -nl: icrnl  → cr を nl に変換する (これが駄目)
    |   -nl: -inlcr → nl を cr に変換する (これはその儘でないと駄目)
    |   -nl: -igncr → cr を無視しない (これもその儘でないと駄目)
    |   -nl: onlcr  → 出力の nl を cr nl に変換する (これもその儘)
    |   -nl: -ocrnl → cr は nl にしない (その儘)
    |   -nl: -onlret → nl は cr として振る舞わない (謎)
    |
    |   結局 -nl -icrnl とかすれば良いのでは??

    stty -nl -icrnl とするだけで済んだ。呆気ない事だった。
    また無事に問題が解決したので、
    accept-single-line-or-newline の判定の修正を行う。
    表示上の行数ではなくてコマンド内に \n があるかどうかで判定する。

  * ble-syntax.sh: 条件式 [[ ... ]] と配列初期化子内の文脈に対応、コメントにも対応 [#D0178]

    以下の問題はこの実装の後に確認したら直っていた。
    (そもそも何故この問題が起こっていたのかよく分かっていなかったが。)

    | 2015-02-17
    |
    | * [[ ]] の括弧が異なる色になる。
    |   "]]" は "[[" の色に合わせる様にしているのに…と思ったら、
    |   これに関してもコマンドとしての着色によって "[[" の色が後で
    |   上書きされている様だ。
    |
    |   取り敢えずコマンドとして解釈されない様に、
    |   ATTR_DEL を rword[0] に代入してみたが…。
    |   これだと [[ に対する引数を complete の規則で取り扱えない。
    |
    |   結局、正しくキーワードと解釈される事を期待して、
    |   "]]" に先に ATTR_CMD_KEYWORD を適用してしまう事にする。
    |   [[ ～ ]] の取り扱いは後で又考え直す事になると思う。
    |
    |   と思ったら今度は急に動かなくなった。
    |   先ず [[ まで入力した時点で初めの単語の長さが 0 になっている。
    |   更に ]] を用いて閉じると正しい長さにはなるが
    |   単語の種類がコマンドから引数に切り替わってしまう。
    |   また "[[ text " と入力すると最後の空白が単語として認識されている。

  * <bug> invalid nest " $()" の先頭に for を挿入した時 [#D0177]
    →これは寧ろチェックのコードの方が誤っていた。nest の形式の変更に追随していなかった。

  * 複数行コマンドの履歴 [#D0176]

    複数行のコマンドの履歴について何とかする…。eval -- ''... に置き換える等。
    読み取り時に負荷になる?

    →複数行のコマンドを履歴に登録する時には eval -- $'' の形式にする事にした。
      これは printf %q を用いて出力する事ができる。
      読み取りの際には history-load の awk で ^eval -- ... に対して一致させる。

    保存する時には printf %q を用いる。bash-3.0 でも bash-4.3 でも $'' の形式になる様だ。

    意外と問題もなく直ぐに実装できた。
    これで複数行のコマンドも心おきなく編集・実行できる。

  * <bug> 表示の属性の更新がうまく行かない事がある。 [#D0175]

    例1: for ((abc)) の a を消すと bc が (( と同じ属性になる。
    例2: for (()) の (()) の中にカーソルを移動して中身を書くと )) の属性が中身と同じになる。

    挿入や削除のあった箇所で sgr の再設定がされていない様子。
    これは見たら直ぐに分かって修正できた。

  * カーソル移動 [#D0174]

    複数行に渡っている場合には up down で中を移動できる様にする。
    カーソルが一番上にある時に up を押した時に前の履歴項目に移動する。

    →一通り対応した。

    従来の kill-forward-line, kill-backward-line, beginning-of-line, end-of-line は
    kill-forward-text, kill-backward-text, beginning-of-text, end-of-text に移動。
    新しく kill-forward-line, kill-backward-line, beginning-of-line, end-of-line,
    forward-line, backward-line, forward-line-or-history-next, backward-line-or-history-prev を実装。
    newline, accept-single-line-or-newline の実装。

  * ble-syntax.sh: $[...] の形式に対応 (何故か bash の説明には一切載っていないが使える)。 [#D0173]

  * ble-edit.sh: printf %()T を用いた実装の導入、PS1 \D{...} に対応 [#D0172]

    | 2013-06-12
    | * <bug> ps1, \D{format} に対応していない。

  * <bug> 編集文字列の行数が変わった時に info.draw の内容がずれる [#D0171]

    これは info.draw の問題というよりは寧ろ
    .ble-edit-draw.update の方の問題の様に見える。
    → .ble-edit-draw.update の側で正しく描画領域を確保して描画する様にしたら直った。

2015-02-24

  * 描画ちらつき [#D0170]

    未だちらつく。全体を再描画するのではなく変更部分だけ更新したい
    先ず、開始時に bash に編集文字列を消されるのに対抗して再描画するのは
    bleopt_suppress_bash_output=1 である今必要はないと思って省略しようとしたら…
    元からちゃんと bleopt_suppress_bash_output を見て省略していた。

    とするとちらつくのは専ら再描画の為に一旦全体を消してから
    全体を再度出力し直している事による。
    現在は実装を一新したので変更のあった部分だけ出力する様に変更を図る。

    現在の実装について確認する。
    特に文字列の座標計算と表示内容の構築を行っているのは以下の関数である。
    .ble-line-text.update-positions
    .ble-line-text.construct
    もう少し関数に細分化・分散していると思っていたが意外とコンパクトに纏まっている。
    現在、update-positions は construct から呼び出されるので直接外部から呼び出す事は無い。
    (むしろ外部から呼び出すと update の回数がずれて
    二重に shift を実行してしまって全体を計算し直すことになったりして良い事は無い。)
    つまり、実質的に interface は .ble-line-text.construct だけという事になる。

    計算結果は現在は専ら .ble-line-text.construct の戻り値を介して取得している。
    しかし、外部からもっと簡単に様々な情報にアクセスする事ができるようにしても良いと考える。
    幸いにしても .ble-line-text.construct の呼出元は一箇所しかないので、
    簡単に interface を変更する事が出来る。


    取り敢えず更新の必要な範囲についてだけ更新を行う様に変更する事を考える。
    実際には文字列の挿入や削除などの場合でも文字列は移動するだけだから ICH や DCH でもっと
    賢く再描画する事も可能かも知れない。
    しかし、取り敢えずの所は移動する文字についても完全に再描画する事にする。
    また、実際に必要とされる文字列についてはの /update で計算するのではなくて、
    使う側が必要になったら構築を呼び出す様に変更する。

  * <重い> 改行を挟んでいれば編集は軽くなると思っていたが軽くない [#D0169]

    update-positions は途中で終わると考えていたが、違うという事なのか?
    実際に調べてみた所 update-positions や highlight はちゃんと更新の必要がある範囲で終わっている様だ。
    試すと明らかに挿入が遅い。末端に文字列を書き込んでいる時にはそんなに重くないのに、
    改行を挟んでいる所に文字列を書き込むと遅い。
    再度試してみたが、そもそも内容が長くなってくると重いのは仕方がないとして、
    やはり途中に挿入するのが特に重い。

    試しに syntax を止めてみたら途端に滅茶苦茶軽くなった。
    syntax が full に走ってしまっている可能性がある…。
    また syntax を入れてみて試してみる。
    やはり死ぬ程遅いが、ble-syntax-highlight+syntax が返す更新範囲はそんなに大きくない。
    次に ble-syntax-highlight+syntax の中身を覗いてみる。
    何と解析が最後まで走っている事が判明した…。

    と思ってよく見てみると _ble_syntax_stat の shift に失敗していた。
    これを直して再度試してみる事にする。未だ最後まで走っている…。
    もっと調べてみるとそもそも dirty-range 拡大が最後まで走っている様だ。
    どうも word による dirty 拡大が連鎖で起こっている様子だ。

    そもそも dirty 拡大の時の拡大領域の値が +1 されているのは何故だったか良く分からなくなった。
    もともとは、その当該要素も確実に再解析の対象になる様にという事だったとは思うが、
    その時点での stat の値が一致していれば直前までの解析で良いのではないか? それでは不十分なのか?
    という事になる。というかそもそも dirty 拡大が必要なのは何故だったか?

    もしかすると word の古い取り扱いに関連していたのかも知れない。
    でもそうだとすると今回新しく word による dirty 拡大をした理由も何だか良く分からなくなる。
    もう少し落ち着いて考える。参照先が消滅している場合にはその stat は無効になる、と考えるのは自然である。
    例え解析の結果によって stat が全く同じ値になったとしてもこれは前の stat と同一か? と言えば異なるとした方が良い。
    とするならば解析範囲の拡大を行う事によってこれに対応するのではなくて、無効になった stat を削除すると言うのが正しい対処法ではないのか?
    word に対する dirty 拡大はもう少し異なる状況である。
    word については解析中断の条件に入っていないので word の情報を消したとしても無意味である。x
    抑も word の先頭が消滅・或いは無効化した時に word が更新された事を検知したいというのが目的だった。
    もし dirty 拡大をしていないと word の先頭が消滅・無効化した時でも再解析によって word の途中で
    一致した文脈状態になった時に其処で解析が終了してしまう。
    その時に _ble_syntax_word_umin _ble_syntax_word_umax に登録されないという問題が生じる。

    でも _ble_syntax_word_umin, _ble_syntax_word_umax に登録するという目的であれば、
    dirty-range 拡大によって無理矢理に解析をやり直させるよりは良い方法がある様に思う。
    無理矢理解析を行わせるように成っている為に必要のない所まで再解析・単語更新を強いる事になる。
    例えば、"$(echo hello world)" において先頭に a を挿入した場合、dirty 拡大を行っている場合、
    echo や hello, world 等までも再解析の対象になり、また _ble_syntax_word_umin の対象になる。
    実際に考慮に入れるべきなのは a"$(echo hello world)" という全体に対してのみの筈だ。
    (もし挿入によって文脈構造が変化する場合については echo hello world も自然に再解釈の対象になるので問題ない)。

    単語内部で更新が起こったかどうかによる判定は別に行うべきではないかと考える。
    と思って確認してみたが、既に単語内部で更新が起こった場合については _ble_syntax_word_umin に登録する様になっていた。
    これについては、念のため不等式を変更して word 先頭で編集が起こった場合にも対応する事にした。

    さて今回の変更で dirty 拡大を完全に廃止した事になるが、
    これによって従来動いていた物が動かなくなってはいないか確認するべきである。
    取り敢えず、編集のあった単語について正しく再解析が行われているかどうかについて確認を行う。

    - 色々試すと、単語の先頭に文字列を挿入しても _ble_syntax_word_umin に登録されなくなった。
      謎だ。と思ったら j を登録すべき所 i を登録していた。
      更に、一番最後の点 (index iN) を更新していなかった。
      文字列の末端でも状態を記録する為、一番最後の点まで確認しなければならないのだ。
      これは取り敢えず解決された。

    これに関しては dirty 拡大の取り扱いを止める事によって解決した。
    これで途中の編集に対して末端まで解析を実行する事は防げた。
    今迄 dirty 拡大を行った元でテストしてきたが、これがないと解析を行うべき所で解析されないなどの問題が
    今後発生するかもしれない。しかし、それはまたその時に対応する事にする。

    しかしながら、多少解消はした物のやはり途中に対する挿入は遅い。
    これは結局 shift をする為にループを回しているのがいけない様に思う。
    末端に挿入する場合には shift を確認する範囲は小さくなる。
    しかし初めの方に挿入する時には文字数と同じ数だけの shift のチェックを行わなければならない。
    何か簡単に shift が実行できてしまう様なデータ形式を思い付けば良いが、
    そうでなければこれは仕方がない。shift が遅いという新しい項目として残してここで終わりにする。

  * <bug> 文字削除時 invalid nest の assertion に引っかかる。 [#D0168]
    invalid nest に引っかかる。
    再現: history で l "$(echo hello)" を出して "$ の直前に文字を挿入。その後文字を削除。
    別に history でなくても起こる様だ。

    dirty 拡大に代わり stat を削除する様に変更と言いつつ、
    stat の該当項目に -1 を代入していただけなのが災いしている?
    良く考えたら -1 既に "より上位の nest が存在しない" だとか "今は word の中ではない" という意味だから、
    本当は良くない。でもそうだとしても nest のチェックに引っかかるのかどうかというと疑問な気はする。
    取り敢えず本当に削除する様に変更して様子を見てみる事にする。
    →出なくなった。考えるのが面倒なのでもし今度出たらその時に考える事にして此処で終わりにする。

  * <bug> 編集内容が零文字になった瞬間に改行が起こって表示が消える。 [#D0167]

    調べてみると編集文字列が "" になった瞬間に
    _ble_line_x _ble_line_y が 53 1 という変な値になっている。
    と思ったらこれは .ble-line-info.draw による表示の位置である。
    しかし、何故編集文字列が空になった時にだけ .ble-line-info.draw の
    位置が _ble_line_x に代入されているのだろうか。
    % と思ったがそれは当然である。
    % 変更点があって文字が描画された時には umin<umax なのでその前に描画が為されている。
    しかしそれでも変だ。では何故 "" になるまでは _ble_line_x に別の値が代入されているのだろう。

    別に文字が "" にならなくても末端から削除をしている時は
    新しい文字を描画する必要はないので umin==umax になっているはずである。

    何だか良く分からないのでまた別の方向でも調べてみる。
    部分更新ではなく、常に全体を更新する様にしてみる。
    →全体更新であっても勝手に改行が入ってしまう様である。
      もしかして何処かにデバグ用に埋め込んだ echo があるのか?
    →どうやら bash がエラーを出力していた様だ。
      何と echo 11.8 "$_ble_syntax_word_umin $_ble_syntax_word_umax" で 0 0 が出力される。
      _ble_syntax_word_umin の代入箇所を探しても 0 になる様な箇所はないのだが…。
      と思ったが分かった。削除した時に _ble_syntax_word_umin の shift によって
      有限の値だった物が 0 になっている。

      これが起こるのは仕方のない事なので、これに対して特別に対策を取る事にした。
      更新しようと考えていた単語が消滅した時には _ble_syntax_word_umin を ++ する。
      それによって対象の単語が一つもなくなった場合には -1 を代入する。

    これで直った。しかし、描画の際にエラーメッセージが消されてしまうというのは厄介な事である。

  * <bug> 改行しても先頭がコマンドになっていない [#D0166]

    何と [[ ${#BASH_REMATCH[0]} =~ $'\n' ]] としていた。当然 # は不要である。
    これは直ぐに直った。

  * <bug> _ble_region_highlight_table で空欄になっている箇所がある。 [#D0165]
    echo " と入力した時の空白に対応する部分。

    これは function ble-syntax/highlight/set-attribute の中で
    既に設定されている物と同じ値かどうかの確認の際に、
    数値として比較していた為に空欄と 0 が同一視されている事による物であった。
    修正した。これは無事に 0 が代入される様になった事を確認した。

    それと共に _ble_syntax_attr_umin における色の既定値を正しく計算する様にした。
    (実際には問題にならなかったかも知れない。
    つまり _ble_syntax_attr_umin は必ず attr の設定されている点が設定される様な気がする。)

  * <bug> 単語の属性適用が後ろに続く単語にも続いている。 [#D0164]
    単語の分割はちゃんとできているのに不思議だ。
    これは属性適用の側のバグだと思われる。

    再現:
    1 以下を先頭から順に入力する
      echo "$(less hello world)"
    2 "$( の直前に文字を挿入する
      echo a"$(less hello world)"
      この時 less の属性が less hello world 全体に適用される。
      その他の部分の着色については問題はない様に見える。

    取り敢えず属性適用の部分で何が起こっているか調べようとすると…。
    属性適用が起こっていない様だ。やはり再度試しても呼び出されていない。
    (よく考えてみれば _ble_syntax_word_umin はこの範囲を含んでいないので当たり前である。
    また、これは期待した動作でもある。この部分は変更していないのだから。)
    さて、この時に何故表示内容が崩れてしまうのか。。

    また、不思議なのは先頭にあるコマンドの着色がそのまま後ろに適用されてしまう点である。
    つまり、一旦 word による属性が全て解除された後に word による属性が適用されない、という訳ではない様だ。
    _ble_syntax_attr が削除されているという事だろうか。
    shift の際に属性が飛んでしまうという事なのか? shift ではちゃんと削除された場所以外は保持している筈なのだが。
    試しに _ble_syntax_attr の中を確認してみる。_ble_syntax_attr の中は正しい値になっている。
    という事は adapter での繋ぎ替えに失敗している? 念のため _ble_region_highlight_table を確認する。
    これも正しい値になっている。という事はやはり adapter が怪し。

    今度 _ble_highlight_layer_adapter_buff の中を出力させてみたらどうやら、
    問題は a を挿入前の時点で既に発生していた様だ。
    $( とした状態で順次入力を行っていくと常に最後にエラーの赤い印が付いた状態で入力していく。
    そうするとどうやら属性 0 が全てはぎ取られていく様だ。
    また遡って調べてみようと思ったが、_ble_region_highlight_table の時点で正しい状態だったから、

    やはり adapter の中での更新が問題な様に思われる。
    と思ったら見つけた。gprev に常に 0 が入っていた。
    これは全体に対して _ble_region_highlight_table を読み出していた時のままになっていたという事だろう。
    i1>0 の時には i1 直前の gprev を読み出す様にした。
    これで a を " 直前に挿入した時の色付けは正しくなった。

    しかし、今度は何故か入力していった時の色がおかしくなった。
    と思ったがこれは当然の事である。部分更新なので途中から出力している。
    それなのに前からの続きとして出力してしまっているので SGR が出力されていない。
    これは ble-edit-draw.update 側を修正する。
    これで正しく動作する様になった。

    意外と修正に手間取った。

  * <bug> _ble_syntax_attr の中に "BLE_ATTR_ERR" の文字列が混入している。 [#D0163]
    一応算術式評価では BLE_ATTR_ERR の中を読みに行くので問題はないとはいえ、その様に設計したつもりはないので修正するべき。
    →これは parse の末端で起こっていた。修正した。

2015-02-23

  * 過去の ToDo について改めて整理を行う [#D0162]

    既に自然に実装された物、解決した物、或いは実装する事に意味が無くなった物などを整理する。

    | 2013-06-12
    |
    | * ble-decode-byte:bind の先頭でプロンプトを再描画する必要がある version の境を調べる。
    |   →これは bleopt_suppress_bash_output の実装で余り意味がなくなった。
    |     bleopt_suppress_bash_output=1 で問題が起きていないので、
    |     今後は bleopt_suppress_bash_output= について積極的な最適化をする事はない。
    |
    | * <bug> ウィンドウサイズを変更するとプロンプトが bash の表示する物になる
    |   これはウィンドウサイズを変更した時に bash が自動的にプロンプトを再描画する為。
    |   SIGWINCH を trap して自前で描画し直せばよい?
    |
    |   2015-02-09 bash-4.3 で試したが問題が再現しない。
    |
    |   2015-02-24 これも bleopt_suppress_bash_output=1 を実装したので
    |   今後はこの問題が発生する事は無いのではないかと考えている。

    これらは出力関連の問題であったが、bleopt_suppress_bash_output の実装により余り意味が無くなったので削除する。

    [Done]

    | 2013-06-10, X7 解析器
    |
    | # bash script の解析器を作る。
    | # これは syntax-highlight, complete 等から用いる。
    |
    | 先ず、シェルスクリプトの文法について整理する。
    |
    | !   履歴展開
    |     ! に非空白の文字列が続いている時
    | "   二重引用符の開始
    | '   単引用符の開始
    | `   コマンド
    | $'  引用符の開始
    | ${  パラメータ展開 {} の開始
    | $(  コマンド置換
    | $(( 算術式置換
    | $他 パラメータ展開
    |
    | コマンド修飾 (コマンドよりも前に来る事ができる物)
    |   [0-9]*(>|>>|&>|&>>|<|<>)(&[0-9]+|arg)
    |   [<>]( プロセス置換開始
    |
    | コマンド
    |   ((  算術式の開始
    |   [[  条件式の開始
    |   {   重文開始
    |   (   サブシェル開始
    |   aaa=hoge
    |   aaa[]=hoge
    |   aaa=(hoge)
    |     コマンドが続く
    |   time
    |   time -p
    |     コマンドが続く
    |
    | ; & | && || |&
    |   コマンドが続く
    |
    | ;; ;& ;;&
    |   case パターンが続く
    |
    | ※incremental に解析できる様に再帰呼び出しなどは避けたい。

    この中で実装されていないのは
    - time -p
    - aaa=(hoge), 他に aaa+=(hoge) というパターンもある。
    - ;; ;& ;;& の後に case のパターンを受ける
    - [[ 条件式の文法に正確に対応していない
    等である。その他については (多少の問題点は残るが) 実装してある。
    上記の物に関しては、より最近の文法対応リストに追加しておく事にする。

    | 2013-06-09
    |
    | * split, 書きかけたけれど結局使っていない関数
    |   function .ble-text.split {
    |     local GLOBIGNORE='*'
    |     test -n "${3+set}" && local IFS="$3"
    |     eval "$1=(\$2)"
    |   }

    これはどうでも良い。最近では手で書いている。というか手で書いた方が楽だ。

    | * ble-decode-char: cmap+default.sh を統合する?
    |
    |   改めてコードを見てみたが、それ程サイズが大きい訳でもないので、
    |   ble.sh の中に埋め込んでしまっても良いかも知れない。
    |   しかし、ユーザにカスタマイズの余地を残す、という意味では別のファイルになっていた方が親切である。
    |
    | * ble-decode-char:
    |
    |   これをユーザの側で生成するのには時間が掛かるので、
    |   予め作成しておいた dump ファイルも一緒に配布するのが良い。
    |
    |   連想配列を使う版と使わない版の二種類だけで良い。
    |   と思ったが、連想配列を使うか使わないかが影響を受けるのは、
    |   cmap の側と言うよりは keyname の方なので、元々巨大ではない。
    |   keyname の部分だけは ble.sh に統合してしまうと言う手もある。
    |
    |   *.dump についても統合してしまうという手もあるが、
    |   これについては中身が巨大なので余り統合する気にはなれない。
    |   (でも、最終的には統合した方が綺麗かも知れない。)
    |
    |   もしも統合しないのだとしたら、何れにしても複数ファイルになってしまう訳だから、
    |   cmap+default.sh を ble.sh 内部に統合する意味も余り無い…。
    |   というか、dump を一緒に配布する場合、
    |   そもそも cmap+default.sh を実行する事はない筈である。
    |

    ble.sh は益々肥大化しているのと、これからも様々な設定ファイルが増えていくだろうと予想されるので、
    single file で提供する事はもう考えない。

    | * <bug> キャレットが編集文字列の先頭にある場合、prompt の最後の文字の SGR が反映されない。
    |
    |   これに対応する為には prompt の指定から SGR を抽出するしかない。
    |   普通は prompt の最後の文字は空白にする (本当か?) ので気にしなくても良い気もするが。
    |
    |   これを真面目に実装するには二通りの方向性が考えられる。
    |
    |   一つは zsh の様に PS1 の色・スタイルの指定を %[] の中でやって貰うという方法である。
    |   これならば TERM に依存せずに解析できるので良い。但し、これは bash に非互換なので、
    |   bash から何も設定を変えずに移る、という事ができなくなる。また、% の指定に対応し始めると、
    |   その他の zsh の指定についても対応しないと収まりが悪い。全て実装しようと重うと大変である。
    |
    |   もう一つは PS1 を頑張って解析して、ESC [ ... m から SGR の指定を取り出す方法である。
    |   現実的には ESC [ m 以外で SGR を解釈する端末が存在するとは思えないから、
    |   これでも良い気がする。

    これも bleopt_suppress_bash_output=1 の実装により重要性が低下した。
    一応 bleopt_suppress_bash_output= の問題点として残して置くが、簡単な一行の説明に収める。

    | 2013-06-08
    |
    | * <bug> source を実行している間に C-c をして中断しようとするとその儘動きが止まる。
    |   通常のループなどで時間が掛かっている場合に C-c で止まる様にするには
    |   trap return INT 等とすれば良かったが、source の内部で時間が掛かっている場合には、
    |   C-c で止めようとするとそのまま全体の動きが止まってしまう様である。
    |
    |   序でに関数内のループで時間が掛かっている場合に関しても調べてみたが、
    |   こちらは C-c で正常に中断する事が出来るようである。
    |
    |   + 2013-06-11 12:29:07
    |     改めて試してみたら、ちゃんと停止はする様である。
    |     accept-line.exec でループ構文を使わずに再帰に書き換えたがその事が影響を与えたかも知れない?
    |     或いは、これは前に試した時の勘違い?
    |
    |     しかしながらまた例によって .ble-stty.enter が実行されていない様である。
    |     何故か分からないが処理の流れ的には正しくできている気がする。
    |     しかし、処理の順番が入れ替わっている気がする。
    |     exec.recursive から先に出力されるべき物が、プロンプトの表示よりも後になっている。
    |     後で再度調べ直す必要がある?

    これは gexec の実装の際に色々試して trap - DEBUG の方向性で解決する事にした。
    これによってどんな場合でも確実に停止できるのではないかと考えている。
    具体的に source を使って検証した訳ではないが、関数では充分にテストしたので大丈夫だと考えている。
    もし問題があったら改めてその時に考える事にして、この項目も削除する事にする。

  * <bug> info.draw で特殊文字が改行に跨っている時の座標計算 [#D0161]

    例えば CR などの特殊文字を ^M と表示しているが、これが改行に跨って表示される。
    その時の座標がずれる。(そもそも改行に跨って表示されるのが誤り?)

    →空白を挿入する様にしていたのだが、挿入する空白の長さを空白を挿入した後の値で計算していた。
    つまり空白を挿入する必要がないという解釈になっていた。式の評価の順序を正しい物に変更した。

  * <bug> update-positions で dend-dbeg が負になると警告が出る [#D0160]
    →プロンプトの内容に変更があった際に初期位置 x y が変わる。
    その時の dbeg=0 の設定の際に dend や dend0 を正しく設定していなかった。

2015-02-22

  * <bug> word の内容変化を検知する事のバグ [#D0159]

    - transpose-chars 等を用いた場合 word の内容が変化しても word の着色が更新されないのではないか?
      →コードを見た所、単語内部で変更が起こった場合にはちゃんと ble-syntax/parse/touch-updated-word している。
      単語の終端点を巻き込んだ変項の場合には、否応なく parse で変更される筈なのでここで touch する必要はない。
      つまり、現状のコードでも問題が起こる事はないように思われる。

      と思ったが正しくできていない。
      echo 'd'is't' で真ん中の is を tranpose して見たが、どうも期待通りに動いていない様だ。
      と思って調べたら、そもそも transpose した時には単語の切り出し自体に失敗している様だ。
      長さ 0 になっている。途中で解析が終わっている為であろう。

    - 解析が単語の途中で終わった時に word が壊れない様にする為には?

      これは真面目に考えなければ対応方法が分からないので後で考える。
      (そもそも単語が終了した所で前の位置 word[wbegin] に書き込むというのが混乱の元なのかも。
      データ形式から考え直した方が良いのかもしれない。)

      眺めていたら簡単に書き換えられそうだったので書き換えた。
      _ble_syntax_word[]は単語の先頭ではなくて単語の終端に置く事にした。動いている。
      _ble_syntax_word を用いた dirty 拡大にも対応した。
      後 dirty 拡大の部分に問題を見つけたのでその部分も修正した。

  * <bug> .ble-line-info.draw を使った時行がずれる [#D0158]

    これは新しい描画関数で出力する様にした時に出力の順序を変えた所為だった。
    出力をバッファリングしている時には、その最中で別の複雑な関数を呼んではいけない。
    内部で独自に出力を行うかも知れず出力の順序
    (と _ble_edit_x, _ble_edit_y の参照順序) が変わるからである。

  * <bug> for や do に色が着かない? [#D0157]

    _ble_syntax_word_umin, _ble_syntax_word_umax の問題の様だ
    → ctx-redirect/check-word-end で wbegin=-1 を設定した後に touch していた所為で、
    _ble_syntax_word_umin=-1 になってしまい、範囲が無効化されていた様だ。
    ble-syntax/parse/touch-updated-word に assertion を追加した。

  * 描画の高速化2: 現在の不具合と layer に対する対応 [#D0156]

    | x 現在 update-positions で位置が変化しただけの部分に対しても表示用の SGR 付き文字列を更新している。
    |   これは省略できる筈。改行やタブなどで出力内容に変化のある部分については別に記録して後で合成して表示する。
    |
    | x transpose-chars 等を用いた場合 word の内容が変化しても word の着色が更新されないのではないか?
    |
    | x word の属性が解除されてもそれが表示に反映されない。

    先ず、word の属性が解除された時の動作について考える事にする。これは layer の実装方法にも関わってくる。
    word の属性が解除された時、元々其処にあった属性を復元したい。
    これは _ble_syntax_attr を参照して再度値を書き込めば簡単に実現はできる。
    しかし、今後 ble-syntax とは独立した形で様々な着色を行う事になると思われる。
    その際に _ble_syntax_attr やら更にその後に付加される word の着色に対して毎回参照したり計算したりするのは現実的ではない。
    様々な着色を分離した形で実装する為にはちゃんとした仕組みが必要になる。

    改めて考えるにこの問題は、「word の着色をしても、概念的にはその下には syntax による着色が残っている」のに、
    それが word の着色によって失われてしまっているという事である。つまり、syntax による着色は依然として
    有効であり、word の着色が戻った時にまた有効になる物であるのに、それを上書きして消してしまっているという事である。
    本来は、word の着色やら syntax の着色やらを全て内部的に保持しておいて、表示の時に有効な物を選択して着色するという事が必要である。
    つまり、簡単に言うと layer 機能が必要になるという事である。

    しかし、layer 機能を実装するに当たって考えるべき事がある。効率である。
    現状で何とかぎりぎりで現実的な速度で表示できるようになっているが、
    layer の機能を愚直に実装した場合、現在の高速化に使っている方法がそのままでは使えないのでかなり重くなる。
    現在の方法を何とか適用しようとしても結構面倒な操作が必要であり、どれぐらい遅くなるかは未知数である。

    ここでは複数の方法について考え、また、layer としてどの程度の機能が必要に成るであろうかを整理する。
    もしかすると完全に layer の様なおおがかりな仕組みは実装しなくても良いかも知れない。

    a 始めに考えた方法は、各 layer で着色された文字列を保持しておき、
      表示の際に有効な layer の部分をぱちぱちつなぎ合わせて実装するという物である。
      しかし、これは同じ layer に属する部分は連続している筈だ、という仮定に基づいている。
      様々な layer が滅茶苦茶に混ざり合っている場合には却って遅くなる。
      また、表示の際につなぎ合わせを実行するので部分更新であっても
      文字列の長さ (というか正確には上位 layer の着色範囲の数) に比例する時間が必要になる。

      そもそも当初は「選択範囲の着色」や「括弧の対応」の着色が念頭にあった。
      これらは精々1つか2つの着色範囲しか持たないので、
      どんなに文字列が長くなったとしても繋ぎ替えの操作の階数は一定数に保たれる。
      しかし今後「各コマンドに対応した引数の着色」などに対応するとなると、
      これらも新しい layer として実装する必要があるし、かつ、
      文字列の長さに比例してつなぎ目も増えていく。

      部分更新やカーソル移動だけでも一定の繋ぎ替えの操作が必要になるのは問題である。
      この方法は全く現実的ではない。しかし、この方法を改良すれば何とかなる可能性はある。

    b 次に考えた方法は各 layer について色の配列を保持し、
      それを用いて表示する側で最終的な文字列を一つ構築するという方法である。
      そして部分更新の際には、各 layer の変更範囲を集計して最終的な文字列自体を書き換える。

      これが一番自然な実装に思われるが多少問題点が存在する。
      「括弧の対応」の場合には離れた2点で局所的な更新が実行される為、
      単純な変更最小点と変更最大点の間を全て更新するという方法にしていると、
      変更範囲が無駄に大きくなってしまう。特に編集文字列全体を囲むような括弧の場合に
      毎回全体を更新するのと同じ事になり非現実的である。

      この場合の対策は二つ考えられる。
      1 一つは変更範囲の管理方法を単純な最小点・最大点のペアではなくもっと詳細な物に変更するという方法。
      2 もう一つは、「括弧の対応」や「選択範囲」などの広い領域を cover する layer の場合には、
        自身の更新の特性を知っている筈で、そちらに編集文字列の update を任せるという方法。

      普通は 1 の方向に進みそうな物だが、これだと実装が複雑になる。
      というかどの様なデータ形式にするのが良いのかも良く考えなければならない。
      単純に (begin,end)* の様な構造にすると例えばしましまに更新した時に更新範囲が複雑になる。
      しましまに近い時は複数の範囲ペアをくっつけて一つの変更範囲ペアにしてしまう方が効率が良い。
      しかし、この様にすると変更範囲の合成も無駄に複雑になる。却って合成操作に計算時間が掛かるかもしれない。
      というか 1 と 2 を組み合わせて、(1) 複雑な着色をする物に関しては (begin,end) を一組だけ報告させて、
      (2) 離れた点での着色になる物に関しては (begin,end) を分割して報告させるなど、
      変更範囲の報告を各 layer に任せてしまえば良いのかも知れない。
      変更範囲ペアがそれ程沢山にならないのであれば
      変更範囲の合成についても複雑な事を考えずに素直に実装して良い。

      それでも未だ微妙な点がある。
      b.1 変更範囲が分かったとしても、どの layer が有効なのかの情報がないので、
        描画文字列を更新する際に上の layer から順番に描画属性が適用されているかを確認しなければならない。
        それも各文字についてこれを実行する必要がある。

        しかし、これは別の方法を用いたとしてもループの順序が異なっているだけで等価な事をする
        必要があるのかも知れない?? でもこの方法だと b.2 に挙げる様な layer の最適化が適用できない。

        変更範囲 pair に layer 情報を付加して対策するとしても、
        layer から着色が削除された場合については、
        結局着色が削除された部分についてどの仮想の layer が有効になるのかを計算しなければならない。
        特に下層の layer が複雑になっているかもしれないし、
        隣の変更範囲 pair と地続きになっている可能性を考えてくっつける事もできるかもしれないし#1、
        …など色々と再計算が複雑になってしまう。layer 情報を付加しても効果は限定的であろう。
        # #1 はこういう事である。層3 の属性を削除した時。更に層2、層1についても変更がある。
        # 更新範囲 <22><1><111> (更新の際に参照する範囲)
        # 変更操作 <33333><111>
        # 層3      .......
        # 層2      <-->
        # 層1        <-------->
        # 変更操作としては二つの範囲であるが、
        # 実際に更新の際に参照する属性が載っている部分はより下層で分裂している。
        # 結果として三つの変更範囲が得られる事になるが、よく見ると<1> と隣の <111> の
        # 範囲は同じ layer を参照しているので無駄に範囲が分裂している事になる。
        # これらの無駄に分裂した物をくっつける事ができるか、或いはくっつけた方が良いのかという事である。
        # この様な分裂は大した問題ではない様にも思えるが本当にそうだろうか。考えてみると、
        # 最大で全 layer での削除範囲の合計x2 個の無駄な分裂が起こる…やはり大した問題ではない気がする。
        # n^(layer 数) 等の様なスケールだったら考え物だった、編集箇所の数に比例する程度なら問題ない。

      b.2 region (選択範囲) だとか括弧の対応だとかはその着色を保持するのに配列を用意するまでの事は無い。
        region に関しては現在の mark と point だけで完全に記述できるし、括弧の対応に関しては
        配列の中は殆どの時に空である。というか、選択範囲の方も選択しない限り空である。

        これらの sparse な配列に対しても全て描画属性が設定されていないか確認するのは無駄だ。

      b.3 選択範囲が解除された時など、以前の状態に戻したくなった時に、
        また全て描画文字列を構築し直す必要がある。

        しかしながら、以前に計算したのと同じ物を計算するのは気にくわないという事を除けば、
        これについては大した問題点ではない様にも思う。というのも以前の状態に戻したくなるという状況は
        頻繁には生じないからである。

        これについてはおまけ的に解決できたら良いという指標で良いだろう。
        (これについて簡単な解決ができる方法の方が、
        将来的に別の問題が起こった時にも解決しやすい・汎用的だろうという程度の目安とする。)

    c 以上を踏まえて (もしかしたら却って非効率かも知れないが) もう一つの方法についても挙げる

      各 layer で「その layer 以下の描画属性を適用した状態の文字列」を管理する方法である。
      変更があった場合には、下の layer から順に変更範囲を上の layer に伝達し、
      下の layer は該当部分の変更を自分の持っている描画文字列に対して適用する。

      しかしこの方法は既に挙げた問題を解決できていない。多少実装が楽になるだろうというだけである。

      c.x1 複数の離れた変更範囲がある場合についての解決策にはなっていないので、
        結局複数の変更範囲 pair を扱う事になる。
      c.x2 次に、下層の layer の描画文字列の切り貼りをする為には、
        index 情報が必要 (各文字の表示にエスケープシーケンスを含めて何文字使っているか) であり、
        これらも独立した配列として管理しなければならない。
        例え選択範囲などの様な単純な描画属性に対してであっても、だ。
      c.o1 被覆されて実際には表示状態に変化を与えない下層の layer の更新が上部に伝達されない、
        というのは一つの利点ではある。しかし、その様な変化がある場合は稀であるし、
        結局内部的には下層の layer の保持する文字列に対する更新が行われている。

      少しこの方法に改良を入れて考えてみる。
      「その layer 以下の描画属性を適用した文字の配列」と考える。
      一番上の layer でなければ繋げた文字列をそのまま使うとは限らない。
      それならばそもそも繋げなくても良いのではないか。
      この様にしておけば index 情報を別に覚えておく必要はなくなる。
      パラメータ展開に index を指定するだけで任意の部分列を取り出す事ができる。
      これで c.x2 の問題はなくなる。

      | 但しカーソル移動をする時の為に index 情報は覚えておく必要がある?
      | とも思ったが、これも IFS= a="${cs[*]:i}" b=${#a} 等としてしまえば良い気がする。
      | そもそもカーソル移動は一回のキー入力に対して 1 回しか実行しないのだから、
      | 常に全ての位置についてのカーソル位置の為の index を保持している必要は全くない。
      | そればかりか、そもそも出力文字列に SCOSC SCORC を埋め込む形でカーソル位置を
      | 表現する必要性があるのかすら疑問である (一応この様にしておけば、何処か別の場所から
      | 出力があった場合 (や ble.sh の座標計算のバグがあった場合に)、
      | ずれても大丈夫というのはあるが。)
      |   という事なので毎回 ${cs[*]::i} 等として文字列を連結して長さを数えれば良い。と
      | 思ったが、連結までするぐらいであれば ${cs[*]::i}$SCOSC${cs[*]:i} とすれば良いだけの気が。
      | 所で、この方法に頼っている時に、文字列が長くなると効率二度の程度の影響があるかは
      | 気になる所である。一般に編集はそれ程の速度で行われる事は無いが、カーソル移動は、
      | キーボードの押しっぱなし等によって相当の速度で入力される可能性がある。従って、
      | 編集の際には効率的に問題にならなくても、カーソル移動の際の効率に影響を与える可能性は残る。
      |
      | 追記: 現状の実装で index 情報を記録しているのは元々は別にカーソル位置を任意に
      | 取り出す為ではなかった。これは、キャッシュした文字列を任意に切り貼りできる様に
      | する為の物であった。後で、これがカーソル移動の際に SCOSC を挿入する位置として
      | 活用できる事に気付いた為に使っているだけの事である (とは言っても他に "効率的" に
      | SCOSC の挿入位置を決める方法、または、カーソル位置の確実な復元方法は分からないが。)
      |
      | また、連結した文字列は一番最後の layer だけで保持する事にすればよい。
      | →そう思ったが、連結した文字列を後で再利用しようと思ったら結局 index 情報が必要になる。
      | index 情報を一緒に管理しながら既存の文字列を切り貼りするのと、
      | 最後のレイヤーが出してきた配列全体を連結するのとどちらの方が効率的かという話になる。
      | 配列全体の連結でもそんなに問題はないかも知れない?
      |
      | 少し時間を計測してみる事にする:
      |
      | a=({1..100000})
      | time IFS= eval 'b="${a[*]}"'
      | real    0m0.077s
      | bash の割に驚異的な速度である。
      |
      | time c="${a[*]::10000}""$ins""${a[*]:10000}"
      | real    0m0.200s
      | 多少時間が掛かる。でも 10 万の要素を連結している事を考えれば充分な速度だ。
      | コマンドラインに 100k も文字を書き込む事などない。10k でも多すぎる。
      |
      | index 情報によって文字列 b の中に於ける index が分かっている場合:
      | time c="${b::40000}""$ins""${b:40000}"
      | real    0m0.053s
      | 文字列にすれば滅茶苦茶速い、という訳でもない様だ。
      | (というかマルチバイトで記憶しているから文字数を数え上げなければならない、
      | という事なのだろうか?)
      |
      | 更に index 情報を用いているので、index 情報の更新も行わなければならない。
      | これだけ巨大な配列になってくると index 情報の shift にも相当の時間が掛かるだろう。
      | (何しろスクリプトで for でループを回さなければならない。)
      |
      | 色々考えるに index 情報を管理するのは効率的に駄目だ。
      | SCOSC でカーソル位置を管理したいと思う場合、
      | カーソル移動の際にも文字列を連結しなければならないのは惜しいが、
      | この辺りはカーソル移動を実際にやってみて遅ければ SCOSC は使うのを止めて、
      | ble.sh による座標計算を信用して update-positions のデータを元にカーソルの位置を動かす事にする。

      結論
      - 各 layer 毎に「その layer 以下で計算される描画属性を適用した文字の配列」を管理・更新する
      - 実装の為に描画属性を持たない文字の配列も用意する。
      - 連結済文字列をキャッシュするのはやめる
      - index 情報の管理も行わない
      - カーソル移動の際は以下の 2 通りが考えられる
        - 配列の連結を用いて SCOSC を埋め込む (毎回全文字列を出力する)
        - update-positions を信用してカーソルを計算した位置に動かす

      | 更に、もう一つ考えるべき事として各文字の一つ一つについて描画属性を付加するか、
      | 同じ属性の文字が続いている限りは描画属性の付加を省略するか、という事である。
      | 各文字一つ一つに対して描画属性を適用すると出力が無駄に長くなってしまう。
      | しかし、同じ属性の文字が続いている限りは付加を省略する、という形だと
      | 切り貼りをする際に切った点に新しく描画属性を追加しなければならないので、
      | 各点に於ける描画属性を別に管理する必要があるという事が問題になる。
      |
      | ユーザから見えなくても、余り汚い出力はしたくないので、
      | 各点に於ける描画属性を管理する方向性を考えたい。
      | さて、これはどの様に管理するのがよいかという事になる。
      |
      | A 一番簡単な方法は各点に於ける描画属性を配列に格納しておくという方法である。
      |   下層 layer から上層 layer まで、各層でその層以下の集約結果を配列として保持するという事である。
      |   しかし、これは update がある度に各 layer で描画属性の配列をコピー・書き換えしなければならず、大変だ。
      |   特に、選択範囲や括弧対応の場合にはこの様な配列を管理し、一々書き換えを行うのは非効率に思われる。
      |
      | B そうではなく、各 layer について "描画属性を返す関数" を実装してその中で最も適した方法で
      |   属性値を計算し返すようにするというのも一つの手である。
      |   複雑な色付けを行っている場合には、単に内部で描画属性の配列を管理する様にすればよい。
      |   さて、各 layer で独立に描画属性を管理する場合 (つまり、より下の layer の値について関知しない時)、
      |   下層 layer への問い合わせを順次行う必要がある (勿論、これは関数の呼出側で行う)。
      |   これの overhead についても多少気になるが、
      |   そもそも更新時の切り貼り自体そんなに沢山の箇所で行うとは思わないので、気にしない。
      |
      |   (寧ろ全ての点について描画属性を即座に返せる様に配列で管理するという A の方が無駄である。)

      結局、描画属性を後で必要とする頻度は小さいとして B を採用する事にする。
      つまり、各 layer について指定した位置での描画属性値を返す関数を用意させる。
      描画属性値が設定されず下位の layer に任せる場合には空文字列もしくは -1 を返させる。

      さて、この様な実装を行うと決めたからには、再度描画用出力の生成関数を実装し直さなければならない…。
      後、既に書いたコードも利用できる様に、既に書いたコードを利用する layer も作った方が良い。
      或いは先にそれを書いてから実装を始める。

      各 layer に関する関数名は ble-highlight-layer:*/* の形式にする。
      ble-edit.sh は複雑化して来たので、これらのコードは ble-color.sh の方に実装する事にする。
      ble-color.sh は当初 highlighter の類を記述する目的で作ったが、
      新しく ble-syntax.sh を作成した事で使われなくなった機能などが沢山ある。
      これらを整理・統合する目的もある。

      実装した。動いている様なので差し替えた。

    取り敢えず今回の実装で以下の項目は解決した。

    | x 現在 update-positions で位置が変化しただけの部分に対しても表示用の SGR 付き文字列を更新している。
    |   これは省略できる筈。改行やタブなどで出力内容に変化のある部分については別に記録して後で合成して表示する。

    元々の目的である

    | x word の属性が解除されてもそれが表示に反映されない。

    に関しては未だ実装していない。レイヤーの仕組みを整えたは良いが、各レイヤーを実装する必要はある。
    word の属性を設定しているレイヤーをどの様に実装するのが良いかはまた別の問題である。
    これについては項目を改めて後で考える事にする。

2015-02-21

  * 描画用のシーケンス構築を高速化する [#D0155]

    色々考えた結果、最終的に (a) 描画用のシーケンスと
    (b) TAB 等の位置を制御しながら出力する update-positions を合成しなければならないので、
    a, b の両方を高速に合成可能な形に改良する必要があるという結論に到る。

    update positions の側に関しては、
    出力の文字が事前に予測不可能な物は TAB 等限られているので、
    予測不可能な物に関してだけ合成時に特別な処理を行うという方向で行く。
    つまり、描画用の側で予測可能な文字についてのシーケンスを生成してしまう
    (予測不可能な物に関しては適当な可能性の高そうな文字列を入れておく)。
    update positions 側では出力する文字に関しては、
    特別な処理を行った物についてだけ記録を行う事にする。

    現状の update-positions の実装について

    | さて update positions では複雑な事を行っていて lc だとか lg だとかの計算も行っている。
    | これらの動作について今一度確認してからでないと update positions を弄れない。
    | 確認事項については以下の通り。
    | - lc lg の詳細な動作について。
    |   例えば行頭や行末での処理、複数文字で構成される文字の場合は?
    | - lc lg で計算した結果を使っている箇所は何処か?
    |   それらの場所に影響が出ない様に書き換える必要がある。
    |
    | 取り敢えず何処で使っているかについて調べる事にする。
    | 先ず update-positions の中で出力している物は lc lk lj g である。
    |
    | | - _ble_line_text_cache_lc については、update-positions 及びその中から呼び出される
    | |   save-cursor で設定されている。そして、.ble-line-text.construct で参照されて
    | |   変数 lc の戻り値を設定するのに使われている。lc は .ble-line-text.construct の戻り値か、
    | |   或いは編集文字列が空の場合にはプロンプトの構築によって計算された値になる可能性もある。
    | |   lc はそのまま _ble_line_cur 配列の第2要素(base0)に格納される。
    | |   _ble_line_cur[2] は .ble-edit-draw.update-adjusted の中で取り出されて、
    | |   .ble-text.c2s を通してから READLINE_LINE に設定される。
    | |
    | | - _ble_line_text_cache_lk は update-positions 及び save-cursor で設定される。
    | |   .ble-line-text.construct の中の初期の方に lk に代入されている。
    | |   lk は .ble-line-text.construct の中のループで参照されているが変更はされていない。
    | |   %%どうやら _ble_line_text_cache は lk の計算のキャッシュとして働いている様子である。%%
    | |   更に export する様なコードの残骸も残っている様だが関連するコードが見当たらないので、
    | |   これに関しては廃止されてから久しい、或いは、何か書きかけて取りやめたという可能性が高い。
    | |   さて、改めてよく見てみると lk は lg を抽出する為に使われている。つまり、
    | |   カーソルの一つ前の文字を出力する時に使う lg が何かを計算する為には、
    | |   カーソルの一つ前の文字の文字 index が必要になりそれが lk になっているという事である。
    | |   lk はその他の用途では使われていない。
    | |
    | | - _ble_line_text_cache_lj はコメントの説明を見てもこれまた何の用途の為にあるのか分からない変数である。
    | |   実際に使われている所を見ると、多分これは以前に高速化を行おうとして実装し書けて終わった機能である。
    | |   改めてもう少し解釈を書いておく事にする。現在の実装では全ての文字について一々計算を行っている。
    | |   しかし ASCII の印字可能文字が続いている場合には毎回計算しなくても位置や文字の計算は唯単に
    | |   increment して行って設定するだけである。なので、その様な場合には最後の ASCII 文字まで
    | |   計算を抑えておいて、最後の ASCII 文字までいった時にそれまで溜めていた計算を一気に行う事ができる。
    | |   lj は連続する印字可能文字の最初の位置を保持していると考えれば良い。
    | |   或いは、もっと実際的な機能としては次に本来の計算を実行するべき index という事になる。
    | |   これがコメントに書かれていた説明である。
    | |
    | |   しかしながら、一気に計算を行うと言っても、カーソル位置計算は簡単にはできないので
    | |   結局毎回計算をする事になっているという具合である。今は常に lj=i-1 の状態でループが回っている。
    | |   カーソル位置計算についても一気に行うコードを書いたら (或いは、単純な increment を続けられる
    | |   という事が分かる範囲を計算して、その範囲内だけで一気に行う様にしたら) lj を実際に遅延させるコードに
    | |   移行する予定であったのだろうと予想される。
    | |
    | |   何れにしてもこの変数は実装の詳細というか、最適化の為に用意した物であるので、
    | |   今回位置から実装し直すにあたってこの機能を継承する必要性はない。
    | |   この変数について実装は未だ不完全であるし、似たような機能が必要になればまた新しく考え直した方が良さそうである。
    | |
    | | - _ble_line_text_cache_g _ble_line_text_cache_ei
    | |   何とこの配列は現在は使用されていない。現在の実装では .ble-text-line.construct の中で
    | |   _ble_region_highlight_table から直接 g を読み取って使っている。
    | |   元々は任意のカーソル位置にある g を取得する為に使っていたという事だろうか。
    | |   しかしそれは _ble_region_highlight_table から読み取れば良い事だし、
    | |   そればかりか _ble_region_highlight_table からの lg の読み出しですら、
    | |   描画SGRと update-positions の合成のループを毎回するので、その中でおまけ的に処理している。
    | |
    | |   と思ったが、もしかするとこれは最適化によって消えた変数ではなくて、
    | |   最適化の為に導入しようとして結局導入には到らなかった変数なのではないだろうか。
    | |   _ble_line_text_cache_ei という似た様な位置で定義されていて使われていない変数があるので、
    | |   多分そう言う事だろう。これらの変数は未だ使われていない変数である。
    | |
    | | - _ble_line_text_cache_cs の意味は明確である。表示の為に出力される文字である。
    | |   使い方も単純で .ble-line-text.update-positions で値を fill して、
    | |   .ble-line-text.construct の合成のループで中身を読み出すという物だ。
    | |   上記の2行以外では参照も代入もされていない。
    | |
    | | - _ble_line_text_cache_x, _ble_line_text_cache_y は _ble_line_text_cache_lc
    | |   と全く同じ経路を辿って、別の関数で使われている。
    | |   つまり、cx cy という変数に一旦入って _ble_edit_cur に格納され、
    | |   その後其処から読み出されて使われている。
    |
    | まとめると、
    | - _ble_line_text_cache_x, _ble_line_text_cache_y, _ble_line_text_cache_cs
    |   が主な計算の目的である。
    | - _ble_line_text_cache_lc, _ble_line_text_cache_lk
    |   は左側にある文字の文字コードと sgr を求めるのに使う。
    |   文字幅などの情報は出力しない。
    | - _ble_line_text_cache_lj _ble_line_text_cache_g _ble_line_text_cache_ei
    |   は実装しかけて中断している機能の為の変数の様に思われる。気にしなくてよさそう。
    |
    | さて、次にしらべるべきなのは lc と lk の処理方法の詳細についてである。
    | - 左側に複数文字からなる文字があった場合や、
    |   改行があった場合の取り扱いはどうなっているのか
    |   →複数文字からなる文字があった場合にはその最後の文字を READLINE_LINE に設定している。
    |
    |
    | - 左側の文字の開始位置 (x y) の管理はどうなっているのか
    |   →これは単に文字コード lc から計算される幅を使ってカーソル位置を ESC [ D
    |   で後退させるだけという実装になっている。なので lc さえあれば良いという考えだ。
    | - 出力する sgr は本当に常に左側の文字の物で良いのか。
    |   もしそうならば何故 i-1 等ではなく lk という変数が存在するのか。
    |   →行頭の場合には右側の文字 (なければ空白) を READLINE_LINE に設定して
    |     READLINE_POINT=0 を設定する様になっている。
    |
    | * lc が "文字列" ではなくて単一の "文字" である理由
    |   READLINE_POINT に設定する値を計算する必要があるから。
    |   文字列であっても各文字についてバイト長を計算すれば READLINE_POINT を計算できるが面倒だ。
    |   単一の文字だけというルールにしておけば一回 c2bc を呼び出すだけで済む。
    |
    | * lj で計算を遅延している理由
    |
    |   これは行頭の文字が来た段階では右側に来る文字を予測できないからである。
    |   右側の文字が確定してから lc を計算する。
    |
    |   > 改めて見てみると lj 周りの実装が少し複雑になっている。
    |   > カーソル位置が行頭にあるのが何回か続くと lj が更新されずに続く事になる。
    |   > これは一体何の為の物だろうか???
    |   > 行頭が何回か続くとその後で一気に更新が実行される。
    |   >
    |   > lj が何の為にあるのか漸くわかった。これは「カーソルが行頭にある場合には
    |   > 左側にある文字ではなくて右側にある文字の情報を返す」という仕様に関係している。
    |   > 行頭に文字がある時には未だ次に文字が来るのか別の改行文字が来るのか分かっていない。
    |   > 右側に通常文字が来た場合にはそれで良いが、改行文字が来た場合には改行を出力する訳にも行かないから、
    |   > 代わりに空白文字を出力する事にするのである。そしてそれど同時に READLINE_POINT を 0 にする。

    現状の実装がどうなっているかについては大体分かった。一番処理を複雑にしているのは lc lk の計算である。
    然し、ここで思ったのだが何故 lc lk を毎回計算してキャッシュしているのかという事である。
    x や y に関しては初めから順に計算して累積していかなければ計算する事ができない。
    なのでカーソルを移動するたびに計算するよりは前に計算した物を再利用した方が速い。
    しかし lc lk に関しては x y cs のキャッシュさえ残っていればどの様な物になるかはその場で計算できる。
    ループの中で累積的に計算し、その時の状態をキャッシュする仕組みにしていると先読みができないのでアルゴリズム的に苦しくなるが、
    x y cs を全て update した後に必要な所だけ計算するという事にすれば先読みも何もあった物ではなく簡単に計算できる。
    それに分離した方が bleopt_suppress_bash_stdout に応じて計算するかしないかの選択もできる。

    取り敢えず x y cs だけを計算してその後でカーソル位置の lc lk だけを計算する様に簡単化した version の
    .ble-line-text.construct を作成してみる事にする。
    →様々なバグや bash の不具合が途中で見付かった為に随分と中断してしまったが、
      .ble-line-text.construct の単純 version は直ぐに実装できた。

    さて使ってみるとバグが出てきた。C-u 等をした時に表示内容が変になる。
    保持している文字列は正常の様だから、shift に失敗しているのではないかという気がする。
    と思ったが、そもそも送られてくる BLELINE_RANGE_UPDATE の時点で変だ。
    10 文字ある文字列の 5 文字目で C-u を実行した場合 (0 0 5) 等となる筈だが、
    (9 10 9) という値が入っている。というか、これは最後に追加した文字の分である。

    何処で変な事になっているのか調べる。
    先ず ble-edit/dirty-range/update の呼出を調べる。
    ble-edit/dirty-range/update 0 0 5 等となって正しい値が設定されている様に見える。
    では結果の _ble_edit_str_dbeg の類はどうなっているか? →これも問題ない。

    分かった。やはり .ble-line-text.construct が悪かった。
    dirty<=0 の時に shift が行われていなかった。
    (9 10 9) という物が表示されている様に見えていたのは、前回の shift の時に出力した物を見ていただけであった。
    dirty<=0 の時には shift がそもそも行われていないので、その前後に設置した出力にも引っかかっていなかったという事である。
    これを修正したらすぐに動くようになった。

    次に、.ble-line-text/update-highlight-layer を実装した。
    これは更新の必要のある部分だけ出力データを更新する物である。
    特に、色付けの変わった文字の部分について再計算を行う。
    現在は update-positions によって位置が変更された部分についても再計算を行っているが、
    これは将来的に削除して、update-positions による更新は別の所で処理する予定である。

    さて、新しく実装したはいいが動きが変だ。
    特定の状態にある時にカーソルを移動するだけでも位置がどんどんずれていく。
    と思ったら、これは dbeg<0 なのにこれを変更開始点としてしまっている所があった為だった。
    単に dbeg>=0 を付け忘れていただけですぐに直った。

    未だカーソルの移動が遅いと思って色々試していたら、
    どうやら ble-syntax-hightlight+syntax の中が重い。
    parse は更新された範囲だけに対して処理をしているので遅い筈はない。
    というかカーソルの移動の時には呼び出されない。という事は、
    その後の属性値の適用が重いという事になる。
    取り敢えず umin, uend を用いてその範囲だけ属性値を更新する様にした。
    それでも遅い。どうも word に対しての処理が重い様である。
    良く考えたら毎回各 word に対してファイルかどうかの判定を行っている。
    これは確かに重かろう。修正した。

    さて。次の問題。属性値の適用を _ble_syntax_attr_umin ～ uend
    の間に限った事によって問題が生じている。
    "word による着色" がなくなった時に再び属性値を _ble_syntax_attr から
    復元しなければならないが、 "word による着色" は _ble_syntax_attr_umin
    等の管理の範囲外である。これを正しく実装する為にはやはり layer の様な仕組みが必要となる。
    しかし layer の仕組みを実装するに当たってどの様にすれば良いかについては申し越し考える必要がある。

    ここでは、以下の問題点を挙げて一旦閉じる事にする。
    - "word による着色" がなくなった時にその部分の着色がなくなるべき

2015-02-20

  * bash-3.1 ESC [ の受信について [#D0154]

    bash-3.1 での ESC [ を受信する為に、以前の修正で ESC [ を CSI に変換していた。
    然し、今回 bash-4.3 で C-@ を受信する為に C-@ (0) を UTF-8 の 2-byte 符号で受信し直す様にした。
    この方法を用いれば ESC [ も "ESC の 2-byte 符号" + "[" として受信し直す事ができる筈だ。
    この様にすれば ble-decode-char に特別なコードを書き込んで
    CSI を無理矢理 ESC [ に戻す等という事をしなくても済みコードも綺麗になる。

    変更した。正しく動作している。

  * <bug> C-x a 等に対して x が読み取られる。 [#D0153]

    ble-decode-byte を見てみた所ちゃんと 24 97 が受信されているのでこれは bind の問題ではない。
    その後の文字の処理の問題か、キーの処理の問題である。

    今度は .ble-decode-char の方で何が受信されているかを確認する。
    UTF-8 decode に問題があるとは思われないので、ここでも 24 97 になっている筈である。
    →果たして 24 97 になっている。OK

    今度は .ble-decode-key の方で受信されている物を確認する。
    67108984 97 が受信されている。67108984 は 16 進数に直すと、0x4000078 である。
    これは Ctrl フラグと 78 = 'X' の組合せになっている。この時点でも問題点は内容に思われる。
    とすると問題があるのは .ble-decode-key の中で行われている処理だろうか。

    と思ったら今迄の処理にかなり問題があるという事が分かった。
    というか段々思い出してきた。色々書き換えようと思って弄っている途中で中断していたような気がする。
    (或いは、訳が分からなくなったが取り敢えず動いているから良いという事にしたのだったか。)

    - 先ず、.ble-decode-key.invoke の KEYS に代入される値について。
      ${var//_/ } ではなく ${var//_/} になっているので key 分割に失敗する。

    - .invoke-default で最後に入力された文字だけを見て既定の関数を呼び出している。これは変だ。
      というかそもそも invoke-default はこのタイミングで呼び出すべき物なのかも謎である。

    - また、.ble-decode-key.invoke に失敗した時に _ble_decode_key__seq をクリアしているので、
      .ble-decode-key.invoke && return
      fallback
      とした時に fallback に辿り着く時には _ble_decode_key__seq の情報が消えて無くなっている。
      _ble_decode_key__seq= は呼出側で処理する事にする。

    - 一致に失敗したというエラーを出力してから途中一致する物がないかを探索している。
      失敗したと表示したのに何かを実行するのは変ではないか?
      でも複数のキーからなるシーケンスで失敗した場合にはその複数のキーについてエラーメッセージが表示されて欲しい。

      例えば、一致に失敗した時に
      1 遡って適用できるシーケンスがないか探す。見付かればそれを処理して終わり
      2 もし任意のキーに対する既定の動作が設定されていれば、それを処理して終わり
      3 何も設定されていなければ全体のキーについてのエラーメッセージを表示する
      と言う処理にすれば良いのではないかと思う。x

      さて、これを実装する為には…遡って適用できるシーケンスが見付かって実行した時点で制御を呼出元に戻したい。
      が、現在の emit の再帰呼び出しの方法だとそれができない。emit 関数を再実装する必要がある様に思う。

    また良く分からなくなった。何が望ましい動作なのだろうか。
    ble_opt_error_kseq_discard の意味を変えた方が良い様な気がしてきた。
    現在の実装を見ると ble_opt_error_kseq_discard になっている場合は部分一致がある場合でも捨てる事になっている。
    しかしそうではなくて、部分一致すら見付からなかった時に残っている
    キーの列をどの様に処理するかというのを制御したいのではないか。
    部分一致について処理しないようにしたいのであれば、そもそも keymap にそういう物を登録しない様にすれば良いだけの話である。
    keymap に色々設定しておいてから、ble_opt_error_kseq_discard で部分一致なバインドを
    on/off にするという使い方も可能ではあるが直観的ではないし、何が便利であるのかも分からない。

    ここで、ble_opt_error_kseq_discard は部分一致も見付からなかった場合に残っている出力を捨てる為の設定とする事にする。

    再実装した。すっきりした。

  * <bug> C-@ を受信できていない @ bash-4.3 [2015-02-11] [#D0152]

    > * bash-4.3 C-@ について
    >
    >   bash-4.3 になって bind -x が三文字以上に対して使える様に bugfix されたが、
    >   同時に C-@ を含むような系列に対して bind が正しく処理されなくなった。
    >   現在 bash-4.3 において C-@ を捕捉する事は出来ていない。

    bind -X を見ると確かに
      "\C-@": "ble-decode-byte:bind 0"
    が登録されているのだが受信できない様だ。

    $ bash
    $ bind '"\C-@":"test"
    $ bind -s | less
    $ bind -x '"\C-@":"echo test"'
    $ bind -X | less

    とここまで来て C-@ を押したら
    bash_execute_unix_command のエラーが発生するという事に気付いた。
    (ちらつきを抑える為に bash の出力を殺したのは良くなかったかも知れない)
    →bash の出力をファイルに書き出して、それをチェックする事にした。
      エラーを吐き出していればそれを visible-bell で表示する。

    仕様がないので "C-@ *" に関しても全て登録する事にした。
    →"C-@ *" に割り当てても駄目なようだ。
      というか C-@ を何度も押しても C-@ を続けている限りはエラーも起きない。
      つまり C-@ に関連して bash は何か特別な処理をしている? 気がする。

    % 2015-02-19
    %
    % 現在の所 bash-4.3 において keymap が見付かりませんでしたと表示されるのは
    % C-@ だけなので、keymap が見付かりませんでしたエラーを受信したら C-@
    % を受信したという事にしてしまうというのも一つの手である。
    % これは既に bash-3 で C-d を受け取るのに使用している方法を使えば良い。

    念のため他の version ではどうなっているかも調べておく。
    bash-4.2 は C-@ は普通に受信できる。bash-4.0 でも普通に受信できる。
    bash-3.2 OK。bash-3.1 OK。やはり bash-4.3 だけで C-@ が受信できない。

    bind -x ではなく単に bind '"\C-@":"hello"' 等とすると正しく受信できると分かった。
    ならば bind '"\C-@":"\xC0\x80"' 等としてしまえば問題ない。
    "\xC0\x80" は UTF-8 の表現方式で 0 を表す。
    (但し、UTF-8 は或る code point を表すのに最小の長さの符号化を要求するので、
    上記は正しくない、或いは、正規化されていない表現、という事になる。
    何れにしても、これは直後に .ble-decode-char+UTF-8 で 0 に翻訳される一時的な物なので問題はない。)
    →これで呆気なく動くようになった。

2015-02-19

  * <bug> 4.3, 3.1 いつの間にかに日本語が入力できなくなっている。いつから? [#D0151]

    3.1 は別の問題であった。独立した項目にする。

    4.3 では無効なシーケンスですという(自分で書いた)エラーメッセージが出る
    3.1, 3.2 では謎の文字が入力される。というか ^# と表示される。
    4.0 では何故か入力できる。"あ" とすれば 227 129 130 が UTF-8 で受信されている。
    4.2 でも入力できる。

    あ E3 81 82

    と思っていたらいよいよ全ての version で読み取れなくなった。
    今迄読み取れていたのは何だったのか…。良く分からない。
    .ble-text.c2s と .ble-text.s2c を弄っただけの筈だが何故だろう。
    スクリプトが行けないのかと思って色々試したがよく分からない。

    と思っていたらそもそも受信している byte が 129 130 だけになっていた。227 が何処かに消えている。
    というか ESC にも bind できていない。色々とおかしい。

    何でか分かった。bind に使う文字をどの様に生成するかが関係していた。
    bind に使う文字は utf-8 でエンコードして渡しては行けない。
    直接バイトを指定するか、そうでなければエスケープシーケンスを用いて渡す必要がある。
    直接バイトを指定すると別の文字とくっついたりして変な事になりそうなので専らエスケープシーケンスを用いる事にする。


    2015-02-20
      と思ったら今度は \C-_ \C-[ \C-] \C-^ 等が動作しなくなった。
      \C-@ も今迄エラーメッセージが表示されていたのに、今は bell が鳴る。
      と調べてみたら、この部分の変更が原因になっていた。
      通常文字までもエスケープシーケンスを用いて表現してしまった為に、
      \C-_ \C-[ \C-] \C-^ が \C-\135, etc になってしまっていた。
      エスケープシーケンスにするのは 127 以上の文字 (8bit 文字 + DEL) だけにして解決した。

  * <bug> bash-3.1, .ble-text.s2c が日本語に対して正しく働いていなかった。 [#D0150]

    先ず 3.1, 3.2 で化けている事について。
    内部的には正しく入力できている様なのでこれは簡単に解決できるだろう。

    ^# 等という文字はないよ?? と思ったが、恐らく C-# とデコードされているのだろう。
    と思ったがやはり変だ。info.draw でも ^# と表示されているこの文字は一体何か?
    info.draw では特別なデコードは行っていない筈である。
    改めてみてみると文字コードについて 0 以上であるという仮定に基づいた処理になっている。
    負の文字コードになっているのであろう。
    そしてそれは文字デコードのエラーフラグが立っている事を示す?
    と思って ble_decode_Erro を確認したが別に符号ビットではなかった。
    というか符号ビットを立てるような富豪はないように見える。^# とは一体何なのか…。

    うーん。そして実際に出力してみると正しく "あ" と入力されている様子である。
    表示だけが変になっているという事の様である。これは一体どういう事なのか…。
    改めて見てみると .ble-text.s2c が怪しい。
    実際に試してみたら果たして -29 という値を吐き出している。

    そしてこれがどの様に実装されているかというと結局
      printf '%d' "'あ"
    の様な事をしている。これを実行してみると確かに -29 と表示される。
    これは utf-8 で "あ" を構成する初めのバイト 227 を signed char で解釈した時の値である。
    さて、とすれば bash-3 で unicode の文字コードを取得する正しい方法を考える必要がある。
    試しに
      /usr/bin/printf '%d' "'あ"
    等としてみたら、227 と表示されて、変な文字が余っているというエラーを出力した。使えない。

    bash-3.1, 3.2 では "${a:b:c}" の形式ではバイト単位ではなく文字単位の操作しかできないし困った…。
    decode してしまったのが問題だったという事なのか。でも、補間の場合など ble-decode-byte
    以外を通して入力される文字列もあり、これらも正しく表示する為には ble-decode-byte+UTF-8
    で逐次キャッシュを作成するという方法は使えない。やはりちゃんと計算する方法が必要である。

    うーん。どうやら
    while read -n 1 a; do printf '%d' "'$a"; done <<<"${text:i:1}"
    とすれば何とかできる様ではある。fork するよりは速いだろうか。

    或いは、c2s があるならば二分法で攻めるという手もあるかもしれない。幸い utf-8 は順序を保存する。
    と思ったが c2s 自体が bash-3 では絶望的に遅いので二分法はしたくない。

  * <bug> bash-4.2 が segfault する。算術式中の配列要素に関係して。 [#D0149]

    | 何処で落ちるのかと調べてみたら .ble-edit-draw.redraw の中である。
    | 更に調べてみると以下の様な何の変哲もない部分である。
    |
    | local dbeg dend dend0
    | ((dbeg=BLELINE_RANGE_UPDATE[0],
    |   dend=BLELINE_RANGE_UPDATE[1],
    |   dend0=BLELINE_RANGE_UPDATE[2]))
    |
    | と、ここで思い出したのだが何かの bash の version が、
    | 一つの算術式の中で複数の配列参照を行うと落ちるという問題があった様な…。
    | 少し試してみた: ((x=arr[1],y=arr[2])) これで落ちる。
    | これは面倒臭い。かなり大幅な書き換えをしなければならない。
    | というか patch を当てるんだったらこの動作についても patch を当てて欲しい。

    算術式の中で配列を使うと segfault する問題について。

    | 算術式の中で配列要素を参照すると、次の token に添字が適用されている様だ。
    |
    | 算術式の中で配列要素を参照して代入すると segmentation fault する。
    | 算術式の中で2回以上配列要素の値を参照すると segmentation fault する。
    | 例えば ((x=arr[1],y=arr[2])) で落ちる。
    | 代入するのは平気な様である。また、参照すると必ず落ちる訳でも無い様だ。
    |
    | 配列でない変数に対しても同様に落ちる。
    | 評価時というよりは構文解析時に落ちているのかも知れない。
    | 括弧で括っても駄目だし、カンマ以外で区切っても駄目。let でも駄目。'' で囲んでも駄目。
    | 結局、安全に評価する為には、複数の参照がない様にするべきなのか?
    |
    | 調べたら http://osdir.com/ml/bug-bash-gnu/2013-01/msg00042.html に報告が上がっている。
    | http://osdir.com/ml/bug-bash-gnu/2013-01/msg00043.html で解決したという事になっているが。。
    | 4.2.39 で少なくともエラーが発生していた様だ。手許の bash-4.2 は 4.2.53 なのだが。。
    | もしかして 4.3 には適用されたけれども 4.2 には結局適用されなかったという事か?
    |
    | 所で上記ページで報告されている ((a=b[1],b=1)) という式を試してみたが、これでも落ちる。
    | つまり、配列に対する参照を複数回行った事が問題ではないという事。。うーん。
    | どの様な時に落ちてどの様な時に落ちないのか。。
    |
    | うーん。gdb で見ると配列添字が来るはずの所に次の tok が来ている。
    | 例えば ((a=b[1],b,c=1)) とすると問題なく動く。
    | ((a=b[1],c,d=1)) でもOK。評価結果も異常はないように見える。
    | また ((a=b[1],0,c=1)) とすると落ちる。((a=b[1],0)) は OK。
    | ((a=b[1],c,d=b[2])) も OK。
    | というか何故か分からないが配列に対する代入を実行しようとしている?
    | つまり、"配列添字" が次の tok にも適用されてしまっているという事か?
    |
    | ((a=b[1],1+1,d=b[2])) これは落ちるが、
    | ((a=b[1],c+1,d=b[2])) これはOK。
    | ((x=(c=123,a=b[1],c+1))) これもOK。評価結果 $x も問題ない。
    |
    | 所で速度比較を行ってみる。
    | ((a=arr[i%3]));((b=arr[i%2+1]))
    | ((a=arr[i%3],dummy,b=arr[i%2+1]))
    | 殆ど違いはない様だ。dummy= として挟んだ方が微妙に速いという程度。

    何れにしても ble-syntax.sh で大量の算術式を使ってしまったから、
    これは大変な書き換えだ…と思って実際に書き換えてみた所、
    意外とクラッシュのパターンになっている式は少ない様だ。
    書き換えたら簡単にはクラッシュしなくなったので取り敢えずはこれで一件落着とする。

    全ての実行パスについて試した訳ではないので未だクラッシュする罠が残っているかもしれないが、
    それは落ちてから考えれば良いという事にする。

  * ble-decode.sh: bind C-x の変更 [#D0148]

    改めてテストしてみた所 C-x 単体に対して bind して segfault するのは 4.2 だけの様だから、
    bash-4.2 の時にだけ "C-x *" のペアで bind する事にした。
    ペアで登録していると2文字目が入力されるまで C-x が届かないので、
    その他の bash の version では "C-x" 単体で bind する事にする。
    (とはいいつつ、emacs keymap の設定だと C-x C-x 等の key binding があるので結局は
    ble.sh の内部で 1 文字目の C-x が pending する事になる訳だが)。

    また、これに伴って既定で bind されている "\C-x *" が上書きされなくなるので、
    bind -sp で列挙した物を全て bind -r する事にした。
    今迄は "\e" で始まる物しか bind -r していなかったが、そんなに速度が変わる物でもないだろう。

    + C-x は 4.2 だけの問題化と思いきや、3.1 がクラッシュした。

      改めて複数の version で確認を取る事にする。
      3.1 は先に述べたように落ちた。具体的には C-x C-b C-b 等として落ちた。
      3.2 も同様に C-x C-b で落ちる。4.0 も同様に落ちる。
      結局 C-x C-b 等と打って落ちないのは bash-4.3 だけである。

      結果として bash-4.2 の時にだけ "C-x *" ではなくて、
      bash-4.2 以下の時は全て "C-x *" で bind する事にした。


  * <bug> 日本語を入力すると位置がずれる @ 4.0 bleopt_suppress_bash_output= [#D0147]

    →どうも 4.0 は 3 と同じ様に bind -x の前後でプロンプトを消去する様だ。
      という事で bind 前後のコードを 3 と共通の物にした。

    また、C-d を捕捉する事もできていない。これについても対応した。
    と思ったら、どうも C-d が捕捉できなかったのは、bind 前後のコードを
    3 と共通の物にした所為で IGNOREEOF が設定されてしまった所為であった。
    4.0 では READLINE_LINE が存在するからわざわざ IGNOREEOF を設定する必要はない。
    4.1 用のコードと同じように READLINE_LINE を設定すれば良い。

    という事で bind 前後のコードの分岐を増やす事にした。
    bash の bind -x 関数の呼出の前のプロンプトの消し方に応じて _ble_bash>=40100 で分岐するのと、
    bash が READLINE_LINE 変数を用意しているかどうかに応じて _ble_bash>=40100 で分岐するのを区別する。

    しかしそれでも未だログアウト時のメッセージの表示位置が変になっている気がする。
    その他のコマンドの実行の時にはずれていないからそれ程問題という訳でもない。
    これは後で対処する事にする。■

  * <bug> 4.0 日本語を入力すると (( の中で日本語を使ったという文句が出る。 [#D0146]
    どこかの算術式に文字列が紛れ込んでいるのだろうか。

    と思ったら関係ない所を直したら何故か動くようになった。
    と思ったが、直した箇所は adjusted をするかどうか、
    つまり READLINE_LINE を用いて bash の出力を制御するかどうかの部分である。
    つまり、問題点は adjusted の部分である。
    もう一度 READLINE_LINE を用いる様に正しく修正して試してみる。これで問題が再現するはず。

    再現した。カーソルの位置と出力されるタイミングから言って、
    これは明らかに adjusted の中から発生している。
    adjusted の中身は弄っていないから lc の計算方法を変更した事が原因であるのは明らかである。

    どうやら .ble-text.c2w が $ret 変数に値を返すはずなのが何も値を設定していない様である。
    前回の値の "あ" というのが残っている。
    もっと調べてみると、どうも ret に予め "あ" 等の文字列が入っていると
    ret を計算する為の筈の算術式の評価に失敗してしまう様である。
    ret は代入される側なので予め入っている値が何であれ関係ない等と思っていたが、
    良く考えてみたら算術式の評価の方法上 ret の中身を展開してまで数式として解釈する筈で、
    ret に何が入っているか分からない状態で算術式を起動するのは危険という事である。

    ble-decode-byte+UTF-8 でも似たような問題がないかと確認してみたら、
    此方の方は全く問題はなかった。こちらは計算した値を使ってそのまま
    decode-char を呼び出す様になっていて、
    外部の関数が用意した変数に値を設定して制御を返すという方式ではないので、
    未初期化の変数が算術式の中に登場するという事は無い。

  * <bug> bleopt_suppress_bash_output= にした時にプロンプトが二重になる [#D0145]

    暫く bash の出力を抑制して処理を行う様にしていたが、
    試しに bleopt_suppress_bash_output= を再度設定して動かしてみた所、
    bash がプロンプトを出力する様になっていた…。
    何故だろう。bind/tail の直後に PS1 をファイルに出力しても PS1 は空だ。
    bash が PS1 の内容を覚えているという事だろうか?
    でも同じ version で少し前には正しく動いていたはずである。

    どうも blerc デフォルトの .bashrc をロードした時になる様だ。
    しかし何故だろうか。何か変な PROMPT_COMMAND が設定されているのかとも思ったがそういう訳でもない。

    どうやら bind -x したコードの内部で PS1 を弄っても反映されない様だ。
    外で PS1 を設定する必要があるという事。
    今迄は ble.sh ロード時に PS1= を設定していたので、それがずっと生きていて動いていたが、
    .bashrc をロードすると PS1 に新しく値が設定されてしまうので駄目という事。

    よく考えたら、今迄もプロンプトが表示されてからすぐに入力をしたりすると
    表示が乱れるなど思い当たる事が他にもある。プロンプトが表示されるのが ble.sh をロードした直後なのに
    その後に未だ .bashrc 等の処理を行っていたのが原因である。
    その時間差の間に何かを入力した事によって表示がずれていた。

    思うに ble.sh のロード・初期化と、実際にアクティブにする attach の操作を分離すべきである。
    ble-initialize ble-attach ble-detach 関数を定義する事にした。
    また ble.sh に noattach の引数を渡した場合には、その場での attach をしない様にした。
    必要な場合は後で ble-attach を呼び出して貰う事にする。

    →これで一応 bleopt_suppress_bash_output= の時にも動作する様になった。
      bash-3.1 の場合にも C-d を正しく捕捉できない事を除けば正しく動作する様になった様に見える。
      (とはいいつつやはりちらつきは気になる。)

  * <bug> ble-detach が動かない [#D0144]

    まとめ
    - awk のエラーメッセージが tmp/$$.bind.save に混入していた
    - awk の -v var=value の中の value はエスケープシーケンスが解釈される
    - bash-4.3 bind -X で表示されるコマンドは特別なエスケープがされていて bind -x では使えない

    > 色々あるが取り敢えず $_ble_term_fghr と言った類の物が直接表示されている。
    >
    > 後、awk を呼び出そうとしたり何か変だ。取り敢えず分かり易い所から。
    > $$.bind.save の中を覗いてみる…と思ったら awk のエラーメッセージが bind.save の中に混入している:
    > awk: 警告: エスケープシーケンス `\'' は `'' と同等に扱われます
    >
    > するべき事は、
    > - awk のエラーメッセージは別の所に出力されるべき
    >   gawk の幾つかの version からは "/dev/fd/数字" を用いる事ができるのでそれが利用できる。
    >   但し少し古い version の gawk で動かなければ結局これは積極的には採用できない。
    > - メッセージの通りエスケープシーケンス \' に対する処理を行う。
    >
    > 何と awk -v APOS="'\\''" 'BEGIN{print APOS;exit}' だけでエラーになる…。
    > awk -v apos="'" 'BEGIN{print apos "\\" apos apos; exit}' はエラーにならない。
    > つまり -v で渡したパラメータに含まれるエスケープシーケンスを解釈するという事???
    > 調べてみたら POSIX レベルでそう動作する事になっている様だ。
    > [[bash - Should awk expand escape sequences in command-line assigned variables? - Stack Overflow>http://stackoverflow.com/questions/13808909/should-awk-expand-escape-sequences-in-command-line-assigned-variables]]
    >
    > 1回 ble-detach して再び ble-attach するとまたプロンプトが2重になる。
    > →これは .ble-edit/edit/attach での guard が1回しかロードされない事を前提とした物だった事による。修正した。
    >
    > 1回 ble-detach して再び ble-attach して、更に ble-detach すると
    > detach できていない。それに加えて "bash: : コマンド見付かりません" というエラーになる。
    > コマンドを実行しようとすると実行できずに、実行コード全体を一つのファイルと見做して実行しようとしている??
    >
    > と思ったら ble-decode-byte:bind が復元対象に入っていた。
    > 復元対象に入らない様に awk でチェックしていたはずなのにと思って確認したら
    > ble-decode-bind と指定していた事によりチェックが正しく機能していなかった。
    > また、それとは別に復元の仕方にも問題がある。
    > "à": "ble-decode-byte:bind 224; eval \\\"$_ble_decode_bind_hook\\\""
    > 等と、過剰にエスケープされている。これについてもう少し詳しく。
    >
    > 始めに attach した直後には bind -spX すると以下の様になる。
    > "\C-@\C-@": "ble-decode-byte:bind 0 0; eval \"$_ble_decode_bind_hook\""
    > その後で ble-detach してもこの結果は変わらない。
    > この次に ble-attach した後に bind.save を見ると
    > bind -x '"\C-@)": "ble-decode-byte:bind 0 41; eval \"$_ble_decode_bind_hook\""'
    > 等となっている。問題はない様に見える。が、これで登録すると先程の様な事になるという事か。
    >
    > →色々 bind -X の出力を調べるとコマンドの中に制御文字が含まれているとエスケープされる様だ。
    >   先ず " と \ は \" と \\ に変換されている。また DEL は \C-? になり ESC は \e になる。
    >   それ以外の制御文字 (0～31) は \C-なんとか の形に変換される。
    >   これらを元の文字に復元する簡便な方法は存在しない様に思われる (bash の機能を使ったとしても)。
    >   仕方がないので awk で変換のコードを書く。面倒なので gsub を繰り返し適用する方針で。
    > →これで取り敢えず正しい bind -x コードを出力する事ができる様になった。
    >
    > さて、これを解決したらすっかり ble-detach が動くようになった。
    > bleopt_suppress_bash_output=1 でもちゃんと問題なく動いている様に見える。
    > 何度も ble-attach, ble-detach を繰り返しても動いている。

2015-02-18

  * 履歴展開の対応 [#D0143]

    ^string1^string2^ の形式の履歴展開の場合、順に入力しても履歴展開と認識されない。
    というか :x 等の modifiers も順に入力しても履歴展開に含まれない。

    解析再開点を履歴展開の直前に置いておくか、何らかの単語?として取り扱わないと駄目。
    (「この点までは stat に値を設定しない」という変数を用意して、
    先読みを実行した場合にその変数に値を設定するというのも興味深い方法である。)

    後、試して気付いた事だが !!$:a 等と定義されていない修飾子を指定すると、
    単に履歴展開をせずに実行されるのかと思いきや、履歴展開のエラーになってコマンドが実行できない。
    このエラー報告と整合性のある色付けにしたい。
    結局、履歴展開についても内部の文法構造を気にして実装するという事になるのだろうか。

    他にも s/../../ や ^..^..^ は途中で中断すると空文字列を指定したとして解釈される事も分かった。
    説明書に書かれていない動作が色々あるが、この動作であれば却って順に入力していけば
    正しく全体が履歴展開として解釈される。
    適当に実装したが現状で大体OKなのではないかという気がする。

  * CSI → ESC [ 翻訳について [#D0142]

    現在 bash-3.1 ESC [ → CSI や、ESC ESC → ... を default keymap に設定しているが、
    その他の keymap の時に処理されないのは問題である。
    例えば isearch の時に bash-3 では矢印キーが使えない事になる。
    もっと前の段階で変換をするべきなのではないか?

    charmap はそう切り替わる物でもないので charmap のレベルで受け取った CSI を
    ESC [ に変更するという方法があると良い。できればハードコードするのではなく一般的な枠組として。
    →と思ったが一般的な枠組にすると強力すぎる様に思うので取り敢えずは
      char==91 に対してハードコードして介入する事にした @ .ble-decode-char
      (utf-8 CSI を送信する様な端末があった場合にもこれで対応できた事になる…が、そんな端末があるかは不明。)

  * <完> bash-3 で C-d を捕捉する方法? [#D0141]

    今は IGNOREEOF を大きな値にして即座にログアウトされない様にしている。
    所で C-d を押すと
      Use "exit" to leave the shell.
    だとか
      ログアウトする為には exit を入力して下さい
    だとか
      シェルから脱出するには "exit" を使用してください。
    だとか言ったメッセージが出力される。

    現在 bleopt_suppress_bash_stdout を設定している場合には
    bash のエラーメッセージはファイルに書き込まれるので、
    このファイルを読み取る事で C-d を押した事を検知する事は出来る。

    但し、押された事が検知できるのは C-d が押された後に初めて別のキーが押された時である。
    C-d では何もイベントが起きてくれないので。

    強引な手だが、常にファイルを監視する子プロセスを作成して、ファイルに Use "exit" ... が書き込まれたら
    シグナルを $$ に送ってそこで処理するという手が使えるかも知れない。
    しかし子プロセスで常にファイルを開いて確認するのでリソースを食う。余り使いたくない方法である。

    また或いは bash のエラー出力先にコプロセスを置いておきそこで受信をするという手も…。
    こちらの方が未だましである。もしかしてこれで行けるんじゃないか…と思って実装してみた。
    動いている…と思いきやすぐにエラーを吐いて終了する。
      trap -- 'myfunc' USR1
    するだけでもエラーになって死ぬので、行っている処理の問題ではなさそう。
    代わりに RTMIN を使ってみたがそれでも同じエラーが発生する。
      trap -- 'echo hello' USR1
    という程度であれば何も起きない。trap の中で関数を呼び出すのが駄目という事だろうか。

    もしかしてシグナルハンドラの処理中にシグナルハンドラが呼び出されている??
    或る程度処理に時間が掛かる関数を設定するとエラーになって死ぬという事だろうか??
    →必要な時にだけ呼び出す様に変更したら動くようになった
      (とはいいつつもシグナルによって動作しているので流石に遅い。しかし何とか動いているので良しとする。)
    →と思ったが内部で呼び出している mv を止めたらそんなに遅くはなくなった。fork はやはり重いという事か。

    > 2013-06-13
    >
    >   * 制限: bash-3 では C-d を捕捉する事ができない。

    取り敢えずこれは解決したとして良いだろう。

  * ble-edit.sh, ble-decode.sh: bugfix, bash-3 でカーソルキーの類が動かない。履歴が読み込まれていない。 [#D0140]

    これらの原因は同じ物であった。高速化の為にコードを生成してそれを直接 source していたが、
    その為に source とプロセス置換を組み合わせたのがいけなかった様だ。
    bash-3 では source はプロセス置換から読み取ってくれない。
    (パイプからは読み取らないというポリシーなのか、
    或いはシークできないと実行できないという事なのか分からないが。)

    source <( ... ) を eval -- "$( ... )" に変更。

2015-02-17

  * ble-syntax (ble-syntax-highlight+syntax): 入れ子エラーの色の範囲 [#D0139]
    例えば "(( echo" 等の場合。
    閉じていない入れ子構造がある場合に、入れ子構造の開始字句をエラー色にしている。
    しかし、一文字目しか色を付けていない為、入れ子開始の字句が複数文字で構成される場合に不格好である。
    字句単位で色を付けられるように fill-g 関数を修正し、それを用いる事にした。

  * ble-edit.sh (accept-line): - で始まるコマンドを実行できない。 [#D0138]
    履歴展開の為にコマンドを history に渡した時に history へのオプションとして解釈されていた。
    というか eval も - で始まるコマンドを扱えないし、history -s で履歴に登録する事もできない。
    eval に関しては -- 以降はコマンド部分として解釈される様なのでそれを用いる。
    よく bash の man を読んでみたら組み込みコマンドの章の一番上の部分に -- について書かれていた。

  * <bug> ble-syntax.sh: 1"$1" と入力してから先頭の 1 を消すと単語情報が壊れる。 [#D0137]
    単語の長さが再計算されていない事による物と思われるが良く分からない。

    落ち着いて現在の実装でどの様な振る舞いになるはずかについて考える。
    1"$1" の時は 1 の部分に単語情報が格納されている。
    ここで 1 を削除すると単語情報も消えて無くなる。
    次に 1 の部分から解析が始まるがこの時に新しく単語の開始点が設置される。(長さ 0)
    所が (単語の開始点が前回と一緒である為) 単語の末端に達する前に解析が終了する。

    さて後段で前方の単語への参照を保持しているはずで、
    参照している単語開始点が編集の対象だった時は dirty 範囲をそこまで拡大する手はずになっていた筈だが。
    見てみると編集の対象かどうかの判定が [i1,i2) になっている。
    これは単語の先頭で編集が行われた場合にその単語は編集されていないという判定である。
    これについてはもう少し考え他方がよいのかも知れないが
    単純そうな [i1,i2] に変更する事にする。(単純な物の方が大概自然である。)

    % どの様にしなければならないかというと。
    % 単語情報を削除してその場に新しく単語情報を追加する場合、

  * <bug> ble-syntax.sh: ${1}1${1} の状態で真ん中の 1 の直前に空白を入れると壊れる。 [#D0136]
    他の部分に空白を入れたり空白以外の文字を入れても何も起こらないが、
    該当箇所に 1 を入れた時にだけ壊れる。

    試行錯誤
    > これについても現在の実装でどうなっているのかについて調べる。
    >
    > 先ず shift の際に何が起こるかについて。${1}2${3} → ${1} 2${3}
    > とずらした事で単語の先頭 (${1}の前) に対する参照が更新される事は無い。
    > 単語の先頭は編集位置よりも前にあるからである。
    > …よく考えたら、${3 を読み取ろうとした時点で inest/wbegin の値が一致してしまうので
    > 其処で単語の読み取りが終了してしまう事になる。
    > 別の単語の中にいながら局所的に同一の文法状態になる事が原因で途中で解析が終了しているという事だ。
    >
    > 本当か? ではなぜ echo ""2${3} → echo "" 2${3} の時には問題が発生しないのか?
    > 残っている情報
    >   ${ を読み取る直前の wbegin は "" の先頭にある。
    >   ${ を読み取る直前の inest は -1 である。
    >   ${ まで読み取った時の wbegin は -1 である。
    >   ${ まで読み取った時の inest は ${ の先頭の位置にある。
    > 新しい解析
    >   ${ を読み取る直前の wbegin は 2 の先頭にある。
    >   ${ を読み取る直前の inest は -1 である。ここは不一致なのでここで停止する事は無い。
    >   ${ まで読み取った時の wbegin は -1 である。
    >   ${ まで読み取った時の inest は ${ の先頭の位置にある。ここで一致する気がするのだが…。
    > dirty-range の拡大も考慮に入れる事にする。
    >   dirty-range の拡大は wbegin/inest の参照先が編集範囲内にある時に発生する。
    >   ${ の外側では wbegin inest は常に wbegin=0 inest=-1 になっている。
    >   これは dirty range の拡大には寄与しない。
    >   ${ の内側では wbegin inest は -1 及び ${} の先頭になっている。
    >   そしてこの先頭 of ${ は編集の対象ではない。つまり dirty-range の拡大は起きない。
    > →もっと色々試してみた結果
    >   (字句単位1)(字句単位2)(字句単位N)${3} の時に、
    >   字句単位1 の直後に空白を挿入する場合は OK で、
    >   字句単位2以後の直後に空白を挿入する場合に駄目になるという事が分かった。

    原因
    "(字句単位1)(字句単位2)(字句単位N)${3}" に空白挿入 の際:
    - 字句単位1の直後に空白を挿入する場合には再開点が単語の先頭になり、
      単語の先頭も編集対象としてマークされる為に単語全体が更新対象になり問題が発生しないという事の様だ。
    - しかし、字句単位2 の直後に空白を挿入する場合には再開点は字句単位2の先頭になり、
      単語全体は更新の対象とは見做されない事になる(ここまでは期待している動作である)。
      所が、その後で内側のネスト状態に入った所で局所的に前回の解析と同じ状態になり停止するという事のようだ。
    - また、字句単位N の直後に空白を挿入した場合には ${3} 全体が更新対象になるのでやはり問題は発生しない。

    対処

    局所的な文脈の一致ではなくて全体的な文脈の一致まで考慮しないと問題が残る。
    例えば現在の実装ではネストレベルが異なる場合でもネストの開始位置さえ同じであれば文脈が一致したと解釈してしまう。
    実装当初には「ネストの開始位置さえ一致していれば文脈的には同じ構造に戻ったと見做しても良い」
    という想定を行っていたが実際にはネストの開始位置が同じであっても文脈の構造が変化した可能性があるという事だ。

    例えば (CTX_EXPR の中で) ( を上書きして [ にした場合などがこれに含まれるのではないかと思う。
    これは類似のまた別の問題だ。現在の文脈情報に開始括弧の情報を含めていない事による。
    開始括弧の対応まで一致しているかどうかを確認する為には [inest] の type が同じかどうかまで確認しなければならない。
    これの比較を怠っている事は結構不味い。

    結局、細心の注意を払ってすれすれで実装するのではなく、安全確実な方法を採る方が良い。
    つまり、現在のネスト情報を親まで全部含めた形で記録して一致するか確認を行う。
    その為のネスト情報をどの様に記録するのが良いか?

    > 一番簡単なのは stat に全ての情報を入れてしまう事である。しかしもう少し効率化できないだろうか。
    > 再開の為に必要なのは stat に現在記録している 3 つ組だけである。
    > 後は自動的に pop によって情報が復元されていく。
    > さて、stat には3つ組しか記録しない様にして、
    > 更に比較を行う為にその場で inest を辿って stat を掘り返す事にするのは非効率である。
    > 代わりに初期の nest 状態だけ復元して、
    > その後は push/pop する時に nest 状態を更新するというのはどうだろう。
    > しかし、この方法で現在の解析の nest 状態を更新する事は出来るが、
    > 前回の解析の nest 状態を追跡する事は出来ない。push/pop の情報は記録していないからだ。
    >
    > 仕方がないので stat に全てを記録してしまう事にする。
    > 幸い _ble_syntax_stat を参照しているのは殆ど ble-syntax/parse だけなので、
    > この関数内での取り扱い方法だけ変更すればOKである。
    > と思ったが…もし stat にネストの全階層を記録していると shift が滅茶苦茶な事になる。
    >
    > というか現在 _ble_syntax_nest に対しては shift を実行していないがこれについても shift する必要があるという事か。
    > 前回使った _ble_syntax_nest は今回は使わないので shift を実行する意味はなかったのである。

    うーん。面倒だ。取り敢えず動くようにする為には
    1. _ble_syntax_nest もシフトする様にする
    2. _ble_syntax_nest を掘り返して文脈が一致するかどうか確認する
    という事になる。掘り返すのは効率的かどうかは疑問だが取り敢えず実装する。
    (今迄問題にならなかった事から、そもそもそんなに掘り返さなくてもすぐに不一致になるのかも。
    改めて考えてみるに其処まで性能の劣化になる様にも思われないのでこれで良い事にする)。

2015-02-16

  * ble-syntax.sh: 単語終了判定の処理の変更 [#D0135]

    ble-syntax/parse/word-end の判定は
    字句単位の開始時ではなくて字句単位の読み取りの終了時にするべき?
    というのも単語を部分編集するとその単語の長さが 0 になってしまうから。
    これは単語を部分編集した時の更新範囲が典型的にその単語の末端までになるので、
    解析もその単語の末端までで終了してしまう事が多いから。
    然し乍ら、word-end は次の字句単位の読み取りの際に呼び出されるので
    その字句単位の終端を設定する機会がないという事になる。

    % しかし、もし word-end の判定を字句単位の終端時に行う事にすると
    % 別の問題が発生する。単語の末尾に字句を追加した時に単語が伸張してくれない。
    % というのも字句の直前で既に単語が終了している事になっているからである。

    再開した時に正しく再開できる様にする為の簡単な条件は、
    その点での解析状態が次の文字に依存してはならない、という事である。
    しかしそれは少々無理がある。次の文字が分からなければ
    字句単位がそこで終わるのかどうかさえ定かではない為である。
    そこで、現在は解析の再開は変更のあった点ではなく「その点よりも前の最近の再開点」としている。

    従って、其処で単語が終了するかどうかの判定もやり直されるのではないかという気がする。
    例えば、単語の末尾に文字を追加する事を考える。文字を追加した時に解析の再開は
    追加した文字の箇所で起こる訳ではない。追加位置の一つ前の再開点から開始される。
    そして一つ前の再開点の時点では未だ単語は終了していない事になっている筈だから、
    正しく単語は伸張されると期待される。
    なので、取り敢えず字句単位の終わりの時点で単語の終了を判定する様に書き換えてみて動くか見る。

    呆気なく動いている。此方の方が実装としても単純だし自然である。
    →初めは CTX_CMDI の類の文脈が成功した時しか単語の終了判定をしていなかったが、
      実際に色々やってみると、nest から抜けた場合や
      CTX_CMDI の文脈で認識されないエラー文字があった場合にも
      そこに単語の終了が来る可能性があるという事に気付いたので、
      任意の ctx の処理の後に単語終了判定を置く事にした。
    →今後、"ctx の処理の後の ctx" に応じて適切な単語終了判定を行える様に
      WORDEND[ctx] 的な配列に関数を入れる事にしても良いかも知れない。

  * ble-edit.sh (_ble_edit_str, ble-edit/dirty-range): 変更範囲の合成について [#D0134]

    入力文字列に対する部分変更があった時に、全体を計算し直すのは非効率である。
    どの様な変更があったのかを記録しておき、変更がなかった部分の計算については省略するのが得策である。
    その為には部分変更を何らかの方法で表現・記録しておかなければならない。
    ここでは str1 → str2 への変更操作を
      str2="${str1::beg0}$ins${str1:end0}"
    の形に一般化して考える事にする。
    この時 str1 の [beg0,end0] の範囲が str2 の [beg,end] になったと考える。
    beg=beg0 であり end=beg0+${#ins} である。この時変更範囲を
      (beg, end, end0) の三つ組みで表す事ができる。

    今考えたいのはこの様な変更操作を 2 回行って str3 を得た時に、
    str1 から str3 への部分変更をどの様な三つ組みで表せるかという事である。
    ※勿論自明な解として (0, ${#str3}, ${#str1}) 等を考える事ができるが、
      今はできるだけ共通部分を長くしたい、
      つまり、変更部分の長さ end-beg を最小にしたいのである。

    式で考えようとしたが式の上での場合分けが面倒だ。
      str1 -(dbeg dend dend0)→ str2 -(beg end end0)→ str3 の時
      i2 = i1<begA?i1: i1<endA0?-1: i1+(endA-endA0)
      i3 = i2<begB?i2: i2<endB0?-1: i2+(endB-endB0)

    記号的に場合分けするのではなく、もう少し具体的に場合分けを考えた方が良い。
      str1 = A [ B ] C → str2 = A | X | C となったとする。
      更に str3 に入る時に何処に切れ目が入るか ("[]" で表す) で分類できる。
      (1) str3 = A0 [A1] A2 |     X      |     C
      (2) str3 = A0 [A1     | X0]     X1 |     C
      (3) str3 = A0 [A1     |     X      | C0] C1
      (4) str3 = A          | X0 [X1] X2 |     C
      (5) str3 = A          | X0     [X1 | C0] C1
      (6) str3 = A          |     X      | C0 [C1] C2
      先ず beg は明らかに min(begA, begB) である。
      次に end は max(endA-endB0+endB, endB) である。
      end0 は end から逆算できる。或いは end の由来を考えて場合分けすれば良い。
      end が endA-endB0+endB の時は endA0 がそのまま end0 になる。
      end が endB の時は end0 = endB0-endA+endA0 になる。

      式で書くと:
      beg = min(begA,begB)
      end = endB + max(endA-endB0,0)
      end0= endA>endB0? endA0 : endB0-endA+endA0
          = endA0 - (endA-endB0>0?0:endA-endB0)

      整理すると:
      beg = min(begA,begB)
      end = endB
      end0= endA0
      if((del=endA-endB0)>0)
        end+=del;
      else
        end0-=del;

    数式での間接参照?
      alpha=111 beta=alpha*2 pref=bet
      echo $((${pref}a))
      → ちゃんと 222 になる。。bash-4.3, bash-4.1, bash-3.1 で確認した。

2015-02-13

  * <完> グローバルで実行するという事? [#D0133]

    % 次の様な関数で eval すればグローバルで評価できるかも。
    % 少し試した段階では問題は生じていない。
    %
    % geval () { trap -- "$*" RTMAX; kill -RTMAX $$; }
    %
    % + 何とジョブ管理にも正しく登録される様である。
    %   グローバルな変数は勿論定義される。
    %
    % + 返却値については流石に kill の戻り値としては入っていないが中で適当に拾えば良い。
    %   geval () { trap -- "$*"$'\n'"echo exit=\$?" RTMAX; kill -RTMAX $$; }
    %   (改行で区切る様にしないと $* が & や ; で終わっていた時に文法エラーになる。)
    %
    %   後 trap の内容を復元する為に
    %   | originalTrap="$(trap -p RTMAX INT)"
    %   | ...
    %   | trap - RTMAX INT
    %   | test -n "$originalTrap" && eval "$originalTrap"
    %   等とすると良いかもしれない。
    %
    %   但し、この様にコマンド実行中だけ ble の用意した trap を実行していると、
    %   コマンド実行中はユーザの trap した内容が実行されないという事に注意する。
    %   (外部コマンドの場合には bash ではなく外部コマンドがシグナルを受け取れるので問題ないが、
    %   シェル関数の場合にはユーザが予め設定した trap でシグナルを受け取る筈だ。)
    %
    % + C-z 時の返却値 → OK 拾える
    %   C-c 時の返却値 → 駄目。拾えない。これは今迄と同じ。なので INT に trap する。
    %   INT の復元もした方が良い? → $(trap -p RTMAX INT) とするだけなので気にしなくて良い。
    %
    % + jobs で kill -RTMAX $$ と表示される。
    %   といっても kill -RTMAX の待ち状態という訳ではないようだ。
    %   証拠に geval の次のコマンドは geval 内のコマンドで C-z した直後に実行されるし、
    %   また、geval 内部で二つの less を呼び出して両方とも C-z しても正しく実行される。

    と思ったら幻想だった。そもそもグローバルで実行していない。
    現在の文脈のままでシグナルハンドラが呼び出されている様だ。
    つまり、シグナルハンドラが関数内の環境に影響を与えられるという事。

    今の所グローバルで実行できるのは bind -x だけしかない気がする。
    しかし bind -x した物を呼び出す為にはユーザに何か入力をして貰わないといけない。
    (入力を再現する方法が有れば良いがそれをシェル内から実行する方法はない気がする)。
    或いは何とかして readline の accept-line を呼び出す事ができればよいが。

    うーん。汚い方法ではあるが、
    bind -x で "ble-decode-byte:bind 1 2 3; eval \"$_ble_onafter_bind\""
    等として任意の物を外で実行できる様にしておくとか。。
    →この方針で実装してみた。存外問題なく動いている。

  * <完> 現在の C-c のトラップの実装に関する疑問 [#D0132]

    return で良いのか? return が使えない場合があるかも?
    →サブシェルを作らずに同じプロセスで実行する場合、
      内側の環境になるのは関数か source しかない。
      つまり、一番外側でない限りは return が使える。
      つまり、現状の様に関数内で実行している限りは return は常に使えるという事。

    return で正しく抜ける事ができるのか?
    一番内側の 関数/source しか抜けられないのでは?
    或いは、入れ子になっている場合に誰が受信するのか?

    | 実験
    |
    | trap INT はどの様な場合に働くのか?
    | 直接 $ sleep 10 に対して C-c しても trap されない。trap が動く条件は? 色々試した。
    | 何か変だ。殆どの場合で動かない様に思われる。
    | bind -x の中からだとまた違った結果になるのか、それとも現在の実装は問題があるのか…。
    | $ trap -- 'echo INT $a' SIGINT
    | $ sleep 10 →×
    | $ : $(sleep 10) →○
    | $ echo 10 && sleep 10 →×
    | $ sleep 10 && echo 10 →×
    | $ (sleep 10) && echo 10 →×
    | $ func1() { sleep 10;}; func1→×
    | $ プロンプトが表示されている時に C-c→○
    | $ for ((i=0;i<100000;i++)); do :; done→○中断する
    |   ループ内では trap できて、しかも自動的に中断されるという事
    | $ fib1() { (($1<=1)) && eval $2=1 && return; fib1 $(($1-1)) ${2}L ; fib1 $(($1-2)) ${2}R; let $2=${2}L+${2}R; }; fib 20 x→○中断する
    |   関数の再帰呼び出しも trap できて、しかも自動的に中断されるという事
    | $ trap 'echo INT $2=${!2};return' INT; fib 20 x→○中断しない
    |   →何度 C-c を押しても最後まで抜けられない…。return があるかないかで動作が異なる様だ。
    | $ for ((i=0;i<100000;i++)); do :; done→○中断する
    |   →これは単純に return ができない為に return をしなかった場合と同じ動作をしているという事。
    |     結局 trap の動作は return コマンドを書いたか書かなかったかではなく、実際に return しているかしていないかを見ている。
    |
    | 分かった事
    | - trap INT は現在の文脈 (関数内/source内) で最大1回だけ実行される
    |   子プロセスが INT を受け取った場合などには受け取らない。
    | - 唯単に trap INT するだけの場合、シェル内で行われている全ての処理が自動的に中断される
    | - trap INT の中で return 等を実行した場合は、return の後で処理が続行される
    |
    | これを受けて C-c を受信した時にどの階層まで抜けるかをコントロールする方法は:
    | - 一気にシェルの処理を終了したい場合には trap の中で return 等を書かない。
    | - 一つ上の関数・source に戻りたい場合は trap の中で return を書く。
    | - 但し、関数呼出を沢山行っている場合 C-c で抜ける事ができなくなる可能性がある。従って return は書かない方が良い。
    |   任意の階数の関数・source を抜ける方法はない。

    結論

    現在の実装は関数の再帰呼び出しなどを C-c で停止する事ができない。
    →実際に試してみた for ループは抜けるが再帰呼び出しはその場では抜けられない。
      (一応各再帰呼び出しは抜けている様である。その為に、
      C-c をすると fib1 の結果が変わる (前回の呼出の時の結果が残っていると正しい結果になるが))
    →これは C-c によってシェル内の無限ループを止める事ができなくなる可能性がある事を示す。よくない。

      trap で $_ble_hook_INT 等として後処理をする関数を付け加え、return はしない様にするべき?
      →これだと local で変数が被覆されている場合などに正しく対処できない。
        まあ _ble_... を宣言しなければ大丈夫である。

    実際にその様に実装してみたら問題がある。
    どうやら bind -x の中で実行している場合には return しないとそのまま実行が継続する様である。
    return すると現在の呼出階層だけは抜ける事ができるので以前はその様に実装していたという事か。
    以下はその前提で書いてみたコード。結局これは使えないという事になった。
    > &pre(agh-prog-bash){
    > function .ble-edit/exec2/eval-prologue {
    >   .ble-stty.leave
    >
    >   # 履歴置換
    >   set -H
    >
    >   # C-c に対する trap
    >   _ble_edit_exec_original_trapint="$(trap -p INT)"
    >   trap .ble-edit/exec/eval-TRAPINT INT
    >   trap 'echo INT' INT
    > }
    > function .ble-edit/exec2/eval {
    >   # BASH_COMMAND に return が含まれていても大丈夫な様に関数内で評価
    >   .ble-edit.accept-line.exec.setexit
    >   eval "$BASH_COMMAND"
    > }
    > function .ble-edit/exec2/eval-TRAPINT {
    >   # eval 中にシェルの処理で C-c (SIGINT) が来るとここに入る
    >
    >   # シェルが C-c で中断した時の終了値
    >   if ((_ble_bash>=40300)); then
    >     _ble_edit_accept_line_lastexit=130
    >   else
    >     _ble_edit_accept_line_lastexit=128
    >   fi
    >
    >   .ble-edit/exec2/eval-epilogue
    >
    >   # 未だ残っていれば続きを実行
    >   # (今迄実行していたコマンドは _ble_edit_accept_line[] から既に削除済)
    >   .ble-edit.accept-line.exec
    > }
    > function .ble-edit/exec2/eval-epilogue {
    >   # C-c trap を削除
    >   trap - INT
    >   eval "$_ble_edit_exec_original_trapint"
    >
    >   .ble-stty.enter
    >   _ble_edit_PS1="$PS1"
    >
    >   .ble-edit.accept-line.exec.adjust-eol
    >
    >   # SIGERR処理
    >   if [ "$_ble_edit_accept_line_lastexit" -ne 0 ]; then
    >     if declare -f TRAPERR &>/dev/null; then
    >       TRAPERR
    >     else
    >       echo "[91m[ble: exit $_ble_edit_accept_line_lastexit][m" 2>&1
    >     fi
    >   fi
    > }
    > function .ble-edit/exec2/recursive {
    >   (($1>=${#_ble_edit_accept_line})) && return
    >
    >   local BASH_COMMAND="${_ble_edit_accept_line[$1]}"
    >   _ble_edit_accept_line[$1]=
    >   if test -n "${BASH_COMMAND//[ 	]/}"; then
    >     # 実行
    >     local PS1="$_ble_edit_PS1" HISTCMD="${#_ble_edit_history[@]}"
    >     local _ble_edit_exec_original_trapint=
    >     .ble-edit/exec2/eval-prologue
    >     .ble-edit/exec2/eval
    >     _ble_edit_accept_line_lastexit="$?"
    >     .ble-edit/exec2/eval-epilogue
    >   fi
    >
    >   .ble-edit/exec2/recursive "$(($1+1))"
    > }
    > }

    ここで trap - RETURN という物を発見する。関数やソースを抜けるたびに実行されるという物のようだ。
    正にこれを使えるのではないか…? と思って trap '((_ble_edit_accept_line_INT)) && return' RETURN
    等としてみたら無限ループになる。それどころかメモリを食い荒らしている。
    ${FUNCNAME[*]} で確認すると RETURN が評価されるのは抜ける関数やソースの中である様だ。
    そこで return を呼び出すと再び trap RETURN が反応してしまうという事になっている様だ。
    つまり、trap - RETURN を用いても呼出元の文脈で評価される訳ではないので呼出元を更に抜ける事はできず、
    その上無限ループになってしまうという事になる。
    #trap '((_ble_edit_accept_line_INT)) && return' RETURN # 無限returnループになる

    今度は trap ERR して見ようとしたが…そもそも呼び出されないようだ。
    (それに trap ERR だと条件式の内部にあるコマンドについては呼び出されないというし確実に抜ける事は出来ない)
    #trap '((_ble_edit_accept_line_INT)) && echo hello && return 128' ERR # 呼び出されない

    或いは trap DEBUG というのを使う事ができるかもしれない。
    DEBUG について色々試してみた。
    - 先ず、trap 'command' DEBUG した command の中では DEBUG は一切発生しない。
      (もし発生していたら無限ループになってしまう。)
    - また、bind -x 関数の中で trap - DEBUG しても bind -x の関数を抜けると消える。
    - trap - DEBUG 等を用いて削除しようとしても何故かできない。trap -p でも何故か一覧に出ない
      | 更に、trap 'command' DEBUG の command の中で trap - DEBUG しようとしても消えない。
      | trap 'echo 123' DEBUG 等と DEBUG を上書きする事もできない。
      | というか trap の中でなくても上書きできない様だ。それどころか trap -p の一覧に出ない。
      | (通常のシェル環境で実行している場合にはちゃんと trap -p で出るのだが)。
      | trap DEBUG した関数内では trap -p の一覧にも出るし trap 'echo 123' DEBUG で後から書き換える事も出来る様だ。
    trap DEBUG をその場で削除できないという謎があるが取り敢えず動く様になったので良しとする。

2015-02-11

  * <bug> home, C-home, ... 等多くのキーに対して keymap が見付からないエラーになる [#D0131]

    やはり初めからシーケンスが登録されているキーに関しては
    中途半端に bind -x するとこのエラーになる様だ。
    bind -x が2文字までしかできないバグは bash-4.3 で解消された様だから、
    登録されているキーシーケンスを全て bind -x してしまう事にした。

    登録されていないキーシーケンスを入力した時には依然として
    keymap が見付からないエラーが発生するが、
    登録されていないエスケープシーケンスは先ず来ない事と、
    来たとしても自然に解釈する事ができないのでこのままでも良い。

    登録されているキーシーケンスの列挙は例によって時間が掛かる様なので、
    これもキャッシュとして出力してしまう事にした。
    実際にやってみて良好に動いているので良しとする。

  * <bug> ログアウトした後も stty の状態が正しくない。 [#D0130]

    % 1 stty が正しく呼ばれているか? 正しく適用されるにはどうすれば良いか?
    %
    %   - visible-bell が最後に勝手に enter しているのかもしれないと思って切ったが駄目。
    %   - enter した時に x と表示する様にして最後に enter が起こっていないか
    %     確認したが起こっていない。
    %   - stty してから暫くしないと適用されないのかと思って sleep して見たが駄目。
    %   - stty してから何か出力しないといけないのかと思って leave してから
    %     メッセージを表示する様にしたが駄目。
    %
    %   C-d の中で leave して cat を実行すると C-c 等で終了できない。
    %   通常のコマンド実行の際にはちゃんと C-c できるのに何故だろう。
    %   何か設定で間違えている事があるのか、関数のネストが関係するのか、...。
    %
    %   cat は C-c が効くのに exit 後は C-c が効かない
    %   そして exit コマンドを実行して終了する時にも stty は正しく設定されていない。
    %   cat の時には正しく設定されていて exit の時には正しく設定されていない理由は何か?
    %   或いは bash 自体が何処かの時点での stty の状態を記録していて
    %   exit の時にその記録した時点での stty に設定してしまうのだろうか。
    %
    %   改めて確認してみる。
    %   C-d の中で直接 cat すると C-c できないが accept-line.add して実行して貰うとちゃんと
    %   C-c で止める事ができる。そこで exit を accept-line.add してみる殊にしたが、
    %   終了後の stty の状態は壊れた状態の儘である。
    %
    %   1 何故かは分からないがその場で実行しても stty は適用されないが
    %     accept-line の実行の枠組を使用して実行すると stty が適用されている。
    %     しかし次の項目にある様にこの振る舞いは今回は訳には立たない。
    %   2 accept-line の枠組を使用して stty が適用された状態にしても、
    %     そこから exit した場合には stty の状態は反映されない。
    %     途中に外部コマンドを挟んでも駄目。
    %
    %   .ble-stty.setup を殺して一度も stty で undef をしない様にしてみたら、
    %   当然の事ながらログアウト後に壊れているという事はないようだ。
    %
    % 2 detach してから exit するという事
    %
    %   bind -x 内 で exit しても勝手に stty の設定が壊れた状態に戻ってしまう。
    %   一旦 stty を正常な状態にして ble だけを終了し、
    %   その後で手動で exit したらどうなるか?
    %   つまり、ble の "detach" だけを行って exit をしない時 stty が壊れなければ、
    %   その後に普通に exit をする事で stty が壊れない様にできる。
    %
    %   これを試す為に、ble の設定を全て解除するコードを書く必要がある。
    %   つまり bind -x した物を全て外し、元々 bind されていた物を再適用する。
    %   →stty が正常な状態で復帰できた。この後で exit をしても壊れない。
    %
    % 3 しかし detach するだけだと分かりにくいのでやはり exit についても実装する。
    %
    %   その場で detach をして bind -x から抜け、その後で時間差で抜ける。
    %   その為にシグナルを用いる。
    %
    %   所が、シグナルハンドラの中で exit をするとその stty の状態で終了する様なので、
    %   シグナルハンドラの中でも stty で正しい状態を設定する様にする。
    %   これで正しい stty の状態で抜ける事ができる様になった。
    %
    %   所が、また問題がある。どうやら入力待ち状態にある時にシグナルは受け付けない様だ。
    %   まあ、スレッドが止まっている状態なのだから当然と言えばそんな気もする。
    %   この所為で次の文字を入力した時に初めて exit される。
    %
    %   と、ここでその場でシグナルを自分に投げたらどうなるのか…と思う。
    %   シグナルハンドラの内部からならば設定した stty で exit できる…
    %   という事はその場で読んでしまって充分なのではないか。
    %   と思ってその様に実装したら期待通りに動く…。
    %
    % 4 残っているのはユーザが exit コマンドを使用した時である
    %
    %   そのまま exit/logout されるとやはり stty が壊れる。
    %   exit/logout 関数を上書きすれば良い。
    %
    %   exit() {
    %     if (($BASHPID==$$)); then
    %       _ble_edit_detach_flag=exit
    %     else
    %       exit "$@"
    %     fi
    %   }

    と、ここで man の exit の所に EXIT トラップについて書かれている…。
    もしかしてこれを設定すれば良いだけの話では…。。
    結局 trap .ble-stty.exit-trap EXIT の一行で済む話だった。

    一応 detach という機能が実装されたので今回の変更が完全に無駄になった訳ではないが。

  * rcfile として起動すると history がロードされない。 [#D0129]
    rcfile の中で history を参照しても中身が未だロードされていない様だ。
    history -n で読み込む事にした。

  * C-S-a 等の \e[2... が読み取れない。というか単なる [ に変換されている…? [#D0128]

    これも同様に bash_execute_unix_command のエラーが発生している様だ。
    試しに bash --norc として起動してから source ble.sh して見たら起きなくなった。
    なので、これに関しては余り気にする必要はない。
    bash --rcfile ble.sh 等として起動すればよい。

    所で --rcfile で起動すると history が正しく読み込まれていない。
    source ble.sh で起動した場合には正しく読み込まれている様である。
    rcfile の中では history を読み取る事が出来ないという事だろうか。

  * ちらつきを抑えるという事 [#D0127]

    ちらつきを抑える為に ble-decode-bind:bind が呼び出される前後で
    標準出力・標準入力を繋ぎ変えて見る事にした。

    % が、ちらつきは変わらない。
    % 今迄ちらつきの無かった所ではちらつきがない儘だし、
    % ちらつきが起こっていた所はちらつきが起こっている。
    %
    % 設定を間違えると何も表示されなくなるから標準出力・標準入力の繋ぎ替え自体は
    % 効いていて、bash が出している物は出力されなくなっている筈である。
    %
    % | 但し、他の可能性もある。
    % | もしかすると bash は fd を個別に持っていてそれに対して出力しているかも?
    % | そうすると繋ぎ替えを 1 2 に対して行っても bash 自体の出力先を変更できない。
    % | 上の実験で何も表示されなくなったように見えたのが勘違いの可能性もある。
    % | つまり、ble では PS1 を空欄にしているので bash が何も出力していない様に見えるが、
    % | 実際には行を消してしまう物を出力しているかもしれない。)
    % |
    % | 念のため簡単なテストをしてみる。
    % | $ exec 3>&1
    % | $ function on { exec 1>&3 2>&3; }
    % | $ function off { exec 1>/dev/null 2>/dev/null; }
    % | $ bind -x '"\C-o":"on"'
    % | $ bind -x '"\C-p":"off"'
    % | 以上の設定の後で C-o C-p で表示・非表示が切り替わる事を確認した。
    % |
    % | つまり bind -x の内部で exec してもちゃんと bash のプロンプト表示も影響を受ける。
    %
    % という事は、ちらつきは bash がプロンプトをクリアする事によって起こるのではなく、
    % ble 自体の再描画によって起こっていると結論する事ができる。
    % (bash がクリアしたプロンプトを直後に再描画しているのは功を奏しているという訳だ)

    改めて動かしてみるとちらつきは起こらなくなっていた。
    テストの時に新しい物をちゃんとロードできていなかったという事か。
    何か腑に落ちないが今後はこの方針で行く事にする。
    一応 ble_opt_suppress_bash_output オプションで繋ぎ替えを off にできる様に残しておく。

    一応註記しておくべき事は、exec で標準出力・標準入力を潰しても
    カーソルの位置などが乱れる事なく動作しているという事である。
    と思ったらカーソルの位置がずれている…。
    →.ble-edit-draw.update-adjusted の関数内で bash の出力に対する対策をしていたので
      exec を実行している場合にはその対策を行わないように修正した。これで動いている。
    →が、しかし今度は C-d で前触れ無く (後処理無く) ログアウトする様になってしまった。
      READLINE_LINE READLINE_POINT の設定はその儘にして位置調整のシーケンスの出力だけ
      を行わない様にした。

    もう一つの確認事項は vbell のクリアがちゃんと出力されるかという事。
    これは 1 2 が端末に繋がっている時に fork している筈だから出力されるのではないかと思うが。
    →実際に試してみた所ちゃんと vbell の消去が出力されている様なので問題ない。

2015-02-09

  * <bug> bind -x '"\"":...' 及び bind -x '"\\":...' [#D0126]

    cygwin の bash-4.1 で改めて動かしてみた所色々問題がある

    1 '\' と '"' が bind -r できていない
      良く考えたら bind -r している訳ではなくて bind -x で上書きをしているのであった。
      そして bind -x している物を調べたら先程弄ったコードの簡単なミスだった。修正。

    2 カーソルキーの類が全て M-\\ と解釈されている
      これは 1 に関連する物だった \\ に bind する代わりに \[ に bind していた所為で
      CSI が M-\\ に翻訳されてしまっていたというだけの話であった。

  * <bug> bash-4.3 日本語が入力できない。 [#D0125]
    8bit 文字は \ooo の形式で bind -x '"\ooo":...' しなければならなくなった。

    | 以前までは bind -x ではマルチバイト文字を 1 文字ずつしか受信できなかったのが、
    | いつの間にかに日本語として受信できるようになった様だ。
    | 今迄は octet の 256 文字を全て登録する事で入力を全て横取りできたが、
    | この所為で unicode にある全ての文字について bind しなければ日本語を受信できなくなった。
    | どうするか…。
    |
    | 例えば以下を設定した状態で "あ" と入力すると hello となる。tttqqqrrr とはならない。
    | hello を bind していない状態だと tttqqqrrr となる。あれ、受信できている…。
    |   bind '"\343\201\202":"hello"'
    |   bind '"\343":"ttt"'
    |   bind '"\201":"qqq"'
    |   bind '"\202":"rrr"'
    | つまり bind -x では受信できない、という事なのか? と思ったらちゃんと受信できる。
    |
    | では ble.sh で受信できないのは何故か? \ooo の形式で指定する必要がある?
    | と思って \ooo の形式で指定する様にしたら直ぐに入力できる様になった。

  * <bug> bash-4.3 "ESC [ 数字" 系のシーケンスを入れると [#D0124]
    bash_execute_unix_command: keymap云々 のエラーになる。

    問題: C-left C-right を使おうとするとキーマップがないと出る

    これは bash --norc から source しても変わらなかった。
    $ TERM=dumb bash --norc
    $ TERM=screen-256color; source ble.sh
    等としても同じだ…
    (というか source ble.sh する前に C-left C-right を試したら TERM=dumb でも動く。)

    他にも試してみたがどうも "ESC [ 数字" 系のシーケンスが全部駄目な様だ。

    仕様がないので "ESC [ *" を全て登録する事にする

  * <bug> bind -r すべき対象を bind -sp | fgrep していたが fgrep が結果をバイナリと判定する事がある [#D0123]

    fgrep -a とオプションを指定する事で解決した。

    | %%問題: bash で起動するとカーソルキーを使えるが bash --norc で起動するとカーソルキーを使えない%%
    |
    | これは謎である。~/.bashrc の中で設定しているものと関係があるのだろうか。
    | source ~/.mwg/bashrc; source ble.sh とするとカーソルキーを使える。
    | source ~/.mwg/share/mshex/shrc/bashrc_interactive でも使える。
    |
    | test-prebind.sh に bashrc_interactive の中から bind 関係の部分を抜き出してみても使える。
    |   どんどん絞り込みをしていく。複数の bind の組合せで起こっている?
    |   かなり不思議な事が起こっている…コメントの有無で結果が変わる…。
    |   そればかりか末尾の改行の数にも依存している。再現性がある事は明らか。
    |   改行の数が一定数以上ならばOK? でも改行の後に何があるかにも依存している。
    |
    |   bind よりも前に何を書いても大丈夫なように見えてコメントを沢山書いたら駄目になった。
    |   どうやら bind よりも前のコメントに何が書かれているかにも依存する様である。
    |   仕方がないのでコメントは以下に移動してくる。
    |
    |   # @bash-4.3
    |   # 以下を読み込んでから ble.sh を読まないと何故かカーソルキーが使えない
    |   #   bind よりも後の空白の数だとかコメントの文字数が
    |   #   違っただけで使えたり使えなかったりする。
    |   #   コメントの内容によっても結果が異なる様だ。
    |   #   bash のメモリ関連のバグだと思われる。セキュリティ的に危ないんじゃないか??
    |
    |   また気付いた事だが、暫く時間が経つと先程まで動いていた test-prebind.sh では動かなくなったりする。
    |
    | bash のバグとしか思えない動作なのでここでは置いておく事にする。
    |
    | →何と新たな事実が判明した…。
    |   カーソルキーが使えない場合については ble.sh 内の bind -r が走っていない。
    |   色々調べると bind -sp は色々物を出力しても、
    |   fgrep の段階で「バイナリ」と判断されたり判断されなかったりする様だ。
    |   fgrep でバイナリと判断されると中身が表示されない為に bind -r が走らない。
    |
    | 結局 何故 bind コマンドの周りのコメントやら何やらが fgrep のバイナリ判定に影響を与えるのかは分からなかった。
    | コメントの有無などで bind -sp で表示される順序などが変わるという事なのだろうか。
    | 或いは fork 元の bash のメモリの内容に fgrep の判定が影響を受けているとか。

  * "bash: bash_execute_unix_command: コマンドのキーマップがありません" と出る問題 [#D0122]

    久しぶりに起動してみたら色々と動かない? @bash-4.3 of padparadscha

    カーソルキーを入力しようとすると
    bash: bash_execute_unix_command: コマンドのキーマップがありません
    等と表示される。検索すると bind -x した時の bind 先が不明な場合に発生するエラーメッセージの様だ。
    ESC で始まるキーシーケンスに対応するキーは全てこれなので ESC 関係が悪さをしているのだろう。

    bind -x した物の一覧を取得する方法があれば良いのだが。
    以前に探した時には見付からなかった気がするが、改めて調べてみる。と、
    bash-4.3 以降では bind -X を用いて bind -x した物の一覧を表示する事ができる様だ。
    早速試してみると確かに bind -x した物の一覧を閲覧する事ができる。

    そこで bind -x した物の削除を試みる。
    普通に bind -r $'\ez' しても削除できない…。
    と思ったら実はちゃんと削除できているが bind -X の表示に反映されていないだけという事が分かった。

    <bashbug> bash-4.3.33, bind -r して削除した後のコマンドが bind -X の一覧から削除されない。

    分かった事: 2文字シーケンスを登録すると1文字目にkeymap変更が割り当てられる

    | どうやら一回でも 2 文字のシーケンスを登録してしまうと
    | それらを全て削除しても 2 文字のキーシーケンスに対応する keymap を探す様だ。
    | 例えば "ab" というシーケンスを登録すると
    | 「"a" は2文字のキーシーケンスの1文字目」という情報が登録されてしまい、
    | a に続けてどの様な文字を打っても対応する2文字のキーシーケンスが見付からない!
    | という状態になってしまう。(実際に "ab" で試してみたらそうなった。)
    |
    | ※唯単に bind -x '"ab":"echo"' && bind -r ab 等としただけでは再現しない。
    |   予めあらゆる 1 文字コマンドについて bind -r && bind -x ... しておくとなる。
    |   bind -x でない通常の readline 関数がそれぞれの文字に割り当てられている場合はそれが呼び出される様だ。
    |   しかし、全てを bind -x で処理する為に readline 関数を解除していると "見付からない" という事になる。
    |   再現方法は以下の通りになる:
    |
    |   $ bind -x '"ab":"echo"' && bind -r ab && bind -x '"a":"echo"'
    |
    |   1つ目のコマンドも3つ目のコマンドも -x でなければ再現しない様だ。つまり、
    |   $ bind '"ab":self-insert' && bind -r ab && bind -x '"a":"echo"' → 再現しない。問題なし。
    |   $ bind -x '"ab":"echo"' && bind -r ab && bind -x '"a":self-insert' → 再現しない。問題なし。
    |   という事である。
    |
    | これを解決する為には "a" で始まるあらゆる2文字のシーケンスを登録すれば良い。
    |
    | これは C-x の状況と似たような状況である。
    | (以前の bash で試した時には C-x に続けて何か入力すると bash 毎落ちていた。
    | これがエラーメッセージを表示するという状態に修正されたのだろう。)

    取り敢えず "ESC なんとか" は如何にも bind -x で登録されそうな組合せなので、
    "ESC *" の全ての組合せを登録してしまう事にする。
    実際には bind -x でどの様な2文字のシーケンスが登録されているのか分からないので、
    あらゆる "* *" の組合せについて登録しない限りは万全とは言えない。
    とはいいつつあらゆる組合せについて 2 文字単位でしか入力を読み取れない状態にもなる。
    これは明らかに不便だ。結局、"ESC *" の組合せを登録する程度が限界だろう。

    分かった事2: ESC は bash-4.3 では初めから2文字のシーケンスの一部と解釈される

    | bash --norc で起動した状態から source ble.sh した場合は ESC * に bind しなくても良いかと思ったが、
    | 実際に試してみた所同様のメッセージ bash: bash_execute_unix_command: コマンドのキーマップがありません
    | が出る。bind -X で確認したが、やはり bind -x は何も存在していない状態から source ble.sh だった。
    | その他の version の bash がどうなのかは試していない。

    つまり、bind -x を何もしていない状態でも "ESC *" に対して bind しなければならないという事。


2013-06-13

  [Done]

  * <bug> bash-3.2.48, bash-3.1: カーソルの表示位置がずれる。 [#D0121]
    と思ったら、そもそも READLINE_LINE 及び READLINE_POINT に対応していない様だ?
    これだと C-d で即座にログアウトしてしまう…。

    →これに関しては READLINE_LINE は空白のままで諦める事にした。
      この状態であれば bash による出力は何も為されないので、
      カーソル位置の修正などを行う必要はなく、ただ .ble-edit-draw.update を実行すればよい。

    →また、C-d に関しては IGNOREEOF を大きな値に設定して取り敢えず諦める事にした。
      制限としては C-d を受信する事が出来ないという事、C-d を押すと
      「ログアウトする為には exit を入力して下さい」と表示され、
      プロンプトの表示などが乱れる (というか何も表示されない) という事。

    [2013-06-13 21:24:46]

  * <bashbug> bash-3.1 [#D0120]
    パラメータ展開の部分文字列で、範囲外のインデックスを指定すると ^? が返ってくる。
    これはどうしようもない。部分文字列は他の場所でも多用している上に代替手段が存在しない。
    (勿論、別のプログラムを呼び出せばこの機能を再現する事は出来るが、
    それをするととても遅くなるので受け入れがたい。)

    bash の ChangeLog を見てみたが、このバグに関する情報は書かれていない様な気がする。
    一応 bash-3.2 から bash-4.0 へ変わる時に配列の ${array[@]:*:*} で stray の ^?
    が出るバグを修正したと書いてある。また、${var##..} で空白が絡む時の stray ^? についても
    バグの修正が為された様だ。

    →何故かは知らないが、a=; echo "(${a::})" とすると ^? が出力されるが、
      a=; x="${a::}"; echo "($x)" とすると正しい結果が返ってくる。
      また "(${a::})" や "a${a::}b" 等とすると ^? が出力されるが、
      "(""${a::}"")" や "a""${a::}""b" とすると ^? は出力されない。
      もし "" で文字列を区切るだけで良いのだとしたら、少ない修正で bash-3.1 にも対応可能である。

      取り敢えずこの修正によって見た目ちゃんと動いている様子である。
      [2013-06-13 21:25:43]

    →また、bash-3.2.48 で確認してみた所、このバグは既に取り除かれている様だ。

2013-06-12

  [Done]

  * <bug> bash-3 では bind -x されたコマンドを受け取った時、 [#D0119]
    一度改行してから実行される為に、行がずれていく。
    プロンプトは消去されないので再描画の必要はない。
    現在位置の情報を更新するだけで良かった。

  * <bug> ble-bind -D: cmap または kbd が全く定義されていない状態で [#D0118]
    ble-bind -D を実行すると内部の declare -p が無引数で実行されて、
    bash 内で定義されている全部の変数が出力されてしまう。
    これは、_ble_decode_cmap_@ または _ble_decode_kbd_@ が 1 つ以上あるか
    どうか確認してから declare -p を呼び出す様にすれば良い。

  * <bug> bash-3.1, ble-decode-kbd ESC の結果が 3 になる。 [#D0117]
    .ble-decode-kbd.get-keycode: tmp の要素を数える所で、
    tmp の先頭要素の文字数を数えていた。

  * <bug> bash-3.1: 何と bash-3.1 の算術式では ?: を数珠繋ぎに出来ない。 [#D0116]
    ちゃんと括弧で括っていかなければならない。これは結構痛いと思ったが、
    意外と書き直さなければならない所は少なかった。

    .ble-text.c2bc+UTF-8, .ble-text.c2w+emacs, .ble-text.c2w.ambiguous

  * <bug> bash-4 未満で _ble_decode_kbd__c2k を -A として宣言していた。 [#D0115]
    -a に書き換えるだけでよい。
    [2013-06-13 00:26:51]

  * <opti> スタイルを一つの整数で表現する。 [#D0114]

    文字列比較などをすると時間が掛かる為。
    ble-color.sh, ble-edit.sh 等を書き換えた。意外とすんなりできた。
    これで .ble-line-text.construct のループ内の処理をできるだけ算術式で記述し、速度向上を図る。
    →変更した。定量的に変化があったかどうかは分からないが。

  * ble-edit.sh: quoted-insert, self-insert, insert-string で [#D0113]
    _ble_edit_mark_active を解除するように変更

  * [ble: exit] の際の色を変更 [#D0112]

  * 履歴展開: 展開に失敗した時の対処。 [#D0111]
    その儘空白のコマンドを実行してしまっていた。
    履歴展開に失敗した時は bash では、前回編集中のコマンドが再度表示される。
    それに倣って書き換えた。
    [2013-06-12 15:15:47]

  * 履歴展開が使えない [#D0110]

    set -H としてみたが eval の中では有効には為らなかった
    (というか、多分、set -H は初めから設定されていたのではないかと思う)。
    history -p で変換してから実行すれば等価だろうか。
    ("" で囲んでも実行された、が、通常の履歴展開の動作もそうなっている様だ。)

    この方針で実装する事にした。
    [2013-06-12 15:14:22]

  * fword: IFS に加えて / も区切とする単語単位の操作を追加。 [#D0109]

  * uword: IFS を参照してそれを基準にして単語境界を決めるように変更。 [#D0108]

2013-06-11

  [Done]

  * <bug> 特定の操作をした時に accept-line の処理が中途半端で終了する [#D0107]
    C-c や C-z など。

    [C-z 完 2013-06-11 12:22:35]

    + C-\ の場合は問題なく続きが実行される。

    + 実は C-z をした時にも同様の事が起こっている様だ。

      こちらについては trap 'echo' TSTP, trap 'echo' 20, trap echo 'SIGTSTP' 等としても設定できない?
      trap -p をすると予め '' が割り当てられている様子である。
      その他にも予め '' が割り当てらｒている TTIN TTOU についても、
      trap を仕掛けても何も trap する事ができない様だ。

      念のため trap : 20; trap -p と、連続で実行してみたがやはり設定できていない。
      つまり、誰かが設定を戻しているという訳ではなく、初めから設定できないという事。
      また、stty susp undef としてから trap してみたが、それでも設定できない。

      然し乍ら C-z をした直後には、何故か redraw は実行される様だ。
      但し、stty の設定は元に戻っていないようで、
      C-c や C-z 等の文字を受け取る事は出来ない。

    + 然し C-z の直後には何故か prompt が表示されている。
      これは一体誰が表示しているのだろうか?
      →確かめてみた所、C-z した時は実行中のコマンド全てに失敗する訳ではないようだ。
        accept-line.exec 内のループを抜けるに留まるらしい。

        for コマンドが C-z を受信するという事だろうか?
        試しに accep-line.exec 呼出元で 1 回ループにくるんで見たところ、
        C-z でそのループまで抜けるようになった。
        つまり、for 等のコマンドを使わずに実行すれば良いという事だろうか。
        (一応再帰と条件分岐さえあればループは可能。)

        試してみた所 && による条件分岐は C-z で止まらない
        また、if 文による条件分岐も C-z では止まらない様だ。

2013-06-10

  [Done]

  * <opti> .ble-line-text.construct 文字連結最適化? [#D0106]
    [2013-06-11 03:37:38 余り効果は無かった]

    カーソル移動だけの時は配置の再計算を省略できるようにしたが、
    カーソル移動がそれ程速くなったとは思えない。(少しは軽くなった気がしないでもないが)
    何がボトルネックになっているのだろう。残りは、文字連結程度しかない。
    なので、文字連結の最適化について考え直してみる。

    色々試してみた結果、配列に格納していって最後に join するのが速いようである。
    また、${#out} の様な長さの評価の仕方は O(N) の計算量なので
    ループの中で毎回参照するのは避けた方が良い。
    →余り改善したようには思われない…。

    或いは単に関数の呼出に時間が掛かっているだけなのか?
    →でもこれはあり得ない。何故なら編集文字列が短い時にはきびきびと動くから。

    それとも cache_g[i] やら cache_ei[i] の代入に時間が掛かっているのか。
    →試しに off にしてみたがそれ程変わった雰囲気もない。

    或いは座標位置の再計算をしてしまっている? → 確認してみたが、ちゃんと再計算は省略されている。

    改めてどの場所で時間が掛かっているか確かめる為に、
    カーソル移動しか起こっていない場合には文字連結部分を省略してみる事にした。
    (この様にするとカーソル移動によって更新されるべき物が更新されないので、実際には使えない方法である。)
    →すると動作がとても速くなったので、やはりこの文字連結を行っている部分が悪い様だ。

    更に、ダミーで文字連結のループを回して何処に時間が掛かっているのか調べる事にした。
    →文字を配列に登録する部分はそんなに時間は掛かっていないようだ。
    →文字列の長さを計算する部分も関係ない。
    →cache_ei や cache_g に代入している部分も関係ない。

    # →と、ここで SGR 系列を追加している部分を有効にしてみたら急に遅くなった。
    #   先程やった時には余り変化が無かったように感じたが恐らく勘違いだった。
    # →どうも文字列比較 if test "$seq" != "$seq0"; then の部分が重い様子である。
    #   (seq, seq0 はそれぞれ3文字なのでそれ程重いとは思えないのだが)
    #   以下のような色々な物を試してみたが、速さに大差は無いようである (当然か)。
    #   if test -n "${seq#"$seq0"}"; then
    #   if test "$seq" != "$seq0"; then
    #   if [ -n "${seq#"$seq0"}" ]; then
    #   if [ "$seq" != "$seq0" ]; then
    #
    #   或いは、sgr の表現を整数にして、整数同士で比較する様にすると速いかも知れない。
    と、ここまでで SGR 系列の部分が怪しいのではないかと色々調べてきたが、
    やはり? 違うようだ。別の所をコメントアウトして SGR 系列の部分だけ残してみると充分速い。

    どうも、何処が特に重いという訳でもなく、これが bash の限界という事のようだ。
    早く dirty または色変更した部分だけしか再計算を実行しなくても済む様に変更した方が良いという事だろう。

  * カーソル移動では dirty を設定しない様に変更。 [#D0105]
    →意外と少なかった。移動は全て .ble-edit.goto-char を介して実行されていた為、
      .ble-edit.goto-char の中で実行されている .ble-edit.set-dirty を削除するだけで良かった。
      その他は set-mark, exchange-point-and-mark ぐらい。

    + と思ったらカーソルを移動しても、カーソルの移動が表示に適用されなくなった。
      良く考えたらカーソルの移動をした場合、文字の配置を再計算する必要はないが、
      表示の際の領域反転などは再度計算し直す必要があるので、
      描画に関しては再度実行する必要がある。

    # * 現在 cursor 移動も dirty として扱っているが、
    #   別にその様に扱う必要性はないのではないか?
    #
    #   dirty としたのは色付け関数によって括弧の強調などの色付けがカーソルの位置に
    #   依存して行われる可能性があったからである。
    #   色付け関数が region_highlight なり何なりを呼び出した時点で、
    #   set-dirty が自動的に為されるような仕組みにしておけば問題ない。

  * <bug> set-mark: 動作が emacs と違う。 [#D0104]
    emacs では既に mark が active な場合でも、
    active なまま新しく現在位置を mark の位置とする。
    active 状態をトグルするなどといった事はしない。
    [2013-06-11 00:23:12]

  * _ble_edit_mark_active [#D0103]
    今迄の型は整数型で 0 または 1 の値を取っていたが、
    今後は様々な種類のマーク (S-move によって有効になったマークなど) を区別する為に、
    + マークが設定されていない場合は ''
    + set-mark によってマークが設定されている場合は '1'
    + S-move によってマークが設定されている場合は 'S'
    + (その他のマークを設定する事が在れば必ず有限長の文字列)
    等のように文字列とする事にした。これに伴って何カ所か修正。
    [2013-06-11 00:14:30]

  * <bug> 今迄 sword としていたのは寧ろ unix-word の事だった。 [#D0102]
    名称を sword から uword に変更。
    [2013-06-10 22:41:22]

  * <bug> uword の定義で空白を SP HT にしているが、LF も含める。 [#D0101]
    [2013-06-10 22:41:28]

  * sword 関連に対応 [2013-06-10 22:43:42] [#D0100]

    IFS=$'|&;()<> \t\n' (シェルのメタ文字) を区切り文字として単語分割する。
    但し、quote については正しく処理していない。

    # unix-word の定義について調べて uword として実装する。

  * forward-word, backward-word を emacs や readline と同様の位置に移動する様に変更。 [#D0099]

  * <opti> 長い文字列を編集するのに時間が掛かる。 [#D0098]

    これは毎回 construct-line でカーソルの位置の計算と出力文字列の構築を行っているからである。
    特に、一つ一つの文字幅を毎回計算しているのが一番重い気がする。
    理想的には dirty な部分以降の計算を実行すれば良いはずである。

    と思ったが、カーソルの位置が変われば SCOSC, SCORC の埋込位置が変わる為、
    現状の実装方法ではやはりカーソルの位置から再度計算し直さなければならない。

    これの解決方法としては、
    + 先ず全ての文字の後で x y lc lg がどの様な状態になるべきかを計算し、これを cache 配列に記憶する。
    + また、全ての文字に対して esc_line 中の何文字目に対応するかも記憶しておく。
    + esc_line 自体も何処かに記憶しておく。
    construct-line 関数は以下の処理を実行する
    1 dirty が設定された場所から位置解析をやり直す。
      この解析では各文字だけを記録し、escape sequences の構築まではしない。
    2 更に色付けの処理を dirty が設定された場所からやり直す。
    3 色付けによって変更された箇所から escape sequences を構築し esc_line とする。
    4 esc_line のカーソル位置と末端に SC と RC を挿入して ret に入れる。
    5 カーソル位置の x y lc lg を取り出す。

    新しく .ble-line-text.construct という関数を作る事にした。

    + 先ず始めに .ble-line-text.update-positions で dirty から x y lc を更新する。

      i文字目を処理している時:

      1 cache_x[i], cache_y[i] の更新
        cache_x[i], cache_y[i] には i 文字目を出力する **前** のカーソル位置が格納される。
        (或いは、i-1 文字目を出力した **後** のカーソル位置とも言う事が出来る。)

      2 次に cache_lc[i] の更新を行う。
        cache_lc[i] は、cache_x[i]!=0 の場合は、その左側に位置する文字、即ち i-1 番目の文字のコードを保持する。
        cache_x[i]==0 の場合は、その次に同じ行に来る文字のコードを保持する。

        cache_lc[i] は x!=0 の時は、前回の文字コード (lc) をそのまま代入すれば良い。
        然し、x==0 の時は、次に x!=0 になるまで代入を実行する事は出来ない。
        ここで変数 li を導入する。li は、次に cache_lc を代入するべき位置を保持する。

        x!=0 の場合には cache_lc[li] ～ cache_lc[i] までの値を代入し、li=i+1 とする。
        x==0 の場合には cache_ic に対する代入は実行せず li の位置も進めない。
        cache_lc[li] ～ cache_lc[i] に対する代入は以下のように行う。
        x!=0 となった行 y が cache_y[j] と一致するならば lc を代入する。# これだと ^A 等の場合に A に化けるのでは?■
        x!=0 となった行 y が cache_y[j] と異なるならば 32 (空白) を代入する。

        for(j=li;j<i;j++)
          assert(_ble_line_text_cache_x[j]==0);

      3 cache_lg[i] の更新は未だ行わない。

    + その後紆余曲折を経て新しい「編集文字列構築器」ができた。
      古い関数
        .ble-cursor.construct-line.chk-cursor
        .ble-cursor.construct-line
      は削除する。
      [2013-06-10 22:02:41]

2013-06-09

  [Done]

  * <bug> source ble.sh でエラーが発生するようになった。 [#D0097]
    どうやら ble-bind で発生している様だ、
    と見てみたら OPTARGS の変数存在確認で "${OPTARGS+set}" を引用符で囲むのを忘れていた。
    [2013-06-10 04:00:03]

  * <opti> プロンプトの初期化が異様に遅い @ cygwin [#D0096]

    プロンプトで \j が3回参照されている。
    それぞれの \j の呼出で2つのプロセスが生成されているので、
    プロンプトの初期化で合わせて 6 つのプロセスが生成されている事になる。
    cygwin のプロセス生成の速度は測ってみたら秒間 10 程度であったので確かに時間を食う。
    (本来はプロセスを生成せずにこれを処理したいが。)

    プロンプトの初期化中にコマンドを実行する場合は、
    コマンドの実行結果をキャッシュするように変更。
    [2013-06-10 03:31:58]

    更に job の数を wc を使わずに数える様に変更。
    [2013-06-10 03:53:44]

    これらの変更によって cygwin でなくてもかなり軽くなった様に思われる。

  * <bug> /bin/printf, source ble.sh 時にエラー @ cygwin [#D0095]
    c2s: /bin/printf が使えない環境で source ble.sh 時にエラーメッセージが出る。
    /bin/printf の stderr を /dev/null に落とすように変更。
    [2013-06-10 03:37:02]

  * <bug> [ -v ] のエラーが発生する @ cygwin [#D0094]
    cygwin 環境で動かしてみる→エラーが発生して初期化に失敗する。
    ble-bind で OPTARGS の変数存在チェックに test -v を使用していた。
    bash-4.1 以下でも動くようにする為には test -n "${OPTARGS+set}" を使用するべき。
    [2013-06-10 03:34:53]

  * <bug> c2s-hex: /bin/printf を用いて [#D0093]
    function .ble-text.c2s-hex を定義するべき所を
    function .ble-text.c2s を定義していた。
    [2013-06-10 03:33:23]

  * <bug> 再描画の際に sgr 情報が失われる。 [#D0092]
    カーソル位置を設定する時、lc と共に sgr の情報として lg も記録するようにしたい。

    construct-prompt に関しては取り敢えず置いておき、
    construct-line の方での対応を済ませる。
    [2013-06-09 19:25:13]

  * <bug> 編集文字列が右端一杯の時に縦の位置がずれる。 [#D0091]
    <del>右端付近に tab があると縦の位置がずれて表示される。</del>

    多分、tab の所為で発生する改行についてちゃんと対策が取れていない為である。
    後でゆっくり考える必要がある。

    と思って色々試していたら、別に tab がなくても編集文字列末端が右端付近に位置している時には
    縦の位置がずれてしまうという事が分かった。
    原因は construct-line の中で SCORC を出力する位置にあった。
    最後の改行を出力する前に SCORC を設定していた。本当は最後の改行の出力も済ませてから
    SCORC を設定するべきだった。

    + これで丁度右端ぎりぎりまで編集文字列がある場合に常に (カーソルが何処にあっても)
      位置がずれると言う問題は解決した。

    + しかし、それでもカーソルが丁度右端にある時のカーソルの位置が変な事になっている。
      右端にあるので本来はカーソルは見えない (?) 筈であるのに最後の文字 (右端から一文
      字戻った場所) に表示されたり、次の行の最後の文字の位置に表示されたりする。

      そもそも一番右端にカーソルが来た場合に何処にカーソルを置くべきかという事だが、
      xenl が有効な端末でも無効な端末でも同様に表示するのであれば、次の行の先頭に表示する
      べきである。(その事も考えて編集文字列が丁度右端に到達している時に、xenl に対して
      改行を出力しているのである)

      問題は、SCOSC をしている時に行末端に位置している為に、SCORC で戻ってきた時に、
      (折角改行したのに) 行末端の位置に戻ってきてしまう事である。
      今迄は行末端に来た時、xenl であっても次に文字が来た時に次の行に自動的に移動するから
      敢えて改行は出力しないようにしていたが、SCORC で戻ってくる事も考えると、
      ちゃんと xenl の場合には明示的に次の行に移っておいて、その後で SCOSC される様にする
      べきである。

      その様に書き換えたらちゃんと期待通りにずれずに動くようになった。TAB がきても問題ない
      [2013-06-09 18:37:58]

  * <bug> 全ての文字に対して SGR を出力している。 [#D0090]
    編集文字列の表示で出力している escape sequence を見てみると SGR が変化していないのに
    毎回 SGR の設定を出力している様だという事が分かった。前回の文字と SGR の設定が同じ場合には、
    SGR の設定は出力しないようにしていた筈である。
    →改めて確認してみた所 seq0=seq としていた。seq0="$seq" でなければならない。
      「前回の SGR」の値が常に誤った設定になっていたから、毎回 SGR が出力されたのである。
    [2013-06-09 18:06:30]

  * <bug> 改行を含むコマンドを編集している時、 [#D0089]
    行の先頭にカーソルがある時に、そこに位置する文字が空白に化けて表示される。
    本来ならば行頭に文字がある場合、その文字を lc に設定する事になっているはずである。

    見てみた所、.ble-cursor.construct-line.chk-cursor までは正しく処理できている様に見える。
    と思ったら、update-adjusted で lc から READLINE_LINE を設定するのではなく、
    単に空白を READLINE_LINE に代入していた。
    [完 2013-06-09 16:53:31]

  * <bug> tab が幅ゼロで表示されている。 [#D0088]
    時々幅を持って表示されるがその規則は謎。

    と思ってみていたら tab の幅が負の大きな値になったりしている。
    絶対値は大体 x と同じぐらいである。と、ここで /it とするべき所を %it としている事に気付いた。
    同様のコードを色々な所に書き散らしていたので、それらも纏めて修正した。
    [2013-06-09 16:43:12]

  * <bug> 改行を含むコマンドを実行すると、実行後にカーソル位置がずれる。 [#D0087]
    [2013-06-09 16:14:26]

    これは前回のプロンプトが表示されていると勘違いして原点に移動する為である。
    _ble_line_x, _ble_line_y を 0 に設定するべき。

    →.ble-edit.accept-line.exec.adjust-eol で
      _ble_line_x, _ble_line_y を 0 に設定する事にした。

  * <bug> quoted-insert [#D0086]
    一部の文字を read -n で読む事が出来ない。
    →これは全ての文字を ble で処理できるようになったら
      ble の仕組みを通じて読む事にすれば良い。

    改めて試してみた所、大概の入力は読み取れている? 後で再度確認する必要有り。
    確認してみた所 ^I ^J ^M の入力をする事ができない。
    やはり、ble-decode-char 辺りに quoted-insert を仕掛ける必要がある。

    # * ble-edit-quoted-insert:
    #   現在はデバグの為に一部の文字列しか捕まえられないので、
    #   read -N を使って実装を行っているが、
    #   全部を ble で処理するようになった時は、
    #   ble-decode-char に対して干渉するだけで良い?

    .ble_decode-char:
    _ble_decode_char__hook 変数を追加、この変数が設定されている場合は、
    この変数に代入されている文字列をコマンドとして実行するように変更。
    [2013-06-09 16:09:46]

  * デフォルトの cmap である term+default を読み込むのに時間が掛かる。 [#D0085]
    [完 2013-06-09 15:46:02]

    恐らく ble-decode-kbd 辺りの処理に時間が掛かっているのではないかと思う。
    ble-bind に -D オプションでも追加して、これを追加した場合は、
    ble-bind コマンドによる設定ではなく、cmap 配列に直接値を代入する方式として、
    設定スクリプトを吐き出す様に変更するか?

    直接値を設定する様にすると既に何かを設定している時にそれを上書きする事で、
    データを破壊する事にもなるかもしれないので、その辺りについては確かめる必要がある。
    基本的には設定を追加・上書きするようにすれば良い。

    →試しに配列に直接値を代入する形式でデータを出力してみた。
      出力したデータは 100 KB にも及び巨大だが、
      それを source してみた所 0.1 秒以内にロードできた。
      速度としては充分である。

    + 既存の設定が存在している時にこれを追加して問題になりそうなのは
      "_" を代入する場合と "数字" を代入する場合である。
      "_" を代入する場合は既存の "数字" の設定があった場合に、その既存の設定を消す事になる。
      "数字" を代入する場合は既存の "_" の設定が存在する場合に、それを消す事になる。
      "数字_" を追加する場合については、既存の設定が何であれ完全に上書きしてしまうので関係ない。

      既存の設定に対して安全に追加する事が出来るように書き換えてみたが、
      やはり処理に時間が掛かるようになった。term+default.sh で生成したエントリを全て追加するのに 1 秒弱かかる。
      直接配列を設定する場合には 0.075 秒しかかかっていなかったので、12-13 倍の違いがある。

      また、dump 結果を source してから気付いた事だが、ただ cmap 内の情報を dump するだけでなく、
      キーとキーコードの対応表も一緒に読み込まなければ意味がない。
      そして、後から登録する方式だと、登録したいキーに対応するキーコードが既に使われている場合に、
      番号の再配置を実行しなければならないが、これはかなり重い処理になると思われるので現実的でない。

    + 結局、現実的には既存の cmap に対して追加登録をするのではなく、
      cmap、キーコード・キー対応表を全て入れ替える形にするしかない。

    + 所で良く考えたら declare -p "${!_ble_decode_...@}" 等とすれば

      特別にロジックを書かなくても変数の内容を直接 dump する事ができるのでは?
      実際に試してみた所、declare で出力した物も、
      自分で書いた配列要素を一つ一つ初期化する形式の物も、
      source するのにはそれ程時間の違いはなかった。両方とも 0.105 秒程度かかる。
      若干 declare の形式の方が時間が掛かっている気もするが、誤差の範囲内であろう。

      今後は declare -p を使って dump する事とし、今迄に書いた関数は削除する:
      [2013-06-09 14:37:52]

      function .ble-decode-char.dump-entry {
        local tseq="$1" ccode
        eval "local -a ccodes=(\${!_ble_decode_cmap_$tseq[@]})"
        echo "_ble_decode_cmap_$tseq=()"
        for ccode in "${ccodes[@]}"; do
          eval "local ent=\${_ble_decode_cmap_$tseq[$ccode]}"
          echo "_ble_decode_cmap_$tseq[$ccode]=$ent"
          if test "${ent//[0-9]/}" = _; then
            .ble-decode-char.dump-entry "${tseq}_$ccode"
          fi
        done
      }
      function .ble-decode-char.dump-entryA {
        local tseq="$1" ccode
        eval "local -a ccodes=(\${!_ble_decode_cmap_$tseq[@]})"
        for ccode in "${ccodes[@]}"; do
          eval "local ent=\${_ble_decode_cmap_$tseq[$ccode]}"
          echo ".ble-decode-char.add-entry $tseq $ccode $ent"
          if test "${ent//[0-9]/}" = _; then
            .ble-decode-char.dump-entryA "${tseq}_$ccode"
          fi
        done
      }
      function .ble-decode-char.add-entryA {
        local bseq="$1" byte="$2" val="$3"
        if test -z "${val##*[0-9]_}"; then
          eval "_ble_decode_cmap_$bseq[$byte]=$val"
        elif test -z "${val##*[0-9]}"; then
          eval "
           local ent=\"\${_ble_decode_cmap_$bseq[$byte]}\"
           _ble_decode_cmap_$bseq[$byte]=${val}\${ent##*[0-9]}
          "
        elif test "$val" = _; then
          eval "
           local ent=\"\${_ble_decode_cmap_$bseq[$byte]}\"
            _ble_decode_cmap_$bseq[$byte]=\${ent%_}${val}
          "
        else
          echo unexpected value 2>&1
        fi
      }

    + cmap+default.dump が存在すればそれを source する事にし、
      もしなければ cmap+default.sh から構築してから dump する様にする。

      と思ったら正しくロードされていない。新しく構築した場合にはちゃんと動いているが、
      cmap+default.dump からロードするとロードされていない。
      関数内から cmap+default.dump を source していて、
      cmap+default.dump 内では declare で変数を宣言している為、
      その関数内の局所的な変数としてロードされている。

      これをちゃんと動く様にする為には declare を宣言しなければ良いのだが、
      連想配列については、それが連想配列だという事を明示的に宣言できない。
      →しかし既に別の場所で宣言している筈だから問題ないのでは?
        実際に試してみた所、既に declare -A されている場合、
        新しく代入する場合でも問題は起こらないという事が分かった。

      と言う訳で先頭の declare -? を削除して dump を出力する事にしたが、
      今度はエラーが発生する。よく見たら代入の右辺に一々引用符がついていて、
      配列としての代入ではなくて一つの長い文字列としての代入になってしまっている。
      declare の時には、declare コマンドが文字列として受け取った右辺を展開してから代入するので問題にならないのだろう。

      今回は値としては常に一文字以上の [0-9_] だけで構成される物なので、引用符を全て外しても問題ないだろう。
      という訳で sed で引用符の類も全て削除する事にした。
      その上で source の時間を計測してみた所 0.064 秒にまで縮んだ (単にファイルサイズの問題のような気もしてきた…)。

    + 無事に cmap+default.dump で現実的な速度で初期化できる様になったので、
      <del>古いコード (必要最低限の物だけの設定) は削除する。</del>
      と思ったが、後でまた欲しくなるかも知れないので、cmap+minimal.sh として残しておく事にした。

2013-06-08

  [Done]

  * <bug> ble-line-info: 表示している間、編集文字列のカーソル位置の文字が空白になる。 [#D0084]
    [完 2013-06-09 01:42:41]

    これはカーソル位置を移動する時に _ble_edit_lc も変更してしまっているのが原因。
    _ble_edit_lc は描画関連の処理が終了してユーザの入力待ち状態になった時に、
    最終的にカーソルが存在しているべき位置の文字を示す物であって、
    これは一時的なカーソルの移動の際に変更するべき物ではない。

    現状では「最終的にカーソルが存在しているべき位置と其処の文字」と、
    「現在の描画処理の為に移動しているカーソルの位置と其処の文字」を一緒に扱っている。
    変数を分けるべきではないだろうか。
    + _ble_line_curx _ble_line_cury _ble_line_curlc は配列に纏める事にし、
      これは「最終的にカーソルがあるべき位置と文字」とする事にした。
      また、_ble_line_x, _ble_line_y という変数を追加し、これを
      「描画中の現在カーソルが存在している位置」とする事にした。

    + .ble-edit-draw.goto-origin, .ble-edit-draw.goto-end 関数を廃止し、
      .ble-edit-draw.goto-xy 関数を定義し、任意の座標に簡単に移動できるようにした。

    + この変更によって .ble-line-info.draw, .ble-line-info.clear で
      復帰する必要が無くなったかも知れない。
      現在のカーソルの位置が分かっているのだから、
      わざわざ元の位置に戻らなくても良い。
      次に移動する必要が生じた時に適切に移動すれば良いだけである。
      (勿論、その為には .ble-line-info.* で現在のカーソル位置の情報を更新する必要がある。)

      最終的に必ず update-adjusted が呼び出される。
      そして update-adjusted は必ず始めに update を呼び出す。
      update は現状の実装では必ず編集文字列部分は表示し直すから、
      結局必ずキャレットの場所へ移動する事になる。

    + と思って実際に試してみたら位置を移動するようになってしまった。

      これは単に _ble_line_x の変数名を _ble_edit_x としていた為であった。
      正しい変数に移動後の座標を書き込んでいなかった。

      しかしこれを修正しても未だカーソルの位置がおかしい。
      座標位置を勘違いしていると言うよりは、
      info 情報を出力した直後のカーソル位置になっていて、
      その後 update-adjusted 等の操作が行われた形跡がない。

      と思ったら _ble_line_y に対して数式をその儘代入していて、
      計算した結果を代入していなかった。
      しかしこのバグは今回の異常とは関係ない気もする。

      果たして実際に試してみると未だ直っていない。
      また、.ble-edit-draw.update の前後で現在の座標位置が変化していない。
      本来であればこの部分で適切な位置への移動が行われると期待している。
      という事で改めて .ble-edit-draw.update を見てみると、
      実は .ble-edit-draw.update の先頭で
      _ble_edit_dirty が全く設定されていない時には何の操作もせずに終了するようになっていた。
      _ble_edit_dirty が設定されていなくても、位置が異なる場合には移動を実施する様に変更する。
      →これで取り敢えずカーソル位置は正しくなった。
      [2013-06-09 01:42:41]

      また、その際に sgr の値を再設定する必要もある。(sgr は今迄は SCORC, DECRC 等に頼っていたが、
      本来は自分で管理できるようにしておきたい所である。)
      これについては別項目で取り扱う事にする。

  * <bug> 複数行に渡る編集を実行している時に、何かを入力する度に表示位置がずれていく。 [#D0083]
    [2013-06-09 01:17:29]

    ずれない様に設計している積もりだったが正しく動作していない様子である。
    先ず始めにずれて上にはみ出た行が消去されていない事から、
    .ble-edit-draw.clear の時点で原点に移動して削除するということができていない様である。
    可能性としては、現在の位置座標を勘違いしているか、原点へ移動する為の制御系列を誤って生成しているかのどちらかである。

    .ble-edit-draw.redraw-cache の始めで現在位置がどうなっているかについて確認を行う。
    →座標値については正しく計算されている様である。
    という事は goto-xy が怪しいと思って改めて考えてみたら、
    今回の場合は y の移動量 dy が負になる。その時に ESC [ A に渡す引数を絶対値にするのを忘れていた。

  * <bug> 色々変更している内にカーソルが先頭に移動するようになってしまった。 [#D0082]
    [完 2013-06-09 01:08:14]

    goto-xy の引数に文字列で式を指定できるようにしていたが、
    これをすると goto-xy の中で新しく宣言した変数に影響を受けて値が変わってしまうので、
    やはり goto-xy の引数にちゃんと評価した後の数値を指定する様に変更した。

  * 不要なデバグ用の古い関数 .ble-dbg,esc2a を削除 [2013-06-09 00:32:04] [#D0081]

  * ble-edit.sh (complete-filename): 引数が一意に確定した場合、 [#D0080]
    ディレクトリ名の場合には後に / を挿入し、それ以外の場合には SP を挿入する様に変更。
    今迄はディレクトリ名であっても後に / を挿入していた。
    [2013-06-08 16:50:34]

  * <bug> ble-decode-kbd: '*' を変換しようとすると、ファイル名展開が実行されてしまう。 [#D0079]
    仮定: * や ?, - が含まれるような single-key 指定は、
          必ず最後の一文字だけが * や ?, - 等の特殊文字である。
          それ以外の指定を行った場合の動作は保証しない。
    仮定: C- 等のような中途半端な指定は C-- と解釈される。
    [2013-06-08 16:01:32]

  * keyflag の定義を emacs と同じ物に変更。 [#D0078]
    Meta=1<<28 Ctrl=1<<27 Shft=1<<26 Hypr=1<<25 Supr=1<<24 Altr=1<<23

  * <bug> ble-decode-kbd: C-- や - 等を正しく変換する事が出来なかった。 [#D0077]

2013-06-06

  [Done]

  * 取り敢えず色付け関数 [#D0076]

  * <bug> C-c: プロセスを停止した直後、プロンプトが表示されない [#D0075]
    [完 2013-06-07 03:52:15]

    これは accept-line の処理が中途半端になったまま終了してしまうからである。

    + C-c 等でプロセスを停止した時に 正しく終了されるか?
      →正しく終了されていない様である。

    先ず何か入力するまでプロンプトが表示されない。
    (但し、^? などに対してはちゃんと読み取れる様である。
    ^? でも何でもいいから入力をすると復帰する。)
    これは accept-line の後の .ble-edit-draw.redraw が実行されていない為であろう。

    適当に trap 'echo hello' INT とすると、
    続きが実行される様になった。因みに hello の文字列は何処かに消える?
    なので trap : INT 等とする事にする。
    (既に存在している trap を上書きしてしまう事になるが仕方がない。)
    [2013-06-07 03:19]

    と思ったが、実際に試してみると、シェルの処理で重い場合に C-c をすると
    trap : INT や trap 'echo hello' INT 等としていた場合にシェルの応答がなくなってしまう
    という事が分かった。因みに trap を何も仕掛けていなければ正しく終了する。

    と、思っていたが trap return INT にしておけば一応問題は起こらない様だ。
    [2013-06-07 03:52:15]

    <del>しかし trap 'return 128' INT にすると今度は return は関数内でなければ
    使えないというエラーメッセージが表示される。</del>
    どうも trap を定義した場所が関数内なら return を書いてもエラーは出ない様だ。
    なので、.ble-edit.accept-line.exec.eval 内で trap をする事にした。
    しかし、return 128 等としても戻り値は常に 0 となる様子なので、
    _ble_edit_accept_line_INT という変数を介して 128 の値を返す事にした。
    [2013-06-07 04:12:50]

  * <bug> readline の accept-line をしない限り $? が設定されない? [#D0074]
    前回のコマンド実行の $? を何処か別の変数に覚えておいて、
    次のコマンドを実行する直前に設定し直せばよい。
    設定するには、return で好きな値を返すだけの適当な関数を作って、
    その関数を呼び出せばよい。
    [2013-06-07 02:20:26]

  * <bug> .ble-edit-comp.complete-filename: 変数リーク ret [2013-06-07 02:02:07] [#D0073]

  * <bug> return による accept-line 中断 [#D0072]
    [2013-06-07 02:09:41]

    C-c や C-z をした時の様に、
    コマンドライン中に return が含まれていた場合にも同様の事が発生する。
    これについてはコマンドを実行する際に一つ関数にくるんで実行すればよい

  * ジョブ管理にアクセスできるか? [#D0071]
    問題なくアクセスできるようである。

  * accept-line: 存在しないコマンドでも history に追加される。 [#D0070]
    [キャンセル 2013-06-07 01:55:03]

    history に追加する前にそのコマンドが存在するか確認。
    そもそも存在しない・実行できないコマンドに対しては history への追加を省略する。

    存在するかどうかの確認は type で確認できる物、及び、for などの文法要素?
    →試しに for を type -t に入れてみたら keyword となったので、
      for 等を特別に区別する必要性はない。

    と改めて調べてみたら、元々の bash でも存在しないコマンドもちゃんと history に追加されていた。
    なのでこれについて解決する必要性はない。

  * <bug> accept-line: [完 2013-06-07 01:53:25] [#D0069]

    ret 変数に値を設定できない。
    というか、accept-line を呼び出すまでにネストした
    関数で local として宣言されている変数名は全て使えない…。

    a. accept-line は呼出のネストの浅い所で実行する?
       (例えば ble-decode-byte などで)
    b. 内部変数として使用している変数名を重複の無い物 (_ble_* を予約) にする?

    a. の方針で行くとしたら、呼出が開始された一番浅い場所を見つける必要がある。
    ble-decode-byte から ble-decode-char, ble-decode-key と呼び出される過程で、
    何処が一番初めに呼ばれたかを判定するのは難しい。

    ble-decode-byte:bind が起点になる場合は明らか。
    ble-decode-char が起点になるかどうかの判定は難しい。
    代わりに内部の呼出では .ble-decode-char を使う事にして、
    外部からの呼出 (起点) では ble-decode-char を使い、
    ble-decode-char は .ble-decode-char の呼出 + 修飾処理、という事にすれば良い。

    従って、書き換えは
    1 全ての ble-decode-byte, ble-decode-char, ble-decode-key の内部呼出を
      .ble-decode-byte, .ble-decode-char, .ble-decode-key に書き換える。
      また、それぞれの関数名も書き換える。
    2 ble-decode-byte, ble-decode-char, ble-decode-key を定義し、
      中で .ble-decode-byte, .ble-decode-char, .ble-decode-key を呼び出すと共に、
      その他の前後の処理を追加する。
    という手順で行えば良い。

    先ず、ble-decode-byte は内部的には何処からも呼び出されていない様である。
    ble-decode-char は ble-decode.sh 内にしか存在しない。
    ble-decode-key は ble-decode.sh が殆どで、ble-edit.sh に一箇所だけ存在する。
    これらを書き換えて、呼出の起点に近い場所で実行するように変更した。

    しかし、未だ漏れている変数が存在するようだ。以下の変数は値が漏れている。
    arr file line ret spec

    spec: .ble-edit.history-add
    line: .ble-edit.history-load, ble-decode-bind
    file: .ble-term.initialize
    arr: ble-getopt
    ret: ble-edit+self-insert, ble-decode-bind, ble-bind,
      ble-decode-unkbd 定義直後にテストコードが残っていた
    _getopt_*: ble-bind

  * <bug> ble-decode-byte+C: 文字コードとして空文字列を返していた。 [#D0068]
    [2013-06-07 00:51:25]

  * C-c 等でプロセスを停止した後、次のコマンドを実行するまで行が二重化する [#D0067]
    [2013-06-07 00:19:05]

    C-c でプロセスが失敗した後に accept-line を押すと line が二重に表示される。
    これは実際に別のコマンドが実行されるまで続く。
    多分、これも stty の設定が変化しているから?
    多分エコーの設定が有効になっている為に、
    C-j/C-m が入力された時に行の位置がずれてしまうからだろう。

    これは空コマンドだった場合にも .ble-stty.enter を実行すればよい。
    というか寧ろ ble-decode-byte:bind 辺りで実行しても良いかも知れない。

  * <bug> accept-line: 時々コマンドを実行した時に現在位置が上の方に移動してしまう。 [#D0066]

    <del>どうも accept-line を実行した時に、カーソル直前に存在する文字が
    特殊文字であるとこの現象が発生するようである。</del>

    どうも特殊文字でなくても、カーソルの位置が line の最後の文字以外に置いてある時に、
    この現象が発生するようである。そして特殊文字を入力する時は大抵、先に引用符を書いておいてから、
    引用符の中に入って特殊文字を入力し、そのまま accept-line する為に、この条件に該当する。

    そしてこの条件が該当しそうな箇所が .ble-edit-draw.goto-end にある。
    と思ったら、_ble_line_cury に x 座標を代入していた。
    [2013-06-06 23:57:43]

  * <bug> カーソルの表示位置がおかしくなった [#D0065]
    construct-line で変数名を変更したのに、それを参照している construct-line.chk-cursor で
    変数名の変更していないのが原因だった。
    [2013-06-06 23:38:24]

  * <bug> \\ や \$ が含まれる時の位置計算が誤っている。 [#D0064]
    [2013-06-06 23:37:21]

  * .ble-line-info.clear: 既にクリアされている場合は動作を省略 [2013-06-06 23:05:49] [#D0063]

  * discard-line, accept-line: 実行の前に .ble-line-info.clear [2013-06-06 23:06:17] [#D0062]

  * construct-prompt: シェル変数 x y lc に計算結果を直接書込をする様に変更。 [#D0061]
    [完 2013-06-06 23:05:09]

    + キャッシュ情報は 配列 _ble_line_prompt に記録する事にした。
      _ble_cursor_prompt__LINENO, _ble_cursor_prompt__RESULT の変数を廃止
    + 呼出元を調整。

  * complete 候補一覧を表示 [#D0060]
    取り敢えず表示するだけ表示 [2013-06-06 18:07:53]

  * ble-decode: [#D0059]
    ble-edit-bind の部分にあった bash に対する bind のロジックを
    ble-decode.sh の方に移動させる事にした。
    [2013-06-06 17:41:05]

  * isearch: C-d を押した時に空欄だと即座に終了してしまう。 [#D0058]
    (C-d に delete-char-or-exit が設定されている場合)。
    なので、isearch で C-d を押した時は isearch モードを抜けてから
    唯の delete-char を実行する様に変更。
    [2013-06-06 17:40:50]

  * C-x に対する hook [#D0057]

  * ble-bind [#D0056]
    ESC → Meta が自動的に実行される様になったので、
    Meta について改めて登録する必要はなくなった。ので、その機能は削除。
    [完 2013-06-06 17:18:33]

  * <bug> ble-decode-char [#D0055]
    [完 2013-06-06 17:02:07]

    M-delete 等の操作が正しく key に翻訳されていない。
    これは ESC を meta に変換する機能を入れても入れなくても同様。
    更に ble-bind -k で Meta の付いた物を自動的に登録しても登録しなくても同じ。

    と思ったらそもそも ble-decode-char 自体に二つ連続した ESC は入ってこない様だ。
    screen または bash bind -x で消えてしまっている可能性がある。

    + 試しに bashrc 内で bind している '[D' と '[C', '[3;5~' を削除してみた。
      削除自体は正しく出来たようだが、依然として '' は消えた儘になっている。

    +  /etc/inputrc を見てみたが '\e\e' に関係する物は設定されていない。
      また、~/.inputrc は作っていなかった。

    + .screenrc を見てみたが C-M-tab に windowlist を割り当てている以外は怪しい所はない。
      それに emacs を起動している間はちゃんと ESC ESC を入力する事が出来ているのだから、
      screen は犯人ではない。やはり bash が怪しい。

    A 仕様がないので、直接 "" に対して bind を実行してしまえばよい。
      其処で bind -x '"":ble-decode-byte:bind 27 27' として見たが、
      そうすると今度は ESC ESC を受け取った時に、
        bash: bash_execute_unix_command: コマンドのキーマップがありません
      というエラーが発生してしまう。

    B 取り敢えず、苦肉の策として ESC ESC を何か別の物に変換して受信する事にした。
      ble-bind -k 'ESC [ 2 7 ^' __esc__
      ble-bind -@f __esc__ 'ble-decode-char 27'
      bind -s '"":"[27^[27^"'

      と思ったら、何故か "ESC ^ ^ ESC ^ ^ [ 2 7 [ 2 7" という謎の順番で受信される。訳が分からない。
      bind -s '"":"[1027~[1027~"' に変えてみたら、
      "ESC 2 2 7 ~ ESC 2 2 7 ~ [ 1 0 [ 1 0" となる。^ が悪かった訳ではない様だ。
      文字数の問題?
      bind -s '"":"[^[^"' → "ESC ESC ESC [ ^ [ ^"
      どうやら ESC 後の 3 番目の文字が繰り返される様である?
      bind -s '"\e\e":"\e[^\e[^"' → "ESC ESC ESC [ ^ [ ^" # bind で文字化けしているのかとも思ったがそうではないようだ。
      bind -s '"\e\e":"\e[~"' → "ESC [ ~ ESC [ ESC ESC ESC ..." # 理解不能

      もしかして、ble-decode-char の方のバグだろうか。。
      今度は ble-decode-byte の方で出力を行ってみる事にした。
      "[27^[27^" → "ESC ^ ESC ^ [ 2 7 [ 2 7"             この時点で謎
      "[1027~[1027~" → "ESC 2 7 ~ ESC 2 7 ~ [ 1 0 [ 1 0" ~ でも駄目
      "[^[^" → "ESC ESC [ ^ [ ^"                         短くしても駄目
      "[1027^" → "ESC 2 7 ^ [ 1 0"                         単体の ESC でも発生する
      "\e[~" → "ESC [ ~"                                     これは正しく受信されている
      "\e[^" → "ESC [ ^"                                     これも OK
      "\e[7^" → "ESC ^ [ 7"                                  これは駄目
      "\e[?^" → "ESC ^ [ ?"                                  これも駄目
      "\e[?~" → "ESC ~ [ ?"                                  これも駄目

      取り敢えず ESC を含んで 3 文字以上のシーケンスが何故か化ける様なので、
      3文字 で "ESC [ ^" とする事にした。
      これで受信される物は正しくなったと思われる。

    + BUG 受信しているバイトは正しいが ble-decode-char が正しく処理してくれない。

      動作を見ていると ESC [ ^ を受け取った時点で __esc__ が生成されている。
      そしてその直後に M-[ が出力されている。
      更に次の "[" を受け取った時に再び M-[ が出力される。

      一つの原因は、_ble_decode_key__seq をクリアしない内にコマンドを実行している為、
      コマンドの内部で新しいキーが来た時に _ble_decode_key__seq に追加されて処理されてしまう事である。
      これは、コマンドを実行する前に _ble_decode_key__seq= とする事で解決する。
      基本的にコマンドを実行する時には、ble-decode-key の内部状態を終了状態と同じにしてからにするべきである。
      要するに破壊的操作を全て終えてから、コマンドを実行する、という事。

      ble-decode-key の中の _ble_decode_char__seq についても同様である。
      これを修正した所、どうやらちゃんと期待通りに動くようになった。

  * ble-decode-char [#D0054]
    ESC を meta に翻訳するのは自動にするべき。
    例えば M-あ などまで考慮していたら、全てを登録し尽くす事は無理なので。

  * <bug> ble-decode-key でシーケンス全体の一致に失敗して、 [#D0053]
    部分一致に成功した時、一致部分の直後のキーが失われる。
    これは 一致した場合に ble-decode-key "$fail" を実行せずに関数を抜けていたのが原因である。
    依然 ble-decode-char で起こったのと同様の問題点。
    その時には ble-decode-key には問題がないと判断したが、問題は在ったようだ。
    [完 2013-06-06 16:58:25]

  * <bug> ble-edit-bind: "\e ": set-mark を unbind できていない。 [#D0052]
    [完 2013-06-06 15:26:53]

  * ble-edit-bind: bind -s についても表示できるから、これについても全て unbind する。 [#D0051]
    [完 2013-06-06 15:26:48]

  * <bug> ble-bind -d [#D0050]
    -m isearch 等を用いて登録したキーシーケンスが表示されない。
    現在登録されている kmap 名のリストを追加して、
    ble-bind -d で全ての kmap について表示するように変更した。

2013-06-05

  [Discussion]

  * COMP_KEY [#D0049]
    bash の manual には最後のキーとあるが、
    文字で表現するのか、名前で表現するのか文字コード (?) で表現するのか分からない。
    実際に、適当な関数を登録して確かめてみると良いだろう。

    →試してみた所文字コードが表示された。
      更に function キーに complete を割り当てて試してみた所、
      バイトシーケンスでの最後のバイトが渡される様である。
      (しかし、これでは不便? な気がするので、独自解釈で ble の keycode を用いる事にする。
      その際に C-* 系統の物は変換した方が良いかも知れない。)

  [Done]

  * visible-bell: 鳴った瞬間だけ緑色に点滅する様に変更。 [#D0048]
    これで連続で visible-bell が鳴った時でも見た目に分かる。

    # + 鳴った瞬間だけ赤くして直ぐに暗くする

  * <bug> isearch: self-insert で単に入力しているだけなのにどんどん遡ってしまう。 [#D0047]
    self-insert の時には現在行から一致を初める様に変更する。
    [完 2013-06-05 23:42:37]

  * <bug> quoted-insert, v だとか q が挿入される [#D0046]
    これは self-insert の仕様変更について行ってなかったのが原因。
    代わりに insert-string を使う実装に変更した。
    [完 2013-06-05 19:57:59]

  * clear-screen: vbell の削除トラップをクリアする [#D0045]
    [完　2013-06-05 19:18:02]

  * isearch: arr の top が行き先と同じであれば、arr に push せずに pop する [#D0044]
    [完 2013-06-05 19:03:41]

  * isearch: 表示位置への移動などをもっとまともな物に変更する。 [#D0043]
    [完 2013-06-05 18:47:07]

  * isearch: 終了時に isearch の表示を消す [#D0042]
    [完 2013-06-05 18:47:17]

  * isearch: prev でもうこれ以上戻れない時、isearch から抜けない [#D0041]
    [完 2013-06-05 18:48:15]

  * c2w 二分法: 0-161 の間の文字が怪しい? [#D0040]
    + 初めから範囲にない場合 (0-161) の場合は先に除外するべきだった。
    + l&1 を括弧で囲む必要があった。
    + while の条件は l<u ではなく l+1<u であった。
    [完 2013-06-05 18:27:32]

  * ble-core.sh (.ble-print-visible-bell): .time 削除で date +%s の値が overflow しない様に [#D0039]
      部分文字列を取りだす部分が間違っていた。
    [2013-06-05 16:14:46]

  * ble-core.sh (.ble-print-visible-bell): SC, RC を頻繁に使うので、後で変更しやすいように [#D0038]
    _ble_term_sc, _ble_term_rc 定数に定義。
    [2013-06-05 16:14:46]

  * __defchar__ は制御文字には適用しないように変更 [#D0037]

2013-06-04

  [Done]

  * <bug> どうも履歴の動作が怪しいような気がする。 [#D0036]
    C-p C-n で動くと変な出てき方をする…気がする。
    それに先程実行したはずのコマンドが出てきたり出てこなかったりする。

    →と思ったら history-add で実際に登録される場合だけ
      _ble_edit_history_ind, _ble_edit_history_edit を初期化していた。
      それ以外の場合は、前回の履歴位置・編集内容をそのまま使う事になっていた。
      そうすると例えば、前回履歴を遡って実行したコマンドは空白に変化し、
      また、現在の履歴の位置も途中の場所にいたりと変な事になる。

    [完 2013-06-05 02:50:10]

  * vbell: [#D0035]
    ble.sh をロードした時に、
    古い .time ファイルは全部削除する機能をつける。

  * ble-bind -c: meta も登録する [#D0034]
    → 完了 2013-06-05 02:40:02

  * ble-bind 引数はシェル変数で渡す様にした方が良い? (-f オプションの削除) [#D0033]
    + self-insert は KEYS[0] シェル変数を用いる様に変更した。
    + f オプションの削除

  * ble-bind -c, -k オプションの名前を変更する [#D0032]
    → それぞれ -k, -f に変更した。2013-06-05 02:40:06

  * bug? bind [#D0031]
    何と " を bind する事ができていない。
    と思って改めて試してみたらちゃんと bind されている??
    取り敢えず保留という事にする。

  * <bug> 次のコマンドを実行するまで prompt が更新されない [#D0030]
    CMD ではなく LINENO を参照するように変更

  * abell はロックするので vbell の後に送信するべき [完 2013-06-05 01:25:27] [#D0029]

  * 矢印キーなどの動作を取得する事が出来るかチェック [完 2013-06-05 01:25:41] [#D0028]
    (1) ESC で始まるシーケンスを全て削除する?
        試しに全て削除してみたら、(自分で bind -x で設定した物を除いて、)
        上下左右のキーや function キーも効かなくなった。
        ので、C-[ さえ bind -x してしまえば恐らく処理できると思われる。

        → source されたスクリプトの中で bind -r を実行しても削除されない?
        と思ったら bind の時は必要だった引用符 " が、bind -r の時には不要だった。

    (2) ESC に bind できるか?
        一応 ESC には bind できているみたいだが、delete を押してもそうと認識されない。
        しかも二回に一回だけ通常の文字列として delete が入力される。
        奇数回目の delete は何処へ行っているのか?

        ble-decode-key の受信する key を見てみた所、
        delete を入力した直後には ble-decode-key には delete が来ない。
        その次の文字を入力すると ble-decode-key に delete が渡される。
        その後に続く文字は一文字ずつ分解されて届く様である。

        先ず、問題点として
        a. ~ を受け取った時点で delete に確定している筈なので、
          その時点で delete が届かないのがおかしい
        b. また、delete が受信された後の文字が単体で必ず decode-key に渡ってくるのが問題である。
        c. delete は処理されなかったはずなのに、その事を表すエラーメッセージが表示されない

    + BUG: delete が届かない? [完 2013-06-05 00:00:50]

      と思って実際に初期化が終わった後の cmap を見てみたら
      最後の文字なのに「継続あり」の _ がついている。
      .ble-decode-char.bind を見たら条件が反対になっていた。
      (.ble-decode-key.bind の方は大丈夫かと思ってみたら大丈夫だった、
      .ble-decode-key.bind に合わせる形の方向で修正した。)

      ** デバグの為に一時的にバグ状態に戻してある **
      →他のバグも解決したのでこれはまた修正した。

    + BUG: 曖昧文字の失敗後に、その失敗に関連した文字がすぐに送信されてくる?
      [完 2013-06-05 01:25:41]

      と思って手でエスケープシーケンスを入力したりしてみたが、少し違うようだ。
      delete ESC [ まで入力した段階では delete までしか出力されていない。
      ここまでの動作は正しいが、次に A を入力した時点で、
      ESC [ A がその儘出力されて出て来る。

      本来は ESC [ A は up と翻訳されて欲しい。
      _ble_decode_cmap_* を見てみたがここの部分は問題ない様に見える。
      (a. の方の BUG の事を考えると、本当は ESC [ A だけでは未だ出力されないはず…。
      そして実際に、先行する delete がない状態では ESC [ A を送信してもその時点では何も出力されない。
      従って、cmap の問題ではなく内部状態に何らかの異常が出来ていると考える方が自然である。)

      と思ってみてみた所、delete ESC [ まで入力した段階では、
      実は未だ ESC [ は bash まで届いていない? 様である。
      screen だか或いは途中の何かが文字を止めているという事だろうか。。
      (と、ここで screen に C-TAB = [9;5^ に対する hook をかけているという事を思い出した)。

      そして、ble-decode-char は delete のシーケンスが残っている状態で
      ESC を受け取った時にそれを組み立てずにそのまま出力しているらしい。
      要するに奇数回目の入力と偶数回目の入力で何が違うかというと、
      偶数回目の入力の一番初めの文字 ESC が到着した時には、
      未だ奇数回目のシーケンスが残留しているという事である。

      という所で、怪しい部分を発見したが…その部分は今回と関係ないような気もする。
      しかし取り敢えず、その部分を修正する (余分な return を消す)。すると今度は、
       ble-decode-key に渡される key 自体は何も可笑しい所がないように見えるのに、
      実際に編集文字列に現れてくる文字列には違う入力されている。。
      先にエラーメッセージが表示されない謎を解決した方が早いかも。

      下のバグを解決したらこちらのバグも解決した。先程の修正で良かった様だ。
      今迄 ESC [ A が裸で出力されている様に見えたのは勘違いで、
      1 delete のシーケンスが残っている状態で ESC が来ると、
        delete だけ出力されて ESC は出力されずに終わる (一つ目のバグ)。
      2 delete のシーケンスが化けて (二つ目のバグ)
        (1) で出力し損ねた ESC になって、self-insert で入力される。
      という流れになっていたのだった。つまり
        ESC [ A ESC [ A
        ~~~~~~~~~~~
        delete      [ A
        ~~~~~~
        ESC         [ A
      と言う風に変換されていたのだった。


      因みに .ble-decode-key.emit の方には同様のバグがないかと確認してみたが、
      その様なバグはなかった。ちゃんと余分な return は消されていた…。

    + BUG: 知らないシーケンスが届いた筈なのにエラーメッセージが表示されない。
      [完 2013-06-05 01:13:43]

      と見てみたら、すぐに気付いた。「知らないシーケンスが届いた時に "$key" 単体を
      文字と解釈できる場合には __defchar__ で処理する」という所で $key の代わりに $fail と
      書いていた。そしてこの $fail は呼出元の ble-decode-char の $fail を参照して、
      出力していない筈の文字を出力してしまうという事になっていた。

      これで解決できたと思ったら、今度は up が変な文字として入力されてしまう様になった。
      これは __defchar__ で処理するのは unicode の16面までという制限をかければ良い。
      0x110000 という定数が何回か出てきたので ble_decode_function_key_base という定数として定義し直した。
      これを用いて文字として解釈できる unicode の範囲を絞って扱う事にした。

  * <bug> history add したコマンドの \ が消えている。 [#D0027]
    [完 2013-06-04 23:26:03]

    どうやら読み込む時に read が勝手に \ を消しているようだ。
    read に勝手に \ を解釈されたくなければ read -r とする。
    登録・書込の方には問題はないようだ。

    他にも read を使っている所があるのでそれについても修正をする必要がある。

  * <bug> .ble-edit.construct-prompt: \w でホームディレクトリ以下のパスが  ~// となる。 [#D0026]
    [完 2013-06-04 23:05:35]

    ~ に続きがある場合に / を追加する様に書いていたが、
    良く考えたら ~ に続きがある場合には / がどうせ先頭になっているので必要なかった。

  * <bug> HISTIGNORE の値に反して一文字のコマンドが history に追加されている [#D0025]
    [完 2013-06-04 22:50:16]

    単に配列変数の名前を間違えていただけだった。

  * <bug> (.ble-edit.construct-prompt): \! (HISTCMD) が常に 1 [#D0024]
    これは bind -x で登録された関数から見るとこうなってしまうという事なのだろうか。
    代わりに _ble_edit_history の要素数を返せば問題はないだろう。
    [完 2013-06-04 22:43:49]

  * <bug> ble-decode-byte を直接呼び出すと PS1 の値が破壊される [#D0023]
    [完 2013-06-04 22:32:33]

    PS1 が解除された状態で ble-decode-byte が呼び出され…?
    調べてみた所、ble-decode-byte の中で PS1 を代入していた。

    良く考えてみたら、再描画や adjust-cursor 等の呼出は、
    直接コマンドを叩いて呼び出した時には必要のない物である。
    なので、bind -x する時専用の ble-decode-byte を作って、
    その中で PS1 の設定や再描画、カーソル位置微調整を行えば良い。
    →その様に変更した。

  * suspend した時にどうなるか? [#D0022]

    特に問題が生じるという訳でもない様だ?
    但し、以下の点については意識する必要がある。

    (1) stty の設定がどうなっているか
        [完 2013-06-04 20:34:42]

        <del>恐らく stty を復元したままになっている。
        従って ^W ^U 等の操作を行う事ができないと思う。</del>

        <del>直後に直すのは諦めるとしても、
        次に ^W ^U など以外の文字が入力された時に、
        stty の状態を確認して元に戻すという事はするべきである。</del>

        と思っていたらどうやら suspend で止まった場合でも、
        スクリプトの続きから開始される様である。
        つまり、accept-line の後半部分も suspend の直後に実行される。
        なので何の問題も生じない。

    (2) コマンド履歴に suspend したプロセスが追加されていない。
        [完 2013-06-04 19:54:07]

        コマンド履歴に追加される前にコマンドが実行されている。
        これは登録を先に行うように変更するだけでよい。

        (但し bash ではコマンド見付からなかった場合には、
        コマンド履歴に追加されないようになっている。
        コマンドを実行に移す前に予め、
        そのコマンドが存在するかどうかぐらいは判定しても良さそう。)

    (3) 編集中のコマンドが残っている [完 2013-06-04 20:36:18]

        これも編集文字列をクリアする前にコマンドを実行しているからである。
        コマンドを実行に移す前に編集文字列をクリアする事にする。

  * ちらつきを抑える方法: 最初に再描画 [完 2013-06-04 18:32:52] [#D0021]
    ble-decode-byte に入った瞬間に .ble-decode-key.redraw を実施する?
    その時は、前回から内容が変わっていない筈なので、前回保存した情報をそのまま出力すれば良い。
    そして呼出が終わった後に変更があればその時点で再描画をまた実行する。

    + BUG: prompt の表示が省略されている [完]

      → 前回保存した内容が prompt 表示を省略する物だった為
      → prompt 表示の省略をしない物をキャッシュに入れておく事にした。

      関数 redraw-cached は「フル」で表示し直すが内容は「前回」のまま、という関数である。
      ので、表示の省略などは行わないので、この方法で良い。

    + BUG: 前回の残像が残っている [完]

      redraw をする際に前回表示した内容を消していないので残ってしまう。
      これは .ble-edit-draw.redraw, .ble-edit-draw.update でも同様に起こりうる問題である。
      (今迄は bash が1行目を勝手に消していたので気付かなかっただけである。)

    + BUG: 表示が滅茶苦茶になる

      原因は色々あった。
      事。
      "前回の表示内容" に関しては保存していたが、
      その内容を出力した際に現在のカーソルが何処に移動するかといった情報を保存・復元するのを忘れていた。
      唯単に前回の表示内容を出力しただけだと、内部的にカーソル位置が先頭から動いていない事になっている。
      なので、ちゃんと "前回の表示内容" を保存すると共に、その内容を表示した時にカーソルが何処へ移動するか等の情報も保存するように変更した。

    何とか、前回の表示内容を再度出力する物が完成したので、昔のコードは削除する。
    | function ble-decode-byte {
    |-  # bash によって描画された物が全部消されている
    |-  # .ble-edit-draw.set-dirty -1
    |+  .ble-edit-draw.redraw-cache

    これでちらつきはかなり改善された。

    しかし、ちらつきが全くないと迄は言えない。もし気になる様だったら

  * bug unkbd [2013-06-04 17:59:04] [#D0020]

    配列への追加で、添字に ${#kbd[@]} とするべき所 ${kbd[@]} としていた。

  * LINENO が更新されない? [#D0019]
    →これは一回 unset LINENO してから自分で設定すればよい。

    どうせ自分で LINENO は管理しなければならないのでこの方法でよい。

2013-06-04

  * X6 stty 関連 (tty が制御文字を奪うという事) [2013-06-04 13:33:26] [#D0018]

    * tty の設定で動かなくなるキーと tty で設定されていても動くキーがある。
      よく分からないので表にする事にする。

      ^S ^Q
        →stty で外すか -ixon の設定にすれば OK
          基本的に -ixon の設定で行く方針。常にこの状態という事にする。

      ^C
        →bind する時は stty intr "" でも問題ない。
          然し、実際に使う時には stty intr undef でないと読み取れない。
      ^Z
        →^C と同様 bind 時はどちらでも問題ない。
          実際に読み取りの時は stty susp undef でないと駄目。
      ^\ (quit) も ^C や ^Z と同様である。

      ^V
        →bind する前に stty lnext undef する必要がある。
          bind した後も stty lnext undef の儘保持しておく必要がある。

      ^U (kill) ^W (werase) も ^V と同じである

      ^?
        →bind する間だけ stty erase undef し、
          <del>その後で stty erase "" などと復元すれば良い?</del>
          と思ったが何故か stty erase undef でなくても動いたり、
          stty erase undef でないと動かなかったりよく分からない。
          取り敢えず ^V の時と同じようにずっと erase undef の儘にしておく事にする。


      <a href="http://lists.gnu.org/archive/html/bug-bash/2004-08/msg00157.html">'bind "\C-?": delete-char' does not work any more</a>

      ※文字列編集中だけ外されている stty 項目がある可能性?

      #              | key    bind  read
      # -------------+-------------------
      # -ixon        | ^S ^Q
      # kill undef   | ^U     必要  必要
      # lnext undef  | ^V     必要  必要
      # werase undef | ^W     必要  必要
      # erase undef  | ^?     必要  必要
      # intr undef   | ^C     不要  必要
      # susp undef   | ^Z     不要  必要
      # susp undef   | ^\     不要  必要
      # -------------+-------------------

    * ^? が偶に bind 出来ないように見える問題

      どうやら一回目に stty を解除して bind に挑戦すると失敗している様で、
      二回目に bind に挑戦すると成功している様だ?
      再度 stty の設定を元の状態に戻して ble.sh を設定してみたら、
      ^? ^U ^V ^W の四つについて bash の bind が機能していないという事が分かった。

      改めて bind -x '"":ble-decode-byte 127' を手で入力してみた所使える様になる。
      やはり stty を設定した直後には bind を設定する事が出来ないという事だろうか。

      色々試してみる
      (1) stty の後に適当に echo するとどうなるか?
          →適当に echo するだけでは駄目なようだ。

      (2) stty の後に sleep で待ってから設定するとどうなるか?
          →sleep で待っても駄目なようだ。

      (3) stty の後に >/dev/null で適当な文字列を書き込むとどうなるか?
          →やはり駄目。

      (4) read -n 1 で適当に文字を読み取るとどうなるか?
          →これでも駄目だった。

      (5) subshell ( date ) を呼び出す
          →駄目

      もしかして source ble.sh で一つのコマンドとして実行しているから設定が有効になっていないという事だろうか?
      後、一回 exit してから入るとうまく行くのは、C-d で exit する直前に .ble-stty.leave していなかったからであった。
      或いは bashrc 等のスクリプトから実行するとうまく行くのかも知れない。

      仕方がないので現状では .ble-decode-byte:bind で、
      既に ^U ^V ^W ^? に bind しているかどうか確認して、
      設定されていない様だったら設定を行う様にする事にした。

    * C-@: 効かないと思っていたら bind できていない [完]

      bind -x '" ":ble-decode-byte 0'
      →確かにこれでは bind できない
        bind は '"' という文字列を受け取ったと勘違いする。

      bind -x '"\C-@":ble-decode-byte 0'
      →これで正しく bind 出来るようになった。

    * 全ての文字を入力可能かどうか確認

      C-@ OK (bind する時に直接 ^@ の文字を引数に指定できない事に注意)
      C-a OK
      C-b OK
      C-c OK (stty intr undef)
      C-d OK (READLINE_LINE にダミー文字を設定。可成り苦労した…)
      C-e OK
      C-f OK
      C-g OK
      C-h OK
      C-i OK
      C-j OK
      C-m OK (stty の改行変換周りで状況が違うかも?)
      C-n OK
      C-o OK
      C-p OK
      C-q OK (stty -ixon)
      C-r OK
      C-s OK (stty -ixon)
      C-t OK
      C-u OK (stty kill undef)
      C-v OK (stty lnext undef)
      C-w OK (stty werase undef)
      C-x OK (二文字の組合せで bind すれば良い)
        * 直接 bind すると C-x に続けて何かの文字を打った瞬間に
          bash が segmentation fault する
        * C-x ? (? = \0 - \377) の組合せで全て登録しておけばよい。
          (恐らく C-x は C-x とそれに続く何らかの文字の組合せでしか使われないだろう。
          その場合にはこれで問題はない。)

      C-y OK
      C-z OK (stty susp undef)

      C-[ OK
        * 単独の C-[ は通常通りに bind するだけで OK。
        * C-[ C-[ の並びは何故か受信できないので、
          bind '"":"[27^[27^"' 等として、
          一旦別のシーケンスに翻訳してから受信する必要がある。

      C-\ OK (stty quit undef)
      C-] OK
      C-_ OK
      C-^ OK (.bashrc で設定しているのを解除する必要はある)
      C-? OK (stty erase undef)

2013-06-04

  * X5 C-x に bind -x すると死ぬ [2013-06-04 09:42:42] [#D0017]

    * 先ず第一に、C-x に対して bind しても、
      単体の C-x に対して bind で指定したコマンドは呼ばれない。
      (bind -r で予め元々登録されていた関数を全て削除しても同様である。)

    * 更に続けて何らかの入力をした場合、
      その sequence が bash bind で何も割り当てられていなかった場合、
      bash が segmentation fault で落ちる。

    * C-x は単体では割り当てられず、
      必ず C-x hoge の形で入ってくるとするならば、
      C-x ではなく C-x ? に対して bind をすれば良い。

2013-06-03

  * X4 history にアクセスする方法 [2013-06-03 08:19:09] [#D0016]

    * history -s で値を設定する事が出来る。

      但し、これは最新の履歴を置き換える形でしか追加する事が出来ない?
      と思ったが、最新の history -s コマンドを置き換えるだけであって、
      昔の履歴を削除する訳ではない様だ (多分)
      →実際に試してみた所期待通りに動いている様なので良しとする。

    * また history -s は HISTIGNORE に該当する物に関しては削除するようだ。
      なので HISTIGNORE などについての特別な配慮は要らず、
      とにかくコマンドを history -s で追加すればよい。

    * 次に isearch で history コマンドを検索する時にどの様にするのが良いのかという事。
      history | grep だと結構処理に時間が掛かりそう
      といって history の内容を何処かの配列に出してくるのも大変な気がする

    * また history 中のコマンドに改行が含まれていた場合、
      検索などの結果が乱れてしまう事になる。

    * 何故か、プロセス置換の中で history を呼び出すと HISTTIMEFORMAT= が有効にならない。
      cat < (HISTTIMEFORMAT=A history)  # 効かない
      cat < (HISTTIMEFORMAT=A; history) # 効く

2013-06-02

  [Done]

  * source 直後の prompt は PS1 をそのままに。 [#D0015]
    未だ一度も呼ばれていないのでそもそも自前でプロンプトを表示していない。
    →分かりにくいのでやめた。
      ble.sh の最後に、自分自身で明示的にプロンプト描画関数を呼び出す事にした。

  * quoted-insert C-@ の扱いについて [#D0014]
    →bash でも元から入力できない様なので気にしない
      self-insert で文字コード 0 を渡された場合には無視

  * 取り敢えず実装する物: [#D0013]
    現在の編集行を表示する機能?
    →これは暫定的に唯 print するだけの物でよい。

  * ble-decode-key, ble-bind: [#D0012]
    コマンドが設定されていない時の既定のコマンドを指定できる様にして、

    其処に self-insert を割り当てていたが、この様にしておくと、
    self-insert で変な文字が入力されてしまう
    (一応 self-insert 中で flag は外す様にしているが)。
    更に、どんなに変な操作をしてもエラーメッセージが表示されない。

    本来コマンドが設定されていないとしても flag の付いていない "文字" だけを
    self-insert で処理するべきである。従って、"文字" に対してだけ既定のコマンドを
    適用するように変更する。これは "文字" だけの既定動作なので変数名としても
    __default とするのは気分が悪い。其処で新しく __defchar__ という名前の keyname/keycode
    を定義し、そのキーに対してコマンドが定義されている場合に、"文字" をそのコマンドで処理するように変更した。

    また、空文字列の bind 呼出で __default に値を設定できる機能は削除した。
    <del>空文字列を指定した場合は、既定の動作を指定する。</del>

  * ble-decode-key: [#D0011]
    と思ったが、isearch-map 等を定義する時には、bind されていない key を指定した場合には、
    通常のモードに復帰してそのモードでの操作を実行したいから default の機能は使用したい。
    また、前の様な実装に戻す事も出来たが折角 __defchar__ を定義したので、
    それと同じ方式にした方が良いだろう。と言う事で __default__ というキーを定義する事にした。

2013-06-01

  * 現在の実装状況 [#D0010]

    ble-getopt
      取り敢えず枠組は完成している。
      後で拡張を行う余地はある。

    ble-decode
      ble-decode-byte
      ble-decode-char
      ble-decode-key

      ble-decode-bind
      ble-decode-kbd
      ble-decode-unkbd

    ble-text 文字幅
      例えば → 8594 が曖昧幅の文字である。
      設定の名称をどの様にするか
        narrow/wide/emacs
        west/east/emacs

  [Done]
  * ble-decode: ble-decode-* 関数の実装 [#D0009]
  * ble-getopt.sh: 短形式オプション引数 (':' 区切) で、'::' の様に、 [#D0008]
    区切が連続する場合に、正しく空引数として認識するように変更。
  * mwg.text.getCharFromCode, mwg.text.getCharCodeAt: [#D0007]
    それぞれ .ble-text.c2s, .ble-text.s2c に名称変更。
  * .ble-text.c2s: [#D0006]
    0x100 以上の文字コードを指定した場合に変な文字に変換されるバグを修正。
  * .ble-text.c2s: [#D0005]
    一度文字コードを取得した文字についてキャッシュする様に変更。

  * X3 末端に改行を置かずに終了したコマンドの扱い [#D0004]

    * その様なコマンドがあるとプロンプトの表示が乱れる原因である。
    * 右に或る回数だけ進んで其処で空白を出力してから行頭に復帰すれば良い?
      元々1桁目にいた場合にはぎりぎり改行をせずに済み、
      2桁目以降にいた場合には改行してしまうように調整をすれば良い。
      右に行くには ESC [ 桁数 C を出力すれば良い。

    * 適当にやってみたが色々やってもうまく行かない。ちゃんと端末の動作を考えるべき。

    * 先ずは xenl の場合。
      幾ら右に行っても一文字出力する分の余裕は必ず残る。
      従って右端に行ってから 2 文字は出力しないと行けない。

      例えば (1) COLS-2 だけ右に進んでから (2) 2 文字出力して、(3) それから復帰する。

      この様にすると
      何も出力していない場合   |   何か出力している場合
  　　(0) [_              ]    |   (0) [a_             ]
          [               ]    |       [               ]
      (1) [------------>_ ]    |   (1) [a------------>_]
          [               ]    |       [               ]
      (2) [             xx_    |   (2) [a             x]
          [               ]    |       [x_             ]
      (3) [_<-------------]    |   (3) [a             x]
          [               ]    |       [_<             ]

      xenl でない端末の場合は COLS-3 に変えれば良いだけか?
      (1) COLS-3 だけ右に進んでから (2) 2 文字出力して、(3) それから復帰する。

      何も出力していない場合   |   何か出力している場合
  　　(0) [_              ]    |   (0) [a_             ]
          [               ]    |       [               ]
      (1) [----------->_  ]    |   (1) [a----------->_ ]
          [               ]    |       [               ]
      (2) [            xx_]    |   (2) [a            xx]
          [               ]    |       [_              ]
      (3) [_<------------ ]    |   (3) [a            xx]
          [               ]    |       [_              ]

      多分これで OK。


  * X2 C-v に bind できない? [#D0003]

    * どうやら stty が C-v を食う設定になっていてこの設定が有効になっている間は、
      bind で C-v に割り当てをしたり C-v に対する割り当てを削除したりと言った操作ができない様だ。
      stty lnext undef で C-v に対する割り当てを削除した上で C-v に対して bind を行えばよい。
      (stty が食う所までは理解できるが、stty の設定によって bind すら出来なくなるのは何故か?)

    * 但し、その後で stty lnext $'\26' などとして設定を元に戻すと、
      やはり C-v は stty に食われて bash にシグナルとして伝達する。
      問題が生じなければ stty lnext undef で放置という事で良い気がする。

      然し C-z に bind する為に結局 stty susp undef をして、
      コマンド実行直前に復元して、コマンド実行後にまた undef するという事をしたくなりそうだから、
      その際には lnext も復元させる事にすればよい。

    * 何故かスクリプトで stty lnext undef の直後に
      bind -x '"":ble-decode-byte 22' を実行すると、
      self-insert が割り当てられてしまう。
      bind -x の文と stty lnext の文を別の関数に配置したらこの様な事は起きなくなったが、謎。

  * X1 [#D0002]

    C-d を受け取る為には READLINE_LINE に何か設定する必要がある。
     するとオリジナルのプロンプトが表示されるがこれをどの様に殺すか?

    [振舞]
    + READLINE_LINE が空の状態だと C-d を受け取れない。
      受け取る前にログアウトしてしまう。
      (man bash には EOF への翻訳は delete-char で行われる様に書かれているが、
      それとは別に C-d を bash が受け取った段階でチェックされ、
      条件に適合すればログアウトしてしまう)
    + READLINE_POINT が READLINE_LINE 末端を指している時は、
      プロンプトを表示し終わった直後に位置の移動は行わない。
      表示後のカーソル位置は、書き込んだ最後の場所になる。
    + READLINE_POINT が READLINE_LINE 先頭を指している場合は、
      bash が其処にカーソルがあるべきと考えている位置にカーソルが移動してしまう。
      (プロンプトの幅?)
    + 制御文字を EADLINE_LINE に代入しても、表示される時には ^A 等の表示に翻訳される。
      従って、通常の文字を代入しておくのが無難である。
    + 試しに READLINE_LINE=$'\0' として READLINE_LINE='1' として見たが、
      これはどうやら READLINE_LINE は空文字列であると解釈されて、
      C-d は即座にログアウトと解釈されてしまうので駄目である。

    [目的]
    + C-d を読む為に READLINE_LINE の内容は何でも良いから 1 文字以上必要
    + プロンプトを表示し終わった時の位置を制御したい

    [対策]
    + PS1 は空欄にする
    + カーソル位置 x が 2 桁目以降にある場合は、
      x-1 桁目に移動して READLINE_LINE には x-1 桁目の文字を入れる。
      READLINE_POINT には 1 (正確には x-1 桁目の文字のバイト数) を代入しておけば良い。
      また SGR で予め x-1 桁目の文字のスタイルを吐き出しておく。
    + カーソル位置 x が 1 桁目にある場合は、
      READLINE_LINE には 1 桁目の文字を入れておく。
      READLINE_POINT には 0 を入れておく。
      また SGR で予め 1 桁目の文字のスタイルを吐き出しておく。
    + 全角文字などに対する対策も必要

    + これを正しく実装する為には、取り敢えず現在のカーソル位置を把握している必要がある。
      またカーソルの左側に位置している文字と、その幅を記録しておく必要もある。
      (幅を記録する必要はあるのか→ない気がする。)

    *rule*

    + lc はカーソルの左側に位置する文字の文字コードを表す。
      常に graphical な文字であり、bash によって直接表示される。
      x=0 の場合には lc に入っている文字コードの値は未定義であり、使用してはならない。
    　(つまり x, lc を設定する側では x=0 の時は lc の中身は気にしなくて良い。)。


    関数 x y lc ; .ble-cursor-move.text text ; x y lc

      .ble-cursor-move.text は指定した文字を現在位置 x y に書き込んだ時に、
      カーソルがどの様に移動するかを計算する。この時 lc の値も一緒に計算する。

      ** 注意点 **
      text に BS や VT が含まれる場合、lc を適切に計算する事が出来ない。
      BS, VT が含まれる場合、その直前の文字 (BS で消した文字の直前の文字、及び、VT で移動した先の左側にある文字)
      を今迄の出力から知る事は出来ない。この様な場合は暫定的に lc=32 (空白文字) を設定する。
      (この関数は prompt の幅を計算する為にある。PS1 に BS や VT などの制御文字を \[ \] で
      囲まずに設定する事は考えにくいので、現状ではこれについて対策する予定はない。)


    関数 .ble-cursor.construct-prompt ; ret=(x y lc ps1esc)

      プロンプト文字列を実体化し ps1esc とする。
      更に、プロンプトを端末の左端から表示し始めた時の、最後のカーソルの位置 x y を計算する。
      また、lc にはカーソルの位置の左側にある文字の文字コードを返す。

      ** 注意点 **
      エスケープシーケンスなど実際に prompt の位置に文字として表示されない物は、必ず \[ ... \] で囲む事。
      \[ \] で囲んだ中でカーソルの移動などを行うとカーソル位置を正しく計算できない可能性がある。
      \[ \] で囲んだ中でカーソルを移動させたとしても、また元の位置に戻す事が望ましい。


    関数 _ble_cursor_x _ble_cursor_lc ; .ble-edit.adjust-cursor

      ble-decode-byte の最後にこの関数を呼び出して、READLINE_LINE, READLINE_POINT
      の調整を実行する事にした。ちゃんと実装した物が完成したので、
      暫定的に書いた調整コードは削除 (以下)

      # # 何か入力されていないと C-d で exit してしまう。
      # # これは delete-char で判定するのではなく、
      # # あらゆる関数を呼び出す前にチェックされる様だ。
      # # また、READLINE_POINT が文字列末端に設定されていれば OK

      # [暫定v1]
      # READLINE_LINE="${_ble_edit_str:_ble_edit_str_ind:1}"
      # test -z "$READLINE_LINE" && READLINE_LINE=' '
      # READLINE_POINT=1

      # [暫定v2]
      # echo -n "[D"
      # if ((_ble_edit_ind>0)); then
      #   READLINE_LINE="${_ble_edit_str:_ble_edit_ind-1:1}"
      # else
      #   READLINE_LINE='_'
      # fi
      # READLINE_POINT=1

2013-05-29 highlight.sh

  * bash で highlight? [#D0001]

    一応、bind -x で通常文字に対して適当な関数を割り当てれば
    入力に対して hook をする事は可能なようである。
    但し、関数の呼出が終わった後に入力行が再度描画されるので、
    折角色を付けて出力したとしても上から塗り潰される事になる。

    後 bind -x のもう一つの問題として、
    複数行に亙る行を編集している時に bind -x の関数を呼び出すと、
    処理が終わった後に再描画される訳だが、
    その時の再描画で表示している行の位置が下にずれる。
    これは bind -x の関数で何の操作もしていなくても同様である。
    これを正しく処理する為には、

    (1) 現在の端末の幅を取得する
    (2) 文字列の表示上の長さを取得する
    (3) prompt の長さを取得する。

    などの機能を正しく実装する必要がある。
    (1) は shopt -s chkwinsize でもすれば取り敢えずできる。
    (3) は (2) さえ正確に記述でき、現在のカーソル位置が分かれば現在の位置から逆算できる。
    逆に言えば、(2) と (3) さえ正確に計算できれば現在のカーソル位置も端末に問い合わせることなく分かるという事でもある。

    + 現在のカーソルの位置を取得する関数は書けた。一応動いている。
      但し CSI 6 n (DSR CPR) に対応している端末でないと動かない。

    * 現在位置を予測するという事

      文字列の表示上の長さを計算するには、
      <del>文字列の文字コードを utf-8 と仮定すれば編集文字列を走査して、</del>
      文字コード列を生成し、更に其処から文字幅に変換して、
      加算するという事をすれば良い。

      と思ったが…実際には改行やら TAB やらがあるので、
      現在の正確な位置が分からないと文字列の表示上の長さなどの情報を取得する事は出来ない。
      やはり何とかして端末が表示される長さを算出する必要があるだろうか。
      端末が表示される長さを取得する方法:

      A READLINE_LINE が空だった時の位置を記録しておく?
        + 漢字や平仮名で始まるコマンドを入力した場合に対処できない。しかしそんなコマンドは存在するだろうか。
        + 前のコマンドの出力が改行で終わらなかった場合にどうなるか?
          →1 文字でも入力すれば再描画されてプロンプトは行頭に出て来る。
            0 文字の時に取得した位置はその時にしか信用できないので、1 文字の時に取得した文字の方が良い?
        + <strong>×</strong> プロンプトは複数行に跨らないという仮定をしないとできない。
          然し、人によってはプロンプトを複数行に分けるという人もいる (cygwin の人みたいに)。

      B 自分で PS1 を解析して長さを計算する?
        + <strong>△</strong> 実装が大変。エスケープシーケンスの類にも対応しなければならない。
        + (\a \n \r \ooo はCと同じ意味, \x \f \b はそのまま出力, \v \t \u は別の意味, \e は ESC)
