diff options
| author | Robert Pluim | 2022-08-02 14:22:32 +0200 |
|---|---|---|
| committer | Robert Pluim | 2022-08-02 14:29:43 +0200 |
| commit | bf47851e0817abcf17eeb4a10d27cf18de2c68a2 (patch) | |
| tree | 7fc3cb4b2dd1726eaa6d1e8807cee27155ba485a | |
| parent | e5e840168c039f3daf9cce05e0b8ac4c49a450ec (diff) | |
| download | emacs-bf47851e0817abcf17eeb4a10d27cf18de2c68a2.tar.gz emacs-bf47851e0817abcf17eeb4a10d27cf18de2c68a2.zip | |
Signal error on duplicate key definitions
* lisp/keymap.el (define-keymap, defvar-keymap): Signal error if the
same key is specified twice. (Bug#56873)
* doc/lispref/keymaps.texi (Creating Keymaps): Document error
signaling behaviour.
* test/src/keymap-tests.el (keymap-test-duplicate-definitions): Test
duplicate definition detection.
| -rw-r--r-- | doc/lispref/keymaps.texi | 6 | ||||
| -rw-r--r-- | lisp/keymap.el | 16 | ||||
| -rw-r--r-- | test/src/keymap-tests.el | 12 |
3 files changed, 31 insertions, 3 deletions
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index 5cb5367bc0e..2be31d63a62 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi | |||
| @@ -374,7 +374,8 @@ number of keys. Here's a very basic example: | |||
| 374 | @end lisp | 374 | @end lisp |
| 375 | 375 | ||
| 376 | This function creates a new sparse keymap, defines the keystrokes in | 376 | This function creates a new sparse keymap, defines the keystrokes in |
| 377 | @var{pairs}, and returns the new keymap. | 377 | @var{pairs}, and returns the new keymap. It signals an error if there |
| 378 | are duplicate key bindings in @var{pairs}. | ||
| 378 | 379 | ||
| 379 | @var{pairs} is a list of alternating key bindings and key definitions, | 380 | @var{pairs} is a list of alternating key bindings and key definitions, |
| 380 | as accepted by @code{keymap-set}. In addition, the key can be the | 381 | as accepted by @code{keymap-set}. In addition, the key can be the |
| @@ -438,7 +439,8 @@ variable. This is what virtually all modes do---a mode called | |||
| 438 | 439 | ||
| 439 | This macro defines @var{name} as a variable, passes @var{options} | 440 | This macro defines @var{name} as a variable, passes @var{options} |
| 440 | and @var{pairs} to @code{define-keymap}, and uses the result as the | 441 | and @var{pairs} to @code{define-keymap}, and uses the result as the |
| 441 | default value for the variable. | 442 | default value for the variable. It signals an error if there are |
| 443 | duplicate key bindings in @var{pairs}. | ||
| 442 | 444 | ||
| 443 | @var{options} is like the keywords in @code{define-keymap}, but | 445 | @var{options} is like the keywords in @code{define-keymap}, but |
| 444 | there's an additional @code{:doc} keyword that provides the doc | 446 | there's an additional @code{:doc} keyword that provides the doc |
diff --git a/lisp/keymap.el b/lisp/keymap.el index 376a30f1065..107565590c1 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el | |||
| @@ -530,7 +530,8 @@ should be a MENU form as accepted by `easy-menu-define'. | |||
| 530 | (keymap keymap) | 530 | (keymap keymap) |
| 531 | (prefix (define-prefix-command prefix nil name)) | 531 | (prefix (define-prefix-command prefix nil name)) |
| 532 | (full (make-keymap name)) | 532 | (full (make-keymap name)) |
| 533 | (t (make-sparse-keymap name))))) | 533 | (t (make-sparse-keymap name)))) |
| 534 | seen-keys) | ||
| 534 | (when suppress | 535 | (when suppress |
| 535 | (suppress-keymap keymap (eq suppress 'nodigits))) | 536 | (suppress-keymap keymap (eq suppress 'nodigits))) |
| 536 | (when parent | 537 | (when parent |
| @@ -544,6 +545,9 @@ should be a MENU form as accepted by `easy-menu-define'. | |||
| 544 | (let ((def (pop definitions))) | 545 | (let ((def (pop definitions))) |
| 545 | (if (eq key :menu) | 546 | (if (eq key :menu) |
| 546 | (easy-menu-define nil keymap "" def) | 547 | (easy-menu-define nil keymap "" def) |
| 548 | (if (member key seen-keys) | ||
| 549 | (error "Duplicate definition for key: %S %s" key keymap) | ||
| 550 | (push key seen-keys)) | ||
| 547 | (keymap-set keymap key def))))) | 551 | (keymap-set keymap key def))))) |
| 548 | keymap))) | 552 | keymap))) |
| 549 | 553 | ||
| @@ -571,6 +575,16 @@ as the variable documentation string. | |||
| 571 | (push (pop defs) opts)))) | 575 | (push (pop defs) opts)))) |
| 572 | (unless (zerop (% (length defs) 2)) | 576 | (unless (zerop (% (length defs) 2)) |
| 573 | (error "Uneven number of key/definition pairs: %s" defs)) | 577 | (error "Uneven number of key/definition pairs: %s" defs)) |
| 578 | (let ((defs defs) | ||
| 579 | key seen-keys) | ||
| 580 | (while defs | ||
| 581 | (setq key (pop defs)) | ||
| 582 | (pop defs) | ||
| 583 | (when (not (eq key :menu)) | ||
| 584 | (if (member key seen-keys) | ||
| 585 | (error "Duplicate definition for key '%s' in keymap '%s'" | ||
| 586 | key variable-name) | ||
| 587 | (push key seen-keys))))) | ||
| 574 | `(defvar ,variable-name | 588 | `(defvar ,variable-name |
| 575 | (define-keymap ,@(nreverse opts) ,@defs) | 589 | (define-keymap ,@(nreverse opts) ,@defs) |
| 576 | ,@(and doc (list doc))))) | 590 | ,@(and doc (list doc))))) |
diff --git a/test/src/keymap-tests.el b/test/src/keymap-tests.el index b0876664ed1..ce96be6869e 100644 --- a/test/src/keymap-tests.el +++ b/test/src/keymap-tests.el | |||
| @@ -430,6 +430,18 @@ g .. h foo | |||
| 430 | (make-non-key-event 'keymap-tests-event) | 430 | (make-non-key-event 'keymap-tests-event) |
| 431 | (should (equal (where-is-internal 'keymap-tests-command) '([3 103])))) | 431 | (should (equal (where-is-internal 'keymap-tests-command) '([3 103])))) |
| 432 | 432 | ||
| 433 | (ert-deftest keymap-test-duplicate-definitions () | ||
| 434 | "Check that defvar-keymap rejects duplicate key definitions." | ||
| 435 | (should-error | ||
| 436 | (defvar-keymap | ||
| 437 | ert-keymap-duplicate | ||
| 438 | "a" #'next-line | ||
| 439 | "a" #'previous-line)) | ||
| 440 | (should-error | ||
| 441 | (define-keymap | ||
| 442 | "a" #'next-line | ||
| 443 | "a" #'previous-line))) | ||
| 444 | |||
| 433 | (provide 'keymap-tests) | 445 | (provide 'keymap-tests) |
| 434 | 446 | ||
| 435 | ;;; keymap-tests.el ends here | 447 | ;;; keymap-tests.el ends here |