Previous: , Up: Display   [Contents][Index]


37.24 双方向テキストの表示

Emacsはアラビア語、ペルシア語、ヘブライ語のような水平方向テキストの自然な表示順がR2L(right-to-left: 右から左)に実行されるようなスクリプトで記述されたテキストを表示できます。さらにL2R(right-to-left: 左から右)のテキストに埋め込まれたR2Lスクリプト(例: プログラムソースファイル内のアラビア語やヘブライ語のコメント)は適宜右から左にR2Lに表示される一方、ラテンスクリプト部やR2Lテキストに埋め込まれた数字はL2Rで表示されます。そのようなL2RとR2Lが混交されたテキストを、わたしたちは双方向テキスト(bidirectional text)と呼んでいます。このセクションでは双方向テキストの編集と表示にたいする機能とオプションについて説明します。

テキストはロジカルな順序(または読込順)、すなわち人間が各文字を読み込むであろう順序で、テキストをEmacsバッファーおよび文字列に格納します。R2Lおよび双方向テキストでは、スクリーン上で文字が表示される順序(ビジュアル順と呼ばれる)はロジカル順と同一ではありません。それら各文字のスクリーン位置は、文字列またはバッファー位置により単調に増加しません。この双方向の並べ替え(bidirectional reordering)を処理を行うに際、EmacsはUnicode双方向アルゴリズム(UBA: Unicode Bidirectional Algorithm)にしたがいます(http://www.unicode.org/reports/tr9/)。現在のところEmacsは、UBAの“Non-isolate Bidirectionality(双方向非分離)”なクラスの実装を提供します。これはまだ、Unicode Standard v6.3.0で提唱された方向分離フォーマットをサポートしていません。

Variable: bidi-display-reordering

このバッファーローカル変数の値が非nil (デフォルト)なら、Emacsは表示で双方向の並べ替えを行う。この並べ替えはバッファーテキスト、同様に文字列表示やバッファー内のテキストプロパティやオーバーレイプロパティ由来のオーバーレイ文字列に効果を及ぼす(Overlay PropertiesおよびDisplay Propertyを参照)。値がnilならEmacsはバッファー内での双方向の並べ替えを行わない。

bidi-display-reorderingのデフォルト値は、モードライン内に表示されるテキスト(Mode Line Formatを参照)、およびヘッダー行(Header Linesを参照)を含む、バッファーにより直接提供されない文字列の並べ替えを制御する。

たとえバッファーのbidi-display-reorderingが非nilでも、Emacsがユニバイトバッファーのテキストの並べ替えを行うことはありません。これはユニバイトバッファーに含まれるのが文字ではなくrawバイトであり、並べ替えに要する方向的なプロパティを欠くからです。したがってあるバッファーのテキストが並べ替えられるかどうかテストするには、bidi-display-reorderingのテスト単独では不十分です。正しいテストは以下のようになります:

 (if (and enable-multibyte-characters
          bidi-display-reordering)
     ;; 表示時にバッファーは並べ替えられるだろう
   )

とはいえ親バッファーが並べ替えられた際には、ユニバイト表示やオーバーレイ文字列は並べ替えられます。これはEmacsによりプレーンASCII文字列がユニバイト文字列に格納されるからです。ユニバイト表示やオーバーレイ文字列が非ASCII文字列を含むなら、それらの文字はL2Rの方向をもつとみなされます。

テキストプロパティdisplay、値が文字列であるようなdisplayプロパティによるオーバーレイ、バッファーテキストを置換するその他任意のプロパティにカバーされたテキストは表示時の並べ替えの際には単一の単位として扱われます。つまりこれらのプロパティにカバーされたテキストのchunk全体が一緒に並べ替えられます。さらにそのようなテキストchunk内の文字の双方向的なプロパティは無視されて、Emacsはあたかもそれらがオブジェクト置換文字(Object Replacement Character)として知られる単一文字で置換されたかのように並べ替えます。これはテキスト範囲上にdisplayプロパティを配置することにより、表示時に周辺テキストを並べ替える方法が変更され得ることを意味しています。このような予期せぬ効果を防ぐには、常に周辺テキストと等しい方向のテキストにたいしてそのようなプロパティを配置してください。

双方向テキストのパラグラフはそれぞれ、R2LかL2Rいずれかの基本方向(base direction)をもちます。L2Rパラグラフはウィンドウの左マージンを先頭に表示され、そのテキストが右マージンに達したら切り詰めや継続されます。R2Lパラグラフはウィンドウの右マージンを先頭に表示され、そのテキストが左マージンに達したら切り詰めや継続されます。

デフォルトではEmacsはテキスト先頭を調べることにより各パラグラフの基本方向を判断します。基本方向の精細な決定手法はUBAにより指定されており、簡潔に言うとその明示にな方向生をもつそのパラグラフ内の最初の文字がパラグラフの基本方向を決定します。とはいえ、あるバッファーが自身のパラグラフにたいして特定の基本方向の強制を要する場合もあります。たとえばプログラムソースコードを含むバッファーは、すべてのパラグラフがL2Rで表示されるよう強制されるべきでしょう。これを行うために以下の変数を使用できます:

Variable: bidi-paragraph-direction

このバッファーローカル変数の値がright-to-leftleft-to-rightいずれかのシンボルなら、そのバッファー内のすべてのパラグラフがその指定された方向をもつとみなされる。その他すべての値はnil (デフォルト)と等価であり、それは各パラグラフの基本方向が内容により判断されることを意味する。

プログラムソースコードにたいするモードは、これをleft-to-rightにセットすること。Progモードはデフォルトでこれを行うので、Progモードから派生したモードは明示的にセットする必要はない(Basic Major Modesを参照)。

Function: current-bidi-paragraph-direction &optional buffer

この関数はbufferという名前のバッファーのポイント位置のパラグラフ方向をリターンする。リターンされる値はleft-to-rightright-to-leftいずれかのシンボルである。bufferが省略またはnilの場合のデフォルトはカレントバッファー。変数bidi-paragraph-directionのバッファーローカル値が非nilなら、リターンされる値はその値と等しくなるだろう。それ以外ならリターンされる値はEmacsにより動的に決定されたパラグラフの方向を反映する。bidi-display-reorderingの値がnilのバッファー、同様にユニバイトバッファーにたいしては、この関数は常にleft-to-rightをリターンする。

バッファーのカレントのスクリーン位置にたいして、ビジュアル順にL2RかR2Lいずれかの方向に厳密なポイント移動を要す場合があります。Emacsはこれを行うためのプリミティブを提供します。

Function: move-point-visually direction

この関数は、カレントで選択されたウィンドウのバッファーにたいしてポイントを、スクリーン上ですぐ右か左のポイントへ移動する。directionが正ならスクリーン位置は右、それ以外ならスクリーン位置は左へ移動するだろう。周囲の双方向コンテキストに依存して、これは潜在的に多くのバッファーのポイントを移動し得ることに注意。スクリーン行終端で呼び出された場合には、この関数はdirectionに応じて適宜、次行か前行の右端か左端のスクリーン位置にポイントを移動する。

この関数は値として新たなバッファー位置をリターンする。

バッファー内で双方向の内容をもつ2つの文字列が並置されているときや、プログラムで1つのテキスト文字列に結合した場合、双方向の並べ替えは以外かつ不快な効果を与える可能性があります。典型的な問題ケースはBuffer MenuモードやRmail Summaryモードのように、バッファーがスペースや区切り文字分割されたテキストの“フィールド”のシーケンスで構成されているときです。それはセパレーターとして使用されている区切り文字が、弱い方向性をもち、周囲のテキストの方向を採用するためです。結果として、双方向の内容のフィールドが後続する数値フィールドは、先行するフィールドヘ左方向に表示され、期待したレイアウトを破壊してしまいます。この問題を回避するための方法がいくつかあります:

Function: bidi-string-mark-left-to-right string

この関数は結果を安全に他の文字列に結合できるよう、あるいはこの文字列とスクリーン上で次行となる行に関連するレイアウトを乱すことなくバッファー内の他の文字列に並置できるよう、自身への引数stringを恐らく変更してリターンする。この関数がリターンする文字列がR2Lパラグラフの一部として表示される文字列なら、それは常に後続するテキストの左に出現するだろう。この関数は自身の引数の文字を検証することにより機能して、もしそれらの文字のいずれかがディスプレイ上の並べ替えを発生し得るなら、この関数はその文字列にLRM文字を付加する。付加されたLRM文字はテキストプロパティinvisibletを与えることにより不可視にできる(Invisible Textを参照)。

並べ替えアルゴリズムはbidi-classプロパティとして格納された文字の双方向プロパティを使用します(Character Propertiesを参照)。Lispプログラムはput-char-code-property関数を呼び出すことにより、これらのプロパティを変更できます。しかしこれを行うにはUBAの完全な理解が要求されるので推奨しません。ある文字の双方向プロパティにたいする任意の変更はグローバルな効果をもちます。これらはEmacsのフレームのすべてのフレームとウィンドウに影響します。

同様にmirroringプロパティは並べ替えられたテキスト内の適切にミラーされた文字の表示に使用されます。Lispプログラムはこのプロパティを変更することにより、ミラーされた表示に影響を与えることができます。繰り返しますがそのような変更はEmacsのすべての表示に影響を与えます。