Search code examples
emacsindentationlocals

Setting per-project indent variables in emacs


My emacs is set to use 2 spaces for indentation globally:

(setq-default indent-tabs-mode nil)
(setq tab-width 2)
(setq js-indent-level 2)
(setq css-indent-offset 2)

But I would like to contribute to a web project (html, css and js mostly) which uses 4 spaces for indentation. So I am trying to set up a .dir-locals.el file in the project directory. The file has the following settings (added with the add-dir-local-variable command):

((nil . ((tab-width . 4)
         (js-indent-level . 4)))

;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.

((js-mode
  (tab-width . 4)))
;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.

((js-mode
  (js-indent-level . 4)))
;;; Directory Local Variables
;;; See Info node `(emacs) Directory Variables' for more information.

((html-mode
  (tab-width . 4)))

But these settings don’t take effect. When I open a .js or .html file in a project subdirectory, pressing tab makes a 2-space indent.

What am I doing wrong?


Solution

  • For starters your .dir-locals.el data is unbalanced (M-x check-parens).

    I'm not sure how that would have happened, but if you can get Emacs to do it, then you should M-x report-emacs-bug. I'm assuming it was from manual editing.

    I'm not sure whether the multiple js-mode items is a valid thing to do. Maybe that's fine, but it seems unusual. (Possibly Emacs is confused by the unbalanced parens, though.)

    Here's your file re-written to use the more common (or at least the documented) dotted-pair notation:

    ((nil . ((tab-width . 4)
             (js-indent-level . 4)))
    
     (js-mode . ((tab-width . 4)
                 (js-indent-level . 4)))
    
     (html-mode . ((tab-width . 4))))
    

    Please note that (for this specific data) you don't need the js-mode and html-mode entries, because they are duplicating the default values for the nil mode entry.

    Edit: Experimentally, add-dir-local-variable seems to behave as expected once the file is in a valid state.

    It prefers creating the more compact list notation where possible -- which is fine; they're equivalent -- but it's useful to be aware of the formatting differences.
    See C-hig (elisp) Dotted Pair Notation RET