unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* unexpected result with keymap inheritance
@ 2016-11-21  0:28 Ernest Adrogué
  2016-11-21 14:12 ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Ernest Adrogué @ 2016-11-21  0:28 UTC (permalink / raw)
  To: help-gnu-emacs

Hi there,

when I remove a binding from a child keymap that is shadowing a binding from
its parent keymap, the resulting binding for the key is not the one in the
parent keymap but the binding from the parent's parent keymap:

(setq parent-map (make-sparse-keymap))
(setq child-map (make-sparse-keymap))
(set-keymap-parent parent-map global-map)
(set-keymap-parent child-map parent-map)
(define-key parent-map [?a] 'backward-char)
(use-local-map child-map)
(key-binding [?a])
=> backward-char
(define-key child-map [?a] 'forward-char)
(key-binding [?a])
=> forward-char
(define-key child-map [?a] nil)
(key-binding [?a])
=> self-insert-command

I thought the last line would evaluate to backward-char.  Is this how it's
supposed to work or is it some kind of bug?

Cheers.



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

* Re: unexpected result with keymap inheritance
  2016-11-21  0:28 unexpected result with keymap inheritance Ernest Adrogué
@ 2016-11-21 14:12 ` Stefan Monnier
  2016-11-21 17:12   ` Alex Kost
  2016-11-22  0:30   ` Ernest Adrogué
  0 siblings, 2 replies; 16+ messages in thread
From: Stefan Monnier @ 2016-11-21 14:12 UTC (permalink / raw)
  To: help-gnu-emacs

> (set-keymap-parent parent-map global-map)

Since `key-binding` checks global-map after the buffer-local map anyway,
putting global-map as the parent of your buffer-local map has basically
no effect.

> (define-key child-map [?a] nil)

This does not *remove* a binding from child-map.  Instead it marks the
key as unbound, thus hiding any potential corresponding binding in
parent keymaps.

Emacs does not provide a "remove binding" operation on keymaps.

> (key-binding [?a])
> => self-insert-command

Here the binding was not found in the buffer-local map but in the global
map instead.


        Stefan




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

* Re: unexpected result with keymap inheritance
  2016-11-21 14:12 ` Stefan Monnier
@ 2016-11-21 17:12   ` Alex Kost
  2016-11-22  2:55     ` Stefan Monnier
  2016-11-22  0:30   ` Ernest Adrogué
  1 sibling, 1 reply; 16+ messages in thread
From: Alex Kost @ 2016-11-21 17:12 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Stefan Monnier (2016-11-21 09:12 -0500) wrote:

>> (set-keymap-parent parent-map global-map)
>
> Since `key-binding` checks global-map after the buffer-local map anyway,
> putting global-map as the parent of your buffer-local map has basically
> no effect.
>
>> (define-key child-map [?a] nil)
>
> This does not *remove* a binding from child-map.  Instead it marks the
> key as unbound, thus hiding any potential corresponding binding in
> parent keymaps.
>
> Emacs does not provide a "remove binding" operation on keymaps.

I miss this "remove key binding" feature a lot!  If I may ask, do you
know whether there are plans to add such a feature?  Thanks.

-- 
Alex



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

* Re: unexpected result with keymap inheritance
  2016-11-21 14:12 ` Stefan Monnier
  2016-11-21 17:12   ` Alex Kost
@ 2016-11-22  0:30   ` Ernest Adrogué
  1 sibling, 0 replies; 16+ messages in thread
From: Ernest Adrogué @ 2016-11-22  0:30 UTC (permalink / raw)
  To: help-gnu-emacs

2016-11-21, 09:12 (-0500); Stefan Monnier escriu:
> > (set-keymap-parent parent-map global-map)
> 
> Since `key-binding` checks global-map after the buffer-local map anyway,
> putting global-map as the parent of your buffer-local map has basically
> no effect.
> 
> > (define-key child-map [?a] nil)
> 
> This does not *remove* a binding from child-map.  Instead it marks the
> key as unbound, thus hiding any potential corresponding binding in
> parent keymaps.
> 
> Emacs does not provide a "remove binding" operation on keymaps.
> 
> > (key-binding [?a])
> > => self-insert-command
> 
> Here the binding was not found in the buffer-local map but in the global
> map instead.

Understood.  Thanks for clarifying this.



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

* Re: unexpected result with keymap inheritance
  2016-11-21 17:12   ` Alex Kost
@ 2016-11-22  2:55     ` Stefan Monnier
  2016-11-22 19:07       ` Alex Kost
  0 siblings, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2016-11-22  2:55 UTC (permalink / raw)
  To: help-gnu-emacs

> I miss this "remove key binding" feature a lot!  If I may ask, do you
> know whether there are plans to add such a feature?  Thanks.

I don't know of any such plan.  It's ugly to implement, it's unclear
what it should do, and the use cases aren't very common.

If you "miss <it> a lot", I suspect you're doing something very unusual,
or you're not aware of some other way to get the same result.


        Stefan




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

* Re: unexpected result with keymap inheritance
  2016-11-22  2:55     ` Stefan Monnier
@ 2016-11-22 19:07       ` Alex Kost
  2016-11-23  1:12         ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Alex Kost @ 2016-11-22 19:07 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Stefan Monnier (2016-11-21 21:55 -0500) wrote:

>> I miss this "remove key binding" feature a lot!  If I may ask, do you
>> know whether there are plans to add such a feature?  Thanks.
>
> I don't know of any such plan.  It's ugly to implement, it's unclear
> what it should do, and the use cases aren't very common.
>
> If you "miss <it> a lot", I suspect you're doing something very unusual,
> or you're not aware of some other way to get the same result.

Well, yes, I think I do something very unusual: I rebind hundreds and
hundreds of default key bindings.  And my use case is: I often want to
just remove a key from some map so that a key from its parent map will
take precedence.

-- 
Alex



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

* Re: unexpected result with keymap inheritance
  2016-11-22 19:07       ` Alex Kost
@ 2016-11-23  1:12         ` Stefan Monnier
  2016-11-23  9:51           ` Alex Kost
  2016-11-23 10:16           ` Ernest Adrogué
  0 siblings, 2 replies; 16+ messages in thread
From: Stefan Monnier @ 2016-11-23  1:12 UTC (permalink / raw)
  To: help-gnu-emacs

> Well, yes, I think I do something very unusual: I rebind hundreds and
> hundreds of default key bindings.

While it's not usual to do that for hundreds of them, rebinding is
normal, so it's something we want to (and do) support.

> And my use case is: I often want to just remove a key from some map so
> that a key from its parent map will take precedence.

Do you have a more concrete description of when you want to do that?


        Stefan




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

* Re: unexpected result with keymap inheritance
@ 2016-11-23  5:43 Edward Flanigan
  2016-11-23  9:05 ` Alex Kost
  0 siblings, 1 reply; 16+ messages in thread
From: Edward Flanigan @ 2016-11-23  5:43 UTC (permalink / raw)
  To: help-gnu-emacs@gnu.org

I use unbind-key quite a bit. It is in bind-key.el from the external "use-package"

(unbind-key "C-'"     org-mode-map)        ;; org-cycle-agenda-files


See if that fits your use case.


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

* Re: unexpected result with keymap inheritance
  2016-11-23  5:43 Edward Flanigan
@ 2016-11-23  9:05 ` Alex Kost
  2016-11-23 14:47   ` Stefan Monnier
  0 siblings, 1 reply; 16+ messages in thread
From: Alex Kost @ 2016-11-23  9:05 UTC (permalink / raw)
  To: Edward Flanigan; +Cc: help-gnu-emacs@gnu.org

Edward Flanigan (2016-11-23 05:43 +0000) wrote:

> I use unbind-key quite a bit. It is in bind-key.el from the external "use-package"
>
> (unbind-key "C-'"     org-mode-map)        ;; org-cycle-agenda-files

If you look at "C-h v org-mode-map", you'll find there something like
this:

  (67108903)

previously it was:

  (67108903 . org-cycle-agenda-files)

and my wish is to remove this sexp from 'org-mode-map' completely.

> See if that fits your use case.

No, it doesn't: 'bind-key' (thus 'unbind-key') is just a wrapper for
'define-key', and as Stefan wrote, 'define-key' does not remove a key
from a keymap, it just binds it to nil.  So when you press the key, you
get "<key> is undefined", while I want to remove the key (to make a key
from a parent map take precedence).

-- 
Alex



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

* Re: unexpected result with keymap inheritance
  2016-11-23  1:12         ` Stefan Monnier
@ 2016-11-23  9:51           ` Alex Kost
  2016-11-23 13:42             ` Stefan Monnier
  2016-11-23 10:16           ` Ernest Adrogué
  1 sibling, 1 reply; 16+ messages in thread
From: Alex Kost @ 2016-11-23  9:51 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Stefan Monnier (2016-11-22 20:12 -0500) wrote:

>> Well, yes, I think I do something very unusual: I rebind hundreds and
>> hundreds of default key bindings.
>
> While it's not usual to do that for hundreds of them, rebinding is
> normal, so it's something we want to (and do) support.
>
>> And my use case is: I often want to just remove a key from some map so
>> that a key from its parent map will take precedence.
>
> Do you have a more concrete description of when you want to do that?

Here is an example.  I want to use some strange keys in all the modes
that derive from 'special-mode', so I do this:

  (define-key special-mode-map (kbd "o") 'backward-char)
  (define-key special-mode-map (kbd "u") 'forward-char)

OK, so far so good, but then I face some mode that also binds these
keys:

--8<---------------cut here---------------start------------->8---
(defvar very-special-mode-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map special-mode-map)
    (define-key map (kbd "o") 'find-file)
    (define-key map (kbd "u") 'undo)
    map))

(define-derived-mode very-special-mode special-mode "Very Special")
--8<---------------cut here---------------end--------------->8---

Now what I want is just to remove "o" and "u" from
'very-special-mode-map', so that my keys from 'special-mode-map' will
take precedence, but I can't do it, as with this:

  (define-key very-special-mode-map (kbd "o") nil)
  (define-key very-special-mode-map (kbd "u") nil)

I will get "<key> is undefined", so I have to bind my keys to the same
commands in this new map again:

  (define-key very-special-mode-map (kbd "o") 'backward-char)
  (define-key very-special-mode-map (kbd "u") 'forward-char)

I met the described case pretty often, and I really miss this "remove
key" functionality.  It would be really convenient for me if I could do:

  (remove-key <some-map> <some-key>)

or since I want to unbind many keys:

  (dolist (key <some-list-of-my-keys>)
    (remove-key <some-map> key))

-- 
Alex



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

* Re: unexpected result with keymap inheritance
  2016-11-23  1:12         ` Stefan Monnier
  2016-11-23  9:51           ` Alex Kost
@ 2016-11-23 10:16           ` Ernest Adrogué
  2016-11-23 15:02             ` Stefan Monnier
  1 sibling, 1 reply; 16+ messages in thread
From: Ernest Adrogué @ 2016-11-23 10:16 UTC (permalink / raw)
  To: help-gnu-emacs

2016-11-22, 20:12 (-0500); Stefan Monnier escriu:
> Do you have a more concrete description of when you want to do that?

Suppose you do

(let ((map minibuffer-local-map))
  (define-key map [(control ?p)] 'previous-history-element)
  (define-key map [(control ?n)] 'next-history-element))

Now, ido defines its own map that inherits from minibuffer-local-map.  In
this map, C-p is bound to ido-toggle-prefix, so one thing you may want to do
is move ido-toggle-prefix to another key, so that it stops shadowing your
C-p binding.  Therefore you would do

(define-key ido-common-completion-map [(control ?o)] 'ido-toggle-prefix)
(unbind-key ido-common-completion-map [(control ?p)])

where unbind-key is a function that removes any reference to a key from the
given map.

Without unbind-key, you have to define the same binding in both maps, which
can be inconvenient if later you decide to change it.  It's not
super-annoying but in my opinion it would be nice to have a function like
unbind-key.

Cheers.



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

* Re: unexpected result with keymap inheritance
  2016-11-23  9:51           ` Alex Kost
@ 2016-11-23 13:42             ` Stefan Monnier
  2016-11-23 21:23               ` Alex Kost
  0 siblings, 1 reply; 16+ messages in thread
From: Stefan Monnier @ 2016-11-23 13:42 UTC (permalink / raw)
  To: Alex Kost; +Cc: help-gnu-emacs

> Now what I want is just to remove "o" and "u" from
> 'very-special-mode-map', so that my keys from 'special-mode-map' will
> take precedence, but I can't do it, as with this:

I see, yes, that makes sense.  I suggest you `M-x report-emacs-bug` and
ask for this feature.

> I will get "<key> is undefined", so I have to bind my keys to the same
> commands in this new map again:
>
>   (define-key very-special-mode-map (kbd "o") 'backward-char)
>   (define-key very-special-mode-map (kbd "u") 'forward-char)

That's the obvious workaround, yes.  It's not that terrible, but I agree
it's less satisfactory.

Another approach if you want these `o` and `u` bindings to apply in
every special-mode buffer, is to do

    (defvar my-special-mode-bindings-map
        (let ((map (make-sparse-keymap)))
          (define-key map (kbd "o") 'backward-char)
          (define-key map (kbd "u") 'forward-char)
          map))

    (define-minor-mode my-special-mode-bindings "Docstring")

    (add-hook 'special-mode-hook #'my-special-mode-bindings)

so you don't have to go through every derivative of special-mode which
rebinds those keys and unbind them in their map.


        Stefan



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

* Re: unexpected result with keymap inheritance
  2016-11-23  9:05 ` Alex Kost
@ 2016-11-23 14:47   ` Stefan Monnier
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2016-11-23 14:47 UTC (permalink / raw)
  To: help-gnu-emacs

> from a keymap, it just binds it to nil.  So when you press the key, you
> get "<key> is undefined", while I want to remove the key (to make a key

You don't necessarily get "undefined": Emacs will first look in the
next keymaps.


        Stefan




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

* Re: unexpected result with keymap inheritance
  2016-11-23 10:16           ` Ernest Adrogué
@ 2016-11-23 15:02             ` Stefan Monnier
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Monnier @ 2016-11-23 15:02 UTC (permalink / raw)
  To: help-gnu-emacs

> (unbind-key ido-common-completion-map [(control ?p)])
> where unbind-key is a function that removes any reference to a key from the
> given map.

unbind-key would be bad name since after the call (lookup-key
ido-common-completion-map [?\C-p]) would still return a binding.

I.e. there are two ways to under "the map", one includes the parent and
the other doesn't.  So, in order to avoid confusion, the name should be
clear regardless of how you look at the map.

I don't have good ideas for a name, tho: remove-key-from-child and
reveal/expose-parent-binding is the best I could come up with so far.

Another option is to use something like

    (define-key <map> <key> :get-from-parent)

Side note:  A keymap can be composed of other keymaps, so it can be an
object of the form (keymap MAP1 MAP2 . PARENT).  In that case, a nil
binding in MAP1 does not hide another binding in MAP2, but does hide
a binding in PARENT.  With a special :get-from-parent binding, we could
get the exact opposite: a :get-from-parent binding in MAP1 could hide
a binding in MAP2 and reveal a binding in PARENT, whereas the most
obvious implementation of reveal-parent-binding would probably mean that
after it, both bindings in MAP2 and in PARENT would be exposed.


        Stefan




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

* Re: unexpected result with keymap inheritance
  2016-11-23 13:42             ` Stefan Monnier
@ 2016-11-23 21:23               ` Alex Kost
  2016-11-24  2:20                 ` Stefan Huchler
  0 siblings, 1 reply; 16+ messages in thread
From: Alex Kost @ 2016-11-23 21:23 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

Stefan Monnier (2016-11-23 08:42 -0500) wrote:

>> Now what I want is just to remove "o" and "u" from
>> 'very-special-mode-map', so that my keys from 'special-mode-map' will
>> take precedence, but I can't do it, as with this:
>
> I see, yes, that makes sense.  I suggest you `M-x report-emacs-bug` and
> ask for this feature.

Thanks, but there are tons of Emacs bugs, and I wouldn't like to bother
you and other contributors with just another feature request.

>> I will get "<key> is undefined", so I have to bind my keys to the same
>> commands in this new map again:
>>
>>   (define-key very-special-mode-map (kbd "o") 'backward-char)
>>   (define-key very-special-mode-map (kbd "u") 'forward-char)
>
> That's the obvious workaround, yes.  It's not that terrible, but I agree
> it's less satisfactory.
>
> Another approach if you want these `o` and `u` bindings to apply in
> every special-mode buffer, is to do
>
>     (defvar my-special-mode-bindings-map
>         (let ((map (make-sparse-keymap)))
>           (define-key map (kbd "o") 'backward-char)
>           (define-key map (kbd "u") 'forward-char)
>           map))
>
>     (define-minor-mode my-special-mode-bindings "Docstring")
>
>     (add-hook 'special-mode-hook #'my-special-mode-bindings)
>
> so you don't have to go through every derivative of special-mode which
> rebinds those keys and unbind them in their map.

Yes, I thought about this variant some time ago, but it doesn't suit my
needs.  In reality I want something more complex than the described
example.  Like, in a couple of modes (derived from special-mode), I want
to use other commands for "o"/"u" keys, so I can bind them as usual.
But if I used a minor mode, its keys would take precedence over the
major modes, so I would have another problem.  Also I rebind many keys
in many minor modes, and these keys would surely conflict with the keys
from my minor modes that I would define as you suggest.

But thanks for your answers!  I really appreciate that you spent your
time on my question.

-- 
Alex



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

* Re: unexpected result with keymap inheritance
  2016-11-23 21:23               ` Alex Kost
@ 2016-11-24  2:20                 ` Stefan Huchler
  0 siblings, 0 replies; 16+ messages in thread
From: Stefan Huchler @ 2016-11-24  2:20 UTC (permalink / raw)
  To: help-gnu-emacs

Alex Kost <alezost@gmail.com> writes:

> Stefan Monnier (2016-11-23 08:42 -0500) wrote:
>
>>> Now what I want is just to remove "o" and "u" from
>>> 'very-special-mode-map', so that my keys from 'special-mode-map' will
>>> take precedence, but I can't do it, as with this:
>>
>> I see, yes, that makes sense.  I suggest you `M-x report-emacs-bug` and
>> ask for this feature.
>
> Thanks, but there are tons of Emacs bugs, and I wouldn't like to bother
> you and other contributors with just another feature request.

I think I could use that "fix/feature" too. I have many global key
bindings, but some modes like gnus etc overwrites it. Also magit as
another example.

I mean I guess I still would have to override the gnus-mode-map but not
for the 5 gnus-sub-mode-maps?

I dont need it that urgend, but it could be useful to have. It also
could be useful for modes like ergoemacs or stuff like that, (flykeys)
maybe even evilmode?




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

end of thread, other threads:[~2016-11-24  2:20 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-21  0:28 unexpected result with keymap inheritance Ernest Adrogué
2016-11-21 14:12 ` Stefan Monnier
2016-11-21 17:12   ` Alex Kost
2016-11-22  2:55     ` Stefan Monnier
2016-11-22 19:07       ` Alex Kost
2016-11-23  1:12         ` Stefan Monnier
2016-11-23  9:51           ` Alex Kost
2016-11-23 13:42             ` Stefan Monnier
2016-11-23 21:23               ` Alex Kost
2016-11-24  2:20                 ` Stefan Huchler
2016-11-23 10:16           ` Ernest Adrogué
2016-11-23 15:02             ` Stefan Monnier
2016-11-22  0:30   ` Ernest Adrogué
  -- strict thread matches above, loose matches on Subject: below --
2016-11-23  5:43 Edward Flanigan
2016-11-23  9:05 ` Alex Kost
2016-11-23 14:47   ` Stefan Monnier

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).