Next: , Previous: , Up: Files   [Contents][Index]


24.11 特定のファイル名の“Magic”の作成

特定のファイル名にたいして特別な処理を実装できます。これはそれらの名前にたいするmagic化と呼ばれます。この機能は主にリモートファイルにたいするアクセスの実装用に使用されます(Remote Files in The GNU Emacs Manualを参照)。

magicファイル名を定義するには、名前クラスを定義するための正規表現とそれにマッチするファイル名用のEmacsファイル操作プリミティブすべてを実装するハンドラーを定義しなければなりません。

変数file-name-handler-alistは各ハンドラーに適用するときを決定する正規表現とともにハンドラーのリストを保持します。各要素は以下の形式をもちます:

(regexp . handler)

ファイルアクセスとファイル名変換にたいするすべてのEmacsプリミティブは、file-name-handler-alistにたいして与えられたファイル名をチェックします。そのファイル名がregexpにマッチしたら、そのプリミティブがhandlerを呼び出してファイルを処理します。

handlerの1つ目の引数には、プリミティブの名前をシンボルとして与えます。残りの引数はそのプリミティブに引数として渡されます(これらの引数の1つ目はほとんどの場合はファイル名自身)。たとえば以下を行って:

(file-exists-p filename)

filenameがハンドラーhandlerをもつなら、handlerは以下のように呼び出されます:

