Subject: bug#62207: 29.0.60; Trying to remove non-existent key binding instead adds a binding

From: Jonas Bernoulli <[email-masked]>
Date: Wed, 15 Mar 2023 17:51:27 +0100

As a side-note, it would be nice if it were possible to lookup a
key in a keymap only, while ignoring bindings in its parent keymap.

I was reminded of this because I had to resurrect some old code of
mine to work around this bug.  The workaround is:

(defun my--keymap-unset (keymap key &optional remove)
  (if remove
      (when (kmu-lookup-local-key keymap key nil t)
        (keymap-unset keymap key t))
    (keymap-unset keymap key)))

And below is the code I had to resurrect in order to make that happen.
If `lookup-key', and similar, took a NOPARENT argument, all of that
could be avoided.

(defun kmu-lookup-local-key ( keymap key
                              &optional accept-default no-remap position)
  "In KEYMAP, look up key sequence KEY.  Return the definition.

Unlike `keymap-lookup' (which see) this doesn't consider bindings
made in KEYMAP's parent keymap."
  (keymap-lookup (kmu--strip-keymap keymap)
                 key accept-default no-remap position))

(defun kmu--strip-keymap (keymap)
  "Return a copy of KEYMAP with all parent keymaps removed.

This not only removes the parent keymap of KEYMAP but also recursively
the parent keymap of any keymap a key in KEYMAP is bound to."
  (cl-labels ((strip-keymap (keymap)
                (set-keymap-parent keymap nil)
                (cl-loop for _key being the key-code of keymap
                         using (key-binding binding) do
                         (and (keymapp binding)
                              (not (kmu-prefix-command-p binding))
                              (strip-keymap binding)))
                keymap))
    (strip-keymap (copy-keymap keymap))))

(defun kmu-prefix-command-p (object)
  "Return non-nil if OBJECT is a symbol whose function definition is a keymap.
The value returned is the keymap stored as OBJECT's variable
definition or else the variable which holds the keymap."
  (and (symbolp object)
       (fboundp object)
       (keymapp (symbol-function object))
       (if (and (boundp  object)
                (keymapp (symbol-value object)))
           (symbol-value object)
         (kmu-keymap-variable (symbol-function object)))))

(defun kmu-keymap-variable-p (object)
  "Return t if OBJECT is a symbol whose variable definition is a keymap."
  (and (symbolp object)
       (boundp  object)
       (keymapp (symbol-value object))))