[Top][All Lists]

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

RE: customizing key definitions with Customize

From: Drew Adams
Subject: RE: customizing key definitions with Customize
Date: Fri, 16 May 2008 00:51:56 -0700

I wrote:

> The code I sent indicates how to do this. As I said, to make 
> the option's customizable key definitions be the only ones
> in the keymap, it is enough to change the :set function I
> used so that it first empties the keymap, before it adds the
> customized keys.
> That is, if a keymap variable is to be completely 
> customizable, then that is what we would want to do: make
> sure that :set not only adds bindings but also changes and
> deletes existing bindings. That is the same :set function I
> sent, but with the addition of a preliminary operation that
> empties the keymap, so that setting the option makes the
> keymap reflect just those key definitions that are present.

Let me expand on that a bit. New keymap-option.el attached - please try it out.

1. In the implementation I sent previously, the :set function only did
`define-key' for the key definitions (after the user was done editing them and
chose `Set for Session'). That meant that no previously existing key bindings
were removed or changed, even if the user changed a `Key' value or clicked DEL
to delete the key definition from the option. Only new bindings were made.

2. To remedy that, the :set function needs to first remove all existing key
bindings, so the only bindings will be those the user has kept. I've done that
now, in the attached version. The :set code now calls `makunbound' and then sets
the keymap variable to (make-sparse-keymap) before it defines the keys per the
user's customizations.

3. With that change, you can no longer use `custom-create-keymap-option' to
create an option that represents only some of a keymap's bindings. As I
mentioned in another mail, that can sometimes be useful, to avoid encouraging
users to fiddle with some bindings, for instance. Probably that behavior should
be optional, so code can choose whether the user's customization should
represent everything about the keymap (replaces its previous value completely)
or only some of its bindings.

4. `custom-create-keymap-option' creates a different variable (option) from the
keymap variable. This is necessary, IMO, because the keymap itself does not
match the custom type - the two variables have different types: one is a keymap
and the other is a `repeat' of `key-definition'. Every keymap can have an
associated user option for customization, but it need not have one created for
it automatically. An explicit call to `custom-create-keymap-option' creates the
option from the keymap variable. Code such as `define-minor-mode' could be made
to automatically call `custom-create-keymap-option' to do that.

5. The prefix keys of a keymap are not present as part of the defcustom. I use
the output of `substitute-command-keys' to capture the bindings of the keymap,
and then filter out those printed as `Prefix Command'. The individual bindings
that use the prefix are all present, but the prefix itself is not present
explicitly as a `key-definition'.

6. However, users need to be able to bind a key to a keymap within Customize,
that is, to create a prefix key. They can do that by using, as the target
`Command', a command whose symbol-function is a keymap. You can, for instance,
customize a key to have the `Command' value of `ctl-x-5-prefix', effectively
making that key a prefix key.

7. In the previous version I sent, input of the keymap variable used strict
completion, and an error was raised if the variable was for some reason not a
symbol bound to a keymap. In the new version, completion is lax, and you can use
`custom-create-keymap-option' to create both the user option and the keymap
itself. IOW, you can input a new symbol `foo-map', and the result is (1) a
keymap variable bound to an empty sparse keymap and (2) the corresponding user
option, `foo-map-defs', which users can customize to add key bindings.

8. With the new version, customization of keymaps is fairly complete, except for
these things: 

a. It still does not do anything special for ranges of keys. It naively produces
a single `Key' entry with a value of, say, `\200 . . ÿ'. I'm not sure what would
be the best way to deal with such key ranges. We could filter them out, but then
the option would not faithfully represent the keymap. If you do, for instance,
`M-x custom-create-keymap-option global-map', it works, and you can then do
`customize-option global-map-defs'. But you will see four range entries as four
single key definitions:

 \200 . . ÿ, bound to `self-insert-command'
 C-0 . . C-9, bound to `digit-argument'
 C-M-@ . . M-, bound to `digit-argument'
 C-M-0 . . C-M-9, bound to `digit-argument'

(And you will see the message "if: Key sequence C-M-@ . . M-  starts with
non-prefix key C-M-@". when the option is created.)

We could parse the range expression and create multiple key definitions from it,
but that would fill the Customize buffer with lots of keys with the same binding
- imagine what that would do for `self-insert-command'. Ideas?

b. You cannot yet use a lambda form as a command to bind to a key. So, for
instance, if a keymap has a key bound to (lambda () (interative) (message
"hello")) then the code currently just strips that key definition from the
option. The input from `substitute-command-keys' is just `??', which is
unhelpful. Similarly,  when customizing, you cannot enter a lambda form as the
`Command' sexp. Perhaps the definition of widget `key-definition' could be
altered to accommodate lambdas.

c. The `edmacro-parse-keys' Emacs bug I reported can cause some menu bindings to
break. It turns a menu item such as <describe> <describe-language-environment>
<Brazilian Portuguese> into <describe> <describe-language-environment>
<European> < B r a z i l i a n   P o r t u g u e s e >. When that bug is fixed,
this problem will go away.

10. The attached version also fixes some bugs that caused
`custom-create-keymap-option' to loop forever. For example, some printouts from
`substitute-command-keys' (e.g. for `emacs-lisp-mode-map') include the following
line, which wasn't taken into account: "  (that binding is currently shadowed by
another mode)". The attached code corrects these problems. This is the kind of
thing I meant by the code being fragile since it uses the output of
`substitute-command-keys' as input. Nevertheless, it seems to work pretty well.

11. I also special-cased `prev-buffer', which, like `mouse-face' and
`ignore-event', appears as a key binding but is not in fact a command. Dunno if
there are anymore such symbols.

Please try the code. Again, the implementation is admittedly fragile and not
pretty - a more direct approach using `map-keymap' or whatever might be
preferable. But this at least works. It gives an idea of a possible UI for
customizing keymaps and some of the choices or issues we might want to discuss.

Attachment: keymap-option.el
Description: Binary data

reply via email to

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