[Message Prev][Message Next][Thread Prev][Thread Next][Message Index][Thread Index]

[MD:2962]vertical-motion の件



寺川です。

Meadow 1.99 の方はまだ準備中のようなので、Emacs 21.1 で、
vertical-motion の調査をしています。
まだ途中ですが、全角追い出し(MD:2934の2番目の例) で起こっている事は
分かってきましたので、できるだけ簡単に説明を試みます。

indent.c の Fvercital_motion() の処理内容は、
  start_display (&it, w, pt);
  move_it_by_lines (&it, XINT (lines), 0);
の二つに尽きます。start_display で、it の状態を設定し、
move_it_by_lines で目的の位置に it を動かすというだけです。
問題は、start_display の方で起こっています。

xdisp.c の start_display() は、
  init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
で、it を初期設定し、
  reseat_at_previous_visible_line_start (it);
で、まず it を論理行の先頭(バッファの先頭か改行(\n)の次)に配置し、それから
  move_it_to (it, CHARPOS (pos), -1, -1, -1, MOVE_TO_POS);
で、カーソルの位置まで、it を vpos, hpos 等の状態を更新しながら動かす。
ということをしています。

move_it_to の内部では目的の位置に至るまで、
  skip = move_it_in_display_line_to (it, to_charpos, -1, MOVE_TO_POS);
という呼び出しを繰り返しています。
move_it_in_display_line_to は、
折り返しに到達したら、MOVE_LINE_CONTINUED を返し、
目的の位置に到達したら、MOVE_POS_MATCH_OR_ZV を返すというようなことを
していて、半角の場合は、MOVE_POS_MATCH_OR_VZ より、MOVE_LINE_CONTINUED 
が優先される形で書かれています。
全角文字が追い出されて折り返している場合で、目的の位置がその追い出された
全角文字の位置だった場合、MOVE_LINE_CONTINUED ではなく、
MOVE_POS_MATCH_OR_VZ の方を返してしまうために、move_it_to が
その折り返しを認識できない、ということで誤動作しているようです。

#こんな事を書いても煩雑で参考にならないでしょうか?

とりあえず、全角追い出しの場合に絞ってどんな対策が出来るかハックして
みたところ、move_it_in_display_line_to の最後で、it の位置が全角文字
かどうかを調べるために、PRODUCE_GLYPHS(it) すると、
  if (it->area == TEXT_AREA)
    it->current_x += it->pixel_width;
が実行されて、current_xが移動してしまうという問題が発生することに
気づきました。PRODUCE_GLYPHS(it) した後に、
  if (it->area == TEXT_AREA)
    it->current_x -= it->pixel_width;
と無理矢理なことをしてやったところ、全角追い出しに関しては、
それらしく動作するようになりました。

PRODUCE_GLYPHS (it) に副作用があるのが困るのですが、
どなたか、他にやり様があるかどうかご存じではないでしょうか?

タブのある行の折り返しは、また違うところに原因が有るようです。

うーむ。全然まとまっていないですね。
emacs のソースがまとまっていないせいという事にしておきます。
#対照的に xemacs のソースはこの辺りずいぶん整理されているようですね。

ではでは。
----
Applause こと 寺川 愛印
applause@xxxxxxxxxx