2022-08-18

display spaceを併用するとウィンドウの先頭でline-prefixが効かなくなる件(Emacs Bug?)

org-modernを試したときに表の先頭が(org-indentによって)インデントされていないことに気がついた。(Emacs 28.1で確認)

ウィンドウの先頭部分が崩れている表
図1: ウィンドウの先頭部分が崩れている表

原因を調べたところ、org-modernに限らず次の条件で問題が起きることが分かった。

  • 行の先頭に対してline-prefixテキストプロパティとdisplayテキストプロパティの両方が指定されている
  • displayプロパティに(space …)を指定している
  • その行がウィンドウの先頭にある

この条件を満たすとき、なぜかline-prefixの効果が消えてしまう。

再現するコードは次の通り。

(progn
  ;; ウィンドウの先頭へ移動
  (goto-char (window-start))
  ;; line-prefixとdisplayの両方のテキストプロパティを持つテキストを挿入
  (insert (propertize "TEXT" ;;←この文字列はdisplayプロパティで置換される
                      'line-prefix "[PREFIX-STR]" ;;←行の前にこれが表示されるはず
                      'display '(space :width 1) ;;NG
                      ;;'display (svg-image (svg-create 10 10)) ;;OK
                      ;;'display "[DISPLAY-STR]" ;;OK
                      )))

displayテキストプロパティの値が(image …)の場合や単なる文字列の場合この現象は起きない。例えば単なる文字列の場合は[PREFIX-STR][DISPLAY-STR]と表示されるが、(space …)の場合は[PREFIX-STR]が表示されず1文字分の空白が表示されるだけとなる。

回避方法はちょっと思いつかない。いっそ表の部分はインデントを全部無効化するとか?

最初phscrollのせいかと思ったがそういうわけでは無さそうだ。

以前にもline-prefixでマウス入力の座標がずれる問題に遭遇したことがある。Emacsのソースコードを確認していないが、この辺りの処理には何らかの構造的な問題があるのかもしれない。私の経験的にもレイアウト処理というのはちゃんと設計しないと複雑怪奇なものになりがちだ。

それにしてもorg-modernの罫線の引き方、displayテキストプロパティの(space :width (1)) で幅1pxの空白を作って、faceに:inverse-video tを指定することで実現してるんだ! だからline-spacingがあっても隙間無く線が表示される。そんな方法考えもしなかった。

(insert
 ;; 1行目 赤い縦線にABC 行間は10
 (propertize "X"
             'display '(space :width (1))
             'font-lock-face '(:inverse-video t :foreground "red"))
 (propertize "ABC\n" 'line-spacing 10)
 ;; 2行目 赤い縦線にDEF
 (propertize "X"
             'display '(space :width (1))
             'font-lock-face '(:inverse-video t :foreground "red"))
 "DEF")

あー、透明な画像で1pxの空白を作れば回避可能かもしれない。でも全行に画像を挿入しまくるのもなぁ……。

(2022-08-27追記: org-modernでorg-indentを使っていると表のウィンドウ先頭部分がインデントされない問題は、displayテキストプロパティを" "にしてfaceの:heightを0.1にすることで回避した。org-modern–tableを色々といじると直せる。ちなみにこれとは別の話だが、org-indentを使っていると表の水平線の下に空白が空いてしまう問題は、org-indentが挿入する空白文字列の高さを小さくすることで回避できる。詳しくはorg-modernとorg-indentを併用したときの表の乱れを直すに書いた)

Pingback / Trackback