Skip to content

Commit

Permalink
util (visible-bell): work around coordinate mismatches in subshells
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Feb 23, 2021
1 parent 1f55913 commit 01cfb10
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 14 deletions.
1 change: 1 addition & 0 deletions memo/ChangeLog.md
Expand Up @@ -14,6 +14,7 @@
- canvas: update emoji database and support `bleopt emoji_version` (motivated by endorfina) `#D1454` d1f8c27
- canvas, edit: support `bleopt info_display` (suggested by 0neGuyDev) `#D1458` 69228fa
- canvas (panel): always call `panel::render` to update height `#D1472` 51d2c05
- util (visible-bell): work around coordinate mismatches in subshells `#D1495` 0000000
- prompt: support `bleopt prompt_status_{line,align}` and `face prompt_status_line` `#D1462` cca1cbc
- prompt: fix missing height allocation for status line `#D1487` b424fa5
- syntax: properly support case patterns `#D1474` `#D1475` `#D1476` 64b55b7
Expand Down
137 changes: 128 additions & 9 deletions note.txt
Expand Up @@ -1204,19 +1204,34 @@ bash_tips
ToDo
-------------------------------------------------------------------------------

2021-02-22
2021-02-23

* global: IFS 対策
* util: カーソルが bottom-dock にいる時の vbell の座標計算
Ref #D1495 ... 取り敢えずの対策

多くの関数は IFS が普通の値になっているという事を前提にして書かれている。
ble.sh の中では一時的に IFS を設定して動作する様になっているが、
ユーザーから使用された時に IFS に変な値が設定されている可能性は排除でいない
現在の実装は vbell が sc..rc を自由に使える前提になっている。しかしカーソル
が bottom-dock に停泊している時に vbell が来るとvbell によって floating
panels の位置が分からなくなってしまい、表示がずれてしまう事になる

* 引数を $* で渡された時の対策は取り敢えず grc -F で ${* もしくは $* に一致させて確認した。
* 配列に対する単語分割 =($...) に関してもチェックは行った。
同じプロセス (親シェル) の中で vbell を処理している場合には、一旦 floating
panel の位置に戻ってから sc..rc をしてそれから再び bottom-dock に戻るという
手順を踏む事によって問題を回避できる。然し、サブシェルの中にいる場合には現
在の最新の配置情報にアクセスできないのでこの方法は取れない。

現在は取り敢えずカーソルが bottom-dock に停泊している事はないとの想定で
sc..rc を実行しているが、例えば info_display=bottom にして vi_cmap を使って
いる時などにこの前提が破れてしまう。

[解決方法]

他に配列を結合する処理に関しても注意が必要になる可能性がある。
つまり、aa="${arr[*]}" の形の処理である。
ちゃんと実装する為には、親シェルで全ての描画を行う様にする必要がある。その
時に問題になるのがどうやって visible-bell の消去のタイミングを親側で決める
かという事。idle を使う方法は bash-4 以降でしか使えない。シグナルを使う方法
には余り頼りたくないが、現実的にはそうするしかないのだろうか。bash-3 と
bash-4 で実装を切り替えても良い。何れにしてもサブシェルと通信を行う枠組みを
整える必要がある気がする。

2021-02-22

* cavnas: 描画の最中で status が高さを取得する時に textarea の内容を削り取る可能性がある

Expand Down Expand Up @@ -3756,6 +3771,110 @@ bash_tips
Done (実装ログ)
-------------------------------------------------------------------------------

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 の方針で回避する事にする。

2021-02-22

* prompt: status line が最初の起動時に表示されていない [#D1492]
Expand Down
10 changes: 5 additions & 5 deletions src/util.sh
Expand Up @@ -4234,18 +4234,18 @@ function ble/term/visible-bell:canvas/show {
local y=${_ble_term_visible_bell_prev[5]}

local -a DRAW_BUFF=()
[[ $_ble_attached ]] &&
[[ :$opts: != *:update:* && $_ble_attached ]] && # WA #D1495
[[ $_ble_term_ri || :$opts: != *:erased:* && :$opts: != *:update:* ]] &&
ble/canvas/panel/ensure-tmargin.draw
if [[ $_ble_term_rc ]]; then
local ret=
[[ $_ble_attached ]] && ble/canvas/panel/save-position goto-top-dock
[[ :$opts: != *:update:* && $_ble_attached ]] && ble/canvas/panel/save-position goto-top-dock # WA #D1495
ble/canvas/put.draw "$_ble_term_ri_or_cuu1$_ble_term_sc$_ble_term_sgr0"
ble/canvas/put-cup.draw $((y0+1)) $((x0+1))
ble/canvas/put.draw "$sgr$message$_ble_term_sgr0"
ble/canvas/put.draw "$_ble_term_rc"
ble/canvas/put-cud.draw 1
[[ $_ble_attached ]] && ble/canvas/panel/load-position.draw "$ret"
[[ :$opts: != *:update:* && $_ble_attached ]] && ble/canvas/panel/load-position.draw "$ret" # WA #D1495
else
ble/canvas/put.draw "$_ble_term_ri_or_cuu1$_ble_term_sgr0"
ble/canvas/put-hpa.draw $((1+x0))
Expand All @@ -4269,15 +4269,15 @@ function ble/term/visible-bell:canvas/clear {
local -a DRAW_BUFF=()
if [[ $_ble_term_rc ]]; then
local ret=
[[ $_ble_attached ]] && ble/canvas/panel/save-position goto-top-dock
#[[ $_ble_attached ]] && ble/canvas/panel/save-position goto-top-dock # WA #D1495
ble/canvas/put.draw "$_ble_term_sc$_ble_term_sgr0"
ble/canvas/put-cup.draw $((y0+1)) $((x0+1))
ble/canvas/put.draw "$sgr"
ble/canvas/put-spaces.draw "$x"
#ble/canvas/put-ech.draw "$x"
#ble/canvas/put.draw "$_ble_term_el"
ble/canvas/put.draw "$_ble_term_sgr0$_ble_term_rc"
[[ $_ble_attached ]] && ble/canvas/panel/load-position.draw "$ret"
#[[ $_ble_attached ]] && ble/canvas/panel/load-position.draw "$ret" # WA #D1495
else
: # 親プロセスの _ble_canvas_x が分からないので座標がずれる
# ble/util/buffer.flush >&2
Expand Down

0 comments on commit 01cfb10

Please sign in to comment.