Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@tadsan

make-variable-buffer-localとmake-local-variableの関係

More than 1 year has passed since last update.

なんか同じような名前の機能だけど別の機能。

三行で

  • Emacsでの「ローカル」とは、変数にバッファごとに独立した値を保持できることです。
  • make-local-variableは、本来ローカルでない変数を現在のバッファで一時的にローカルにします。
  • make-variable-buffer-local は、その変数が常にローカルとしてセットされるようにします。

この両者の関係は、Emacs 24.3で追加された subr.el を見ればわかりやすいです。
emacs-26.0.91より抜萃。

subr.el
(defmacro setq-local (var val)
  "Set variable VAR to value VAL in current buffer."
  ;; Can't use backquote here, it's too early in the bootstrap.
  (declare (debug (symbolp form)))
  (list 'set (list 'make-local-variable (list 'quote var)) val))

(defmacro defvar-local (var val &optional docstring)
  "Define VAR as a buffer-local variable with default value VAL.
Like `defvar' but additionally marks the variable as being automatically
buffer-local wherever it is set."
  (declare (debug defvar) (doc-string 3))
  ;; Can't use backquote here, it's too early in the bootstrap.
  (list 'progn (list 'defvar var val docstring)
        (list 'make-variable-buffer-local (list 'quote var))))

Emacs Lispでのニュアンスとしては、defvar-は変数定義、setq-は変数のセット(代入・束縛)ですね。

そもそもEmacs 24.3以降では覚えやすいdefvar-localsetq-localを使っておけばいいので、わざわざ紛しい方を覚えておく必要は特にありません。

つまり、以下の記述はEmacs 24.3未満との互換性を考慮する必要がある場合の専用だと思ってください。

解説

make-local-variable

本来は全体で共有される変数だが、特別にバッファローカルにしたい場合に利用します。

init.el
(defun my/enh-ruby-mode-hook ()
  "Enhanced Ruby Modeでだけ ac-ignore-case を t にしたいお"
  (set (make-local-variable 'ac-ignore-case) t))

ac-ignore-caseは本来カスタマイズ変数なので、その影響は全体に影響します。そのため、特定のモードでは特別にローカルとして設定する必要があるのです。

しかし、 (set (make-local-variable 'ac-ignore-case) t) ってビジュアルがもう野暮ったい。

init.el
(defun my/enh-ruby-mode-hook ()
  "Enhanced Ruby Modeでだけ ac-ignore-case を t にしたいお"
  (setq-local ac-ignore-case t))

setq-localで超すっきりしましたね。

make-variable-buffer-local

最初からバッファローカルとして設定させたい変数に利用します。

copy-file-on-save-dest-dir.dir-locals.el で設定させたいのです。

copy-file-on-save.el
;;;###autoload
(progn
  (defvar copy-file-on-save-dest-dir nil
    "Path to deployment directory or convert (mapping) function.")
  (make-variable-buffer-local 'copy-file-on-save-dest-dir)
  (put 'copy-file-on-save-dest-dir 'safe-local-variable #'stringp))

copy-file-on-save-dest-dirって何回も書かなきゃいけないのはだるいですね。

copy-file-on-save.el
;;;###autoload
(progn
  (defvar-local copy-file-on-save-dest-dir nil
    "Path to deployment directory or convert (mapping) function.")
  (put 'copy-file-on-save-dest-dir 'safe-local-variable #'stringp))

一行減りました! うれしい! そんなことより、僕みたいな記憶力の悪い人間ミスをしにくいコードになったのは嬉しいことです。

まとめ

みんなは早うEmacs 24.3以下を切ってdefvar-localsetq-localを使ってな。

6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
tadsan
僕に警備する自宅をください。Emacs初心者。Rubyist。 全ての投稿された記事は別段の表記がない限りはCC 3.0 BY-SA https://creativecommons.org/licenses/by-sa/3.0/deed.ja で二次利用できます。 記事中に含まれる全てのコードスニペットの著作権は抛棄するので、煮るなり焼くなりお好きにどうぞ。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?