2011-02-28 49 views
7

我已經定義與以下內容爲.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模式掛機名單,我有這個鉤子函數:

(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文件,該消息由記錄210表示cr/virtualenv-namenil。然而,當我用C-h對這個名字時,我得到了「saas」。

顯然這裏有一個加載順序問題;有沒有辦法讓我的模式鉤子語句響應目錄本地變量?

回答

12

發生這種情況是因爲normal-mode按此順序調用(set-auto-mode)(hack-local-variables)

但是hack-local-variables-hook是局部變量後運行已被處理,這使得一些解決方案:

  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. 第二種選擇是利用可選的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的評論提示了第三種方法。它不像其他兩個那麼幹淨,但是無論如何都很有趣。我不喜歡造成(hack-local-variables)被調用兩次的想法,但我發現,如果你設置的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: fooLocal Variables:評論似乎是一個問題,因爲它是由(hack-local-variables)處理,所以如果設置模式,我認爲這會導致遞歸。

    在實踐中,我能夠通過使用一個簡單的函數作爲'模式'來觸發問題,它只是試圖運行它的鉤子;然而,使用「正確」模式進行測試並不會出現問題,所以它在現實中可能是安全的。我沒有深入研究(因爲其他兩種解決方案比這更清晰),但我猜想延遲模式鉤子機制可能解釋了它?

+0

也許你可以從你的鉤子調用(hack-local-variables)? – Lindydancer 2011-03-01 07:51:33

+2

我希望我能兩次對此表示讚賞。 – 2011-03-01 18:09:29