diff --git a/memo/ChangeLog.md b/memo/ChangeLog.md index 717bac50..df7f0012 100644 --- a/memo/ChangeLog.md +++ b/memo/ChangeLog.md @@ -60,6 +60,7 @@ - term: work around quirks of Solaris xpg4 awk `#D1481` 0000000 - term: support key sequences and control sequences of Solaris console `#D1481` 0000000 +- term: work around Cygwin-console bug of bottom `IL`/`DL` `#D1482` 000000 ## Internal changes and fixes diff --git a/note.txt b/note.txt index 77ab315f..7b03bef9 100644 --- a/note.txt +++ b/note.txt @@ -1204,6 +1204,18 @@ bash_tips ToDo ------------------------------------------------------------------------------- +2021-02-22 + + * cygwin: 下部での IL が動かない旨を報告する? + + 後 DA2 応答をしてくれないか頼みたい。 + + $ printf 'Line %s\n' {0..100}; /bin/sleep 1; printf '\e[L'; /bin/sleep 1 + + 最下部で DL を実行した時にも何か変な事が起こる。 + + $ printf 'Line %s\n' {0..100}; /bin/sleep 1; printf '\e[M'; /bin/sleep 1 + 2021-01-28 * progcolor: ble/syntax/progcolor/eval-word を着色を跨いでキャッシュできないか @@ -3811,6 +3823,189 @@ bash_tips 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 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 が使えない時にどの様にすれば良いか。 diff --git a/src/canvas.sh b/src/canvas.sh index b7a3280b..82352879 100644 --- a/src/canvas.sh +++ b/src/canvas.sh @@ -367,8 +367,9 @@ function ble/canvas/put.draw { DRAW_BUFF[${#DRAW_BUFF[*]}]="$*" } function ble/canvas/put-ind.draw { - local count=${1-1} - local ret; ble/string#repeat "$_ble_term_ind" "$count" + local count=${1-1} ind=$_ble_term_ind + [[ :$2: == *:true-ind:* ]] && ind=$'\eD' + local ret; ble/string#repeat "$ind" "$count" DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret } function ble/canvas/put-ri.draw { @@ -376,6 +377,16 @@ function ble/canvas/put-ri.draw { local ret; ble/string#repeat "$_ble_term_ri" "$count" DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret } +## @fn ble/canvas/put-il.draw [nline] [opts] +## @fn ble/canvas/put-dl.draw [nline] [opts] +## @param[in,opt] nline +## 消去・挿入する行数を指定します。 +## 省略した場合は 1 と解釈されます。 +## @param[in,opt] opts +## panel +## vfill +## no-lastline +## Cygwin console 最終行バグ判定用の情報です。 function ble/canvas/put-il.draw { local value=${1-1} ((value>0)) || return 0 @@ -388,6 +399,58 @@ function ble/canvas/put-dl.draw { DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value} } +# Cygwin console (pcon) では最終行で IL/DL すると画面全体がクリアされるバグの対策 +if ((_ble_bash>=40000)) && [[ ( $OSTYPE == cygwin || $OSTYPE == msys ) && $TERM == xterm-256color ]]; then + function ble/canvas/.is-il-workaround-required { + local value=$1 opts=$2 + + # Cygwin console 以外の端末ではそもそも対策不要。 + [[ ! $_ble_term_DA2R ]] || return 1 + + # 複数行挿入・削除する場合は現在位置は最終行ではない筈。 + ((value==1)) || return 1 + + # 対策不要と明示されている場合は対策不要。 + [[ :$opts: == *:vfill:* || :$opts: == *:no-lastline:* ]] && return 1 + + # ble/canvas/panel 内部で移動中の時は opts=panel が指定される。 + # panel 集合の最終行にいない場合は対策不要。 + [[ :$opts: == *:panel:* ]] && + ! ble/canvas/panel/is-last-line && + return 1 + + return 0 + } + + function ble/canvas/put-il.draw { + local value=${1-1} opts=$2 + ((value>0)) || return 0 + if ble/canvas/.is-il-workaround-required "$value" "$2"; then + if [[ :$opts: == *:panel:* ]]; then + DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 + else + DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[S\e[A\e[L\e[B\e[T' + fi + else + DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_il//'%d'/$value} + DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux + fi + } + function ble/canvas/put-dl.draw { + local value=${1-1} opts=$2 + ((value>0)) || return 0 + if ble/canvas/.is-il-workaround-required "$value" "$2"; then + if [[ :$opts: == *:panel:* ]]; then + DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 + else + DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[S\e[A\e[M\e[B\e[T' + fi + else + DRAW_BUFF[${#DRAW_BUFF[*]}]=$_ble_term_el2 # Note #D1214: 最終行対策 cygwin, linux + DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value} + fi + } +fi function ble/canvas/put-cuu.draw { local value=${1-1} DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_cuu//'%d'/$value} @@ -458,7 +521,7 @@ function ble/canvas/put-move-y.draw { if [[ $MC_SID == $$ ]]; then # Note #D1392: mc (midnight commander) の中だと layout が破壊されるので、 # 必ずしも CUD で想定した行だけ移動できると限らない。 - ble/canvas/put-ind.draw "$dy" + ble/canvas/put-ind.draw "$dy" true-ind else ble/canvas/put-cud.draw "$dy" fi @@ -489,6 +552,26 @@ function ble/canvas/bflush.draw { DRAW_BUFF=() } +## @fn ble/canvas/put-clear-lines.draw [old] [new] [opts] +## @param[in,opt] old new +## 消去前と消去後の行数を指定します。 +## old を省略した場合は 1 が使われます。 +## new を省略した場合は old が使われます。 +## @param[in,opt] opts +## panel +## vfill +## no-lastline +function ble/canvas/put-clear-lines.draw { + local old=${1:-1} + local new=${2:-$old} + if ((old==1&&new==1)); then + ble/canvas/put.draw "$_ble_term_el2" + else + ble/canvas/put-dl.draw "$old" "$3" + ble/canvas/put-il.draw "$new" "$3" + fi +} + #------------------------------------------------------------------------------ # ble/canvas/trace.draw # ble/canvas/trace @@ -1856,7 +1939,7 @@ function ble/canvas/panel/layout/.get-available-height { ret=${heights[index]} } -function ble/canvas/panel#reallocate-height.draw { +function ble/canvas/panel/reallocate-height.draw { local lines=$((${LINES:-25}-_ble_canvas_panel_tmargin)) local i n=${#_ble_canvas_panel_class[@]} @@ -1878,6 +1961,11 @@ function ble/canvas/panel#reallocate-height.draw { ble/canvas/panel#set-height.draw "$i" "${heights[i]}" done } +function ble/canvas/panel/is-last-line { + local ret + ble/arithmetic/sum "${_ble_canvas_panel_height[@]}" + ((_ble_canvas_y==ret-1)) +} function ble/canvas/panel/goto-bottom-dock.draw { if [[ ! $_ble_canvas_panel_bottom ]]; then @@ -1991,7 +2079,7 @@ function ble/canvas/panel#report-cursor-position { ((_ble_canvas_x=x,_ble_canvas_y=ret+y)) } -function ble/canvas/panel#increase-total-height.draw { +function ble/canvas/panel/increase-total-height.draw { local delta=$1 ((delta>0)) || return 1 @@ -2021,7 +2109,7 @@ function ble/canvas/panel#increase-total-height.draw { ble/canvas/goto.draw 0 $((top_height==0?0:top_height-1)) ble/canvas/put-ind.draw $((new_height-1-_ble_canvas_y)); ((_ble_canvas_y=new_height-1)) ble/canvas/panel/goto-vfill.draw && - ble/canvas/put-il.draw "$delta" + ble/canvas/put-il.draw "$delta" vfill } ## @fn ble/canvas/panel#set-height.draw panel height opts @@ -2042,22 +2130,21 @@ function ble/canvas/panel#set-height.draw { fi elif ((delta>0)); then # 新しく行を挿入 - ble/canvas/panel#increase-total-height.draw "$delta" + ble/canvas/panel/increase-total-height.draw "$delta" ble/canvas/panel/goto-vfill.draw && - ble/canvas/put-dl.draw "$delta" + ble/canvas/put-dl.draw "$delta" vfill ((_ble_canvas_panel_height[index]=new_height)) case :$opts: in (*:clear:*) ble/canvas/panel#goto.draw "$index" - ble/canvas/put-dl.draw "$old_height" - ble/canvas/put-il.draw "$new_height" ;; + ble/canvas/put-clear-lines.draw "$old_height" "$new_height" panel ;; (*:shift:*) # 先頭に行挿入 ble/canvas/panel#goto.draw "$index" - ble/canvas/put-il.draw "$delta" ;; + ble/canvas/put-il.draw "$delta" panel ;; (*) # 末尾に行挿入 ble/canvas/panel#goto.draw "$index" 0 "$old_height" - ble/canvas/put-il.draw "$delta" ;; + ble/canvas/put-il.draw "$delta" panel ;; esac else @@ -2066,19 +2153,18 @@ function ble/canvas/panel#set-height.draw { case :$opts: in (*:clear:*) ble/canvas/panel#goto.draw "$index" - ble/canvas/put-dl.draw "$old_height" - ble/canvas/put-il.draw "$new_height" ;; + ble/canvas/put-clear-lines.draw "$old_height" "$new_height" panel ;; (*:shift:*) # 先頭を削除 ble/canvas/panel#goto.draw "$index" 0 0 - ble/canvas/put-dl.draw "$delta" ;; + ble/canvas/put-dl.draw "$delta" panel ;; (*) # 末尾を削除 ble/canvas/panel#goto.draw "$index" 0 "$new_height" - ble/canvas/put-dl.draw "$delta" ;; + ble/canvas/put-dl.draw "$delta" panel ;; esac ((_ble_canvas_panel_height[index]=new_height)) ble/canvas/panel/goto-vfill.draw && - ble/canvas/put-il.draw "$delta" + ble/canvas/put-il.draw "$delta" vfill fi ble/function#try "${_ble_canvas_panel_class[index]}#panel::onHeightChange" "$index" @@ -2099,12 +2185,7 @@ function ble/canvas/panel#clear.draw { local height=${_ble_canvas_panel_height[index]} if ((height)); then ble/canvas/panel#goto.draw "$index" 0 0 sgr0 - if ((height==1)); then - ble/canvas/put.draw "$_ble_term_el2" - else - ble/canvas/put-dl.draw "$height" - ble/canvas/put-il.draw "$height" - fi + ble/canvas/put-clear-lines.draw "$height" fi } function ble/canvas/panel#clear-after.draw { @@ -2117,8 +2198,9 @@ function ble/canvas/panel#clear-after.draw { local rest_lines=$((height-(y+1))) if ((rest_lines)); then ble/canvas/put.draw "$_ble_term_ind" - ble/canvas/put-dl.draw "$rest_lines" - ble/canvas/put-il.draw "$rest_lines" + [[ $_ble_term_ind != $'\eD' ]] && + ble/canvas/put-hpa.draw $((x+1)) + ble/canvas/put-clear-lines.draw "$rest_lines" ble/canvas/put-cuu.draw 1 fi } @@ -2189,7 +2271,7 @@ function ble/canvas/panel/ensure-tmargin.draw { ble/canvas/put-cuu.draw $((top_height-1+tmargin)) ble/canvas/excursion-start.draw ble/canvas/put-cup.draw 1 1 - ble/canvas/put-il.draw "$tmargin" + ble/canvas/put-il.draw "$tmargin" no-lastline ble/canvas/excursion-end.draw fi ble/canvas/excursion-start.draw @@ -2214,10 +2296,10 @@ function ble/canvas/panel/ensure-tmargin.draw { if [[ $_ble_term_rc ]]; then ble/canvas/excursion-start.draw ble/canvas/put-cup.draw 1 1 - ble/canvas/put-il.draw "$tmargin" + ble/canvas/put-il.draw "$tmargin" no-lastline ble/canvas/excursion-end.draw else - ble/canvas/put-il.draw "$tmargin" + ble/canvas/put-il.draw "$tmargin" no-lastline fi ble/canvas/put-cud.draw "$tmargin" fi diff --git a/src/edit.sh b/src/edit.sh index e8eb09d3..a16e085c 100644 --- a/src/edit.sh +++ b/src/edit.sh @@ -1201,7 +1201,7 @@ function ble/edit/info/.render-content { _ble_edit_info=("$x" "$y" "$content") local -a DRAW_BUFF=() - ble/canvas/panel#reallocate-height.draw + ble/canvas/panel/reallocate-height.draw ble/canvas/panel#clear.draw "$_ble_edit_info_panel" ble/canvas/panel#goto.draw "$_ble_edit_info_panel" ble/canvas/put.draw "$content" @@ -2107,7 +2107,7 @@ function ble/textarea#render/.determine-scroll { # panel の高さを要求。この後 height <= nline になる筈。 if ((height!=nline)); then - ble/canvas/panel#reallocate-height.draw + ble/canvas/panel/reallocate-height.draw height=${_ble_canvas_panel_height[_ble_textarea_panel]} fi @@ -2170,9 +2170,9 @@ function ble/textarea#render/.perform-scroll { local shift=$((_ble_textarea_scroll-new_scroll)) local draw_shift=$((shift&2 ble-edit/bind/stdout.on + ble/util/buffer.flush >&2 # C-c に対して ble/builtin/trap/install-hook INT # 何故か改めて実行しないと有効にならない diff --git a/src/util.sh b/src/util.sh index 877e7c58..571818c8 100644 --- a/src/util.sh +++ b/src/util.sh @@ -4074,17 +4074,18 @@ function ble/term:cygwin/initialize.hook { _ble_term_ri=$'\e[A' # DLの修正 - # Note: Cygwin console では DL が最終行まで - # 消去する時、何も消去されない…。 function ble/canvas/put-dl.draw { local value=${1-1} i ((value)) || return 1 + + # Note: DL が最終行まで消去する時、何も消去されない…。 DRAW_BUFF[${#DRAW_BUFF[*]}]=$'\e[2K' if ((value>1)); then local ret ble/string#repeat $'\e[B\e[2K' $((value-1)); local a=$ret DRAW_BUFF[${#DRAW_BUFF[*]}]=$ret$'\e['$((value-1))'A' fi + DRAW_BUFF[${#DRAW_BUFF[*]}]=${_ble_term_dl//'%d'/$value} } }