emacs-devel
[Top][All Lists]
Advanced

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

customizing key definitions with Customize


From: Drew Adams
Subject: customizing key definitions with Customize
Date: Sun, 11 May 2008 12:40:29 -0700

Users can customize key definitions by using commands such as `global-set-key'
or by using functions such as `define-key' in their init files. And `kbd' helps
them by letting them use external key descriptions. 

It can sometimes be useful to let users use Customize to update key-binding
definitions. The `key-sequence' widget added in Emacs 22 is helpful here, but it
only takes care of the key-sequence part of a binding, not the map part or the
target command part. Also, defining keys can sometimes mean remapping existing
commands instead of providing a key sequence to bind, and the `key-sequence'
widget doesn't apply in that case.

I've been using a key definition widget as a custom type, to let users of a
library use only Customize to customize key bindings, if they want. 

The widget uses a `choice' to let you either specify a key sequence to bind or a
command to be remapped. Dunno if this is of general interest, but here is what I
use.

(define-widget 'key-definition 'lazy
  "Key definition.
A list of three components: KEYMAP, KEY, COMMAND, that represents a
binding of command COMMAND in keymap KEYMAP according to KEY.
KEY is either a key sequence (string or vector) or a command.
If KEY is a command, then the binding represented is its remapping to
command COMMAND."
  :tag "Key Definition" :indent 1 :offset 0
  :type
  '(list
    (restricted-sexp :tag "Keymap"
     :match-alternatives ((lambda (x) (keymapp (eval x))))
     :value global-map)
    (choice
     (key-sequence :tag "Key" :value [ignore])
     (restricted-sexp :tag "Command to remap"
      :match-alternatives (commandp) :value ignore))
    (restricted-sexp :tag "Command"
     :match-alternatives (commandp) :value ignore)))

You can then create a user option for a set of key definitions (or, less likely,
for a single key binding), where a key definition includes the keymap, the key
(or command to remap), and the target command.

For example, here is a `defcustom' that uses a `repeat' of the widget to define
a set of bindings:

(defcustom some-bindings
  `((test-map ,(kbd "C-a") forward-char)
    (test-map end-of-line backward-char)
    (test-map-2 ,(kbd "C-a") forward-word)
    (test-map-2 end-of-line backward-word)) ""
  :type '(repeat key-definition)
  :set #'(lambda (sym defs)
           (custom-set-default sym defs)
           (dolist (key-def defs) (define-key-from-key-def key-def)))
  :initialize #'custom-initialize-set)

The :set function uses this helper:

(defun define-key-from-key-def (key-def)
  "Define a key using a key-definition data structure
Argument KEY-DEF is a list of type `key-definition' or
`conditional-key-definition'."
  (let ((map (eval (car key-def)))
        (key (cadr key-def))
        (command (caddr key-def))
        (condition (cadddr key-def)))
    (when (or (not condition) (eval condition))
      (if (symbolp key)
          (define-key map (vector 'remap key) command)
        (define-key map key command)))))

The condition part is not present, and so is not used, in `key-definition', but
it is present and used in the similar widget `conditional-key-definition'
mentioned in the doc string. That has an additional list item that is eval'd to
determine under what conditions to make the binding. The definition is the same
as for `key-definition', except that the `list' has this entry, in addition:
(sexp :tag "Condition"). I use conditional key definitions to, for example, deal
with different Emacs versions.

Attached is a file you can play with to try this out. I'm no widget wizard, so
there is perhaps a better way to define the widgets. In particular, what is
common between them could perhaps be factored out somehow. Suggestions welcome.

If there is interest in something like this, we could add it to wid-edit.el. Key
bindings are something that most users want to change, and there currently is no
ready way for them to do that entirely within Customize. This approach lets
libraries define a default set of bindings and lets users use Customize to
modify them.

Attachment: test-key-def-widgets.el
Description: Binary data


reply via email to

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