前のサブセクション(ラウンドトリップ仕様を参照)で説明したラウンドトリップ指定とは対照的に、変数after-insert-file-functions
とwrite-region-annotate-functions
を使用して読み取りと書き込みの変換を個別に制御できます。
変換はある表現を起点として他の表現を生成します。これを行う変換が1つだけのときは、何を起点とするかに関して競合は存在しません。しかし複数の変換呼び出しが存在する場合には、同じデータを起点にする必要がある2つの変換の間に競合が発生するかもしれません。
この状況を理解するには、write-region
中のテキストプロパティの変換コンテキストが最善です。たとえばあるバッファーの位置42の文字が‘X’で、それのテキストプロパティがfoo
だとします。foo
にたいする変換が、たとえばそのバッファーに‘FOO:’を挿入することにより行われる場合には、それは位置42の文字‘X’を‘F’に変更します。そして次の変換は間違ったデータを起点に開始されるでしょう。
競合を避けるためには協調的な変換がバッファーを変更せずに、position昇順でソートされた(position
. string)
という形式の要素をもつリストを注釈(annotations)に指定します。
2つ以上の変換が存在する場合には、write-region
はそれらの注釈を1つのソート済みリストに破壊的にマージします。後でそのバッファーのテキストを実際にファイルに書き込む際に、対応する位置にある指定された注釈を混合します。これはすべてバッファーを変更せずに行われます。
読み取り時にはこれとは対照的にそのテキストの混合された注釈は即座に処理されます。insert-file-contents
は変更される何らかのテキストの先頭にポイントをセットしてから、そのテキストの長さで変換関数を呼び出します。これらの関数は常に挿入されるテキストの先頭のポイントをリターンするべきです。最初の変換により注釈が削除されても、その後の変換が誤って処理することはないので、このアプローチは読み取りに際しては正しく機能します。すべての変換関数は、それが認識する注釈のスキャン、その注釈の削除、バッファーテキストの変更(たとえばテキストプロパティのセット等)、およびそれらの変更に由来する更新されたテキスト長のリターンを行うべきです。1つの関数によりリターンされた値は次の関数への引数になります。
write-region
にたいして呼び出す関数のリスト。リスト内の各関数は書き込まれるリージョンの開始と終了の2つの引数で呼び出される。これらの関数はそのバッファーのコンテンツを変更するべきではない。かわりに注釈をリターンすること。
特別なケースとして、関数がカレントと異なるバッファーをリターンするかもしれない。Emacsはこれを、出力される変更されたテキストをカレントバッファーが含むものとして理解する。つまりEmacsはwrite-region
呼び出しの引数startとendを、新たなバッファーのpoint-min
とpoint-max
に変更して与える。さらに以前のすべての注釈はこの関数により処理されるのでEmacsはそれらの破棄も行う。
この変数の値が非nil
なら、それは関数であること。この関数はwrite-region
完了後に引数なしで呼び出される。
write-region-annotate-functions
内のある関数がカレントと異なるバッファーをリターンした場合には、Emacsはwrite-region-post-annotation-function
を複数回呼び出す。Emacsは最後にカレントだったバッファーでそれを呼び出し、その前にカレントだったバッファーで再度これを呼び出す、...のようにして元のバッファーに戻る。
したがってwrite-region-annotate-functions
内の関数は、バッファーを作成して、kill-buffer
のそのバッファーでのローカル値にこの変数を与え、変更されたテキストでそのバッファーをセットアップして、そのバッファーをカレントにすることができる。そのバッファーは、write-region
完了後にkillされるだろう。
このリスト内の各関数は、挿入されるテキストの先頭にポイントがある状態で、挿入される文字数を1つの引数としてinsert-file-contents
により呼び出される。すべての関数はポイントを未変更のまま、その関数によって変更された挿入後テキストの新たな文字数をリターンすること。
わたしたちは、ユーザーがファイル内にテキストプロパティを格納したりそれらを取得するために、そしてさまざまなデータフォーマットを体験することにより適切なフォーマットを見つけるために、これらのフックを使用してLispプログラムを記述することを推奨します。最終的にはわたしたちがEmacs内にインストールできる、良質で汎用性のある拡張をユーザーが開発することを望みます。
わたしたちはテキストプロパティの名前や値として、任意のLispオブジェクトの処理を試みることは推奨しません — なぜなら汎用的なプログラムはおそらく記述が困難かつ低速だからです。かわりに十分な柔軟性をもちエンコードが難しすぎない、想定されるデータ型のセットを選択してください。