11

次の内容で.dir-locals.elファイルを定義しました。

((python-mode . ((cr/virtualenv-name . "saas"))))

私の.emacsには、この値を取得してvirtualenvパスを提供する次の関数があります。

(defun cr/virtualenv ()
  (cond (cr/virtualenv-name (format "%s/%s" virtualenv-base cr/virtualenv-name))
        ((getenv "EMACS_VIRTUAL_ENV") (getenv "EMACS_VIRTUAL_ENV"))
        (t "~/.emacs.d/python")))

最後に、私のpython-mode-hookリストには、次のフック関数があります。

(add-hook 'python-mode-hook 'cr/python-mode-shell-setup)

(defun cr/python-mode-shell-setup ()
  (message "virtualenv-name is %s" cr/virtualenv-name)
  (let ((python-base (cr/virtualenv)))
    (cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
           (setq python-python-command (concat python-base "/bin/ipython"))
           (setq py-python-command (concat python-base "/bin/ipython"))
           (setq py-python-command-args '( "-colors" "NoColor")))
          (t
           (setq python-python-command (concat python-base "/bin/python"))
           (setq py-python-command (concat python-base "/bin/python"))
           (setq py-python-command-args nil)))))

新しいPythonファイルを開くと、ログに記録されたメッセージはそれが。cr/python-mode-shell-setupであることを示しています。ただし、名前を変更すると、代わりに「saas」が表示されます。cr/virtualenv-namenil

明らかに、ここにはロード順序の問題があります。モードフックステートメントをディレクトリローカル変数に応答させる方法はありますか?

4

1 に答える 1

18

これは、normal-mode呼び出し(set-auto-mode)(hack-local-variables)その順序で発生します。

ただしhack-local-variables-hook、ローカル変数が処理された後に実行されるため、いくつかのソリューションが可能になります。

  1. 1つ目は、Emacsにメジャーモードごとに新しい「ローカル変数フック」を実行させることです。

    (add-hook 'hack-local-variables-hook 'run-local-vars-mode-hook)
    (defun run-local-vars-mode-hook ()
      "Run a hook for the major-mode after the local variables have been processed."
      (run-hooks (intern (concat (symbol-name major-mode) "-local-vars-hook"))))
    
    (add-hook 'python-mode-local-vars-hook 'cr/python-mode-shell-setup)
    

    (元の関数は、そのアプローチで変更せずに使用できます。)

  2. 2番目のオプションは、指定された関数をバッファローカルにするオプションのLOCAL引数を利用することです。add-hookこのアプローチでは、フックを次のように書くことができます。

    (add-hook 'python-mode-hook 'cr/python-mode-shell-setup)
    
    (defun cr/python-mode-shell-setup ()
      (add-hook 'hack-local-variables-hook
                (lambda () (message "virtualenv-name is %s" cr/virtualenv-name)
                  (let ((python-base (cr/virtualenv)))
                    (cond ((and (fboundp 'ipython-shell-hook) (file-executable-p (concat python-base "/bin/ipython")))
                           (setq python-python-command (concat python-base "/bin/ipython"))
                           (setq py-python-command (concat python-base "/bin/ipython"))
                           (setq py-python-command-args '( "-colors" "NoColor")))
                          (t
                           (setq python-python-command (concat python-base "/bin/python"))
                           (setq py-python-command (concat python-base "/bin/python"))
                           (setq py-python-command-args nil)))))
                nil t)) ; buffer-local hack-local-variables-hook
    

    つまり、最初に実行され、現在のバッファに対してのみpython-mode-hook無名関数を登録します。hack-local-variables-hookそして、その関数は、ローカル変数が処理された後に呼び出されます。

  3. Lindydancerのコメントは、3番目のアプローチを促します。他の2つほどきれいではありませんが、それでも興味深いことがわかりました。(hack-local-variables)2回呼び出されるというアイデアは好きではありませんでしたが、local-enable-local-variablesバッファをローカルに設定すると(hack-local-variables)、何も実行できなくなるため、次のように実行できます。

    (defun cr/python-mode-shell-setup ()
      (report-errors "File local-variables error: %s"
        (hack-local-variables)))
      (set (make-local-variable 'local-enable-local-variables) nil)
      (let ((python-base (cr/virtualenv)))
        ...))
    

    明らかに、これは通常の実行シーケンスを少し変更するため、副作用が発生する可能性があります。同じメジャーモードがファイル内のローカル変数コメントによって設定されている場合、これにより無限再帰が発生する可能性があるのではないかと心配していましたが、実際には問題にはならないようです。

    ローカル変数ヘッダーのコメント(例-*- mode: foo -*-)は、によって処理される(set-auto-mode)ため、問題ありません。でもmode: foo Local Variables:コメントは。で処理されるので問題になるよう(hack-local-variables)ですので、そのように設定すると再帰が発生すると思いました。

    実際には、フックを実行しようとするだけの「モード」として単純な関数を使用することで、問題を引き起こすことができました。ただし、「適切な」モードでテストしても問題は発生しなかったため、実際にはおそらく安全です。私はこれをさらに調べませんでした(他の2つのソリューションはこれよりもはるかにクリーンであるため)が、遅延モードフックメカニズムがおそらくそれを説明していると思いますか?

于 2011-02-28T22:39:48.643 に答える