Last modified: 2007-11-19 02:40 (JST)

Emacs のファイルローカル変数

Emacs には編集するファイルごとにファイル名に関係なく編集モードを指定したり、 ローカル変数を設定したりするための機能があります。 この機能に関する覚え書きのようなものです。

Emacs のマニュアルではこの機能を使って設定する変数を File Variables (ファイル変数) や単に local variable (ローカル変数) と呼んだりしていますが、 これだと他のバッファローカル変数や Emacs-Lisp のローカルバインディングと紛らわしいので、ここでは GNU Emacs Lisp Reference Manual の 2.9版の表記 (File Local Variables) を参考にして「ファイルローカル変数」と書いています。

ここで単に Emacs と書いているのは GNU Emacs のことです。私がそれしか使ってないもんで…

基本的にバージョン 20.7〜22.1 の Emacs について調べたことを書いています。これ以外のバージョン (19.x やまだ出ていない 22.2 以降) でも大筋ではおそらく変わらないと思いますが細かい点で違う可能性があります。

基本

特定の編集モードを指定する

ファイルの1行目-*- (US-ASCII のハイフン、アスタリスク、ハイフン) で挟んで Emacs のメジャー/マイナーモードの名前を書いておくと、そのファイルを Emacs で開いたときにそのモードになります。プログラム言語のソースファイルの場合はコメントの中になるようにするとよいでしょう。

/* -*- C -*-     C 言語の場合 */
% -*- latex -*-  LaTeX ソースの場合
// 1行目ならどこにあってもよい               -*- C++ -*-

実際には Emacs は、 -*- で挟まれた単語の大文字をすべて小文字に変換し、さらに -mode をつなげてできる名前をもつ Emacs-Lisp の関数を呼び出しているだけです (前の3つの例ならそれぞれ c-modelatex-modec++-mode)。なので名前が -mode で終わる関数であれば何でも呼び出せます。普通はそんな名前はメジャーモードかマイナーモードの関数にしか付けませんが。

特定の変数に値を設定する

-*- モード名 -*-」の モード名 の代わりに、 Emacs-Lisp の変数名と値のペアを : で区切って書くことができます。 このようにするとそのファイルを開いたときに自動的にその変数が指定された値に設定されます。 変数名と値のペアは ; (セミコロン) で区切っていくつでも書くことができますが、全体を1行目 (画面上の1行ではなく最初の改行文字まで) に収める必要があります。つまり途中で改行できません。 ただし : の後や ; の前後にスペースやタブ文字を入れることはできるようです。また、最後の値の後ろ (-*- の直前) には ; を書いても書かなくてもかまいません。

/* -*- comment-column: 56; c-file-style: "bsd" -*- */

この例は変数 comment-column を数値 56 に設定し、 c-file-style を文字列 "bsd" に設定します。

