branch: elpa/bind-map
commit 75aac732c10d97bc8dc49196c6623a09faf30d37
Merge: f23cfc13222 5913a860c56
Author: Justin Burkett <[email protected]>
Commit: GitHub <[email protected]>

    Merge pull request #13 from aaronjensen/evil-override
    
    Alternative technique for Evil binding
---
 bind-map.el | 128 +++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 79 insertions(+), 49 deletions(-)

diff --git a/bind-map.el b/bind-map.el
index 41e6e5b5f03..fd7cb053300 100644
--- a/bind-map.el
+++ b/bind-map.el
@@ -170,23 +170,6 @@ be activated.")
     (put map-sym (pop properties)
          (when properties (pop properties)))))
 
-(defun bind-map-evil-local-mode-hook ()
-  "Called to activate local state maps in a buffer."
-  ;; format is (OVERRIDE-MODE STATE KEY DEF)
-  (dolist (entry bind-map-evil-local-bindings)
-    (let* ((map (intern (format "evil-%s-state-local-map" (nth 1 entry))))
-           (mode (nth 0 entry))
-           (global-mode (intern (format "global-%s" (nth 0 entry))))
-           (set-explicitly (intern (format "%s-set-explicitly" mode))))
-      (when (and (boundp global-mode) (boundp mode)
-                 (boundp set-explicitly) (boundp map)
-                 (keymapp (symbol-value map))
-                 (symbol-value global-mode)
-                 (not (and (symbol-value set-explicitly)
-                           (null (symbol-value mode)))))
-        (define-key (symbol-value map) (nth 2 entry) (nth 3 entry))))))
-(add-hook 'evil-local-mode-hook 'bind-map-evil-local-mode-hook)
-
 (defvar bind-map-major-modes-alist '()
   "Each element takes the form (MAP-ACTIVE (MAJOR-MODE1
 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
   ;; format is (ACTIVATE-VAR MAJOR-MODES-LIST)
   (dolist (entry bind-map-major-modes-alist)
     (if (boundp (car entry))
-      (setf (symbol-value (car entry))
-            (not
-             (null
-              (member major-mode
-                      (mapcan
-                       #'bind-map--lookup-major-modes (cdr entry))))))
+        (set (make-local-variable (car entry))
+             (let* ((modes (cdr entry))
+                    (expanded (mapcan #'bind-map--lookup-major-modes modes)))
+               (and (memq major-mode expanded) t)))
       (message "bind-map: %s is void in change major mode hook" (car entry)))))
 (add-hook 'change-major-mode-after-body-hook
           'bind-map-change-major-mode-after-body-hook)
@@ -241,7 +222,20 @@ then append MAJOR-MODE-LIST to the existing cdr."
         (setcdr current (append (cdr current)
                                 major-mode-list))
       (push (cons activate-var major-mode-list)
-            bind-map-major-modes-alist))))
+            bind-map-major-modes-alist)))
+  ;; Recompute activation immediately for existing buffers so the change takes 
effect
+  ;; without requiring a mode change.
+  (let* ((entry (assq activate-var bind-map-major-modes-alist))
+         (modes (and entry (cdr entry)))
+         (expanded (when modes (mapcan #'bind-map--lookup-major-modes modes))))
+    (when expanded
+      (dolist (buf (buffer-list))
+        (with-current-buffer buf
+          (when (boundp activate-var)
+            (set (make-local-variable activate-var)
+                 (and (memq major-mode expanded) t))
+            (when (featurep 'evil)
+              (evil-normalize-keymaps))))))))
 
 (defun bind-map-kbd-keys (keys)
   "Apply `kbd' to KEYS filtering out nil and empty strings."
@@ -341,6 +335,8 @@ mode maps. Set up by bind-map.el." map))
          (turn-on-override-mode (intern (format "turn-on-%s" override-mode)))
          (turn-on-override-mode-doc (format "Enable `%s' except in minibuffer"
                                             override-mode))
+         (ensure-override-mode-func (intern (format "bind-map--ensure-%s" 
override-mode)))
+         (ensure-override-mode-doc (format "Ensure %s is enabled in 
appropriate buffers." override-mode))
          (evil-keys (or (plist-get args :evil-keys)
                         bind-map-default-evil-keys))
          (evil-states (or (plist-get args :evil-states)
@@ -379,8 +375,16 @@ mode maps. Set up by bind-map.el." map))
        `((with-no-warnings (defvar-local ,active-var nil))
          (add-to-list 'minor-mode-map-alist (cons ',active-var ,root-map))
          (bind-map-add-to-major-mode-list ',active-var ',major-modes)
-         ;; call once in case we are already in the relevant major mode
-         (bind-map-change-major-mode-after-body-hook)))
+         ;; Normalize activation across existing buffers immediately
+         (let* ((modes ',major-modes)
+                (expanded (mapcan #'bind-map--lookup-major-modes modes)))
+           (dolist (buf (buffer-list))
+             (with-current-buffer buf
+               (when (boundp ',active-var)
+                 (set (make-local-variable ',active-var)
+                      (and (memq major-mode expanded) t))
+                 (when (featurep 'evil)
+                   (evil-normalize-keymaps))))))))
 
      (when (and override-minor-modes
                 (null major-modes)
@@ -395,7 +399,24 @@ mode maps. Set up by bind-map.el." map))
              ,override-mode-doc)
            (,global-override-mode 1))
          (add-to-list 'emulation-mode-map-alists
-                      (list (cons ',override-mode ,root-map)))))
+                      (list (cons ',override-mode ,root-map)))
+         ;; Ensure Evil includes this map by also adding to minor-mode maps
+         (add-to-list 'minor-mode-map-alist (cons ',override-mode ,root-map))
+         ;; Normalize Evil keymaps when the override mode toggles
+         (with-eval-after-load 'evil
+           (add-hook ',(intern (format "%s-hook" override-mode))
+                     #'evil-normalize-keymaps))
+         ;; Defensive hook to ensure the mode is enabled in buffers that may
+         ;; have been created in unusual ways (e.g., programmatically via
+         ;; get-buffer-create). This catches cases where 
after-change-major-mode-hook
+         ;; might not fire or fires before the global mode is enabled.
+         (defun ,ensure-override-mode-func ()
+           ,ensure-override-mode-doc
+           (when (and ,global-override-mode
+                      (not ,override-mode)
+                      (not (minibufferp)))
+             (,override-mode 1)))
+         (add-hook 'buffer-list-update-hook #',ensure-override-mode-func)))
 
      (if (or minor-modes major-modes)
          ;; only bind keys in root-map
@@ -409,28 +430,37 @@ mode maps. Set up by bind-map.el." map))
 
      (when evil-keys
        (if (or minor-modes major-modes)
-          `((eval-after-load 'evil
-              '(progn
-                 (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
-                   (dolist (state ',evil-states)
-                     (when ',major-modes
-                       (define-key
-                         (evil-get-auxiliary-keymap ,root-map state t)
-                         key ',prefix-cmd))
-                     (dolist (mode ',minor-modes)
-                       (when (fboundp 'evil-define-minor-mode-key)
-                         (evil-define-minor-mode-key
-                          state mode key ',prefix-cmd)))))
-                 (evil-normalize-keymaps))))
-        `((eval-after-load 'evil
-            '(progn
-               (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
-                 (dolist (state ',evil-states)
-                   (when ,override-minor-modes
-                     (push (list ',override-mode state key ',prefix-cmd)
-                           bind-map-evil-local-bindings))
-                   (evil-global-set-key state key ',prefix-cmd)))
-               (evil-normalize-keymaps))))))
+           `((eval-after-load 'evil
+               '(progn
+                  ;; Bind per-state leaders in the auxiliary keymaps of 
root-map
+                  (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
+                    (dolist (state ',evil-states)
+                      (when ',major-modes
+                        (define-key (evil-get-auxiliary-keymap ,root-map state 
t)
+                          key ',prefix-cmd))
+                      (dolist (mode ',minor-modes)
+                        (evil-define-minor-mode-key ',evil-states mode key 
',prefix-cmd))))
+                  (evil-normalize-keymaps))))
+         `((eval-after-load 'evil
+             '(progn
+                (dolist (state ',evil-states)
+                  ;; Mark the root-map overriding for precedence
+                  (evil-make-overriding-map ,root-map state)
+                  ;; Bind keys in the per-state auxiliary keymaps
+                  (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
+                    (define-key (evil-get-auxiliary-keymap ,root-map state t)
+                      key ',prefix-cmd)))
+                ;; Also associate bindings with the override minor mode so they
+                ;; are scoped to buffers where it is enabled
+                (when ,override-minor-modes
+                  (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
+                    (evil-define-minor-mode-key ',evil-states ',override-mode 
key ',prefix-cmd)))
+                ;; Fall back to global bindings when not overriding minor modes
+                (unless ,override-minor-modes
+                  (dolist (key (bind-map-kbd-keys (list ,@evil-keys)))
+                    (dolist (state ',evil-states)
+                      (evil-global-set-key state key ',prefix-cmd))))
+                (evil-normalize-keymaps))))))
 
      (when bindings
        `((bind-map-set-keys ,map

Reply via email to