From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Alex Schroeder Newsgroups: gmane.emacs.devel Subject: Re: Customizing key bindings (was: Re: [CVS] f7, f8 bound..) Date: Wed, 04 Sep 2002 02:45:45 +0200 Sender: emacs-devel-admin@gnu.org Message-ID: <87y9aipop2.fsf@emacswiki.org> References: <200208271621.g7RGLNm30516@rum.cs.yale.edu> <5xhehfe3aj.fsf@kfs2.cua.dk> <874rdfaytt.fsf@pot.cnuce.cnr.it> <5xvg5sh06u.fsf@kfs2.cua.dk> <20020830235528.GA13207@gnu.org> <87ofbji88u.fsf@emacswiki.org> <87sn0scb0b.fsf@emacswiki.org> <87bs7er99v.fsf@emacswiki.org> <877ki2r8nr.fsf@emacswiki.org> NNTP-Posting-Host: localhost.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: main.gmane.org 1031100216 8902 127.0.0.1 (4 Sep 2002 00:43:36 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Wed, 4 Sep 2002 00:43:36 +0000 (UTC) Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by main.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 17mOGc-0002JS-00 for ; Wed, 04 Sep 2002 02:43:34 +0200 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.12 #1 (Debian)) id 17mOpY-0006cf-00 for ; Wed, 04 Sep 2002 03:19:41 +0200 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.10) id 17mOI3-0002Vf-00; Tue, 03 Sep 2002 20:45:03 -0400 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.10) id 17mOGp-0002IF-00 for emacs-devel@gnu.org; Tue, 03 Sep 2002 20:43:47 -0400 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.10) id 17mOGm-0002I1-00 for emacs-devel@gnu.org; Tue, 03 Sep 2002 20:43:46 -0400 Original-Received: from relay01.cablecom.net ([62.2.33.101]) by monty-python.gnu.org with esmtp (Exim 4.10) id 17mOGl-0002Hx-00 for emacs-devel@gnu.org; Tue, 03 Sep 2002 20:43:43 -0400 Original-Received: from smtp.swissonline.ch (mail-4.swissonline.ch [62.2.32.85]) by relay01.cablecom.net (8.12.5/8.12.5/SOL/AWF/MXRELAY/20020820) with ESMTP id g840hg20016036 for ; Wed, 4 Sep 2002 02:43:42 +0200 (CEST) (envelope-from alex@emacswiki.org) Original-Received: from confusibombus (dclient217-162-239-43.hispeed.ch [217.162.239.43]) by smtp.swissonline.ch (8.11.6/8.11.6/SMTPSOL/AWF/2002040101) with ESMTP id g840heH10731 for ; Wed, 4 Sep 2002 02:43:40 +0200 (MEST) Original-Received: from alex by confusibombus with local (Exim 3.35 #1 (Debian)) id 17mOIj-00009i-00 for ; Wed, 04 Sep 2002 02:45:45 +0200 Original-To: emacs-devel@gnu.org X-Face: ^BC$`[IcggstLPyen&dqF+b2'zyK#r.mU*'Nms}@&4zw%SJ#5!/7SMVjBS7'lb;QK)|IPU5U'o1'522W4TyzB3Ab*IBo^iw]l4|kUbdZuUDO6=Um-.4IzhNiV'B"@K#jy_(wW|Zbk[34flKY^|PrQ?$u2\fKg^]AY>wOX#H32i In-Reply-To: <877ki2r8nr.fsf@emacswiki.org> (Alex Schroeder's message of "Wed, 04 Sep 2002 00:49:12 +0200") Original-Lines: 182 User-Agent: Gnus/5.090008 (Oort Gnus v0.08) Emacs/21.2.90 (i686-pc-linux-gnu) Errors-To: emacs-devel-admin@gnu.org X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.devel:7413 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:7413 Hm, I am a bit confused. The following is for people who want to help me fix the code. Here is what happens: I have a defkeymap macro now, that seems to do the right thing. See the test keymap at the end. The defkeymap creates a keymap and uses the value given as the standard-value. When you use customize, however, it does not use the variable value of the keymap but the custom-keymap property, which is nil. When you add a keybinding, the custom-keymap property holds a binding such as (("3" buffer-menu)). The variable-value of the keymap is now a key map that holds the binding for 3, and inherits from the standard-value. Cool, so far. Everything seems to work. It even saves the correct customization (only the binding for 3, not the entire keymap). Here comes the problem, now. When you customize the variable a second time, custom detects a mismatch. And I cannot discover what the problem is. I have started playing with the get and set methods to figure out what is going on, but as far as I can tell, (("3" buffer-menu)) should be a legal value for customization. Per, do you know the answer? I am too tired right now to keep at it. :) Alex. ;;; cus-key.el -- Customize support for changing key bindings. (require 'wid-edit) (defvar custom-global-keymap (let ((map (make-sparse-keymap))) (set-keymap-parent map global-map) map) "Global keymap for use by Customize. This is automatically generated from `global-key-bindings', you should never change this manually. Instead, change either `global-map' from Lisp or `global-key-bindings' from Customize.") (defun quoted-key-insert (key) "Insert a string representation of the next key typed. The string representation is a representation understood by `read-kbd-macro'." (interactive "KPress a key: ") (insert (edmacro-format-keys key))) (defvar key-sequence-widget-map (let ((map (make-sparse-keymap))) (set-keymap-parent map widget-field-keymap) (define-key map (kbd "C-q") 'quoted-key-insert) map) "Keymap for the `key-sequence' widget.") (define-widget 'key-sequence-field 'string "Field for entering key bindings." :tag "Key sequence" :keymap key-sequence-widget-map) (define-widget 'key-sequence-button 'push-button "Button for entering key bindings." :tag "Key sequence" :action 'key-sequence-button-action) (defun key-sequence-button-action (widget &optional event) (let ((key (read-key-sequence "Press key sequence: "))) (widget-value-set (widget-get widget :parent) (edmacro-format-keys key)) (widget-setup))) (define-widget 'key-sequence 'group "Widget for entering key bindings." :tag "Read key sequence" :value "" :value-create 'key-sequence-value-create :value-delete 'widget-children-value-delete :value-get 'widget-choice-value-get) (defun key-sequence-value-create (widget) (let ((button (widget-create-child widget '(key-sequence-button))) (field (widget-create-child-value widget '(key-sequence-field :format " %v") (widget-get widget :value)))) (widget-put widget :children (list field)) (widget-put widget :buttons (list button)))) (define-widget 'command 'function "An interactive Lisp function." :complete-function (lambda () (interactive) (lisp-complete-symbol 'commandp)) :prompt-match 'commandp :match-alternatives '(commandp) :validate (lambda (widget) (unless (commandp (widget-value widget)) (widget-put widget :error (format "Invalid function: %S" (widget-value widget))) widget)) :value 'ignore :tag "Command") (defmacro defkeymap (symbol map doc &rest args) "Define SYMBOL to be a keymap with value MAP. DOC is the keymap documentation." ;; It is better not to use backquote in this file, ;; because that makes a bootstrapping problem ;; if you need to recompile all the Lisp files using interpreted code. (nconc (list 'custom-declare-keymap (list 'quote symbol) (list 'quote map) doc) args)) (defun custom-declare-keymap (symbol map doc &rest args) "Like `defkeymap', but SYMBOL and MAP are evaluated as normal arguments. MAP should be an expression to evaluate to compute the default value, not the default value itself. The DOC string will be expanded with some standard instructions for customization." ;; Keymaps are variables. The only difference is that we know lots ;; of defcustom properties already. (setq doc (concat doc "\n While entering the name of a key, you can either type keys yourself just as they appear in the manual, as in C-c a. You must use angle brackets for function keys, as in . You can also hit C-q and type the key. C-q will insert the correct string representation for you. For longer sequences, you can also invoke the [Key sequence] button, and type the entire key sequence directly. While entering the name of the command, you can use M-TAB to complete it.")) (apply 'custom-declare-variable symbol map doc :type '(repeat (group key-sequence command)) :set 'custom-set-keymap :get 'custom-get-keymap args)) (defun custom-set-keymap (sym bindings) "Update keymap SYM with BINDINGS. This creates a new keymap based on BINDINGS, and sets the parent of that new keymap to the standard-value of SYM. This is set as the new variable value of SYM. At the same time, the additions by themselves are stored in the custom-keymap property." (let ((org (eval (car (get sym 'standard-value)))) (map (make-sparse-keymap))) (set-keymap-parent map org) ;; When defkeymap is called for the first time, BINDINGS is the ;; standard-value. When customized, BINDINGS is no longer a ;; keymap but an alist of bindings. (unless (equal bindings org) (mapc (lambda (bind) (define-key map (read-kbd-macro (car bind)) (cadr bind))) bindings) (put sym 'custom-keymap (list bindings))) (set-default sym map))) (defun custom-get-keymap (sym) "Return the additions to the standard-value of keymap SYM. These additions are stored in the custom-keymap property by `custom-set-keymap'." (car (get sym 'custom-keymap))) ;; Example: (defkeymap my-keymap (let ((map (make-sparse-keymap))) (define-key map (read-kbd-macro "") 'bbdb) map) "Keymap to demonstrate `defkeymap'.") ;; my-keymap ;; (keymapp my-keymap) ;; (custom-get-keymap 'my-keymap) ;; (put 'my-keymap 'custom-keymap nil) ;; (get 'my-keymap 'standard-value) ;; (customize-option 'my-keymap) ;; (unintern 'my-keymap) (provide 'cus-key) ;;; cus-key.el ends here