(funcall handler 'file-exists-p filename)

関数が2つ以上の引数を受け取る場合には、それらはファイル名でなければならず、関数はそれらのファイル名それぞれにたいしてハンドラーをチェックします。たとえば、

(expand-file-name filename dirname)

以下を行うと、filenameにたいするハンドラーをチェックした後にdirnameにたいするハンドラーをチェックします。どちらの場合でもhandlerは以下のように呼び出されます:

(funcall handler 'expand-file-name filename dirname)

その後にhandlerfilenamedirnameのいずれかを処理するか解決する必要があります。

指定されたファイル名が2つ以上のハンドラーにマッチする場合には、ファイル名の中で最後に開始するマッチが優先されます。リモートファイルアクセスのようなジョブにたいするハンドラーに先立って、解凍のようなジョブにたいするハンドラーが最初に処理されるようにこのルールが選択されました。

以下はmagicファイル名ハンドラーが処理する操作です:

access-fileadd-name-to-filebyte-compiler-base-file-name
copy-directorycopy-filedelete-directorydelete-filediff-latest-backup-filedirectory-file-namedirectory-filesdirectory-files-and-attributesdired-compress-filedired-uncache
expand-file-namefile-accessible-directory-pfile-aclfile-attributesfile-directory-pfile-equal-pfile-executable-pfile-exists-pfile-in-directory-pfile-local-copyfile-modesfile-name-all-completionsfile-name-as-directoryfile-name-completionfile-name-directoryfile-name-nondirectoryfile-name-sans-versionsfile-newer-than-file-pfile-notify-add-watchfile-notify-rm-watchfile-ownership-preserved-pfile-readable-pfile-regular-pfile-remote-pfile-selinux-contextfile-symlink-pfile-truenamefile-writable-pfind-backup-file-nameget-file-bufferinsert-directoryinsert-file-contents
loadmake-auto-save-file-namemake-directorymake-directory-internalmake-symbolic-link
process-filerename-fileset-file-aclset-file-modesset-file-selinux-contextset-file-timesset-visited-file-modtimeshell-commandstart-file-processsubstitute-in-file-name
unhandled-file-name-directoryvc-registeredverify-visited-file-modtime
write-region

insert-file-contentsにたいするハンドラーはvisit引数が非nilなら、通常は(set-buffer-modified-p nil)によりそのバッファーの変更フラグをクリアーする必要があります。これにはもしそのバッファーがロックされていたら、ロックを解除する効果もあります。

ハンドラー関数は上記すべての操作を処理しなければならず、他の操作が将来追加される可能性もあります。これらの操作自体すべてを実装する必要はありません — 特定の操作にたいして特別なことを行う必要がないときは、その操作を“通常の方法”で処理するよう、そのプリミティブを再呼び出しできます。認識できない操作にたいしては、常にそのプリミティブを再呼び出しするべきです。以下は、これを行う方法の1つです:

(defun my-file-handler (operation &rest args)
  ;; 特別に処理する必要がある、
  ;; 特別な操作を最初にチェックする
  (cond ((eq operation 'insert-file-contents) …)
        ((eq operation 'write-region) …)
        …
        ;; 関知しないその他の操作を処理する
        (t (let ((inhibit-file-name-handlers
                  (cons 'my-file-handler
                        (and (eq inhibit-file-name-operation operation)
                             inhibit-file-name-handlers)))
                 (inhibit-file-name-operation operation))
             (apply operation args)))))

ハンドラー関数が通常のEmacsプリミティブを呼び出す決定をした際には、無限再帰を引き起こすような同一ハンドラーからのプリミティブの再呼び出しを防ぐ必要があります。上記の例では変数inhibit-file-name-handlersinhibit-file-name-operationによって、これを行う方法を示しています。上記の例のように、これらを正確に使用するよう注意してください。複数ハンドラーの正しい振る舞いと、それぞれがハンドラーをもつかもしれない2つのファイル名にたいする操作にたいする詳細は非常に重要です。

ファイルへの実アクセスにたいして実際には特別なことを行わないハンドラー(たとえばリモートファイル名にたいしてホスト名の補完を実装するハンドラーなど)は、safe-magicプロパティに非nilをもつべきです。たとえば、Emacsは通常はPATH内で見い出されるようなディレクトリーが、プレフィックス‘/:’によりmagicファイル名に見えるような場合に、magicファイル名にならないよう“保護”します。しかし、safe-magicプロパティに非nilをもつハンドラーがそれらにたいして使用された場合、‘/:’は追加されません。

ファイル名ハンドラーは普通とは異なる方法でそれを処理(handle)するのがどの操作(operation)なのかを宣言するために、operationsプロパティをもつことができます。このプロパティが非nil値をもつなら、それは操作のリストであるべきです。その場合には、それらの操作だけがハンドラーを呼び出すでしょう。これは無駄を省きますが、主な目的はオートロードされるハンドラー関数が実際に処理を行うとき以外はロードされないようにすることです。

通常のプリミティブにたいして単にすべての操作を延期しても機能しません。たとえばファイル名ハンドラーがfile-exists-pにたいして適用された場合には、通常のloadコードは正しく機能しないでしょうから、ハンドラー自身でloadを処理しなければなりません。しかしハンドラーがfile-exists-pプロパティを使用してfile-exists-pを処理しないことを宣言した場合には、普通とは異なる方法でloadを処理する必要はなくなります。

Variable: inhibit-file-name-handlers

この変数は特定の操作にたいして現在のところ使用を抑制されているハンドラーのリストを保持する。

Variable: inhibit-file-name-operation

特定のハンドラーにたいしてその時点で抑制されている操作。

Function: find-file-name-handler file operation

この関数はfileというファイル名にたいするハンドラー関数、それが存在しなければnilをリターンする。引数operationはそのファイルを処理する操作であること。これはハンドラー呼び出し時に1つ目の引数として渡すことになる値である。operationinhibit-file-name-operationと等しいか、そのハンドラーのoperations内に存在しなければ、この関数はnilをリターンする。

Function: file-local-copy filename

この関数はファイルfilenameがまだローカルマシン上になければ、それをローカルマシン上の通常の非magicファイルにコピーする。magicファイル名は、それらが他のマシン上のファイルを参照する場合には、file-local-copy操作を処理するべきである。リモートファイルアクセス以外の目的にたいして使用されるmagicファイル名は、file-local-copyを処理するべきではない。この場合には関数はそのファイルをローカルファイルとして扱うだろう。

filenameがローカルなら、それがmagicか否かにかかわらずこの関数は何も行わずにnilをリターンする。それ以外ならローカルコピーファイルのファイル名をリターンする。

Function: file-remote-p filename &optional identification connected

この関数はfilenameがリモートファイルかどうかをテストする。filenameがローカル(リモートではない)ならリターン値はnilfilenameが正にリモートならリターン値はそのリモートシステムを識別する文字列。

この識別子文字列はホスト名とユーザー名、およびリモートシステムへのアクセスに使用されるメソッドを表す文字列も同様に含めることができる。たとえばファイル名/sudo::/some/fileにたいするリモート識別子文字列は/sudo:root@localhost:

2つの異なるファイルにたいしてfile-remote-pが同じ識別子をリターンした場合には、それらが同じファイルシステム上に格納されていて互いに配慮しつつアクセス可能であることを意味する。これはたとえば同時に両方のファイルにアクセスするリモートプロセスを開始することが可能なことを意味する。ファイルハンドラーの実装者はこの方式を保証する必要がある。

identificationは文字列としてリターンされるべき識別子の一部を指定する。identificationにはmethoduserhostのシンボルを指定できる。他の値はすべてnilのように扱われて、それは完全な識別子文字列をリターンすることを意味する。上記の例ではリモートのuser識別子文字列はrootになるだろう。

connectedが非nilなら、たとえfilenameがリモートであってもEmacsがそのホストにたいする接続をもたなければ、この関数はnilをリターンする。これは接続が存在しない際の接続の遅延を回避したいときに有用。

Function: unhandled-file-name-directory filename

この関数は、magicではないディレクトリーの名前をリターンする。これは、filenameがmagicでなければ、それのディレクトリーパートを使用する。magicファイル名にたいしては、何の値をリターンするかを決定するために、ファイル名ハンドラーを呼び出す。filenameがローカルプロセスからアクセス不能な場合、ファイル名ハンドラーはnilをリターンすることにより、それを示すべきである。

これはサブプロセスの実行に有用。すべてのサブプロセスは自身が所属するカレントディレクトリーとして非magicディレクトリーをもたなければならず、この関数はそれを導出するよい手段である。

User Option: remote-file-name-inhibit-cache

リモートファイルの属性は、よりよいパフォーマンスのためにキャッシュすることができる。キャッシュがEmacsの制御外で変更されると、そのキャッシュ値は無効になり再読込しなければならない。

この変数がnilにセットされているとキャッシュ値は決して失効しない。このセッティングはEmacs以外にリモートファイルを変更するものがないことが確実な場合のみ慎重に使用すること。これがtにセットされているとキャッシュ値は決して使用されない。これはもっとも安全な値であるがパフォーマンスは低下するかもしれない。

折衷的な値としてはこれを正の数字にセットする。これはキャッシュされてからその数字の秒数の間は、ャッシュ値を使用することを意味する。リモートファイルが定期的にチェックされる場合には、この変数を定期的なチェックの間隔より小さい値にletバインドするのは、よい考えかもしれない。たとえば:

(defun display-time-file-nonempty-p (file)
  (let ((remote-file-name-inhibit-cache
         (- display-time-interval 5)))
    (and (file-exists-p file)
         (< 0 (nth 7 (file-attributes
                       (file-chase-links file)))))))