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
  • There are several dups for this question, including https://emacs.stackexchange.com/questions/22245/how-to-stop-auto-backup-in-some-directory-in-emacs/22252 and https://emacs.stackexchange.com/questions/7391/how-to-get-an-value-from-a-buffer-local-variable/7406. E.g., search for `permanent-local`. – Drew Jan 08 '23 at 17:06
  • Thank you @Drew . Yes, this question is a duplicate of those. The solution was `permanent-local`, and since https://emacs.stackexchange.com/questions/7391/how-to-get-an-value-from-a-buffer-local-variable/7406 most clearly presents that solution, it might make sense to mark this question as a duplicate of that one. – breatheoutbreathein Jan 11 '23 at 01: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 Jan 11 '23 at 01: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." – breatheoutbreathein Jan 20 '23 at 23:03
  • Sigh. Sometimes rules meant to serve the community end up imposing the wrong kind of order... – Drew Jan 21 '23 at 03:24
  • Poetic... ;) Let me know if I can do something about it! – breatheoutbreathein Jan 22 '23 at 09:12
  • Sorry, I don't know what can be done about it. It's been raised at Meta StackExchange, but it seems it's gone nowhere. – Drew Jan 22 '23 at 22:24

1 Answers1

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.

phils
  • 48,657
  • 3
  • 76
  • 115
  • 1
    You may find the details at https://stackoverflow.com/a/19295380/324105 wrt what happens when major modes are called to be helpful reading as well. – phils Jan 08 '23 at 05:04
  • Your comment on SO was helpful in understanding that `(hack-local-variables)` runs twice when manually calling `(set-auto-mode)` manually. Thank you!! – breatheoutbreathein Jan 08 '23 at 10:45