4

This has been driving me crazy, I can't get this to work. I want to link the on-off status of a handful of minor modes, in particular evil-mode, evil-quickscope-mode, hl-paren-mode, and a few others. I don't necessarily want evil globally, but once I turn on evil-mode I want the other modes to also turn on (and correspondingly turn off once evil turns off).

Is there a way to accomplish this cleanly? The closest I've come involved using mode-hooks, but somehow the modes always got out of sync (evil on, others off. others on, evil off. etc.)

edit: Posting the relevant mode-hooks section of my init.el:

;; Evil Mode Setup
(require 'evil-leader)
(evil-leader/set-leader ",")
(evil-leader/set-key "q" 'kill-buffer-and-window)
(evil-leader/set-key "b" 'ibuffer)

(defun after-all-loads () (require 'evil))
(add-hook 'after-init-hook 'after-all-loads)
(define-key global-map "\C-xv" 'evil-mode)
(add-hook 'evil-mode-hook 'hl-paren-mode)
(add-hook 'evil-mode-hook 'evil-visual-mark-mode)
(add-hook 'evil-mode-hook 'evil-quickscope-mode)
(add-hook 'evil-mode-hook 'evil-leader-mode)
Kyle Rush
  • 75
  • 5
  • It sounds like you are on the right track with using mode-hooks. Can you post the relevant portions of your init file? – Scott Weldon Apr 15 '16 at 17:46
  • E.g., evil-quickscope-mode is defined via define-minor-mode. The doc for define-minor-mode says: "When called from Lisp, the mode command toggles the mode if the argument is `toggle', disables the mode if the argument is a non-positive integer, and enables the mode otherwise (including if the argument is omitted or nil or a positive integer)." – Tobias Apr 15 '16 at 18:00
  • I've edited the relevant portion of my init.el into my question. The issue I have specifically is that it works fine the first time I invoke evil, then I switch to a new buffer and evil stays on but the other modes all turn off. Then I have to toggle evil back off and on again to get the other modes back. – Kyle Rush Apr 15 '16 at 18:44

2 Answers2

2

Just define your own minor mode that does what you want. It can turn on/off any number of modes when you turn it on/off. It can set variables, set up key bindings, and do pretty much anything you want.

IOW, you make a super-minor-mode that encapsulates whatever you want, including a bunch of other minor modes.

Turn on your new minor mode whenever you want - in your init file or on some hook or just interactively.

C-h f define-minor-mode

Drew
  • 77,472
  • 10
  • 114
  • 243
1

You need to be aware of whether a minor mode is global or buffer-local before you can reliably enable or disable it along with other modes. (See the list of mode types at the bottom of https://emacs.stackexchange.com/a/20915 )

(FYI, all of the following information was ascertained by checking the definitions of the various functions with M-x find-function -- although it helps to know what you're looking for, of course.)

evil-quickscope-mode and evil-leader-mode are buffer-local, so you can enable or disable them along with other buffer-local minor modes. I'm not sure where your hl-paren-mode is from, but I'll assume that's also buffer-local.

evil-visual-mark-mode is a global minor mode, so attempting to toggle it in specific buffers is wrong. You can probably enable this once and then not touch it (being a global mode, I would presume that it knows when evil is or isn't active). Assuming it's autoloaded:

(eval-after-load 'evil
  '(evil-visual-mark-mode 1))

evil-mode itself is a globalized minor mode. That means it's a global mode which controls a buffer-local mode (this one is named evil-local-mode), and probably all of the interesting functionality is managed by the buffer-local mode. As such, I imagine you actually want to tie your other buffer-local minor modes to evil-local-mode.

(defcustom my-evil-minor-modes
  '(evil-leader-mode
    evil-quickscope-mode
    hl-paren-mode)
  "Buffer-local minor modes to enable or disable with `evil-local-mode'."
  :type  '(repeat symbol)
  :group 'evil)

(defun my-evil-local-mode-hook ()
  "Enable or disable all of `my-evil-minor-modes' with `evil-local-mode'."
  (let ((state (if evil-local-mode 1 0)))
    (mapc (lambda (mode) (funcall mode state))
          my-evil-minor-modes)))

(add-hook 'evil-local-mode-hook 'my-evil-local-mode-hook)

You could copy and modify that for evil-mode-hook in order to enable/disable the global evil-visual-mark-mode along with the also-global evil-mode, but I don't think you actually want that, because you can enable evil-local-mode without enabling evil-mode.

phils
  • 50,977
  • 3
  • 79
  • 122