Subject: Re: bug#13948: no key-binding-locus

From: Josh <[email-masked]>
Date: Tue, 23 Apr 2013 12:41:28 -0700

On Wed, Mar 13, 2013 at 1:34 PM, Brian Malehorn <[email-masked]> wrote:
> Why isn't there a key equivalent to variable-binding-locus? As
> in, a way to figure out where a particular keybinding is coming
> from. For example,
>
>     M-x key-binding-locus C-j
>
> would evaluate to 'lisp-interaction-mode-map, which is the first
> map in which C-j was found.

+1.  The hierarchy, search order, and precedence of Emacs' various
keymaps and key translation mechanisms is complex and in my experience
seldom well understood by users.  This often manifests as confusion
about why global-set-key or local-set-key forms that users have added
to their init files do not have the expected effects.

The documentation that Brian quoted below doesn't seem very useful to
a typical Emacs user trying to troubleshoot key binding problems.  One
reason is that while the mechanisms for binding keys are described in
the Emacs manual[0], the key binding lookup procedure is not described
therein, but instead in the Elisp manual[1] where it is likely to be
overlooked.  A second reason is that even for those users who do
manage to find that info node, perhaps with info-apropos for example,
a "pseudo Lisp" description is not very helpful to users who don't
know Lisp.

I think the command Brian suggested would help average users with
little to no Elisp knowledge to debug key binding problems, especially
if it supported optionally showing all of the keymaps that were
searched in the process.

It would also be helpful for describe-key to show the governing keymap
and to disclose the existence and location of any shadowed key
bindings, something like this:

  C-c { runs the command some-foo-mode-command, which is an interactive
  autoloaded compiled Lisp function bound by `foo-mode.el' in `foo-mode-map'.

  It is bound to C-c {[, any other non-shadowed bindings]

  Shadowed C-c { bindings in other keymaps:
    bar-minor-mode-command (bound by `bar-mode.el' in `bar-mode-map'.
    my-func (bound by `init.el' in `global-map')

  [remainder of standard describe-key output follows]

Josh

[0] (info "(emacs) Key Bindings")
[1] (info "(elisp) Searching Keymaps")

> In terms of implementation, the process for finding a binding is
> described in (info "(elisp) Searching Keymaps"):
>
>     ...Here is a pseudo-Lisp description of the order and
>     conditions for searching them:
>
>      (or (cond
>           (overriding-terminal-local-map
>            (FIND-IN overriding-terminal-local-map))
>           (overriding-local-map
>            (FIND-IN overriding-local-map))
>           ((or (FIND-IN (get-char-property (point) 'keymap))
>        (FIND-IN-ANY emulation-mode-map-alists)
>        (FIND-IN-ANY minor-mode-overriding-map-alist)
>        (FIND-IN-ANY minor-mode-map-alist)
>        (if (get-text-property (point) 'local-map)
>            (FIND-IN (get-char-property (point) 'local-map))
>          (FIND-IN (current-local-map))))))
>          (FIND-IN (current-global-map)))