emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

minor mode map question


From: Drew Adams
Subject: minor mode map question
Date: Wed, 27 Dec 2006 23:00:14 -0800

I haven't been able to figure out what's happening here, and
I'd appreciate some help understanding.

I have a minor mode defined with define-minor-mode, as
follows:

(define-minor-mode foo-mode "foo mode"
  :global t :init-value nil
  (if foo-mode
      (define-foo-map)
    (makunbound 'foo-mode-map)))

The idea is that the minor mode map, `foo-mode-map' is
defined by `define-foo-map' anew each time foo mode is
entered. The `makunbound' is just something I added during
testing, trying to figure out what is happening.

Function `define-foo-map' creates `foo-mode-map' from
scratch using `make-sparse-keymap'. One of the bindings it
creates is this:

(substitute-key-definition 
 'switch-to-buffer 'foo-buffer
 foo-mode-map (current-global-map))

I enter foo-mode for the first time, with `M-x foo-mode'.
As expected, `C-x b' is then bound to `foo-buffer'.

I exit foo mode and then load iswitchb and turn on
`iswitchb-mode'. It doesn't seem to matter if I use command
`iswitchb-mode' or `iswitchb-default-keybindings'.  Each of
those changes the binding of `C-x b' to `iswitch-buffer', as
I would expect: the former in `iswitchb-mode-map'; the
latter in the global map.

In both cases, I get behavior that I don't understand when
foo mode is entered again.  When it is first entered, things
are OK: `foo-mode-map' is still unbound, because of the
previous `makunbound'. And, at that point, `C-x b' is still
bound to `iswitchb-buffer', which I would also expect.

I would in fact expect `C-x b' to remain bound to
`iswitchb-buffer' even in foo mode, because the binding in
foo mode should only steal the bindings of
`switch-to-buffer', which is no longer globally bound to
`C-x b'.

However, the first thing `foo-mode' does is to set the
variable `foo-mode' to t, and as soon as it does that, `C-x
b' is somehow bound to `foo-buffer' - even though
`foo-mode-map' is still unbound! IOW, `foo-mode' has not yet
even defined `foo-mode-map', but somehow the previous
definition of `C-x b' in `foo-mode-map' is in effect again.
This is the part I don't understand.

What am I not understanding about this? Is it something to
do with how `substitute-key-definition works' or something
to do with how `define-minor-mode' works?

Something that I can't see in the debugger seems to be
happening to the `foo-mode-map' key bindings as soon as
variable `foo-mode' is set to t.  I don't see how that can
happen.

Using `define-foo-map' does redefine `foo-mode-map' each
time foo mode is entered - I know that for a fact. But for
some reason that redefinition still ends up with a
`foo-buffer' binding for `C-x b' (the value of
`foo-mode-map' shows the binding of `foo-buffer').  The call
to `substitute-key-definition' doesn't seem to be respecting
the current global map, in which `switch-to-buffer' is not
bound to `C-x b'. 

And I don't see how the `C-x b' binding can be in effect as
soon as variable `foo-mode' is set to t, even before
`foo-mode-map' is created! That is, even when `foo-mode-map'
is undefined, `C-x b' is bound to `foo-buffer'. And after
`foo-mode-map' is defined, the map shows `C-x b' bound to
`foo-buffer'.

I've tried using both `iswitchb-mode' and the obsolete
`iswitchb-default-keybindings'. I have the problem in both
cases, though not necessarily for the same reason (I don't
know the reasons). In the former case, I'm dealing with two
global minor modes, each of which does this:

(substitute-key-definition 
 'switch-to-buffer '*-buffer ; * = foo or iswitchb
 *-map           ; * = foo-mode or iswitchb-global
 (current-global-map))

In the case of `iswitchb-default-keybindings', I'm dealing
with one global minor mode, foo, and a global binding by
iswitchb. That global binding, in the ctl-x-map, stays: it
shows that `b' is bound in ctl-x-map to `iswitchb-buffer',
even though `C-h k' shows that `C-x b' is bound to
`foo-buffer'.

In the reverse direction, there is a difference between
`iswitchb-mode' and `iswitchb-default-keybindings':

- If I enter iswitchb-mode first, and then enter foo mode, I
have the same problem: `C-x b is always set to `foo-buffer'
in `foo-mode'. That surprises me, because the code defining
iswitchb-mode is similar to that defining foo-mode: I would
guess that reversing the order would mean that
`iswitchb-buffer' might replace `foo-buffer', instead of the
reverse. The only difference I see is that `iswitchb-mode'
declares its keymap using a positional keymap argument and
defines it statically, whereas `foo-mode' creates its keymap
dynamically each time the mode is entered.

- However, if I use `iswitchb-default-keybindings' first,
and then enter foo mode, then there is no problem: `C-x b'
stays bound to `iswitchb-buffer' even in foo mode.

Hope I was clear enough. I'm a bit tired and confused right
now ;-). Any clarification is appreciated.








reply via email to

[Prev in Thread] Current Thread [Next in Thread]