* customizing key definitions with Customize
@ 2008-05-11 19:40 Drew Adams
2008-05-11 22:02 ` Lennart Borgman (gmail)
` (2 more replies)
0 siblings, 3 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-11 19:40 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 4025 bytes --]
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 #2: test-key-def-widgets.el --]
[-- Type: application/octet-stream, Size: 4011 bytes --]
(define-widget 'conditional-key-definition 'lazy
"Conditional key definition.
A list of four components: KEYMAP, KEY, COMMAND, CONDITION, that
represents a binding of command COMMAND in keymap KEYMAP according to
KEY, if CONDITION evaluates to non-nil.
KEY is either a key sequence (string or vector) or a command.
COMMAND is a command.
CONDITION is a sexp.
If KEY is a command, then the binding represented is its remapping to
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)
(sexp :tag "Condition")))
(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)))
(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)))))
(defun key-def-set (var key-def)
"Set function for types `key-definition', `conditional-key-definition'."
(custom-set-default var key-def)
(define-key-from-key-def key-def))
(setq test-map (make-sparse-keymap))
(setq test-map-2 (make-sparse-keymap))
(setq foobar t)
(defcustom foo `(test-map ,(kbd "C-a") forward-char) ""
:type 'key-definition
:set #'key-def-set
:initialize #'custom-initialize-set)
(defcustom bar `(test-map end-of-line forward-char) ""
:type 'key-definition
:set #'key-def-set
:initialize #'custom-initialize-set)
(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)
(defcustom cond-foo `(test-map ,(kbd "C-a") forward-char t) ""
:type 'conditional-key-definition
:set #'key-def-set
:initialize #'custom-initialize-set)
(defcustom cond-bar `(test-map end-of-line forward-char foobar) ""
:type 'conditional-key-definition
:set #'key-def-set
:initialize #'custom-initialize-set)
(defcustom some-conditional-bindings
`((test-map ,(kbd "C-a") forward-char t)
(test-map end-of-line backward-char foobar)
(test-map-2 ,(kbd "C-a") forward-word t)
(test-map-2 end-of-line backward-word foobar)) ""
:type '(repeat conditional-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)
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 19:40 customizing key definitions with Customize Drew Adams
@ 2008-05-11 22:02 ` Lennart Borgman (gmail)
2008-05-11 22:28 ` Drew Adams
2008-05-12 8:59 ` Reiner Steib
2008-05-12 11:20 ` Richard M Stallman
2 siblings, 1 reply; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-11 22:02 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Drew Adams wrote:
> 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.
I like the idea, but can't it be taken one step further: Wouldn't it be
nice with a "sparse-keymap widget"? And then of course
`customize-sparse-keymap'.
Or have you already done this too, Drew?
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-11 22:02 ` Lennart Borgman (gmail)
@ 2008-05-11 22:28 ` Drew Adams
2008-05-11 22:40 ` Lennart Borgman (gmail)
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-11 22:28 UTC (permalink / raw)
To: 'Lennart Borgman (gmail)'; +Cc: emacs-devel
> I like the idea, but can't it be taken one step further:
> Wouldn't it be nice with a "sparse-keymap widget"? And then
> of course `customize-sparse-keymap'.
>
> Or have you already done this too, Drew?
No, I haven't taken it further than what I wrote. But I don't really know what
you have in mind. Perhaps you can elaborate or go further with the idea
yourself?
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 22:28 ` Drew Adams
@ 2008-05-11 22:40 ` Lennart Borgman (gmail)
2008-05-11 23:02 ` Drew Adams
0 siblings, 1 reply; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-11 22:40 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Drew Adams wrote:
>> I like the idea, but can't it be taken one step further:
>> Wouldn't it be nice with a "sparse-keymap widget"? And then
>> of course `customize-sparse-keymap'.
>>
>> Or have you already done this too, Drew?
>
> No, I haven't taken it further than what I wrote. But I don't really know what
> you have in mind. Perhaps you can elaborate or go further with the idea
> yourself?
I was just thinking `customize-sparse-keymap'. That would bring up the
current bindings in that keymap in a custom buffer using widgets similar
to your `key-definition' widget.
Some more bits are needed of course to make it useful: adding, disabling
etc.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-11 22:40 ` Lennart Borgman (gmail)
@ 2008-05-11 23:02 ` Drew Adams
2008-05-11 23:09 ` Lennart Borgman (gmail)
2008-05-14 5:24 ` Drew Adams
0 siblings, 2 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-11 23:02 UTC (permalink / raw)
To: 'Lennart Borgman (gmail)'; +Cc: emacs-devel
> >> I like the idea, but can't it be taken one step further:
> >> Wouldn't it be nice with a "sparse-keymap widget"? And then
> >> of course `customize-sparse-keymap'.
> >>
> >> Or have you already done this too, Drew?
> >
> > No, I haven't taken it further than what I wrote. But I
> don't really know what
> > you have in mind. Perhaps you can elaborate or go further
> with the idea
> > yourself?
>
> I was just thinking `customize-sparse-keymap'. That would
> bring up the current bindings in that keymap in a custom
> buffer using widgets similar to your `key-definition' widget.
I see. Yes, that could be easily done.
> Some more bits are needed of course to make it useful:
> adding, disabling etc.
If you mean adding and deleting key definitions (bindings), then that is already
there - you just click INS or DEL, as usual. If you mean something else, what?
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 23:02 ` Drew Adams
@ 2008-05-11 23:09 ` Lennart Borgman (gmail)
2008-05-11 23:19 ` Drew Adams
2008-05-14 5:24 ` Drew Adams
1 sibling, 1 reply; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-11 23:09 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Drew Adams wrote:
>> Some more bits are needed of course to make it useful:
>> adding, disabling etc.
>
> If you mean adding and deleting key definitions (bindings), then that is already
> there - you just click INS or DEL, as usual. If you mean something else, what?
Yes, you are right, INS and DEL are already there.
I also thought that it might be good to be able to disable a single
keybinding. Otherwise one would have to revert all the keybindings to
find out what the default was for that binding.
Buyt I think this last point need some more thought.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-11 23:09 ` Lennart Borgman (gmail)
@ 2008-05-11 23:19 ` Drew Adams
2008-05-11 23:23 ` Lennart Borgman (gmail)
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-11 23:19 UTC (permalink / raw)
To: 'Lennart Borgman (gmail)'; +Cc: emacs-devel
> >> Some more bits are needed of course to make it useful:
> >> adding, disabling etc.
> >
> > If you mean adding and deleting key definitions (bindings),
> > then that is already there - you just click INS or DEL,
> > as usual. If you mean something else, what?
>
> Yes, you are right, INS and DEL are already there.
>
> I also thought that it might be good to be able to disable a single
> keybinding. Otherwise one would have to revert all the keybindings to
> find out what the default was for that binding.
>
> But I think this last point need some more thought.
If the option being customized is a set (`repeat') of key definitions
(bindings), then that is the unit of reverting, IIUC.
Only the object of customization can be reverted to its default value, just as
only that object can be set or saved. Pieces of the object are not individually
subject to these operations. To be able to set, save, or revert a single key
description, it would need to have its own defcustom. AFAIK.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 23:19 ` Drew Adams
@ 2008-05-11 23:23 ` Lennart Borgman (gmail)
2008-05-11 23:34 ` Drew Adams
0 siblings, 1 reply; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-11 23:23 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Drew Adams wrote:
> Only the object of customization can be reverted to its default value, just as
> only that object can be set or saved. Pieces of the object are not individually
> subject to these operations. To be able to set, save, or revert a single key
> description, it would need to have its own defcustom. AFAIK.
Can't this be handled by saving the original key binding together with
the new binding? Can't a widget have invisible properties to handle this
in the custom buffer?
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-11 23:23 ` Lennart Borgman (gmail)
@ 2008-05-11 23:34 ` Drew Adams
2008-05-12 20:42 ` Lennart Borgman (gmail)
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-11 23:34 UTC (permalink / raw)
To: 'Lennart Borgman (gmail)'; +Cc: emacs-devel
> > Only the object of customization can be reverted to its
> > default value, just as only that object can be set or
> > saved. Pieces of the object are not individually
> > subject to these operations. To be able to set, save, or
> > revert a single key description, it would need to have
> > its own defcustom. AFAIK.
>
> Can't this be handled by saving the original key binding
> together with the new binding? Can't a widget have invisible
> properties to handle this in the custom buffer?
I really don't know. As I said, I'm no widget wizard.
I suppose anything is possible. But has anything like that ever been done for
other types of collections? Is it really something we want to get into?
It doesn't seem to me a big deal to revert all of the edited (or edited and set)
bindings in order to revert a single change you might have made. What it really
comes down to is setting (or saving, depending on the kind of reverting you want
to do) the option each time you change one of the collection members (in this
case, key definitions), before you change another. If you have set (or saved)
the option just before you edit a single member, then reverting will, in effect,
revert only that member. AFAIK.
I don't know anything about implementing what you mention, but I guess I'm also
questioning whether much would be gained by it.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 19:40 customizing key definitions with Customize Drew Adams
2008-05-11 22:02 ` Lennart Borgman (gmail)
@ 2008-05-12 8:59 ` Reiner Steib
2008-05-12 20:58 ` Drew Adams
2008-05-12 11:20 ` Richard M Stallman
2 siblings, 1 reply; 43+ messages in thread
From: Reiner Steib @ 2008-05-12 8:59 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
On Sun, May 11 2008, Drew Adams wrote:
> 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.
Simon Josefsson has writing something related in 2003/2004 [1,2], I
think.
[But the discussion back then drifted away to the lack of "Move
up/down" buttons in customize.]
Bye, Reiner.
[1] <http://thread.gmane.org/gmane.emacs.devel/18903>
From: Simon Josefsson <jas <at> extundo.com>
Subject: Customize key bindings?
To: emacs-devel
Date: 2003-12-29 22:28:22 GMT
[2] <http://thread.gmane.org/gmane.emacs.devel/21955>
From: Simon Josefsson <jas <at> extundo.com>
Subject: cus-misc: customize autoloads, environment variables (and key bindings)
To: emacs-devel
Date: 2004-04-20 19:43:03 GMT
--
,,,
(o o)
---ooO-(_)-Ooo--- | PGP key available | http://rsteib.home.pages.de/
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 19:40 customizing key definitions with Customize Drew Adams
2008-05-11 22:02 ` Lennart Borgman (gmail)
2008-05-12 8:59 ` Reiner Steib
@ 2008-05-12 11:20 ` Richard M Stallman
2008-05-12 14:01 ` Drew Adams
2008-05-12 20:42 ` Lennart Borgman (gmail)
2 siblings, 2 replies; 43+ messages in thread
From: Richard M Stallman @ 2008-05-12 11:20 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Using Customize to rebind keys would be a good feature to add;
but in order to make this fit in well with Emacs, it should
store the bindings in keymaps. For instance, if you customize
the bindings of Lisp mode, it should do that by altering
the bindings in lisp-mode-map.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-12 11:20 ` Richard M Stallman
@ 2008-05-12 14:01 ` Drew Adams
2008-05-13 0:03 ` Juri Linkov
2008-05-13 5:16 ` Richard M Stallman
2008-05-12 20:42 ` Lennart Borgman (gmail)
1 sibling, 2 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-12 14:01 UTC (permalink / raw)
To: rms; +Cc: emacs-devel
> Using Customize to rebind keys would be a good feature to add;
> but in order to make this fit in well with Emacs, it should
> store the bindings in keymaps. For instance, if you customize
> the bindings of Lisp mode, it should do that by altering
> the bindings in lisp-mode-map.
Not sure what you mean. The code I sent does let users change bindings in the
keymap. If such an option were provided for Lisp mode, users could use it to
change `lisp-mode-map' bindings. However, it is true that if a binding is
changed in some other way, it is not then reflected in the user option. That
could be fixed.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-12 11:20 ` Richard M Stallman
2008-05-12 14:01 ` Drew Adams
@ 2008-05-12 20:42 ` Lennart Borgman (gmail)
1 sibling, 0 replies; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-12 20:42 UTC (permalink / raw)
To: rms; +Cc: Drew Adams, emacs-devel
Richard M Stallman wrote:
> Using Customize to rebind keys would be a good feature to add;
> but in order to make this fit in well with Emacs, it should
> store the bindings in keymaps. For instance, if you customize
> the bindings of Lisp mode, it should do that by altering
> the bindings in lisp-mode-map.
I think the unit of operation should be something like
customize-sparse-keymap with a corresponing custom widget for sparse
keymaps.
As I wrote before Drew's widget code for key bindings is probably a good
base for that code.
There are some difficult things to master:
- When should the customized keymaps be applied?
- How to deal with current code that setup the keymaps?
My suggestion would be to apply the customized keymaps at the end of the
loading of the file that contains the definition of the keymaps. But I
do not know if this is possible.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-11 23:34 ` Drew Adams
@ 2008-05-12 20:42 ` Lennart Borgman (gmail)
0 siblings, 0 replies; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-12 20:42 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Drew Adams wrote:
>>> Only the object of customization can be reverted to its
>>> default value, just as only that object can be set or
>>> saved. Pieces of the object are not individually
>>> subject to these operations. To be able to set, save, or
>>> revert a single key description, it would need to have
>>> its own defcustom. AFAIK.
>> Can't this be handled by saving the original key binding
>> together with the new binding? Can't a widget have invisible
>> properties to handle this in the custom buffer?
>
> I really don't know. As I said, I'm no widget wizard.
>
> I suppose anything is possible. But has anything like that ever been done for
> other types of collections? Is it really something we want to get into?
>
> It doesn't seem to me a big deal to revert all of the edited (or edited and set)
> bindings in order to revert a single change you might have made. What it really
> comes down to is setting (or saving, depending on the kind of reverting you want
> to do) the option each time you change one of the collection members (in this
> case, key definitions), before you change another. If you have set (or saved)
> the option just before you edit a single member, then reverting will, in effect,
> revert only that member. AFAIK.
>
> I don't know anything about implementing what you mention, but I guess I'm also
> questioning whether much would be gained by it.
You have a point there. It is much better to concentrate on getting
customize-sparse-keymap to work at all.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-12 8:59 ` Reiner Steib
@ 2008-05-12 20:58 ` Drew Adams
0 siblings, 0 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-12 20:58 UTC (permalink / raw)
To: 'Reiner Steib'; +Cc: emacs-devel
> > 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.
>
> Simon Josefsson has writing something related in 2003/2004 [1,2], I
> think.
Interesting. I wasn't aware of that code, but the approach is similar (I too
started with an `alist' type).
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-12 14:01 ` Drew Adams
@ 2008-05-13 0:03 ` Juri Linkov
2008-05-13 0:40 ` Lennart Borgman (gmail)
` (3 more replies)
2008-05-13 5:16 ` Richard M Stallman
1 sibling, 4 replies; 43+ messages in thread
From: Juri Linkov @ 2008-05-13 0:03 UTC (permalink / raw)
To: Drew Adams; +Cc: rms, emacs-devel
>> Using Customize to rebind keys would be a good feature to add;
>> but in order to make this fit in well with Emacs, it should
>> store the bindings in keymaps. For instance, if you customize
>> the bindings of Lisp mode, it should do that by altering
>> the bindings in lisp-mode-map.
>
> Not sure what you mean. The code I sent does let users change bindings in the
> keymap. If such an option were provided for Lisp mode, users could use it to
> change `lisp-mode-map' bindings. However, it is true that if a binding is
> changed in some other way, it is not then reflected in the user option. That
> could be fixed.
Another alternative is to make keybindings first-class entities
for Customize like faces with their `defface' definition.
So customized and saved settings in a customization file
would be like:
(custom-set-keybindings
;; custom-set-keybindings was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
...)
that will override the default bindings in the corresponding keymaps.
--
Juri Linkov
http://www.jurta.org/emacs/
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 0:03 ` Juri Linkov
@ 2008-05-13 0:40 ` Lennart Borgman (gmail)
2008-05-13 14:59 ` Richard M Stallman
` (2 subsequent siblings)
3 siblings, 0 replies; 43+ messages in thread
From: Lennart Borgman (gmail) @ 2008-05-13 0:40 UTC (permalink / raw)
To: Juri Linkov; +Cc: rms, Drew Adams, emacs-devel
Juri Linkov wrote:
>>> Using Customize to rebind keys would be a good feature to add;
>>> but in order to make this fit in well with Emacs, it should
>>> store the bindings in keymaps. For instance, if you customize
>>> the bindings of Lisp mode, it should do that by altering
>>> the bindings in lisp-mode-map.
>> Not sure what you mean. The code I sent does let users change bindings in the
>> keymap. If such an option were provided for Lisp mode, users could use it to
>> change `lisp-mode-map' bindings. However, it is true that if a binding is
>> changed in some other way, it is not then reflected in the user option. That
>> could be fixed.
>
> Another alternative is to make keybindings first-class entities
> for Customize like faces with their `defface' definition.
> So customized and saved settings in a customization file
> would be like:
>
> (custom-set-keybindings
> ;; custom-set-keybindings was added by Custom.
> ;; If you edit it by hand, you could mess it up, so be careful.
> ;; Your init file should contain only one such instance.
> ;; If there is more than one, they won't work right.
> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
> ...)
>
> that will override the default bindings in the corresponding keymaps.
Looks like a good step towards customize-sparse-keymap.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-12 14:01 ` Drew Adams
2008-05-13 0:03 ` Juri Linkov
@ 2008-05-13 5:16 ` Richard M Stallman
2008-05-14 5:23 ` Drew Adams
1 sibling, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-13 5:16 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
> Using Customize to rebind keys would be a good feature to add;
> but in order to make this fit in well with Emacs, it should
> store the bindings in keymaps. For instance, if you customize
> the bindings of Lisp mode, it should do that by altering
> the bindings in lisp-mode-map.
Not sure what you mean. The code I sent does let users change bindings in the
keymap.
Does it change them in the keymap directly?
Could you use it for Lisp mode if you want to?
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 0:03 ` Juri Linkov
2008-05-13 0:40 ` Lennart Borgman (gmail)
@ 2008-05-13 14:59 ` Richard M Stallman
2008-05-13 23:59 ` Juri Linkov
2008-05-13 15:07 ` customizing key definitions with Customize David Reitter
2008-05-14 5:23 ` Drew Adams
3 siblings, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-13 14:59 UTC (permalink / raw)
To: Juri Linkov; +Cc: drew.adams, emacs-devel
Another alternative is to make keybindings first-class entities
for Customize like faces with their `defface' definition.
So customized and saved settings in a customization file
would be like:
(custom-set-keybindings
;; custom-set-keybindings was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
'(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
...)
That looks clean and useful to me.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 0:03 ` Juri Linkov
2008-05-13 0:40 ` Lennart Borgman (gmail)
2008-05-13 14:59 ` Richard M Stallman
@ 2008-05-13 15:07 ` David Reitter
2008-05-13 19:05 ` David Kastrup
2008-05-14 5:23 ` Drew Adams
3 siblings, 1 reply; 43+ messages in thread
From: David Reitter @ 2008-05-13 15:07 UTC (permalink / raw)
To: Juri Linkov; +Cc: rms, Drew Adams, emacs-devel
On 13 May 2008, at 01:03, Juri Linkov wrote:
>
> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
> ...)
>
> that will override the default bindings in the corresponding keymaps.
... and one presumably wouldn't just copy the value into emacs-lisp-
mode-map, but have every single binding override its corresponding
default, while inheriting the remaining defaults.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 15:07 ` customizing key definitions with Customize David Reitter
@ 2008-05-13 19:05 ` David Kastrup
0 siblings, 0 replies; 43+ messages in thread
From: David Kastrup @ 2008-05-13 19:05 UTC (permalink / raw)
To: David Reitter; +Cc: Juri Linkov, rms, Drew Adams, emacs-devel
David Reitter <david.reitter@gmail.com> writes:
> On 13 May 2008, at 01:03, Juri Linkov wrote:
>>
>> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
>> ...)
>>
>> that will override the default bindings in the corresponding keymaps.
>
> ... and one presumably wouldn't just copy the value into emacs-lisp-
> mode-map, but have every single binding override its corresponding
> default, while inheriting the remaining defaults.
Overriding is automatic by having the customized bindings appear at the
front. The main question is where to store the customized value and how
to make it appear at the front of the mode map once it gets loaded.
I think we have a customization type "hook" which might provide
reasonable implementation ideas.
--
David Kastrup, Kriemhildstr. 15, 44793 Bochum
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 14:59 ` Richard M Stallman
@ 2008-05-13 23:59 ` Juri Linkov
2008-05-14 1:10 ` Stefan Monnier
2008-05-14 16:40 ` Richard M Stallman
0 siblings, 2 replies; 43+ messages in thread
From: Juri Linkov @ 2008-05-13 23:59 UTC (permalink / raw)
To: rms; +Cc: drew.adams, emacs-devel
> Another alternative is to make keybindings first-class entities
> for Customize like faces with their `defface' definition.
> So customized and saved settings in a customization file
> would be like:
>
> (custom-set-keybindings
> ;; custom-set-keybindings was added by Custom.
> ;; If you edit it by hand, you could mess it up, so be careful.
> ;; Your init file should contain only one such instance.
> ;; If there is more than one, they won't work right.
> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
> ...)
>
> That looks clean and useful to me.
A question remains to decide is what would be a good user interface
for editing key bindings. For instance, after typing
M-x customize-keymap RET emacs-lisp-mode-map RET
what the user will see: all current key bindings in this keymap
(this may be too many as some keymaps have dozens of key bindings),
or an empty list with the single [Insert] button to add new key
bindings that will override the existing ones after saving the
Customization buffer.
--
Juri Linkov
http://www.jurta.org/emacs/
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 23:59 ` Juri Linkov
@ 2008-05-14 1:10 ` Stefan Monnier
2008-05-14 16:40 ` Richard M Stallman
1 sibling, 0 replies; 43+ messages in thread
From: Stefan Monnier @ 2008-05-14 1:10 UTC (permalink / raw)
To: Juri Linkov; +Cc: rms, drew.adams, emacs-devel
>> Another alternative is to make keybindings first-class entities
>> for Customize like faces with their `defface' definition.
>> So customized and saved settings in a customization file
>> would be like:
>>
>> (custom-set-keybindings
>> ;; custom-set-keybindings was added by Custom.
>> ;; If you edit it by hand, you could mess it up, so be careful.
>> ;; Your init file should contain only one such instance.
>> ;; If there is more than one, they won't work right.
>> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
>> ...)
>>
>> That looks clean and useful to me.
> A question remains to decide is what would be a good user interface
> for editing key bindings. For instance, after typing
Also, what would be the semantics of the above `custom-set-keybindings'.
Stefan
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-13 0:03 ` Juri Linkov
` (2 preceding siblings ...)
2008-05-13 15:07 ` customizing key definitions with Customize David Reitter
@ 2008-05-14 5:23 ` Drew Adams
3 siblings, 0 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-14 5:23 UTC (permalink / raw)
To: 'Juri Linkov'; +Cc: rms, emacs-devel
> >> Using Customize to rebind keys would be a good feature to add;
> >> but in order to make this fit in well with Emacs, it should
> >> store the bindings in keymaps. For instance, if you customize
> >> the bindings of Lisp mode, it should do that by altering
> >> the bindings in lisp-mode-map.
> >
> > Not sure what you mean. The code I sent does let users
> > change bindings in the keymap. If such an option were provided
> > for Lisp mode, users could use it to change `lisp-mode-map'
> > bindings. However, it is true that if a binding is
> > changed in some other way, it is not then reflected in the
> > user option. That could be fixed.
>
> Another alternative is to make keybindings first-class entities
> for Customize like faces with their `defface' definition.
> So customized and saved settings in a customization file
> would be like:
>
> (custom-set-keybindings
> ;; custom-set-keybindings was added by Custom.
> ;; If you edit it by hand, you could mess it up, so be careful.
> ;; Your init file should contain only one such instance.
> ;; If there is more than one, they won't work right.
> '(emacs-lisp-mode-map (([tab] 'lisp-indent-or-complete) ...))
> ...)
>
> that will override the default bindings in the corresponding keymaps.
That was the idea behind using a user option for key definitions. Whether having
a separate user option is better or worse could be discussed.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-13 5:16 ` Richard M Stallman
@ 2008-05-14 5:23 ` Drew Adams
2008-05-14 16:39 ` Richard M Stallman
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-14 5:23 UTC (permalink / raw)
To: rms; +Cc: emacs-devel
> > Using Customize to rebind keys would be a good feature to add;
> > but in order to make this fit in well with Emacs, it should
> > store the bindings in keymaps. For instance, if you customize
> > the bindings of Lisp mode, it should do that by altering
> > the bindings in lisp-mode-map.
>
> Not sure what you mean. The code I sent does let users
> change bindings in the keymap.
>
> Does it change them in the keymap directly?
> Could you use it for Lisp mode if you want to?
Still not sure what you mean, but yes, it changes them in the keymap
("directly"=?).
Yes, you can use it for Lisp mode.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-11 23:02 ` Drew Adams
2008-05-11 23:09 ` Lennart Borgman (gmail)
@ 2008-05-14 5:24 ` Drew Adams
1 sibling, 0 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-14 5:24 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 5562 bytes --]
> > >> I like the idea, but can't it be taken one step further:
> > >> Wouldn't it be nice with a "sparse-keymap widget"? And then
> > >> of course `customize-sparse-keymap'.
> > >>
> > >> Or have you already done this too, Drew?
> > >
> > > No, I haven't taken it further than what I wrote. But I
> > > don't really know what you have in mind. Perhaps you can
> > > elaborate or go further with the idea yourself?
> >
> > I was just thinking `customize-sparse-keymap'. That would
> > bring up the current bindings in that keymap in a custom
> > buffer using widgets similar to your `key-definition' widget.
>
> I see. Yes, that could be easily done.
Not quite as easily as I thought, at least for me. ;-)
I did take a look, however, and came up with the following code (attached).
There are no doubt more elegant and more direct ways to do this than to use
`substitute-command-keys' and `eval'. Probably something like `map-keymap' could
be used, but its automatic ancestor keymap recursion scared me off.
The approach I used is certainly ugly and perhaps fragile, but it seems to work.
It works for menu maps also. It excludes prefix keys. It special-cases
`mouse-face' and `ignore-event', since they are not in fact commands. (Hence,
the `key-definition' widget is different from what I sent before - it no longer
requires the `Command' sexp to be a command.)
If nothing else, this gives an idea of what a UI for customizing keymaps might
be like. Please try it out, as follows:
Command `custom-create-keymap-option' creates a user option of the same name as
its keymap argument, but with `-defs' appended. E.g.,
M-x custom-create-keymap-option RET bookmark-map
Completion is available for keymap-valued symbols. Then you can customize the
new option that corresponds to the keymap:
M-x customize-option RET bookmark-map-defs
Note that, as I mentioned before, you can specify a command to remap instead of
a key to bind (use Value Menu).
And yes, the keymap itself is modified when you change key definitions in
Customize - the option's :set function does that.
However, the option is currently decoupled from the keymap to some extent: The
:set function currently just does `define-key' for each of its key definitions.
It does not also reinitialize (empty out) the keymap so that it will have only
those definitions. That could be done, but it's worth thinking about whether
that is always what is wanted (probably).
This means that, currently: If you change the command part of a key definition,
the same key becomes bound to the new command. But if you change the key part of
a key definition, the new key becomes bound to the same command - but the old
key is not unbound from the command. Similarly, DEL deletes the key definition
from the user option, but it does not unbind the key in the keymap. IOW, you are
editing the option, and the :set function for the option currently just does
`define-key' for whatever definitions are present.
Also, in a new Emacs session, after saving the option, there is nothing that
automatically defines the corresponding keymap from the option. Currently, the
library that defines the keymap would need to explicitly initialize it from the
option, in order for the saved value to be picked up in a future session.
In Icicles, for instance, the bindings are picked up from the option whenever
you enter Icicle mode. In Icicles, I use code similar to what I sent previously,
which provides users only some of the key definitions, by default. It is not my
intention to invite users to customize the whole keymap (but they are of course
able to do that via INS).
That I think is a useful part of this approach of having an option separate from
the keymap: Whereas `custom-create-keymap-option' blindly includes all of a
keymap's bindings in the option it creates, libraries could instead choose to
provide a hand-rolled (or pruned) option that includes only some of the
bindings.
Defining keymaps from their corresponding options could perhaps be built into
Emacs somehow - either generally or just for specific contexts, such as minor
mode keymaps (e.g. via macro `define-minor-mode'). The code responsible for
this, whether automatic or not, would check whether a keymap option existed and,
if so, would use it to define the keymap.
There are lots of possibilities, depending on what uses are seen for something
like this.
While testing the code, BTW, I uncovered 2 or 3 Emacs bugs. These are the bug
report threads:
1. "kbd returns wrong value"
2. "substitute-command-keys incorrect for self-insert-command"
3. "\ is considered whitespace syntax in Lisp mode?" (maybe only a doc bug - not
clear to me, anyway)
#1 is a bug in `edmacro-parse-keys' (or in the `Describe' menu, depending on how
you look at it). It causes a bogus entry if you try `M-x
custom-create-keymap-option menu-bar-help-menu', because `<Brazilian
Portuguese>' has a space in it.
Related to #2 and #3: if you try `custom-create-keymap-option' on a non-sparse
keymap, such as `global-map' or `dired-mode-map', you will see an entry that
looks like this in Customize:
INS DEL Key Definition: List:
Choice: Value Menu Key: \200 . . ÿ
I haven't tried to make such an entry do anything useful. That is, the custom
type here does not recognize \200 . . ÿ as a key range - it treats it as an
ordinary, single key sequence. Such an entry should probably just be filtered
out, unless it can be made useful.
[-- Attachment #2: keymap-option.el --]
[-- Type: application/octet-stream, Size: 5591 bytes --]
(define-widget 'key-definition 'lazy
"Key definition.
A list of two components: KEY, BINDING.
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 BINDING, which must also be a command."
:tag "Key Definition" :indent 1 :offset 0
:type
'(list
(choice
(key-sequence :tag "Key" :value [ignore])
(restricted-sexp :tag "Command to remap"
:match-alternatives (commandp) :value ignore))
(sexp :tag "Command")))
(defun custom-create-keymap-option (map)
"Define a user option for keymap MAP."
;; $$$ How to exclude full keymaps? Is it worth it?
(interactive
(list (intern
(completing-read
"Keymap (symbol): " obarray
(lambda (s) (and (boundp s) (keymapp (symbol-value s))))
t nil 'variable-name-history))))
(unless (and (symbolp map) (boundp map)
(keymapp (symbol-value map)))
(error "`%S' is not a keymapp" map))
(let ((opt-name (intern (concat (symbol-name map) "-defs")))
(defs ()))
(with-temp-buffer
(princ (substitute-command-keys
(concat "\\{" (symbol-name map) "}")) (current-buffer))
(goto-char (point-min))
(with-syntax-table emacs-lisp-mode-syntax-table
(while (re-search-forward
"^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(let ((col (- (match-end 1) (match-beginning 1))))
(while (and (not (eobp)) (not (looking-at "\n\\s-*\n")))
(when (eolp) (delete-region (line-beginning-position)
(1+ (line-end-position))))
(while (looking-at "^\\S-+.+\\s-+Prefix Command$")
(delete-region (line-beginning-position)
(1+ (line-end-position))))
(end-of-line)
(skip-chars-backward "^ \t\n")
(when (looking-at "\\(\\sw\\|\\s_\\)+$")
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0)))
(cmd-beg (match-beginning 0))
eokey-pos)
(cond ((or (fboundp sym)
(memq sym '(mouse-face ignore-event)))
(end-of-line)
(insert ")")
(goto-char cmd-beg)
(skip-chars-backward " \t")
(setq eokey-pos (point))
(insert "\")") ; +2
(forward-line 0)
(insert "(,(kbd \"") ; +8
(while (< (point) (+ 8 eokey-pos))
(when (looking-at "\\(\"\\|\\\\\\)")
(insert "\\"))
(forward-char))
(goto-char (+ 10 cmd-beg))
(forward-line))
(t
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1)
(beginning-of-line)
(delete-region
(line-beginning-position)
(1+ (line-end-position)))))))
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1)
(forward-line -1)
(delete-region (line-beginning-position)
(1+ (line-end-position 2))))))))))
(goto-char (point-min))
(while (re-search-forward
"^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(forward-line -3)
(delete-region (line-beginning-position)
(1+ (line-end-position 3))))
(insert "`(\n")
(goto-char (point-max))
(insert ")")
(goto-char (point-min))
(setq defs (eval (read (current-buffer)))))
(eval
`(defcustom ,opt-name
',defs
,(format "Customizable keymap for `%s'." map)
:type '(repeat key-definition)
:set #'(lambda (sym defns)
(custom-set-default sym defns)
(let (key command)
(dolist (key-def defns)
(setq key (car key-def)
command (cadr key-def))
(if (symbolp key)
(define-key
,map (vector 'remap key) command)
(define-key ,map key command)))))
:initialize #'custom-initialize-set))))
(defun custom-create-keymap-option-1 ()
(end-of-line)
(skip-chars-backward "^ \t\n")
(when (looking-at "\\(\\sw\\|\\s_\\)+$")
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0))))
(cond ((fboundp sym)
(end-of-line)
(insert ")")
(forward-line -1)
(end-of-line)
(insert "\")") ; +2
(forward-line 0)
(insert "(,(kbd \"") ; +8
(forward-line 2))
(t
(forward-line 0)
(delete-region (line-beginning-position)
(1+ (line-end-position 2)))))))))
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-14 5:23 ` Drew Adams
@ 2008-05-14 16:39 ` Richard M Stallman
2008-05-15 4:36 ` Drew Adams
0 siblings, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-14 16:39 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Still not sure what you mean, but yes, it changes them in the keymap
("directly"=?).
Yes, you can use it for Lisp mode.
Can you show how it would be used for Lisp mode?
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-13 23:59 ` Juri Linkov
2008-05-14 1:10 ` Stefan Monnier
@ 2008-05-14 16:40 ` Richard M Stallman
2008-05-15 4:46 ` Drew Adams
1 sibling, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-14 16:40 UTC (permalink / raw)
To: Juri Linkov; +Cc: drew.adams, emacs-devel
what the user will see: all current key bindings in this keymap
(this may be too many as some keymaps have dozens of key bindings),
or an empty list with the single [Insert] button to add new key
bindings that will override the existing ones after saving the
Customization buffer.
Perhaps we should handle this with two alternatives, like
customization of fonts. You can customize a font either in terms of
its appearance in the current kind of screen, or its general conditions
that apply to all kinds of screens.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-14 16:39 ` Richard M Stallman
@ 2008-05-15 4:36 ` Drew Adams
2008-05-15 17:39 ` Richard M Stallman
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-15 4:36 UTC (permalink / raw)
To: rms; +Cc: emacs-devel
> Yes, you can use it for Lisp mode.
>
> Can you show how it would be used for Lisp mode?
See my message from yesterday, with the attached Lisp file. Load the file and
try it for yourself. I gave the example of bookmark-map, but you can just as
easily use lisp-mode map - just substitute "lisp-mode" for "bookmark":
> Command `custom-create-keymap-option' creates a user option
> of the same name as its keymap argument, but with `-defs'
> appended. E.g.,
>
> M-x custom-create-keymap-option RET bookmark-map
>
> Completion is available for keymap-valued symbols. Then you
> can customize the
> new option that corresponds to the keymap:
>
> M-x customize-option RET bookmark-map-defs
Please read the whole message, however, to minimize misunderstanding.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-14 16:40 ` Richard M Stallman
@ 2008-05-15 4:46 ` Drew Adams
2008-05-15 17:39 ` Richard M Stallman
2008-05-16 7:51 ` Drew Adams
0 siblings, 2 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-15 4:46 UTC (permalink / raw)
To: rms, 'Juri Linkov'; +Cc: emacs-devel
> what the user will see: all current key bindings in this keymap
> (this may be too many as some keymaps have dozens of key
> bindings),
> or an empty list with the single [Insert] button to add new key
> bindings that will override the existing ones after saving the
> Customization buffer.
>
> Perhaps we should handle this with two alternatives, like
> customization of fonts. You can customize a font either in terms of
> its appearance in the current kind of screen, or its general
> conditions that apply to all kinds of screens.
Perhaps we should handle it as I suggested: customize an option. A keymap-valued
symbol is just a variable. Either such a variable could itself be made a user
option or, as I showed, a separate but corresponding user option can be created.
Both approaches can be treated the same way (e.g. as I indicated); it depends on
what we want.
If we want a given keymap variable itself to be completely customizable (i.e.,
for all of its keys), then we can just make it a defcustom of the sort I
indicated. If we want some keymap variables not to be options, then we need not
use defcustom for them. If we want a given keymap variable to have only some of
its keys customizable (at least by default), then we can create a separate user
option that corresponds to only those keys.
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.
Unlike faces, keymaps, apart from keymap-valued variables, do not have names, so
the approach I suggested makes sense: customize keymap variables, not
"first-class" keymap objects.
We could instead entertain the idea of treating keymaps like faces - giving them
names independently of using variables, but I don't see the point in that. It
should be enough to turn, say, `lisp-mode-map' into a defcustom of the sort that
I indicated, if we want to make it entirely customizable.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-15 4:46 ` Drew Adams
@ 2008-05-15 17:39 ` Richard M Stallman
2008-05-16 8:01 ` Drew Adams
2008-05-16 7:51 ` Drew Adams
1 sibling, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-15 17:39 UTC (permalink / raw)
To: Drew Adams; +Cc: juri, emacs-devel
> Perhaps we should handle this with two alternatives, like
> customization of fonts. You can customize a font either in terms of
> its appearance in the current kind of screen, or its general
> conditions that apply to all kinds of screens.
Perhaps we should handle it as I suggested: customize an option. A
keymap-valued symbol is just a variable. Either such a variable
could itself be made a user option or, as I showed, a separate but
corresponding user option can be created. Both approaches can be
treated the same way (e.g. as I indicated); it depends on what we
want.
If we want a given keymap variable itself to be completely customizable (i.e.,
for all of its keys), then we can just make it a defcustom of the sort I
indicated. If we want some keymap variables not to be options, then we need not
use defcustom for them.
Now it seems you are saying that the _code_ should choose whether the
user should see the entire keymap or just his changes.
We were already aware of that possibility, but it has an obvious
drawback. That is why I suggested that we instead let the _user_
choose one or the other, for each keymap.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-15 4:36 ` Drew Adams
@ 2008-05-15 17:39 ` Richard M Stallman
2008-05-16 8:02 ` Drew Adams
0 siblings, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-15 17:39 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
Command `custom-create-keymap-option' creates a user option of the same =
name as
its keymap argument, but with `-defs' appended. E.g.,
M-x custom-create-keymap-option RET bookmark-map
We should not ask _users_ to type any commands to make a map
customizable. Rather, all the keymaps that Emacs knows about should
be known to Custom as well. So anything that has to be done in order
to make a keymap known to Custom should be done in the Lisp code.
It would make sense to have a command `customize-keymap' as a user
interface for running Custom to customize one particular keymap.
But we also should be able to include keymaps in custom groups.
Unlike faces, keymaps, apart from keymap-valued variables, do not
have names, so the approach I suggested makes sense: customize
keymap variables, not "first-class" keymap objects.
If that works out conveniently, I am not against it.
It would be nice if the macros for defining major modes
were connected to this, so that all the keymaps were
customizable.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-15 4:46 ` Drew Adams
2008-05-15 17:39 ` Richard M Stallman
@ 2008-05-16 7:51 ` Drew Adams
2008-05-18 1:22 ` Drew Adams
1 sibling, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-16 7:51 UTC (permalink / raw)
To: rms, 'Juri Linkov'; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 6918 bytes --]
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>
<European>
<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 #2: keymap-option.el --]
[-- Type: application/octet-stream, Size: 5970 bytes --]
(define-widget 'key-definition 'lazy
"Key definition.
A list of two components: KEY, BINDING.
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 BINDING, which must also be a command."
:tag "Key Definition" :indent 1 :offset 0
:type
'(list
(choice
(key-sequence :tag "Key" :value [ignore])
(restricted-sexp :tag "Command to remap"
:match-alternatives (commandp) :value ignore))
(sexp :tag "Command")))
(defun custom-create-keymap-option (map)
"Define a user option for keymap MAP."
(interactive
(list (intern
(completing-read
"Keymap (symbol): " obarray
(lambda (s) (and (boundp s) (keymapp (symbol-value s))))
nil nil 'variable-name-history))))
(let ((opt-name (intern (concat (symbol-name map) "-defs")))
(defs ()))
(if (not (and (symbolp map) (boundp map) (keymapp (symbol-value map))))
(set map (make-sparse-keymap))
(with-temp-buffer
(princ (substitute-command-keys
(concat "\\{" (symbol-name map) "}")) (current-buffer))
(goto-char (point-min))
(with-syntax-table emacs-lisp-mode-syntax-table
(while (re-search-forward
"^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(let ((col (- (match-end 1) (match-beginning 1))))
(while (and (not (eobp)) (not (looking-at "\n\\s-*\n")))
(if (or (eolp)
(looking-at "^\\S-+.+\\s-+Prefix Command$")
(looking-at ".+(binding currently shadowed)$")
(looking-at "^\\s-+(that binding is currently \
shadowed by another mode)$")
(looking-at "^.+\\s-+[?][?]"))
(delete-region (line-beginning-position)
(1+ (line-end-position)))
(end-of-line)
(skip-chars-backward "^ \t\n")
(looking-at "\\(\\sw\\|\\s_\\)+$")
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0)))
(cmd-beg (match-beginning 0))
eokey-pos)
(cond ((or (fboundp sym)
(memq sym '(mouse-face ignore-event prev-buffer)))
(end-of-line)
(insert ")")
(goto-char cmd-beg)
(skip-chars-backward " \t")
(setq eokey-pos (point))
(insert "\")") ; +2
(forward-line 0)
(insert "(,(kbd \"") ; +8
(while (< (point) (+ 8 eokey-pos))
(when (looking-at "\\(\"\\|\\\\\\)")
(insert "\\"))
(forward-char))
(goto-char (+ 10 cmd-beg))
(forward-line))
(t
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1 col)
(beginning-of-line)
(delete-region
(line-beginning-position)
(1+ (line-end-position)))))))
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1 col)
(forward-line -1)
(delete-region (line-beginning-position)
(1+ (line-end-position 2))))))))))
(goto-char (point-min))
(while (re-search-forward
"^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(forward-line -3)
(delete-region (line-beginning-position)
(1+ (line-end-position 3))))
(insert "`(\n")
(goto-char (point-max))
(insert ")")
(goto-char (point-min))
(setq defs (eval (read (current-buffer))))))
(eval
`(defcustom ,opt-name
',defs
,(format "Customizable keymap for `%s'." map)
:type '(repeat key-definition)
:set #'(lambda (sym defns)
(custom-set-default sym defns)
(makunbound ',map)
(setq ,map (make-sparse-keymap))
(let (key command)
(dolist (key-def defns)
(setq key (car key-def)
command (cadr key-def))
(if (symbolp key)
(define-key
,map (vector 'remap key) command)
(define-key ,map key command)))))
:initialize #'custom-initialize-set))))
(defun custom-create-keymap-option-1 (col)
(end-of-line)
(skip-chars-backward "^ \t\n")
(when (looking-at "\\(\\sw\\|\\s_\\)+$")
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0))))
(cond ((or (fboundp sym)
(memq sym '(mouse-face ignore-event)))
(end-of-line)
(insert ")")
(forward-line -1)
(end-of-line)
(insert "\")") ; +2
(forward-line 0)
(insert "(,(kbd \"") ; +8
(forward-line 2))
(t
(forward-line 0)
(delete-region (line-beginning-position)
(1+ (line-end-position 2)))))))))
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-15 17:39 ` Richard M Stallman
@ 2008-05-16 8:01 ` Drew Adams
2008-05-16 17:46 ` Richard M Stallman
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-16 8:01 UTC (permalink / raw)
To: rms; +Cc: juri, emacs-devel
> handle it as I suggested: customize an option. A keymap-valued
> symbol is just a variable. Either such a variable could itself
> be made a user option or, as I showed, a separate but
> corresponding user option can be created. Both approaches can
> be treated the same way (e.g. as I indicated); it depends on
> what we want.
>
> If we want a given keymap variable itself to be completely
> customizable (i.e., for all of its keys), then we can just
> make it a defcustom of the sort I indicated. If we want some
> keymap variables not to be options, then we need not
> use defcustom for them.
>
> Now it seems you are saying that the _code_ should choose whether the
> user should see the entire keymap or just his changes.
Don't know what you mean by that. What I meant was that it could be useful for
code (e.g. a library, built-in or 3rd-party) to decide whether and how much of a
given keymap should be customizable, by default. I'm talking possibilities, not
"should".
I can see some use value in not always presenting a user, by default, with a
complete keymap to customize. That's all. That doesn't mean we couldn't also
provide a way for a user to go ahead and customize the whole keymap. I'm
thinking of user convenience and possible confusion.
> We were already aware of that possibility, but it has an obvious
> drawback. That is why I suggested that we instead let the _user_
> choose one or the other, for each keymap.
I'm not sure we're saying something different. Nothing would prevent a user from
customizing a complete keymap. But a library might want to (also) give users a
lite keymap option that only shows some of the keys in a map.
Anyway, in the approach I outlined, the flexibility is there to do both.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-15 17:39 ` Richard M Stallman
@ 2008-05-16 8:02 ` Drew Adams
2008-05-16 17:46 ` Richard M Stallman
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-16 8:02 UTC (permalink / raw)
To: rms; +Cc: emacs-devel
> Command `custom-create-keymap-option' creates a user
> option of the same = name as
> its keymap argument, but with `-defs' appended. E.g.,
>
> M-x custom-create-keymap-option RET bookmark-map
>
> We should not ask _users_ to type any commands to make a map
> customizable.
"Should", "should". This thread started with my mail about libraries
(programmers) using defcustom to provide users the ability to customize some key
bindings. It would typically be libraries, not users, that would create
customizable keymaps (i.e. options). But please don't get hung up on where or
when the option is created. The first item to discuss is the means of
customizing - how it works in Lisp and what the user experiences in Customize.
There are lots of possibilities along the lines of the topic raised, including
complete customization of a keymap or of all keymaps, and automatic defcustoms
(or defkeymaps or whatever) for all keymaps. Let's keep the discussion open for
the moment, without immediately nailing down what "should" be done.
> Rather, all the keymaps that Emacs knows about should
> be known to Custom as well. So anything that has to be done in order
> to make a keymap known to Custom should be done in the Lisp code.
Should be _doable_ in Lisp code. It's not a foregone conclusion that we want
users to use Customize on all keymaps. But Lisp should be able to make any
keymap customizable.
> It would make sense to have a command `customize-keymap' as a user
> interface for running Custom to customize one particular keymap.
Yes. In the approach I suggested, that is just `customize-option'. I hope you
will at least try the code.
> But we also should be able to include keymaps in custom groups.
Keymaps or keymap-valued variables? That's one question. The approach I outlined
was to use the latter. And being normal defcustoms, they can of course be
included in groups.
> Unlike faces, keymaps, apart from keymap-valued variables, do not
> have names, so the approach I suggested makes sense: customize
> keymap variables, not "first-class" keymap objects.
>
> If that works out conveniently, I am not against it.
>
> It would be nice if the macros for defining major modes
> were connected to this, so that all the keymaps were
> customizable.
I agree. But we might (might) want to be able to specify some keymaps, or some
parts of some keymaps, as not customizable - or at least not make it immediate
and easy to customize them.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-16 8:01 ` Drew Adams
@ 2008-05-16 17:46 ` Richard M Stallman
2008-05-16 18:00 ` David Kastrup
0 siblings, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-16 17:46 UTC (permalink / raw)
To: Drew Adams; +Cc: juri, emacs-devel
I can see some use value in not always presenting a user, by default, with a
complete keymap to customize. That's all. That doesn't mean we couldn't also
provide a way for a user to go ahead and customize the whole keymap. I'm
thinking of user convenience and possible confusion.
Perhaps you are right. I think that the first task is to define the
mechanism so it can implement both modes. Then we could decide
which of the two modes should be the default.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-16 8:02 ` Drew Adams
@ 2008-05-16 17:46 ` Richard M Stallman
2008-05-16 23:58 ` Drew Adams
0 siblings, 1 reply; 43+ messages in thread
From: Richard M Stallman @ 2008-05-16 17:46 UTC (permalink / raw)
To: Drew Adams; +Cc: emacs-devel
It would typically be libraries, not users, that would create
customizable keymaps (i.e. options). But please don't get hung up on where or
when the option is created.
I asked you to show me what it would look like to use this in Lisp
mode, and that is what you showed me. I took you at your word and
commented on what you showed me, and now you say I am "hung up".
I have said what I think about how to make this a good feature.
Since I will not be the one to implement it, I think I have done
all that I can usefully do.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-16 17:46 ` Richard M Stallman
@ 2008-05-16 18:00 ` David Kastrup
2008-05-16 23:58 ` Drew Adams
2008-05-17 5:00 ` Richard M Stallman
0 siblings, 2 replies; 43+ messages in thread
From: David Kastrup @ 2008-05-16 18:00 UTC (permalink / raw)
To: rms; +Cc: juri, Drew Adams, emacs-devel
Richard M Stallman <rms@gnu.org> writes:
> I can see some use value in not always presenting a user, by
> default, with a complete keymap to customize. That's all. That
> doesn't mean we couldn't also provide a way for a user to go ahead
> and customize the whole keymap. I'm thinking of user convenience
> and possible confusion.
>
> Perhaps you are right. I think that the first task is to define the
> mechanism so it can implement both modes. Then we could decide which
> of the two modes should be the default.
The problem with customizing the whole keymap is that it should shake
the modifications out and store just the difference against the default
map. Otherwise, any modifications of the defaults by the package
authors will not picked up.
Also we use the keymaps to store toolbar and menubar data, and we do
that in a precomputed manner. That's not something we want to throw at
the user by default.
--
David Kastrup
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-16 18:00 ` David Kastrup
@ 2008-05-16 23:58 ` Drew Adams
2008-05-17 5:00 ` Richard M Stallman
1 sibling, 0 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-16 23:58 UTC (permalink / raw)
To: 'David Kastrup', rms; +Cc: juri, emacs-devel
> > I can see some use value in not always presenting a user, by
> > default, with a complete keymap to customize. That's all. That
> > doesn't mean we couldn't also provide a way for a user
> > to go ahead and customize the whole keymap. I'm thinking of
> > user convenience and possible confusion.
> >
> > Perhaps you are right. I think that the first task is to define the
> > mechanism so it can implement both modes. Then we could
> > decide which of the two modes should be the default.
>
> The problem with customizing the whole keymap is that it should shake
> the modifications out and store just the difference against
> the default map. Otherwise, any modifications of the defaults by the
> package authors will not picked up.
I agree with what each of you has said here.
> Also we use the keymaps to store toolbar and menubar data, and we do
> that in a precomputed manner. That's not something we want
> to throw at the user by default.
I'm not sure I understand completely what you mean, but I think I agree with
that also. I do think, though, that it will be good, in general, to be _able_ to
let users customize menu bindings for at least some keymaps.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-16 17:46 ` Richard M Stallman
@ 2008-05-16 23:58 ` Drew Adams
0 siblings, 0 replies; 43+ messages in thread
From: Drew Adams @ 2008-05-16 23:58 UTC (permalink / raw)
To: rms; +Cc: emacs-devel
> It would typically be libraries, not users, that would create
> customizable keymaps (i.e. options). But please don't get
> hung up on where or when the option is created.
>
> I asked you to show me what it would look like to use this in Lisp
> mode, and that is what you showed me. I took you at your word and
> commented on what you showed me, and now you say I am "hung up".
I didn't say you were hung up. I asked you to please not get hung up on that
topic.
Probably it would have been better if I had used different words. What I meant
by my request was that we postpone that part of the discussion until after we've
figured out what the "means of customizing" should be - "how it works in Lisp
and what the user experiences in Customize." That's all I meant - not that you
are hung up in any way.
I was no doubt not clear enough on how I see this - I hope it's clear now what I
meant: Libraries (Lisp code) would propose to users what bindings are available
to be customized (but that wouldn't stop them from customizing more if they
wanted).
I sent the option-creation function in the form of a command that provides
completion so that people could easily try the code out with different keymaps.
A priori, I have nothing for or against letting users also use such a command,
but I envisioned the creation of the keymap options being done by Lisp code,
typically.
> I have said what I think about how to make this a good feature.
> Since I will not be the one to implement it, I think I have done
> all that I can usefully do.
Likewise, I guess. Will anybody be implementing such a feature in Emacs? I think
it would be a useful addition. I haven't claimed and I won't claim that the
implementation I sent is how things should ultimately be done. I offered it
mainly to as a prototype to show what key-definition customization might look
like for a user and to explore some of the possible issues.
I separated user option and keymap variable for the reasons I gave: (1) leaving
open the possibility of not necessarily encouraging customization of all keys in
a keymap and (2) the implementation issue that a keymap structure is not
immediately one that Customize can use (without changes). Alternatively,
Customize could perhaps be made to understand keymaps directly.
I hope that some agreement can be reached on what kind of UI and implementation
would be most useful, and I hope someone with good Customize knowledge is
interested in working on that implementation. This could be a useful feature.
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: customizing key definitions with Customize
2008-05-16 18:00 ` David Kastrup
2008-05-16 23:58 ` Drew Adams
@ 2008-05-17 5:00 ` Richard M Stallman
1 sibling, 0 replies; 43+ messages in thread
From: Richard M Stallman @ 2008-05-17 5:00 UTC (permalink / raw)
To: David Kastrup; +Cc: juri, drew.adams, emacs-devel
The problem with customizing the whole keymap is that it should shake
the modifications out and store just the difference against the default
map.
I agree it would be useful to store the customization as a diff, if
that is possible.
^ permalink raw reply [flat|nested] 43+ messages in thread
* RE: customizing key definitions with Customize
2008-05-16 7:51 ` Drew Adams
@ 2008-05-18 1:22 ` Drew Adams
2008-05-18 9:07 ` Key/menu bug? (was: customizing key definitions with Customize) David Kastrup
0 siblings, 1 reply; 43+ messages in thread
From: Drew Adams @ 2008-05-18 1:22 UTC (permalink / raw)
To: rms, 'Juri Linkov'; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 4222 bytes --]
> 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.
That doesn't really do the trick, unfortunately.
The keymap itself, not just the keymap variable, needs to be reinitialized and
then filled with the new bindings, because the keymap might already have been
used as part of other keymaps.
In the :set function I had, I've thus replaced (makunbound ',map) and (setq ,map
(make-sparse-keymap)) with (when (keymapp ,map) (setcdr ,map nil)). That seems
to fix that problem, but there are other problems, listed below. The updated
code is attached.
1. Non-sparse keymaps, such as `global-map', can end up with some of their keys
undefined after customization.
I cobbled together some code that processes key ranges such as "SPC .. ~", in
particular to handle the multiple bindings of things like `self-insert-command'
in non-sparse keymaps. The attached code raises an error for a non-sparse
keymap, but you can comment out the two lines that raise the error (marked "<===
1"), to try it.
2. However, some maps, such as `global-map', can still end up with some of their
keys undefined. You won't want to try `global-map' with error handling #1 turned
off. If you want to experiment with `global-map', comment out the line marked
"<=== 2".
I'm not sure why some key definitions are not reinstated as they should be.
Perhaps it has to do with the order of processing the key definitions (e.g. wrt
prefix keys).
3. The approach I've used of relying on the output of `substitute-command-keys'
does not work completely for menu maps, because it loses the other information
besides the real binding (e.g. command). For instance, if this is a menu item:
(search-documentation
menu-item "Search Documentation"
(keymap
(emacs-terminology
menu-item "Emacs Terminology" search-emacs-glossary (nil)
:help "Display the Glossary section of the Emacs manual")
...))
Then the :set function changes that to just this:
(search-documentation
keymap (emacs-terminology . search-emacs-glossary))
So this is another reason why we should work directly from the keymap, using,
say, `map-keymap', and not try to use the output of `substitute-command-keys'.
To deal with menus generally, we would need to extend the definion of
`key-definition' to accommodate not only the binding (command) but also the
other stuff that menu bindings include. A less satisfying alternative would be
to just forego being able to customize menu keymaps. The attached code just
raises an error if you try to create an option for a menu keymap.
4. There still is an `edmacro-parse-keys' bug that prevents some keys from being
handled correctly. With the attached code, the only such key in the global map
is, I think, "M-<" - see the separate bug report. Someone more knowledgeable
will need to fix `edmacro-parse-keys' the right way.
I won't be going any further with this, but I hope someone will. I spent more
time on it than I wished, but I hope that some of what I explored might help
someone else do things right. I've added some comments in the code, in case it
helps.
There hasn't been much interest expressed, but I think this would be a good
feature if done right. Users can customize the rest of Emacs, besides key
bindings, and bindings can be fairly complex to work with. Besides letting users
customize bindings generally, such a feature can be used by a library to control
(e.g. encourage/discourage) which bindings users customize (with Customize).
HTH.
[-- Attachment #2: keymap-option.el --]
[-- Type: application/octet-stream, Size: 12601 bytes --]
(define-widget 'key-definition 'lazy
"Key definition.
A list of two components: KEY, BINDING.
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 BINDING, which must also be a command."
:tag "Key Definition" :indent 1 :offset 0
:type
'(list
(choice
(key-sequence :tag "Key" :value [ignore])
(restricted-sexp :tag "Command to remap"
:match-alternatives (commandp) :value ignore))
(sexp :tag "Command")))
(defun custom-create-keymap-option (map)
"Define a user option for keymap MAP."
(interactive
(list (intern (completing-read
"Keymap (symbol): " obarray
(lambda (s) (and (boundp s) (keymapp (symbol-value s))))
nil nil 'variable-name-history))))
(when (boundp map)
(when (keymap-prompt (symbol-value map))
(error "Cannot create option for a menu keymap"))
(unless (listp (cadr (symbol-value map))) ; <====================== 1
(error "Cannot create option for a non-sparse keymap"))) ; <===== 1
(let ((opt-name (intern (concat (symbol-name map) "-defs")))
(defs ()))
(if (not (and (symbolp map) (boundp map) (keymapp (symbol-value map))))
(set map (make-sparse-keymap)) ; New map.
;; Print key bindings in a temp buffer, wrap each with `kbd', then read & eval.
(with-temp-buffer
(princ (substitute-command-keys
(concat "\\{" (symbol-name map) "}")) (current-buffer))
(goto-char (point-min))
(with-syntax-table emacs-lisp-mode-syntax-table
(while (re-search-forward
"^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(let ((col (- (match-end 1) (match-beginning 1))))
(while (and (not (eobp)) (not (looking-at "\n\\s-*\n")))
(if (or (eolp) ; Delete these kinds of lines.
(looking-at "^\\S-+.+\\s-+Prefix Command$")
(looking-at ".+(binding currently shadowed)$")
(looking-at "^\\s-+(that binding is currently \
shadowed by another mode)$")
(looking-at "^.+\\s-+[?][?]")) ; This is from a `lambda'.
(delete-region (line-beginning-position) (1+ (line-end-position)))
(end-of-line)
(skip-chars-backward "^ \t\n")
(looking-at "\\(\\sw\\|\\s_\\)+$") ; Cmd name or last part of key.
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0)))
(cmd-beg (match-beginning 0))
eokey-pos)
(cond ((or (fboundp sym) ; Command or pseudo-command.
(memq sym '(mouse-face ignore-event prev-buffer)))
(end-of-line)
(insert ")")
(goto-char cmd-beg)
(skip-chars-backward " \t")
(setq eokey-pos (point))
(insert "\")") ; +2
(forward-line 0)
(cond ((looking-at
(concat "^\\(\\S-.*\\) \\.\\. \\(.+\\)\")\\s-+"
(symbol-name sym)))
(let ((key1 (match-string 1))
(key2 (match-string 2)))
(do-key-range sym (key-to-char key1)
(key-to-char key2))))
(t
(insert "(,(kbd \"") ; +8
(while (< (point) (+ 8 eokey-pos))
(when (looking-at "\\(\"\\|\\\\\\)")
(insert "\\"))
(forward-char))
(goto-char (+ 10 cmd-beg))
(forward-line))))
(t ; Not a command. Last part of key name.
;; E.g., this might be "Portuguese>" in key description
;; <describe> <describe-language-environment>
;; <European> <Brazilian Portuguese>
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1 col)
(beginning-of-line)
(delete-region (line-beginning-position)
(1+ (line-end-position)))))))
(forward-line)
(if (looking-at "^\\s-+\\S-+$")
(custom-create-keymap-option-1 col)
(forward-line -1)
(delete-region (line-beginning-position)
(1+ (line-end-position 2))))))))))
(goto-char (point-min))
(while (re-search-forward "^key +binding\n\\(-+ +\\)-+\n\n" nil t)
(forward-line -3)
(delete-region (line-beginning-position) (1+ (line-end-position 3))))
(insert "`(\n") (goto-char (point-max)) (insert ")") ; Wrap all bindings.
(goto-char (point-min))
(setq defs (eval (read (current-buffer)))))) ; Create list of key-definitions.
(eval
`(defcustom ,opt-name
',defs
,(format "Customizable keymap for `%s'." map)
:type '(repeat key-definition)
:set #'(lambda (sym defns)
(custom-set-default sym defns)
;; Wipe out the keymap, so user deletions and replacements will
;; take effect.
;; If you try using `global-map', comment out this line first.
(when (keymapp ,map) (setcdr ,map nil)) ; <========= 2
(let (key command)
(dolist (key-def defns)
(setq key (car key-def)
command (cadr key-def))
(if (symbolp key)
(define-key ,map (vector 'remap key) command)
(define-key ,map key command)))))
:initialize #'custom-initialize-set))))
(defun custom-create-keymap-option-1 (col)
(end-of-line)
(skip-chars-backward "^ \t\n")
(when (looking-at "\\(\\sw\\|\\s_\\)+$")
(if (>= (current-column) col)
(let ((sym (intern-soft (match-string 0))))
(cond ((or (fboundp sym)
(memq sym '(mouse-face ignore-event)))
(end-of-line)
(insert ")")
(forward-line -1)
(end-of-line)
(insert "\")") ; +2
(forward-line 0)
(insert "(,(kbd \"") ; +8
(forward-line 2))
(t
(forward-line 0)
(delete-region (line-beginning-position)
(1+ (line-end-position 2)))))))))
;; These three functions are used to convert a range of keys such as "SPC .. ~"
;; to a sequence of kbd entries that can be read to create bindings.
(defun do-key-range (symb ch1 ch2)
"Create kbd entries for the keys (characters) CH1 through CH2."
(delete-region (line-beginning-position) (1+ (line-end-position)))
(while (<= ch1 ch2)
(insert "(,(kbd \"" (char-to-key-string ch1) "\") " (symbol-name symb) ")\n")
(setq ch1 (1+ ch1))))
(defun char-to-key-string (char)
"Return string representation of character CHAR."
(let ((strg (char-to-string char)))
(cond ((eq char ?\ ) (setq strg "SPC"))
((eq char ?\") (setq strg "\\\""))
((eq char ?\\) (setq strg "\\\\")))
strg))
(defun key-to-char (key)
"Convert key representation to character."
(let ((ekey (edmacro-parse-keys key)))
(if (vectorp ekey) (aref ekey 0) (string-to-char ekey))))
;; Tried to fix this so that it would correctly handle key descriptions such as this:
;; "<describe> <describe-language-environment> <European> <Brazilian Portuguese>"
;; But the substituted regexp breaks the correct handling of "M-x <". Needs work.
(defun edmacro-parse-keys (string &optional need-vector)
(let ((case-fold-search nil)
(pos 0)
(res []))
(while (and (< pos (length string))
;; This is the only change I made. Each of these doesn't work for
;; some cases, however - Emacs bug filed.
;; ORIGINAL: (string-match "[^ \t\n\f]+" string pos)
;; DK suggestion: (string-match "[^ \t\n\f<]+\\|<[^>]+>" string pos))
(string-match "[^ \t\n\f<]+\\|<[^>]+>\\|<+" string pos))
(let ((word (substring string (match-beginning 0) (match-end 0)))
(key nil)
(times 1))
(setq pos (match-end 0))
(when (string-match "\\([0-9]+\\)\\*." word)
(setq times (string-to-number (substring word 0 (match-end 1))))
(setq word (substring word (1+ (match-end 1)))))
(cond ((string-match "^<<.+>>$" word)
(setq key (vconcat (if (eq (key-binding [?\M-x])
'execute-extended-command)
[?\M-x]
(or (car (where-is-internal
'execute-extended-command))
[?\M-x]))
(substring word 2 -2) "\r")))
((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
(progn
(setq word (concat (substring word (match-beginning 1)
(match-end 1))
(substring word (match-beginning 3)
(match-end 3))))
(not (string-match
"\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
word))))
(setq key (list (intern word))))
((or (equal word "REM") (string-match "^;;" word))
(setq pos (string-match "$" string pos)))
(t
(let ((orig-word word) (prefix 0) (bits 0))
(while (string-match "^[ACHMsS]-." word)
(incf bits (cdr (assq (aref word 0)
'((?A . ?\A-\^@) (?C . ?\C-\^@)
(?H . ?\H-\^@) (?M . ?\M-\^@)
(?s . ?\s-\^@) (?S . ?\S-\^@)))))
(incf prefix 2)
(callf substring word 2))
(when (string-match "^\\^.$" word)
(incf bits ?\C-\^@)
(incf prefix)
(callf substring word 1))
(let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
("LFD" . "\n") ("TAB" . "\t")
("ESC" . "\e") ("SPC" . " ")
("DEL" . "\177")))))
(when found (setq word (cdr found))))
(when (string-match "^\\\\[0-7]+$" word)
(loop for ch across word
for n = 0 then (+ (* n 8) ch -48)
finally do (setq word (vector n))))
(cond ((= bits 0)
(setq key word))
((and (= bits ?\M-\^@) (stringp word)
(string-match "^-?[0-9]+$" word))
(setq key (loop for x across word collect (+ x bits))))
((/= (length word) 1)
(error "%s must prefix a single character, not %s"
(substring orig-word 0 prefix) word))
((and (/= (logand bits ?\C-\^@) 0) (stringp word)
;; We used to accept . and ? here,
;; but . is simply wrong,
;; and C-? is not used (we use DEL instead).
(string-match "[@-_a-z]" word))
(setq key (list (+ bits (- ?\C-\^@)
(logand (aref word 0) 31)))))
(t
(setq key (list (+ bits (aref word 0)))))))))
(when key
(loop repeat times do (callf vconcat res key)))))
(when (and (>= (length res) 4)
(eq (aref res 0) ?\C-x)
(eq (aref res 1) ?\()
(eq (aref res (- (length res) 2)) ?\C-x)
(eq (aref res (- (length res) 1)) ?\)))
(setq res (edmacro-subseq res 2 -2)))
(if (and (not need-vector)
(loop for ch across res
always (and (if (fboundp 'characterp)
(characterp ch) ; Emacs 23+
(char-valid-p ch)) ; Emacs < 23
(let ((ch2 (logand ch (lognot ?\M-\^@))))
(and (>= ch2 0) (<= ch2 127))))))
(concat (loop for ch across res
collect (if (= (logand ch ?\M-\^@) 0)
ch (+ ch 128))))
res)))
^ permalink raw reply [flat|nested] 43+ messages in thread
* Key/menu bug? (was: customizing key definitions with Customize)
2008-05-18 1:22 ` Drew Adams
@ 2008-05-18 9:07 ` David Kastrup
0 siblings, 0 replies; 43+ messages in thread
From: David Kastrup @ 2008-05-18 9:07 UTC (permalink / raw)
To: Drew Adams; +Cc: 'Juri Linkov', rms, emacs-devel
"Drew Adams" <drew.adams@oracle.com> writes:
> 4. There still is an `edmacro-parse-keys' bug that prevents some keys
> from being handled correctly. With the attached code, the only such
> key in the global map is, I think, "M-<" - see the separate bug
> report. Someone more knowledgeable will need to fix
> `edmacro-parse-keys' the right way.
I was trying to guess whether there can be something like M-<menu-bar>
or similarly contrived, so I did C-h k, held control and selected a menu
entry.
This gave me
<menu-bar> <buffer> C-@ runs the command (lambda nil (interactive)
(switch-to-buffer #<buffer *wide reply to Drew Adams*>)), which is an
interactive Lisp function.
It is bound to <menu-bar> <buffer> C-@.
(anonymous)
Not documented.
This can't be right, can it? It is on
GNU Emacs 23.0.60.13 (i686-pc-linux-gnu, GTK+ Version 2.12.9) of
2008-05-13 on lola
--
David Kastrup, Kriemhildstr. 15, 44793 Bochum
^ permalink raw reply [flat|nested] 43+ messages in thread
end of thread, other threads:[~2008-05-18 9:07 UTC | newest]
Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-11 19:40 customizing key definitions with Customize Drew Adams
2008-05-11 22:02 ` Lennart Borgman (gmail)
2008-05-11 22:28 ` Drew Adams
2008-05-11 22:40 ` Lennart Borgman (gmail)
2008-05-11 23:02 ` Drew Adams
2008-05-11 23:09 ` Lennart Borgman (gmail)
2008-05-11 23:19 ` Drew Adams
2008-05-11 23:23 ` Lennart Borgman (gmail)
2008-05-11 23:34 ` Drew Adams
2008-05-12 20:42 ` Lennart Borgman (gmail)
2008-05-14 5:24 ` Drew Adams
2008-05-12 8:59 ` Reiner Steib
2008-05-12 20:58 ` Drew Adams
2008-05-12 11:20 ` Richard M Stallman
2008-05-12 14:01 ` Drew Adams
2008-05-13 0:03 ` Juri Linkov
2008-05-13 0:40 ` Lennart Borgman (gmail)
2008-05-13 14:59 ` Richard M Stallman
2008-05-13 23:59 ` Juri Linkov
2008-05-14 1:10 ` Stefan Monnier
2008-05-14 16:40 ` Richard M Stallman
2008-05-15 4:46 ` Drew Adams
2008-05-15 17:39 ` Richard M Stallman
2008-05-16 8:01 ` Drew Adams
2008-05-16 17:46 ` Richard M Stallman
2008-05-16 18:00 ` David Kastrup
2008-05-16 23:58 ` Drew Adams
2008-05-17 5:00 ` Richard M Stallman
2008-05-16 7:51 ` Drew Adams
2008-05-18 1:22 ` Drew Adams
2008-05-18 9:07 ` Key/menu bug? (was: customizing key definitions with Customize) David Kastrup
2008-05-13 15:07 ` customizing key definitions with Customize David Reitter
2008-05-13 19:05 ` David Kastrup
2008-05-14 5:23 ` Drew Adams
2008-05-13 5:16 ` Richard M Stallman
2008-05-14 5:23 ` Drew Adams
2008-05-14 16:39 ` Richard M Stallman
2008-05-15 4:36 ` Drew Adams
2008-05-15 17:39 ` Richard M Stallman
2008-05-16 8:02 ` Drew Adams
2008-05-16 17:46 ` Richard M Stallman
2008-05-16 23:58 ` Drew Adams
2008-05-12 20:42 ` Lennart Borgman (gmail)
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).