5

Seems like most major modes clear all local variables before initializing. It also seems like many major modes read variables while initializing to customize their behavior.

If I want to set a file or directory local variable to determine major mode behavior (for example, overwriting web mode's web-mode-engines-alist in .dir-locals.el), how can it be done so that the local variables are written before the major mode actually initializes, but are not cleared?

One way to do it would be to bind/rebind global variables using ((nil . ((eval . ((lambda () (setq name val))))))) in .dir-locals.el. The nil key seems to run before any major-modes are entered. Still, it doesn't seem ideal to overwrite global config. For example, maybe I want to work on multiple projects in the same emacs instance.

3
  • 1
    Some related reading: stackoverflow.com/q/19280851, stackoverflow.com/q/5147060
    – phils
    Commented Aug 15, 2016 at 1:15
  • 1
    I did see those. Very thorough answers, thank you! It seems though that both the problems of reloading dir-local variables and of accessing them in major mode hooks are slightly different than mine. In all solutions the local variables are made available strictly after the major mode has initialized (ie, run the body given in define-derived-mode)
    – sfridman
    Commented Aug 16, 2016 at 9:49
  • 1
    I'm new to Emacs btw. I'm wondering now though, if the correct answer is that if major mode authors want to allow users to customize this phase, they need to write the code such that the execution of the major mode body is somehow deferred until after the local variables have been loaded?
    – sfridman
    Commented Aug 16, 2016 at 9:51

2 Answers 2

3

If you want to set a buffer-local value for a given mode, do so after the mode has been established. You do that by putting the value-assignment on the mode hook.

For example, if you want to set local variable foo to 42 in lisp-mode then do something like this:

(add-hook 'lisp-mode (lambda () (setq-local fill-paragraph-function  'my-fill-para)))

Or better yet, since it facilitates programmatic access, including use of remove-hook, use a named function:

(defun my-set-lisp-fill () (setq-local fill-paragraph-function  'my-fill-para))

(add-hook 'lisp-mode 'my-set-lisp-fill)
3
  • @phils: Right you are; updated.
    – Drew
    Commented Aug 15, 2016 at 1:15
  • 1
    Thanks for the answer! Unfortunately it seems like, since buffer locals are also killed when switching major modes, this solution has the same problem as file and dir local variables in that they cannot be accessed in the initialization stage of a major mode
    – sfridman
    Commented Aug 16, 2016 at 9:26
  • 1
    I've edited the initial question to be more specific
    – sfridman
    Commented Aug 16, 2016 at 9:42
1

Try something like this: (make the variable permanent-local and call web-mode after setting the variables)

((web-mode . ((eval . (progn
                        (setq-local web-mode-engines-alist '(("django" . "\\.html\\'")))
                        (put 'web-mode-engines-alist 'permanent-local t)
                        (web-mode))))))
2
  • 1. You're setting the global value of web-mode-engines-alist. 2. If you made it buffer-local first, calling web-mode would delete the buffer-local value before anything else happened, unless you also give it the permanent-local symbol property.
    – phils
    Commented Sep 28, 2016 at 19:29
  • @phils Updated! Thanks for your comments!
    – xuhdev
    Commented Sep 28, 2016 at 23:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.