変数の値は、 Lisp リーダによって読まれた値がそのまま使われ、評価はされません。例えば -*- foo: bar -*- と書いたとき、変数 foo に設定されるのは bar というシンボルであって、変数 bar が参照されるわけではありません。また -*- hoge: (aho 1) -*- と書いてある場合は (aho 1) は関数の呼び出しではなくてシンボル aho と整数 1 からなるリストを表します (普通の Lisp プログラムで ' を付けたときと同じ)。モード指定を除き、変数名や値の大文字小文字は区別されます。

ただし、ここで設定された変数を使う Lisp ライブラリがこれらのシンボルやリストを変数や関数の呼び出しと解釈することはありえます。

「1行目」に関する規則

ファイルが空白行 (空行やスペース、タブ文字だけの行) で始まっているときは、それらの行は読み飛ばされます。つまり最初の「内容がある」行が1行目になります。

さらに、その行が #! で始まっている場合は、その次の行に -*--*- を書くことができます。 これは #! で始まるファイルは Un*x では1行目全体がそのファイルのインタプリタの指定として扱われるためです。

次のファイルは通常は「#! /bin/sh」に従って shell-script-mode になりますが、 2行目に -*- Perl -*- があるので perl-mode になります。

#! /bin/sh
# -*- Perl -*-
eval 'exec perl -S "$@"'
    if 0;

特殊な変数名

いくつかの「変数名」には特殊な働きがあります。 実際にこのような名前の変数が設定されるわけではありません。

mode
モード関数を呼び出します。値は「-*- モード名 -*-」で指定する モード名 と同じもの (つまり関数名から -mode を取ったもの、大文字小文字は自由) を指定します。例えば「-*- mode: HTML -*-」は単に「-*- HTML -*-」と書いた場合と同じです (こっちの書き方を使うと、他のローカル変数の定義が同時にできます)。
eval
「値」が Emacs-Lisp の式として評価されます。 理論上 Emacs でできることは何でもできることになります。
coding
バッファの文字コーディングシステムとして指定された値を使います。値は set-buffer-file-coding-system コマンドで指定するものと同じです (Lisp のシンボルとして指定)。 MIME で使われている名前 (ただし全て小文字で: 例えば iso-2022-jpeuc-jpshift_jis など) を使っておくとたぶん将来的にも確実…かも。
unibyte
この変数名が現れると、そのファイルを読み込んだバッファはユニバイト (単一バイト) モードになります (全てのバイトは1バイトの文字として扱われ、日本語のようなマルチバイト文字は扱えません)。 Emacs のマニュアルでは値として t を指定するように書かれていますが、少なくとも Emacs 21.3 までの実装では値は関係ないようです (バグのような気が)。

ローカル変数セクション

ファイルローカル変数を指定するもう1つの方法が、 ファイルの末尾に「ローカル変数セクション」を置く方法です。 末尾に書くので設定する変数が多い場合にもファイルの先頭がゴチャゴチャになりません。 また複数行に分けて書くので見やすく書けます。

ローカル変数セクションは、 「Local Variables:」という文字列を含む行で始まり、 「End:」という文字列を含む行で終わります (この2つの文字列では大文字小文字の違いは無視されます)。 それらの間には1行に1つずつ「変数名:」の形式で変数と値を指定します。 (: の前後にはスペース/タブ文字を入れることができます … ただし Local Variables:: の前を除く)。さきに説明した mode などの特殊な変数名も使えます。また、これも同様に「」は評価されません。

Local Variables:
mode: Indented-Text
coding: euc-jp
fill-column: 70
End:

末尾といっても「末尾に近い所」であれば本当に末尾である必要はありません。 Emacs は、ファイル末尾から最大 3,000 文字遡って文字列「Local Variables:」を探すのでこの範囲にあれば構いません。 ただし、この範囲のいずれかの行が改ページ文字 (ASCII コード 12、 ^L) で始まっているとそこで検索を打ち切ります。

上のような原理から、ローカル変数セクション全体の長さは 3,000 文字を超えることはできません (普通は超えないと思いますが…)。ちなみにこの 3,000 という数字は Lisp ライブラリ (files.el) でハードコーディングされており簡単には変えられません。

ローカル変数セクションの各行には、 行頭・行末に一定の文字列があってもかまいません。 この機能を使えばプログラム言語のコメント中にローカル変数リストを入れられます。 例えば

/* Local variables: */
/* compile-command: "make" */
/* End: */

// Local variables:
// compile-command: "make"
// End:

/*
 * Local variables:
 * compile-command: "make"
 * End:
 */

のように書くことができます。ただし、これら行頭・行末の文字列は Local variables: の行から検出されるので、他の行もこの行と形式を揃える必要があります。 たとえば、

/* Local variables:
   compile-command: "make"
   End: */

のようには書けません (エラーになります)。

セキュリティ的なこと

-*--*- やローカル変数セクションで指定される変数は、すべて Emacs ではバッファローカル変数として扱われます。 したがってあるファイルで設定した値が編集中の (もしくはこれから編集される) 他のファイルに影響を及ぼすことは (普通は) ありません。

ただし、特殊な変数名「eval」を使うと Emacs のすべての機能が実行できてしまうので、非常に危険です。このため Emacs は eval に出会うと値を評価する前にユーザに確認を求めます。 ユーザが拒否したときは式は評価されません。

その他フック変数なども直接ではありませんが任意のコードを実行するために使えるので、自動的に設定されるのは好ましくありません。そこで Emacs では次のルールによって設定できる変数と値を制限しています。

Emacs 21以前

Emacs 22以降

上で「許可しません」となっているものは設定する前にユーザに確認を求め、 ユーザが許可した場合は設定します (この動作は変えることができます)。 ただしユーザがスーパーユーザの場合は確認を求めず設定もしません。

さきの例でも使った変数 compile-command は変数名が -command で終わっていますが、 safe-local-variable プロパティが設定されておりローカル変数として自由に設定できます。

例外として、 eval: (put '関数名 'lisp-indent-hook ) の形式で が数値か 'defun の場合のみ、 ユーザに確認を求めずに実行されます。これは (Emacs-)Lisp モードで特定の関数 (またはマクロ) のインデント形式を設定するために使われます。

注意

設定の優先順位

Emacs が新しくファイルを開くとき、 -*- やローカル変数セクションは次の順序で処理されます。

  1. -*--*- にコーディングシステムとユニバイト指定があるか調べ、ある場合はそれに従って設定します
  2. 指定が無ければ、ローカル変数セクションにコーディングシステムとユニバイト指定があるか調べ、あればそれに従って設定します
  3. (コーディングシステムもユニバイトモードも指定されなかった場合は、この段階でコーディングシステムの自動判定が行われます)
  4. -*--*- で編集モードが指定されているか調べ、指定されていればそのモードコマンドを実行します
  5. モードが指定されなかった場合は、ファイル名と変数 auto-mode-alist からモードを調べて設定します
  6. ファイル名からモードが求められず、1行目にインタプリタ指定 (#! ファイル名) がある場合はそのインタプリタ名と interpreter-mode-alist からモードを調べて設定します
  7. -*--*- で指定された変数を設定します
  8. ローカル変数セクションの変数、モードの指定を順次設定します

各々の中では、単に現れた順に設定されます。同じ変数名が指定された場合は後に設定された値が有効になりますが、モード指定や eval の場合は (最後の値だけでなく) 現れるたびに処理されます。

-*- では、 mode: で指定された編集モードコマンドは、その他の変数の指定より後に書いていても、実際には先に実行されます。これに対して、ローカル変数セクションではモードコマンドの実行も変数の設定も合わせて現われた順に行われます。

ローカル変数セクションでメジャーモードを指定するときは、メジャーモードを一番最初に指定してください。メジャーモードコマンドは実行時にそのバッファのバッファローカル変数を消去することになっているので、これより前に変数を指定しても意味がありません。

複数のモードを指定したとき

複数のモードを指定すると (mode: を複数回使ったり、「-*-モード-*-」とローカル変数セクションでの mode: を併用したときなど)、指定されたモード関数全てが (変数の優先順位と同じ順序で) 呼び出されます。ただし、エラーになったときはそこで中断されます。メジャーモードを複数呼び出してもあまり意味はありませんが、マイナーモードを設定するには便利です。

-*- mode: text; mode: auto-fill -*-
テキストモードでオートフィルを使用する。
インデント付きテキストモードでアウトラインモードを使用する。
Local variables:
mode: indented-text
mode: outline-minor
End:

このように使うときは必ずメジャーモードを先に指定します。マイナーモードをメジャーモードより先に指定しても意味がありません。

存在しないモードを指定したとき

-*--*- を使って存在しないモードを指定すると、

ローカル変数セクションで存在しないモードを指定したときは、どのバージョンでも 「File local-variables error: (void-function hogehoge-mode)」というエラーになって処理は中断されます。エラーを起こしたモード指定以降のモード指定、ローカル変数指定は処理されません。

-*--*- やローカル変数セクションが複数あるとき

-*--*- やローカル変数セクションはそれぞれ多くとも1つしか認識されません。 もし複数書かれていた場合は、どちらもファイル先頭に近いものだけが認識されます。ただし、ローカル変数セクションの場合はファイル末尾から最大3,000文字の範囲内 (ただし、この中に行頭が改ページ文字である行がある場合は、そのような行のうち最もファイル末尾に近い行からファイル末尾までの範囲内) で先頭に近いもの、となります。 例えば次の例ではいずれも2番目の指定は無視されます。

-*- Text -*-    -*- fill-column: 70 -*-
-*- mode: Text -*-   -*- fill-column: 70 -*-
-*- Text -*-     -*- HTML -*-

誤認識の防止

ファイル中にたまたま Local Variables: という文字列が含まれていると、 Emacs は後続の行をローカル変数リストとして解釈しようとして、解釈できないとエラー (「File local-variables error: (...)」など) を出してしまいます。 これを防ぐためには次のような方法があります。

また、 -*- でファイル先頭でファイルローカル変数を指定するときは、 設定する値に文字列「-*-」、 <空白、タブまたは ;> に続く「mode:」、文字「;」が現われていはいけません。 特に文字列を変数に設定する場合などはエスケープシーケンスなどの方法でこれらが現われないようにしてください。

速度の問題

メジャーモードは、ファイル先頭の -*- で指定する方がファイル末尾のローカル変数セクションで指定するよりファイルの読み込みが速くなります (大抵の場合、その違いは誤差の範囲と思いますが)。これは、ローカル変数セクションでモードを指定すると、いったんファイル名などからモードを決めてから指定されたモードに再設定することになり二度手間となってしまうからです。

関連するコマンド

M-x normal-mode
現在のバッファのファイル名・内容に対して、モードやローカル変数の指定を強制的に再実行します。 #!-*- の指定、またローカル変数セクションを書き換えたときに便利です。このコマンドを実行すると、変数 enable-local-variables の値に関わらずローカル変数が設定されます。ただし、 enable-local-variablesnil のときは -*- でのモード指定は無視されます (ローカル変数セクションでのモード指定には enable-local-variables の値に関わらず従います)。

関連する (カスタマイズ) 変数

enable-local-variables (デフォルト: t)
nil に設定するとファイルを開いたときに -*- やローカル変数セクションを認識しません。編集モードは他の方法 (ファイル名など) で決定されます。 nil でも t でもない値に設定すると -*- やローカル変数セクションに従って変数を設定したりモードを変更したりする前にユーザに確認をとります。
local-enable-local-variables (デフォルト: t)
この変数が nil であれば enable-local-variables の値に関わらずローカル変数セクションをすべて無視します (-*- の解釈には影響しません)。この変数はメジャーモードコマンドなどによって設定されることを意図しているようですが、そのファイルではローカル変数セクションを認識させないようにするという裏技的な使い方もできます (enable-local-variables はファイルローカル変数として設定することはできないようになっています)。
enable-local-eval (デフォルト: シンボル maybe)
ファイルを開いたときにそのファイル中の「eval: S式」の指定や、フック変数などセキュリティ上危険度の高い変数の指定に従うかどうか指定します。 t であれば黙って従います (たいへん危険です)。 nil であれば黙って無視します。それ以外の値であれば S式 を評価したり変数に設定する前にユーザに確認をとります。
ignored-local-variables (デフォルト: (enable-local-eval))
この変数 (リスト) に列挙されている変数は、ファイルローカル変数として設定することはできません (指定しても黙って無視されます)。セキュリティ上の理由などで絶対にファイルローカル変数として設定されるべきでない変数を指定します。
inhibit-first-line-modes-suffixesinhibit-first-line-modes-regexps (初期値: それぞれ nil("\\.tar\\'" "\\.tgz\\'"))
-*- によるモード指定を解釈するかどうかをファイル名から決定するパターンを指定します。どちらも正規表現のリストで指定し、次のルールで解釈するかどうかが決まります。
  1. 読み込んだファイルのファイル名を filename とします。
  2. filenameinhibit-first-line-modes-suffixes のいずれかの要素にマッチすれば、 filename からマッチした部分とそれ以降の部分を取り除き、新たに filename とします。
  3. これをマッチする要素がなくなるまで繰り返します。
  4. filenameinhibit-first-line-modes-regexps のいずれかの要素にマッチすれば、そのファイルでは -*- によるモード指定を行いません。
なお他のローカル変数の指定はこれとは関係なく行われます。また inhibit-first-line-modes-suffixes に指定する正規表現には文字列終端にマッチさせるために「\'」 (Emacs-Lisp で書くなら \\') を含めておくほうがいいでしょう。
safe-local-variable-values (Emacs 22 以降のみ、初期値: nil)
連想リストのような形式のリストで、ファイルローカル変数の変数名 (シンボル) と設定しようとする値のペア (cons セル) に等しい (equal) 要素がこのリスト中にある場合、その設定は安全とみなしてユーザに確認せずに設定します。 Emacs 22 以降は安全でないファイルローカル変数の設定に対してユーザに確認を求め、このときに ! をタイプすると以降同じ変数に同じ値を設定するときに確認を求めてこないようにする機能がありますが、それはこの変数に要素を追加することで実現されています。なおこの変数自体をファイルローカル変数として設定することはできません (Emacs 22 では ignored-local-variables にこの変数が追加されています)。

ファイルローカル変数として設定すると便利かも知れない変数

それぞれの変数について、詳しくはその変数のドキュメント (M-x describe-variable RET 変数名 RET) またはその変数を使う機能のドキュメントにあたってください。

c-file-style
C や C++、 Java などのプログラムのインデントスタイルを文字列で指定します。標準では "gnu" (GNUスタイル)、 "bsd" (BSDスタイル)、 "linux" (Linuxカーネルでよく使われる形式) などが使えます。
fill-column
オートフィル (自動折り返し) を行う桁位置を数字で指定します。
compile-command
M-x compile で実行されるシェルコマンドを文字列で指定します。この変数の名前は -command で終わっていますが、標準でプロパティ safe-local-variable が設定されていて文字列であれば自由に値を設定できます。
version-control
番号つきバックアップファイル (foo.c.~1~ など) の作り方を制御します。 t なら常に作り、 nil なら既に番号つきのバックアップファイルがある場合のみ作ります。 never に設定すると全く作りません (foo.c~ のような通常のバックアップファイルを作ります)。
kept-new-versionskept-old-versions
番号つきバックアップファイルを作るとき、際限なくバックアップファイルが増えるのを防ぐために Emacs は新しい方、または古い方から一定数のファイルを残して削除します。このとき残すファイルの数を指定するための変数です。