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


24.11 Making Certain File Names “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がローカル(リモートではない)の場合、リターン値はnilである。filenameが正にリモートの場合、リターン値はそのリモートシステムを識別する文字列である。

この識別子文字列は、ホスト名とユーザー名、およびリモートシステムへのアクセスに使用されるメソッドを表す文字列も同様に含めることができる。たとえば、ファイル名/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)))))))