4

I am trying to enable electric-indent-mode for all modes except fundamental-mode, where it is just annoying. In my init file, I have the following:

(electric-indent-mode +1)
(add-hook 'after-change-major-mode-hook
          (lambda ()  (if (eq major-mode 'fundamental-mode)
                          (electric-indent-mode -1))))

This, however always disables electric-indent-mode because the value of major-mode is always 'fundamental-mode when the hook is invoked. Seems that the value of that variable is changed AFTER the hook is called? Makes no sense to me.

Anyone have a suggestion on how to achieve this? There is no fundamental-mode-hook unfortunately.

Drew
  • 75,699
  • 9
  • 109
  • 225
tinskip
  • 41
  • 1

2 Answers2

2

electric-indent-mode is a global mode, so if your function ever gets invoked, it will disable it everywhere.

You then also have the problem that if the global mode is enabled, new buffers which are never given a new major mode at all will have that behaviour, because the hook you're using never runs.

electric-indent-local-mode is the equivalent buffer-local minor mode, so I think you should disable the global mode, and instead enable the local mode everywhere you want it, which you can do using much the same technique you've shown in your question.

(electric-indent-mode 0)

(add-hook 'after-change-major-mode-hook #'my-electric-indent-local-mode-maybe)

(defun my-electric-indent-local-mode-maybe ()
  "Enable `electric-indent-local-mode' if appropriate."
  (unless (eq major-mode 'fundamental-mode)
    (electric-indent-local-mode 1)))

I'll add that the local mode turns out to be a hack of the global mode, such that as far as describe-mode is concerned it's the global mode which is active or inactive on a per-buffer basis. This is pretty confusing when testing :)


You could alternatively do this:

(defun my-electric-indent-rules (_char)
  "Used with `electric-indent-functions'."
  (when (eq major-mode 'fundamental-mode)
    (setq electric-indent-inhibit t) ;; Prevent future attempts.
    'no-indent)) ;; Deny the current attempt.

(add-hook 'electric-indent-functions #'my-electric-indent-rules)

I don't recommend it for your case though, because it's having to process things every time it might need to indent something, as opposed to configuring the behaviour once per buffer.

(Thanks to Andrew Swann for pointing out that we could make this latter approach more efficient in the fundamental-mode case by also setting electric-indent-inhibit.)

phils
  • 48,657
  • 3
  • 76
  • 115
1

Instead of toggling the electric-indent-mode directly you can set the variable electric-indent-inhibit:

(electric-indent-mode t)
(add-hook 'after-change-major-mode-hook 
          (lambda ()  (if (eq major-mode 'fundamental-mode)
                          (setq electric-indent-inhibit t))))

This variable is buffer local.

Andrew Swann
  • 3,436
  • 2
  • 15
  • 43
  • `after-change-major-mode-hook` isn't necessarily called in the buffers they are interested in. – phils Dec 03 '21 at 10:40
  • @phils I see. I worked in the cases I tested, but as you say the buffers may be created in different ways. Would it perhaps be best to change your code to set this variable, which then inhibit further attempts to electric indent in the buffer, and so be run only once. – Andrew Swann Dec 04 '21 at 12:59
  • That's a good idea; I'll add that. – phils Dec 04 '21 at 20:55