バッファローカルとは
- Emacs Lispのすべての変数は「バッファローカル」というフラグを持っている
- このフラグはバッファごとに設定されている。たとえば、「変数
x
をバッファ*scratch*
においてバッファローカルにする」といった操作ができる - 変数は、何も設定しなければ、どのバッファにおいても、バッファローカルではない
バッファローカル変数の性質
- 変数には「バッファごとの値」と「デフォルト値」が設定できる
- (現在のバッファにおいて)バッファローカルな変数の読み出し
variable-name
・セット(setq variable-name 1)
は、「バッファごとの値」に対して行われる - (現在のバッファにおいて)バッファローカルでない変数の読み出し・セットは、「デフォルト値」に対して行われる
local-variable-p
変数x
が(現在のバッファにおいて)バッファローカルかどうかは、
(local-variable-p 'x)
で確認できる。
make-local-variable
、kill-local-variable
変数x
を現在のバッファにおいてバッファローカルにするには、
(make-local-variable 'x)
を評価する。
変数x
を現在のバッファにおいてバッファローカルでなくするには、
(kill-local-variable 'x)
を評価する。
default-value
、setq-default
(default-value 'x)
を評価すると、x
がバッファローカルであるかどうかに関わらず、x
のデフォルト値が読み出される。
(setq-default x 1)
を評価すると、x
がバッファローカルであるかどうかに関わらず、x
のデフォルト値が1にセットされる。
例
この例は、新たに作成したバッファ上で評価することを推奨する。また、評価にはlispxmp.elを用いることを推奨する。
(setq x 'default-value-1)
(make-local-variable 'x)
(setq x 'buffer-local-value)
(local-variable-p 'x) ; => t
x ; => buffer-local-value
(with-temp-buffer ; 一時バッファ上で評価
(local-variable-p 'x) ; => nil
x ; => default-value-1
(setq x 'default-value-2)
x ; => default-value-2
)
x ; => buffer-local-value
(default-value 'x) ; => default-value-2
(setq-default x 'default-value-3)
x ; => buffer-local-value
(default-value 'x) ; => default-value-3
(kill-local-variable 'x)
(local-variable-p 'x) ; => nil
x ; => default-value-3
バッファローカルとlet
Emacs Lispでは、let
フォームなどによって、ローカルな変数を作ることができる。「バッファローカル」と「ローカル」は全く異なる概念である。
例1
この例は、新たに作成したバッファ上で評価することを推奨する。
現在のバッファ名をCurrent Buffer
とする。
(setq x 'default-value-1)
(make-local-variable 'x)
(setq x 'buffer-local-value)
(local-variable-p 'x) ; => t
x ; => buffer-local-value
(let ((x 'buffer-local-value-in-let))
(local-variable-p 'x) ; => t
x ; => buffer-local-value-in-let
(with-temp-buffer
(local-variable-p 'x) ; => nil
x ; => default-value-1
(setq x 'default-value-2)
x ; => default-value-2
)
x ; => buffer-local-value-in-let
(default-value 'x) ; => default-value-2
)
x ; => buffer-local-value
with-temp-buffer
内でのx
の読み書きは、デフォルト値に対して行われる。したがって、'buffer-local-value-in-let
を読み出すことはできない。また、with-temp-buffer
内でx
の値をセットしても、x
はCurrent Buffer
においてバッファローカルであるため、値は変化しない。ただし、デフォルト値は変更されているので、(default-value 'x)
によってその値を読み出すことができる。
例2
この例は、新たに作成したバッファ上で評価することを推奨する。
現在のバッファ名をCurrent Buffer
とする。
(setq x 'default-value-1)
;; バッファ "Another Buffer" を作成し、 "Another Buffer" 上で評価
(with-current-buffer (get-buffer-create "Another Buffer")
(make-local-variable 'x)
(setq x 'buffer-local-value-1))
(local-variable-p 'x) ; => nil
x ; => default-value-1
(let ((x 'default-value-in-let))
(local-variable-p 'x) ; => nil
x ; => default-value-in-let
;; バッファ "Another Buffer" 上で評価
(with-current-buffer "Another Buffer"
(local-variable-p 'x) ; => t
x ; => buffer-local-value-1
(setq x 'buffer-local-value-2)
x ; => buffer-local-value-2
(default-value 'x) ; => default-value-in-let
(setq-default x 'default-value-2))
x ; => default-value-2
)
x ; => default-value-1
Another Buffer
においてx
はバッファローカルであるため、x
の読み書きは、バッファごとの値に対して行われる。Current Buffer
でセットした値は、(default-value 'x)
によって読み出すことができる。また、setq-default
によって、Current Buffer
で読み出される値を設定することができる。
make-variable-buffer-local
(make-variable-buffer-local 'x)
を評価すると、(setq x 1)
などとしてx
に値をセットしたとき、x
が自動的に(現在のバッファにおいて)バッファローカルになる。この、自動的にバッファローカルにする効果は、すべてのバッファにおいて有効になる。
例1
この例は、Emacsを再起動してから評価することを推奨する。
(setq x1 'default-value)
(make-variable-buffer-local 'x1)
(local-variable-p 'x1) ; => nil
x1 ; => default-value
(setq x1 'buffer-local-value)
(local-variable-p 'x1) ; => t
x1 ; => buffer-local-value
(make-variable-buffer-local 'x1)
を評価した後に、x1
の値をセットすると、x1
が自動的にバッファローカルになっている。
例2
この例は、Emacsを再起動してから評価することを推奨する。
(setq x2 'default-value)
(make-variable-buffer-local 'x2)
(with-temp-buffer
(local-variable-p 'x2) ; => nil
x2 ; => default-value
(setq x2 'buffer-local-value)
(local-variable-p 'x2) ; => t
x2 ; => buffer-local-value
)
(local-variable-p 'x2) ; => nil
x2 ; => default-value
(make-variable-buffer-local 'x2)
を評価したバッファとは、異なるバッファの上でx2
に値をセットしても、x2
は(移ったバッファにおいて)バッファローカルになる。
let
によるシャドウイング
(make-variable-buffer-local 'x)
を評価したのち、let
などでx
をシャドウした上で値をセットしても、x
はバッファローカルにならない。
例3
この例は、Emacsを再起動してから評価することを推奨する。
(setq x3 'default-value)
(make-variable-buffer-local 'x3)
(let ((x3 'default-value-in-let-1))
(local-variable-p 'x3) ; => nil
x3 ; => default-value-in-let-1
(setq x3 'default-value-in-let-2)
(local-variable-p 'x3) ; => nil
x3 ; => default-value-in-let-2
)
(make-variable-buffer-local 'x3)
を評価したあとで、let
によってx3
に値をセットしているが、x3
はバッファローカルにならない。また、シャドウした後のx3
に値をセットしても、x3
はバッファローカルにならない。
例4
この例は、Emacsを再起動してから評価することを推奨する。
(let ((x4 'default-value-in-let))
(make-variable-buffer-local 'x4)
(setq x4 'buffer-local-value))
(local-variable-p 'x4) ; => t
x4 ; => buffer-local-value
ローカルな変数にmake-variable-buffer-local
を適用しても、変数をシャドウせずにセットすれば、バッファローカルになる。ただし、これは邪悪なコードらしく、評価すると
Making x4 buffer-local while let-bound!
という警告がエコーエリアに表示される。
注意すべきは、
(make-variable-buffer-local 'x)
を評価した時点では、x
はバッファローカルにならないことである。make-variable-buffer-local(変数をバッファローカルにする)という名前は、この点で誤解しやすい。そのため、筆者はinit.elで
(defalias 'make-variable-autolocal 'make-variable-buffer-local)
と設定している。