unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* minor mode map question
@ 2006-12-28  7:00 Drew Adams
  2007-01-01  2:15 ` Drew Adams
  0 siblings, 1 reply; 5+ messages in thread
From: Drew Adams @ 2006-12-28  7:00 UTC (permalink / raw)


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.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: minor mode map question
  2006-12-28  7:00 minor mode map question Drew Adams
@ 2007-01-01  2:15 ` Drew Adams
  2007-01-02  3:08   ` Richard Stallman
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Drew Adams @ 2007-01-01  2:15 UTC (permalink / raw)


Got no response to my previous email on this, but I figured things out.

FYI - The problem was that although the minor-mode map was updated each time
the mode was entered, this was not reflected in `minor-mode-map-alist' -
that alist continued to have the old keymap. The solution was to delete and
re-create the minor-mode entry in `minor-mode-map-alist' each time the mode
is entered. That ensures that `substitute-key-definition' respects the
current global map, and that is reflected in the minor-mode map.

I wish that you could provide, as the cdr of an entry to
`minor-mode-map-alist', an expression to be evaled to a keymap value, or
perhaps a function that is called to return a keymap value. That would
obviate needing to delete and re-add an entry, just to ensure that the alist
is up-to-date whenever the keymap changes. It seems a bit weird to me that
`minor-mode-map-alist' is so static, given how dynamic Emacs is otherwise.
Why not use a keymap-valued variable or keymap-returning function here,
instead of an actual keymap?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: minor mode map question
  2007-01-01  2:15 ` Drew Adams
@ 2007-01-02  3:08   ` Richard Stallman
  2007-02-26 18:04   ` Johan Bockgård
  2007-02-26 20:09   ` Stefan Monnier
  2 siblings, 0 replies; 5+ messages in thread
From: Richard Stallman @ 2007-01-02  3:08 UTC (permalink / raw)
  Cc: emacs-devel

    I wish that you could provide, as the cdr of an entry to
    `minor-mode-map-alist', an expression to be evaled to a keymap value, or
    perhaps a function that is called to return a keymap value. That would
    obviate needing to delete and re-add an entry, just to ensure that the alist
    is up-to-date whenever the keymap changes. It seems a bit weird to me that
    `minor-mode-map-alist' is so static, given how dynamic Emacs is otherwise.
    Why not use a keymap-valued variable or keymap-returning function here,
    instead of an actual keymap?

That sounds ok as something to be added after the release.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: minor mode map question
  2007-01-01  2:15 ` Drew Adams
  2007-01-02  3:08   ` Richard Stallman
@ 2007-02-26 18:04   ` Johan Bockgård
  2007-02-26 20:09   ` Stefan Monnier
  2 siblings, 0 replies; 5+ messages in thread
From: Johan Bockgård @ 2007-02-26 18:04 UTC (permalink / raw)
  To: emacs-devel

"Drew Adams" <drew.adams@oracle.com> writes:

> I wish that you could provide, as the cdr of an entry to
> `minor-mode-map-alist', an expression to be evaled to a keymap
> value, or perhaps a function that is called to return a keymap
> value. That would obviate needing to delete and re-add an entry,
> just to ensure that the alist is up-to-date whenever the keymap
> changes. It seems a bit weird to me that `minor-mode-map-alist' is
> so static, given how dynamic Emacs is otherwise. Why not use a
> keymap-valued variable or keymap-returning function here, instead of
> an actual keymap?

(info "(elisp)Controlling Active Maps")

 -- Variable: minor-mode-map-alist
    [...]
    The CDR can be either a keymap (a list) or a symbol whose function
    definition is a keymap.

-- 
Johan Bockgård

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: minor mode map question
  2007-01-01  2:15 ` Drew Adams
  2007-01-02  3:08   ` Richard Stallman
  2007-02-26 18:04   ` Johan Bockgård
@ 2007-02-26 20:09   ` Stefan Monnier
  2 siblings, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2007-02-26 20:09 UTC (permalink / raw)
  To: Drew Adams; +Cc: Emacs-Devel

> I wish that you could provide, as the cdr of an entry to
> `minor-mode-map-alist', an expression to be evaled to a keymap value, or
> perhaps a function that is called to return a keymap value. That would
> obviate needing to delete and re-add an entry, just to ensure that the alist
> is up-to-date whenever the keymap changes. It seems a bit weird to me that
> `minor-mode-map-alist' is so static, given how dynamic Emacs is otherwise.
> Why not use a keymap-valued variable or keymap-returning function here,
> instead of an actual keymap?

A keymap-valued variable is quite doable.
But something more dynamic is slightly tricky because the code tries to only
allocate memory *after* processing *one* key.  The reason is that in case we
run out of memory, we still want to guarantee progress (or something like
that).

Basically we want to avoid something like:
1 - prepare to read a key: fetch the active keymaps.
2 - oops, running out of memory while doing that, let's signal an error.
3 - unhandled error, let's go back to the toplevel (i.e. to point 1).

I'm not sure how important it is to avoid such a freeze, since the
alternative is "read a key, signal an error, read a key, signal an error",
but the code does go through some extra trouble for this.


        Stefan

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-02-26 20:09 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-28  7:00 minor mode map question Drew Adams
2007-01-01  2:15 ` Drew Adams
2007-01-02  3:08   ` Richard Stallman
2007-02-26 18:04   ` Johan Bockgård
2007-02-26 20:09   ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).