automatically disable a global minor mode for a specific major mode
Asked Answered
L

2

31

I have centered-cursor-mode activated globaly, like this:

(require 'centered-cursor-mode)
(global-centered-cursor-mode 1)

It works fine, but there are some major modes where I would like to disable it automatically. For example slime-repl and shell.

There is another question dealing with the same problem, but another minor mode. Unfortunately the answers only offer workarounds for this specific minor mode (global-smart-tab-mode), that doesn't work with centered-cursor-mode.

I tried this hook, but it has no effect. The variable doesn't change.

(eval-after-load "slime"
  (progn
    (add-hook 'slime-repl-mode-hook (lambda ()
                                      (set (make-local-variable 'centered-cursor-mode) nil)))
    (slime-setup '(slime-repl slime-autodoc))))
Lamed answered 26/7, 2011 at 22:44 Comment(0)
L
14

I made a new global minor mode, that doesn't get activated in certain modes. The lambda is the function that gets called in every new buffer to activate the minor mode. That is the right place to make exceptions.

(require 'centered-cursor-mode)

(define-global-minor-mode my-global-centered-cursor-mode centered-cursor-mode
  (lambda ()
    (when (not (memq major-mode
                     (list 'slime-repl-mode 'shell-mode)))
      (centered-cursor-mode))))

(my-global-centered-cursor-mode 1)

It should work for every other global minor mode. Just copy the definition global-xxx-mode and make the right exceptions.

Lamed answered 27/7, 2011 at 18:37 Comment(1)
It does not seem to work when you switch from one major mode to anotherBreger
F
21

Global minor modes created with the define-globalized-minor-mode1 macro are a bit tricky. The reason your code doesn't appear to do anything is that globalized modes utilise after-change-major-mode-hook to activate the buffer-local minor mode that they control; and that hook runs immediately after the major mode's own hooks4.

Individual modes may implement custom ways of specifying some kind of black list or other method of preventing the mode from being enabled in certain circumstances, so in general it would be worth looking at the relevant M-x customize-group options for the package to see if such facilities exist. However, a nice clean general way of achieving this for ANY globalized minor mode is eluding me for the moment.

It's a shame that the MODE-enable-in-buffers function defined by that macro doesn't do the same (with-current-buffer buf (if ,global-mode ...)) check which is performed by the global mode function. If it did, you could simply use slime-repl-mode-hook to make the global mode variable buffer-local and nil.

A quick hack is to check2 what the turn-on argument is for the globalized minor mode definition (in this instance it's centered-cursor-mode itself3), and write some around advice to stop that from being evaluated for the modes in question.

(defadvice centered-cursor-mode (around my-centered-cursor-mode-turn-on-maybe)
  (unless (memq major-mode
                (list 'slime-repl-mode 'shell-mode))
    ad-do-it))
(ad-activate 'centered-cursor-mode)

Something we can do (with an easy re-usable pattern) is immediately disable the buffer-local minor mode again after it has been enabled. An after-change-major-mode-hook function added with the APPEND argument to add-hook will reliably run after the globalized minor mode has acted, and so we can do things like:

(add-hook 'term-mode-hook 'my-inhibit-global-linum-mode)

(defun my-inhibit-global-linum-mode ()
  "Counter-act `global-linum-mode'."
  (add-hook 'after-change-major-mode-hook
            (lambda () (linum-mode 0))
            :append :local))

1 or its alias define-global-minor-mode which I feel should be avoided, due to the potential for confusion with "global" minor modes created with define-minor-mode. "Globalized" minor modes, while still involving a global minor mode, work very differently in practice, so it is better to refer to them as "globalized" rather than "global".

2 C-hf define-globalized-minor-mode RET shows that turn-on is the third argument, and we check that in the mode definition with M-x find-function RET global-centered-cursor-mode RET.

3 with this approach, that fact is going to prevent you from ever enabling this minor mode with slime-repl-mode or shell-mode buffers, whereas a globalized minor mode with a separate turn-on function could still be invoked in its non-global form if you so desired.

4 https://mcmap.net/q/371875/-how-to-keep-dir-local-variables-when-switching-major-modes

Furman answered 27/7, 2011 at 5:56 Comment(0)
L
14

I made a new global minor mode, that doesn't get activated in certain modes. The lambda is the function that gets called in every new buffer to activate the minor mode. That is the right place to make exceptions.

(require 'centered-cursor-mode)

(define-global-minor-mode my-global-centered-cursor-mode centered-cursor-mode
  (lambda ()
    (when (not (memq major-mode
                     (list 'slime-repl-mode 'shell-mode)))
      (centered-cursor-mode))))

(my-global-centered-cursor-mode 1)

It should work for every other global minor mode. Just copy the definition global-xxx-mode and make the right exceptions.

Lamed answered 27/7, 2011 at 18:37 Comment(1)
It does not seem to work when you switch from one major mode to anotherBreger

© 2022 - 2024 — McMap. All rights reserved.