emacs-elpa-diffs
[Top][All Lists]
Advanced

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

[elpa] externals/compat 145d344d37 45/84: Add prefixed define-key from E


From: ELPA Syncer
Subject: [elpa] externals/compat 145d344d37 45/84: Add prefixed define-key from Emacs 29.1
Date: Tue, 3 Jan 2023 08:57:34 -0500 (EST)

branch: externals/compat
commit 145d344d374060a64c74d34b91956f67d71832aa
Author: Philip Kaludercic <philipk@posteo.net>
Commit: Philip Kaludercic <philipk@posteo.net>

    Add prefixed define-key from Emacs 29.1
---
 compat-29.el    | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 compat-tests.el | 23 +++++++++++++++++++++
 compat.texi     | 19 +++++++++++++++++
 3 files changed, 106 insertions(+)

diff --git a/compat-29.el b/compat-29.el
index cd57b2565e..bf313b4b21 100644
--- a/compat-29.el
+++ b/compat-29.el
@@ -29,6 +29,7 @@
 ;; - `plist-get'
 ;; - `plist-put'
 ;; - `plist-member'
+;; - `define-key'
 
 ;;; Code:
 
@@ -176,6 +177,69 @@ The value is actually the tail of PLIST whose car is PROP."
           (throw 'found plist))
         (setq plist (cddr plist))))))
 
+;;;; Defined in keymap.c
+
+(compat-defun define-key (keymap key def &optional remove)
+  "In KEYMAP, define key sequence KEY as DEF.
+This is a legacy function; see `keymap-set' for the recommended
+function to use instead.
+
+KEYMAP is a keymap.
+
+KEY is a string or a vector of symbols and characters, representing a
+sequence of keystrokes and events.  Non-ASCII characters with codes
+above 127 (such as ISO Latin-1) can be represented by vectors.
+Two types of vector have special meanings:
+ [remap COMMAND] remaps any key binding for COMMAND.
+ [t] creates a default definition, which applies to any event with no
+    other definition in KEYMAP.
+
+DEF is anything that can be a key's definition:
+ nil (means key is undefined in this keymap),
+ a command (a Lisp function suitable for interactive calling),
+ a string (treated as a keyboard macro),
+ a keymap (to define a prefix key),
+ a symbol (when the key is looked up, the symbol will stand for its
+    function definition, which should at that time be one of the above,
+    or another symbol whose function definition is used, etc.),
+ a cons (STRING . DEFN), meaning that DEFN is the definition
+    (DEFN should be a valid definition in its own right) and
+    STRING is the menu item name (which is used only if the containing
+    keymap has been created with a menu name, see `make-keymap'),
+ or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
+ or an extended menu item definition.
+ (See info node `(elisp)Extended Menu Items'.)
+
+If REMOVE is non-nil, the definition will be removed.  This is almost
+the same as setting the definition to nil, but makes a difference if
+the KEYMAP has a parent, and KEY is shadowing the same binding in the
+parent.  With REMOVE, subsequent lookups will return the binding in
+the parent, and with a nil DEF, the lookups will return nil.
+
+If KEYMAP is a sparse keymap with a binding for KEY, the existing
+binding is altered.  If there is no binding for KEY, the new pair
+binding KEY to DEF is added at the front of KEYMAP."
+  :realname compat--define-key-with-remove
+  :prefix t
+  (if remove
+      (let ((prev (lookup-key keymap key))
+            (parent (memq 'key (cdr keymap)))
+            fresh entry)
+        (when prev
+          ;; IMPROVEME: Kind of a hack to avoid relying on the specific
+          ;; behaviour of how `define-key' changes KEY before inserting
+          ;; it into the map.
+          (define-key keymap key (setq fresh (make-symbol "fresh")))
+          (setq entry (rassq fresh (cdr keymap)))
+          (if (> (length (memq entry (cdr keymap)))
+                 (length parent))
+              ;; Ensure that we only remove an element in the current
+              ;; keymap and not a parent, by ensuring that `entry' is
+              ;; located before `parent'.
+              (ignore (setcdr keymap (delq entry (cdr keymap))))
+            (define-key keymap key prev))))
+    (define-key keymap key def)))
+
 ;;;; Defined in subr.el
 
 (compat-defun function-alias-p (func &optional noerror)
diff --git a/compat-tests.el b/compat-tests.el
index c51a2e8041..265b8a26bf 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -2111,6 +2111,29 @@ being compared against."
          3 #'<=)
   (ought nil '(1 :one 2 :two 3 :three) 4 #'<=))
 
+(ert-deftest compat-define-key ()
+  "Check if `define-key' handles the REMOVE argument."
+  (let ((map (make-sparse-keymap))
+        (super (make-sparse-keymap)))
+    (set-keymap-parent map super)
+    (define-key super "a" 'always)
+    ;; We should be able to command a key that was just bound.
+    (define-key map "a" 'ignore)
+    (should (eq (lookup-key map "a") 'ignore))
+    (should (eq (lookup-key super "a") 'always))
+    ;; After removing it we should find the key in the parent map.
+    (compat-define-key map "a" nil t)
+    (should (eq (lookup-key map "a") 'always))
+    (should (eq (lookup-key super "a") 'always))
+    ;; Repeating this shouldn't change the result
+    (compat-define-key map "a" 'anything t)
+    (should (eq (lookup-key map "a") 'always))
+    (should (eq (lookup-key super "a") 'always))
+    ;; Removing it from the parent map should remove it from the child
+    ;; map as well.
+    (compat-define-key super "a" 'anything t)
+    (should (eq (lookup-key map "a") nil))
+    (should (eq (lookup-key super "a") nil))))
 
 (provide 'compat-tests)
 ;;; compat-tests.el ends here
diff --git a/compat.texi b/compat.texi
index 0caa67467f..c296cec066 100644
--- a/compat.texi
+++ b/compat.texi
@@ -2542,6 +2542,25 @@ time comparisons are limited to calls with the same tag.
 These functions are prefixed with @code{compat} prefix, and will require
 manual loading even after the release of Compat 29.1.0.0:
 
+@c copied from lispref/keymaps.texi
+@defun compat-define-key
+This function is like @code{keymap-set} (@pxref{Changing Key
+Bindings,,,elisp}, but understands only the legacy key syntaxes.
+
+In addition, this function also has a @var{remove} argument.  If it is
+non-@code{nil}, the definition will be removed.  This is almost the
+same as setting the definition to @code{nil}, but makes a difference
+if the @var{keymap} has a parent, and @var{key} is shadowing the same
+binding in the parent.  With @var{remove}, subsequent lookups will
+return the binding in the parent, whereas with a @code{nil} definition the
+lookups will return @code{nil}.
+
+@xref{Low-Level Key Binding,,,elisp}.
+
+This compatibility version handles the optional argument
+@var{remove}.
+@end defun
+
 @c copied from lispref/lists.texi
 @defun compat-plist-get plist prop &optional predicate
 This returns the value of the @var{property} property stored in the



reply via email to

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