Skip to content

Commit 75aac73

Browse files
authored
Merge pull request #13 from aaronjensen/evil-override
Alternative technique for Evil binding
2 parents f23cfc1 + 5913a86 commit 75aac73

File tree

1 file changed

+79
-49
lines changed

1 file changed

+79
-49
lines changed

bind-map.el

Lines changed: 79 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -170,23 +170,6 @@ be activated.")
170170
(put map-sym (pop properties)
171171
(when properties (pop properties)))))
172172

173-
(defun bind-map-evil-local-mode-hook ()
174-
"Called to activate local state maps in a buffer."
175-
;; format is (OVERRIDE-MODE STATE KEY DEF)
176-
(dolist (entry bind-map-evil-local-bindings)
177-
(let* ((map (intern (format "evil-%s-state-local-map" (nth 1 entry))))
178-
(mode (nth 0 entry))
179-
(global-mode (intern (format "global-%s" (nth 0 entry))))
180-
(set-explicitly (intern (format "%s-set-explicitly" mode))))
181-
(when (and (boundp global-mode) (boundp mode)
182-
(boundp set-explicitly) (boundp map)
183-
(keymapp (symbol-value map))
184-
(symbol-value global-mode)
185-
(not (and (symbol-value set-explicitly)
186-
(null (symbol-value mode)))))
187-
(define-key (symbol-value map) (nth 2 entry) (nth 3 entry))))))
188-
(add-hook 'evil-local-mode-hook 'bind-map-evil-local-mode-hook)
189-
190173
(defvar bind-map-major-modes-alist '()
191174
"Each element takes the form (MAP-ACTIVE (MAJOR-MODE1
192175
MAJOR-MODE2 ...)). The car is the variable used to activate a map
@@ -198,12 +181,10 @@ when the major mode is an element of the cdr. See
198181
;; format is (ACTIVATE-VAR MAJOR-MODES-LIST)
199182
(dolist (entry bind-map-major-modes-alist)
200183
(if (boundp (car entry))
201-
(setf (symbol-value (car entry))
202-
(not
203-
(null
204-
(member major-mode
205-
(mapcan
206-
#'bind-map--lookup-major-modes (cdr entry))))))
184+
(set (make-local-variable (car entry))
185+
(let* ((modes (cdr entry))
186+
(expanded (mapcan #'bind-map--lookup-major-modes modes)))
187+
(and (memq major-mode expanded) t)))
207188
(message "bind-map: %s is void in change major mode hook" (car entry)))))
208189
(add-hook 'change-major-mode-after-body-hook
209190
'bind-map-change-major-mode-after-body-hook)
@@ -241,7 +222,20 @@ then append MAJOR-MODE-LIST to the existing cdr."
241222
(setcdr current (append (cdr current)
242223
major-mode-list))
243224
(push (cons activate-var major-mode-list)
244-
bind-map-major-modes-alist))))
225+
bind-map-major-modes-alist)))
226+
;; Recompute activation immediately for existing buffers so the change takes effect
227+
;; without requiring a mode change.
228+
(let* ((entry (assq activate-var bind-map-major-modes-alist))
229+
(modes (and entry (cdr entry)))
230+
(expanded (when modes (mapcan #'bind-map--lookup-major-modes modes))))
231+
(when expanded
232+
(dolist (buf (buffer-list))
233+
(with-current-buffer buf
234+
(when (boundp activate-var)
235+
(set (make-local-variable activate-var)
236+
(and (memq major-mode expanded) t))
237+
(when (featurep 'evil)
238+
(evil-normalize-keymaps))))))))
245239

246240
(defun bind-map-kbd-keys (keys)
247241
"Apply `kbd' to KEYS filtering out nil and empty strings."
@@ -341,6 +335,8 @@ mode maps. Set up by bind-map.el." map))
341335
(turn-on-override-mode (intern (format "turn-on-%s" override-mode)))
342336
(turn-on-override-mode-doc (format "Enable `%s' except in minibuffer"
343337
override-mode))
338+
(ensure-override-mode-func (intern (format "bind-map--ensure-%s" override-mode)))
339+
(ensure-override-mode-doc (format "Ensure %s is enabled in appropriate buffers." override-mode))
344340
(evil-keys (or (plist-get args :evil-keys)
345341
bind-map-default-evil-keys))
346342
(evil-states (or (plist-get args :evil-states)
@@ -379,8 +375,16 @@ mode maps. Set up by bind-map.el." map))
379375
`((with-no-warnings (defvar-local ,active-var nil))
380376
(add-to-list 'minor-mode-map-alist (cons ',active-var ,root-map))
381377
(bind-map-add-to-major-mode-list ',active-var ',major-modes)
382-
;; call once in case we are already in the relevant major mode
383-
(bind-map-change-major-mode-after-body-hook)))
378+
;; Normalize activation across existing buffers immediately
379+
(let* ((modes ',major-modes)
380+
(expanded (mapcan #'bind-map--lookup-major-modes modes)))
381+
(dolist (buf (buffer-list))
382+
(with-current-buffer buf
383+
(when (boundp ',active-var)
384+
(set (make-local-variable ',active-var)
385+
(and (memq major-mode expanded) t))
386+
(when (featurep 'evil)
387+
(evil-normalize-keymaps))))))))
384388

385389
(when (and override-minor-modes
386390
(null major-modes)
@@ -395,7 +399,24 @@ mode maps. Set up by bind-map.el." map))
395399
,override-mode-doc)
396400
(,global-override-mode 1))
397401
(add-to-list 'emulation-mode-map-alists
398-
(list (cons ',override-mode ,root-map)))))
402+
(list (cons ',override-mode ,root-map)))
403+
;; Ensure Evil includes this map by also adding to minor-mode maps
404+
(add-to-list 'minor-mode-map-alist (cons ',override-mode ,root-map))
405+
;; Normalize Evil keymaps when the override mode toggles
406+
(with-eval-after-load 'evil
407+
(add-hook ',(intern (format "%s-hook" override-mode))
408+
#'evil-normalize-keymaps))
409+
;; Defensive hook to ensure the mode is enabled in buffers that may
410+
;; have been created in unusual ways (e.g., programmatically via
411+
;; get-buffer-create). This catches cases where after-change-major-mode-hook
412+
;; might not fire or fires before the global mode is enabled.
413+
(defun ,ensure-override-mode-func ()
414+
,ensure-override-mode-doc
415+
(when (and ,global-override-mode
416+
(not ,override-mode)
417+
(not (minibufferp)))
418+
(,override-mode 1)))
419+
(add-hook 'buffer-list-update-hook #',ensure-override-mode-func)))
399420

400421
(if (or minor-modes major-modes)
401422
;; only bind keys in root-map
@@ -409,28 +430,37 @@ mode maps. Set up by bind-map.el." map))
409430

410431
(when evil-keys
411432
(if (or minor-modes major-modes)
412-
`((eval-after-load 'evil
413-
'(progn
414-
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
415-
(dolist (state ',evil-states)
416-
(when ',major-modes
417-
(define-key
418-
(evil-get-auxiliary-keymap ,root-map state t)
419-
key ',prefix-cmd))
420-
(dolist (mode ',minor-modes)
421-
(when (fboundp 'evil-define-minor-mode-key)
422-
(evil-define-minor-mode-key
423-
state mode key ',prefix-cmd)))))
424-
(evil-normalize-keymaps))))
425-
`((eval-after-load 'evil
426-
'(progn
427-
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
428-
(dolist (state ',evil-states)
429-
(when ,override-minor-modes
430-
(push (list ',override-mode state key ',prefix-cmd)
431-
bind-map-evil-local-bindings))
432-
(evil-global-set-key state key ',prefix-cmd)))
433-
(evil-normalize-keymaps))))))
433+
`((eval-after-load 'evil
434+
'(progn
435+
;; Bind per-state leaders in the auxiliary keymaps of root-map
436+
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
437+
(dolist (state ',evil-states)
438+
(when ',major-modes
439+
(define-key (evil-get-auxiliary-keymap ,root-map state t)
440+
key ',prefix-cmd))
441+
(dolist (mode ',minor-modes)
442+
(evil-define-minor-mode-key ',evil-states mode key ',prefix-cmd))))
443+
(evil-normalize-keymaps))))
444+
`((eval-after-load 'evil
445+
'(progn
446+
(dolist (state ',evil-states)
447+
;; Mark the root-map overriding for precedence
448+
(evil-make-overriding-map ,root-map state)
449+
;; Bind keys in the per-state auxiliary keymaps
450+
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
451+
(define-key (evil-get-auxiliary-keymap ,root-map state t)
452+
key ',prefix-cmd)))
453+
;; Also associate bindings with the override minor mode so they
454+
;; are scoped to buffers where it is enabled
455+
(when ,override-minor-modes
456+
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
457+
(evil-define-minor-mode-key ',evil-states ',override-mode key ',prefix-cmd)))
458+
;; Fall back to global bindings when not overriding minor modes
459+
(unless ,override-minor-modes
460+
(dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
461+
(dolist (state ',evil-states)
462+
(evil-global-set-key state key ',prefix-cmd))))
463+
(evil-normalize-keymaps))))))
434464

435465
(when bindings
436466
`((bind-map-set-keys ,map

0 commit comments

Comments
 (0)