1

Why does (set-auto-mode) remove the local variable binding and how I can keep the local binding around?

(defvar-local test-var nil)
(setq test-var t)
(message "%s" test-var) ;; t
(set-auto-mode)
(message "%s" test-var) ;; nil
7
  • There are several dups for this question, including emacs.stackexchange.com/questions/22245/… and emacs.stackexchange.com/questions/7391/…. E.g., search for permanent-local.
    – Drew
    Commented Jan 8, 2023 at 17:06
  • Thank you @Drew . Yes, this question is a duplicate of those. The solution was permanent-local, and since emacs.stackexchange.com/questions/7391/… most clearly presents that solution, it might make sense to mark this question as a duplicate of that one. Commented Jan 11, 2023 at 1:06
  • I think you can delete your own question. Otherwise, I think it can't be closed till 5 or so people vote to close it.
    – Drew
    Commented Jan 11, 2023 at 1:29
  • @Drew hmm, I tried deleting it and I got "You cannot delete this question as others have invested time and effort into answering it." Commented Jan 20, 2023 at 23:03
  • Sigh. Sometimes rules meant to serve the community end up imposing the wrong kind of order...
    – Drew
    Commented Jan 21, 2023 at 3:24

1 Answer 1

1

The first thing that any major mode does is call kill-all-local-variables.

 This function eliminates all the buffer-local variable bindings of
 the current buffer except for variables marked as permanent and
 local hook functions that have a non-‘nil’ ‘permanent-local-hook’
 property (*note Setting Hooks::).  As a result, the buffer will see
 the default values of most variables.

 This function also resets certain other information pertaining to
 the buffer: it sets the local keymap to ‘nil’, the syntax table to
 the value of ‘(standard-syntax-table)’, the case table to
 ‘(standard-case-table)’, and the abbrev table to the value of
 ‘fundamental-mode-abbrev-table’.

 The very first thing this function does is run the normal hook
 ‘change-major-mode-hook’ (see below).

 Every major mode command begins by calling this function, which has
 the effect of switching to Fundamental mode and erasing most of the
 effects of the previous major mode.  To ensure that this does its
 job, the variables that major modes set should not be marked
 permanent.

 ‘kill-all-local-variables’ returns ‘nil’.

how I can keep the local binding around?

A buffer-local variable is “permanent” if the variable name (a
symbol) has a ‘permanent-local’ property that is non-‘nil’.  Such
variables are unaffected by ‘kill-all-local-variables’, and their local
bindings are therefore not cleared by changing major modes.  Permanent
locals are appropriate for data pertaining to where the file came from
or how to save it, rather than with how to edit the contents.

E.g. To define a variable which should be permanent-local:

(defvar VARNAME ...)
(put 'VARNAME 'permanent-local t)

Setting this property for variables which were not intended to be treated that way should be done with due care and consideration for whatever ramifications that will have.

2
  • 1
    You may find the details at stackoverflow.com/a/19295380/324105 wrt what happens when major modes are called to be helpful reading as well.
    – phils
    Commented Jan 8, 2023 at 5:04
  • Your comment on SO was helpful in understanding that (hack-local-variables) runs twice when manually calling (set-auto-mode) manually. Thank you!! Commented Jan 8, 2023 at 10:45

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