Allow removing keymap definitions

* src/keymap.c (initial_define_lispy_key): Adjust caller.
(store_in_keymap): Allow removing definitions in addition to
setting them to nil.
(Fdefine_key): Ditto.
(define_as_prefix): Adjust caller.

* src/term.c (term_get_fkeys_1): Adjust caller.
This commit is contained in:
Lars Ingebrigtsen 2021-11-16 08:02:22 +01:00
parent aa4cffccac
commit 560c921ed8
4 changed files with 92 additions and 22 deletions

View file

@ -593,6 +593,12 @@ Use 'exif-parse-file' and 'exif-field' instead.
* Lisp Changes in Emacs 29.1
+++
** 'define-key' now takes an optional REMOVE argument.
If non-nil, remove the definition from the keymap. This is subtly
different from setting a definition to nil (when the keymap has a
parent).
+++
** New function 'file-name-split'.
This returns a list of all the components of a file name.

View file

@ -73,7 +73,8 @@ static Lisp_Object where_is_cache;
/* Which keymaps are reverse-stored in the cache. */
static Lisp_Object where_is_cache_keymaps;
static Lisp_Object store_in_keymap (Lisp_Object, Lisp_Object, Lisp_Object);
static Lisp_Object store_in_keymap (Lisp_Object, Lisp_Object, Lisp_Object,
bool);
static Lisp_Object define_as_prefix (Lisp_Object, Lisp_Object);
static void describe_vector (Lisp_Object, Lisp_Object, Lisp_Object,
@ -130,7 +131,8 @@ in case you use it as a menu with `x-popup-menu'. */)
void
initial_define_lispy_key (Lisp_Object keymap, const char *keyname, const char *defname)
{
store_in_keymap (keymap, intern_c_string (keyname), intern_c_string (defname));
store_in_keymap (keymap, intern_c_string (keyname),
intern_c_string (defname), Qnil);
}
DEFUN ("keymapp", Fkeymapp, Skeymapp, 1, 1, 0,
@ -729,7 +731,8 @@ get_keyelt (Lisp_Object object, bool autoload)
}
static Lisp_Object
store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
store_in_keymap (Lisp_Object keymap, register Lisp_Object idx,
Lisp_Object def, bool remove)
{
/* Flush any reverse-map cache. */
where_is_cache = Qnil;
@ -805,21 +808,26 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
}
else if (CHAR_TABLE_P (elt))
{
Lisp_Object sdef = def;
if (remove)
sdef = Qnil;
/* nil has a special meaning for char-tables, so
we use something else to record an explicitly
unbound entry. */
else if (NILP (sdef))
sdef = Qt;
/* Character codes with modifiers
are not included in a char-table.
All character codes without modifiers are included. */
if (FIXNATP (idx) && !(XFIXNAT (idx) & CHAR_MODIFIER_MASK))
{
Faset (elt, idx,
/* nil has a special meaning for char-tables, so
we use something else to record an explicitly
unbound entry. */
NILP (def) ? Qt : def);
Faset (elt, idx, sdef);
return def;
}
else if (CONSP (idx) && CHARACTERP (XCAR (idx)))
{
Fset_char_table_range (elt, idx, NILP (def) ? Qt : def);
Fset_char_table_range (elt, idx, sdef);
return def;
}
insertion_point = tail;
@ -838,7 +846,12 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
else if (EQ (idx, XCAR (elt)))
{
CHECK_IMPURE (elt, XCONS (elt));
XSETCDR (elt, def);
if (remove)
/* Remove the element. */
insertion_point = Fdelq (elt, insertion_point);
else
/* Just set the definition. */
XSETCDR (elt, def);
return def;
}
else if (CONSP (idx)
@ -851,7 +864,10 @@ store_in_keymap (Lisp_Object keymap, register Lisp_Object idx, Lisp_Object def)
if (from <= XFIXNAT (XCAR (elt))
&& to >= XFIXNAT (XCAR (elt)))
{
XSETCDR (elt, def);
if (remove)
insertion_point = Fdelq (elt, insertion_point);
else
XSETCDR (elt, def);
if (from == to)
return def;
}
@ -1054,8 +1070,11 @@ possibly_translate_key_sequence (Lisp_Object key, ptrdiff_t *length)
/* GC is possible in this function if it autoloads a keymap. */
DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 3, 0,
DEFUN ("define-key", Fdefine_key, Sdefine_key, 3, 4, 0,
doc: /* 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
@ -1082,10 +1101,16 @@ DEF is anything that can be a key's definition:
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. */)
(Lisp_Object keymap, Lisp_Object key, Lisp_Object def)
(Lisp_Object keymap, Lisp_Object key, Lisp_Object def, Lisp_Object remove)
{
bool metized = false;
@ -1155,7 +1180,7 @@ binding KEY to DEF is added at the front of KEYMAP. */)
message_with_string ("Key sequence contains invalid event %s", c, 1);
if (idx == length)
return store_in_keymap (keymap, c, def);
return store_in_keymap (keymap, c, def, !NILP (remove));
Lisp_Object cmd = access_keymap (keymap, c, 0, 1, 1);
@ -1260,6 +1285,9 @@ lookup_key_1 (Lisp_Object keymap, Lisp_Object key, Lisp_Object accept_default)
DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
doc: /* Look up key sequence KEY in KEYMAP. Return the definition.
This is a legacy function; see `keymap-lookup' for the recommended
function to use instead.
A value of nil means undefined. See doc of `define-key'
for kinds of definitions.
@ -1413,7 +1441,7 @@ static Lisp_Object
define_as_prefix (Lisp_Object keymap, Lisp_Object c)
{
Lisp_Object cmd = Fmake_sparse_keymap (Qnil);
store_in_keymap (keymap, c, cmd);
store_in_keymap (keymap, c, cmd, Qnil);
return cmd;
}

View file

@ -1358,7 +1358,7 @@ term_get_fkeys_1 (void)
char *sequence = tgetstr (keys[i].cap, address);
if (sequence)
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
make_vector (1, intern (keys[i].name)));
make_vector (1, intern (keys[i].name)), Qnil);
}
/* The uses of the "k0" capability are inconsistent; sometimes it
@ -1377,13 +1377,13 @@ term_get_fkeys_1 (void)
/* Define f0 first, so that f10 takes precedence in case the
key sequences happens to be the same. */
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
make_vector (1, intern ("f0")));
make_vector (1, intern ("f0")), Qnil);
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k_semi),
make_vector (1, intern ("f10")));
make_vector (1, intern ("f10")), Qnil);
}
else if (k0)
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (k0),
make_vector (1, intern (k0_name)));
make_vector (1, intern (k0_name)), Qnil);
}
/* Set up cookies for numbered function keys above f10. */
@ -1405,8 +1405,10 @@ term_get_fkeys_1 (void)
if (sequence)
{
sprintf (fkey, "f%d", i);
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence),
make_vector (1, intern (fkey)));
Fdefine_key (KVAR (kboard, Vinput_decode_map),
build_string (sequence),
make_vector (1, intern (fkey)),
Qnil);
}
}
}
@ -1422,7 +1424,7 @@ term_get_fkeys_1 (void)
char *sequence = tgetstr (cap2, address); \
if (sequence) \
Fdefine_key (KVAR (kboard, Vinput_decode_map), build_string (sequence), \
make_vector (1, intern (sym))); \
make_vector (1, intern (sym)), Qnil); \
}
/* if there's no key_next keycap, map key_npage to `next' keysym */

View file

@ -373,6 +373,40 @@ g .. h foo
(should (eq (lookup-key (current-global-map) ["C-x C-f"]) 'find-file))
(should (eq (lookup-key (current-global-map) [?\C-x ?\C-f]) 'find-file)))
(ert-deftest keymap-removal ()
;; Set to nil.
(let ((map (define-keymap "a" 'foo)))
(should (equal map '(keymap (97 . foo))))
(define-key map "a" nil)
(should (equal map '(keymap (97)))))
;; Remove.
(let ((map (define-keymap "a" 'foo)))
(should (equal map '(keymap (97 . foo))))
(define-key map "a" nil t)
(should (equal map '(keymap)))))
(ert-deftest keymap-removal-inherit ()
;; Set to nil.
(let ((parent (make-sparse-keymap))
(child (make-keymap)))
(set-keymap-parent child parent)
(define-key parent [?a] 'foo)
(define-key child [?a] 'bar)
(should (eq (lookup-key child [?a]) 'bar))
(define-key child [?a] nil)
(should (eq (lookup-key child [?a]) nil)))
;; Remove.
(let ((parent (make-sparse-keymap))
(child (make-keymap)))
(set-keymap-parent child parent)
(define-key parent [?a] 'foo)
(define-key child [?a] 'bar)
(should (eq (lookup-key child [?a]) 'bar))
(define-key child [?a] nil t)
(should (eq (lookup-key child [?a]) 'foo))))
(provide 'keymap-tests)
;;; keymap-tests.el ends here