emacs-evil/evil

`evil-define-key' can no longer bind key in `gtags-mode-map'

TheBB opened this issue · 6 comments

Originally reported by: York Zhao (Bitbucket: york, GitHub: york)


Here is all in .eamcs

(require 'evil)
(evil-mode 1)

(require 'gtags)

(eval-after-load 'gtags
  '(progn
     ;; gtags-mode
     (evil-define-key 'motion gtags-mode-map
       "\C-]" 'gtags-find-tag-from-here)
     (evil-define-key 'normal gtags-mode-map
       "\C-t" 'gtags-pop-stack)))

Open a C++ file (or any file), type "M-x gtags-mode". Type "C-h k C-]" and I suppose to see
the key being binded to gtags-find-tag-from-here' but it's not, what it shows is still the old binding evil-jump-to-tag'. Same thing happens if you type "C-h
k C-t". This used to be working for me, I have no idea why it just stops working
anymore. Even last night it worked for awhile, nothing has changed but it just
never works.


Original comment by Frank Fischer (Bitbucket: lyro, GitHub: lyro):


Nasty bug. The problem is that the list of active auxiliary keymaps needs to be updated (i.e., exactly those auxiliary keymaps are activated whose corresponding "activator" keymap (in this case gtags-mode-map) is active). This update usually happens after each state switch. This means if you, after starting gtags-mode, switch to insert state and back then the auxiliary keymap with your bindings should be active. Unfortunately this does not happen after enabling or disabling some minor mode currently (I have no idea if there is something like after-change-major-mode-hook for minor modes). In the meantime a workaround would be to call evil-normalize-keymaps immediately after loading gtags-mode.

Original comment by York Zhao (Bitbucket: york, GitHub: york):


The problem is that the list of active auxiliary keymaps needs to be updated
(i.e., exactly those auxiliary keymaps are activated whose corresponding
"activator" keymap (in this case gtags-mode-map) is active). This update usually
happens after each state switch.

This makes sense.

This means if you, after starting gtags-mode, switch to insert state and back
then the auxiliary keymap with your bindings should be active.

This finally explained why it was working for me every day at my office (this is
something I can't live without), but "suddenly" stopped working yesterday while at
home, because at office I was editing the C++ source code all the time while
yesterday I didn't have a need to edit anything.

Unfortunately this does not happen after enabling or disabling some minor mode
currently (I have no idea if there is something like
after-change-major-mode-hook for minor modes).

Too bad if there is no `after-change-major-mode-hook' for minor-mode.

In the meantime a workaround would be to call evil-normalize-keymaps
immediately after loading gtags-mode.

Added "(evil-normalize-keymaps)" to `gtags-mode-hook' and worked. Apparently
this is just a workaround as this requires adding "(evil-normalize-keymaps)" to
every minor mode hook in similar situation. If there is no way to solve this I
guess you might want to write this in the manual and/or add comment in the
source code.

Thank you very much for the explaination Frank.

Original comment by Vegard Øye (Bitbucket: epsil, GitHub: epsil):


What Frank says is correct - and fixable. I can make evil-define-key call evil-normalize-keymaps if the keymap being updated is currently active (i.e., is listed in (current-active-maps)).

Original comment by Frank Fischer (Bitbucket: lyro, GitHub: lyro):


But would this be sufficient? I may be wrong, but AFAIK evil-define-key is usually called before the buffer is created (not necessarily in a corresponding mode-hook). When the buffer is created and gtags-mode is enabled after evil (or enabled exlicitely using M-x gtags-mode) then this call to evil-define-key and hence evil-normalize-keymaps would not be executed.

Original comment by Vegard Øye (Bitbucket: epsil, GitHub: epsil):


True. evil-normalize-keymaps is presently very economical: it only concerns itself with auxiliary keymaps that are currently active. However, the //entry// for an auxiliary keymap, once it is created, is actually very toggleable, because it depends on the same mode variable as the main keymap. A heavier, but more general approach would therefore be to find all auxiliary keymaps up-front.

The big question is whether it will be efficient enough (keymap normalization is currently unnoticeable, and I very much intend to keep it so). I'll run some tests with make profiler and see what can be done.

TheBB commented

Original comment by Nick DeCoursin (Bitbucket: CapinCape, GitHub: Unknown):


Here's a couple more issues that reference the same bug:
[issue 497](https://bitbucket.org/lyro/evil/issues/497/regarding-initial-states* 1. )
and issue 391