1

I'm having endless problems with the details of keymap binding syntax.

This style works fine with define-key, and kbd on my own keymap name:

;;; make my own keymap, with prefix C-;
(define-prefix-command 'my-prefix)
(define-key global-map (kbd "C-;") 'my-prefix-pairs)
(setq my-prefix-pairs
      '(
        ((kbd "e")    function-1)
        ((kbd "C-f")  function-2)
        ))
(dolist (pair my-prefix-pairs)
  (define-key my-prefix (eval (car pair)) (cadr pair)))

This style also works fine, with global-set-key and mapc:

;;; Control-C bindings, reserved by Emacs for personal bindings
(mapc
 #'(lambda (x) (global-set-key (car x) (car (cdr x))))
 '(
   ("\C-ce"          my-function-1)
   ("\C-c\C-f"       my-function-2)
   ))

But I just can't this style to work for global-set-key and kbd:

(setq my-prefix-pairs
      '(
        ("e"      function-1)
        ("C-f"    function-2)
        ))
(dolist (pair my-prefix-pairs)
  (global-set-key  (kbd (concat "C-c " (car pair))) (cadr pair)))

What am I doing wrong in the last style? What would work, to bind keys globally in the Control-X-prefix map? I've looked at other keybinding postings on SO, but didn't find anything that worked for this particular problem.

Update 1 for comment below

Very strange to hear from a poster below that this code works with emacs -Q. I can't imagine why other styles work fine, but this style won't work with my init setup.

Anyhow, to answer his question, with the following binding at the top of the binding list,

   ("w"    kill-ring-save)

I get this error from the debugger:

Debugger entered--Lisp error: (error "Key sequence C-c w starts with non-prefix key C-c")
define-key((keymap #^[nil nil keymap ...
                   #^^[3 0 set-mark-command move-beginning-of-line ...
                   #^^[1 0 #^^[2 0 

global-set-key("^Cw" kill-ring-save))  ;;the ^C is a real ^C
(while --dolist-tail-- (setq pair (car --dolist-tail--))
     (global-set-key (kbd (concat "C-c " (car pair))) (cadr pair))
     (setq --dolist-tail-- (cdr --dolist-tail--)))
(let ((--dolist-tail-- kwj-ctl-c-pairs) pair)
  (while --dolist-tail-- (setq pair (car --dolist-tail--))
       (global-set-key (kbd (concat "C-c " (car pair))) (cadr pair))
       (setq --dolist-tail-- (cdr --dolist-tail--))))
eval((let ((--dolist-tail-- kwj-ctl-c-pairs) pair)
     (while --dolist-tail-- (setq pair (car --dolist-tail--))
            (global-set-key (kbd (concat "C-c " (car pair))) (cadr pair))
            (setq --dolist-tail-- (cdr --dolist-tail--)))) nil)

And using emacs -Q and pasting this code into the scratch buffer, I also get a debugger error:

(setq my-prefix-pairs
  '(
    ("e"      function-1)
    ("C-f"    function-2)
    ))
(dolist (pair my-prefix-pairs)
  (global-set-key  (kbd (concat "C-c " (car pair))) (cadr pair)))


Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p (concat "C-c " (car pai$
  read-kbd-macro((concat "C-c " (car pair)))
  #[(keys) "\301^H!\207" [keys read-kbd-macro] 2 1987665]((concat "C-c " (car pair)))
  (kbd (concat "C-c " (car pair)))
  (global-set-key (kbd (concat "C-c " ...)) (cadr pair))

Update 2 after more comments and hacking

After more hacking and the "your code works for me" comment below, I starting stripping everything down in my init, and trying to build up my keybindings from scratch.

I am running Gnu Emacs 24.5.1 as a .dmg app on a recent Mac OSX machine. (But the problem also occurs with the native OSX Emacs v 22.)

Here is one problematic line, for certain (Actually, I show two syntaxes for it). It causes the error if it is in, and I get no errors if it is out.

    ;;        ("C- "     set-mark-command)
    ;;        ("C-SPC "  set-mark-command)

Debugger entered--Lisp error: 
(error "Key sequence C-c w starts with non-prefix key C-c")

Those lines both cause the error, even though a similar syntax "C-SPC" in this line does not. (This line uses define-key global-map, not (global-set-key...).

(define-key global-map (kbd "C-SPC") 'avy-goto-word-or-subword-1)

And I would swear I've had this line in my init for months, with apparently no problem, but it won't work now. (I say this because my fingers automatically go to ctl-c ctl-spc to set the mark..) Neither version works now, and my finger-memory is protesting... :-)

(define-key global-map (kbd "C-c C-SPC") 'set-mark-command)
(global-set-key (kbd "C-c C-SPC") set-mark-command)
  • At least in the last bit of code, you are running over my-prefix-pairs instead of my-ctl-c-pairs. – amitp Jun 25 '16 at 18:49
  • You are correct, and I have fixed the posting. I was pasting together fragments, and trying to use names (my-ctl-c-pairs) to help readers. Apologies. – Kevin Jun 25 '16 at 18:54
  • Your code works for me, starting from emacs -Q. What happens when you do it? – Harald Hanche-Olsen Jun 25 '16 at 19:47
  • Very strange that it works for you. But I suppose it's good news that my code is not far off. In my init file, I only have a few other keybindings ahead of the examples shown here. I tried to change the order in my init file, but it didn't seem to help. – Kevin Jun 25 '16 at 21:01
  • 1
    What Emacs version are you using? I think at some point kbd was changed from macro to function. – npostavs Jun 25 '16 at 21:23
1

Here's the ending story, hopefully expressed in a reproducible way for the Emacs maintainers. The big lesson is NOT to use " " space characters in keybinding syntaxes, even if you've been using " " space characters for many years successfully... :-)

;; This is my ENTIRE .emacs file.

(find-file "~/.emacs")

(global-set-key (kbd (concat "C-c " "t")) 'ct-testregion-toggle)
;; This syntax works because it has no trailing whitespace, and a
;; non-white second keybinding ("t"). Other non-white bindings
;; in the second position such as "C-k" or "C-SPC" will work too.

(setq my-prefix-pairs
  '(
    ("w"    kill-ring-save)
    ;; Control-C w
    ;; This syntax works because it is non-white

    ;; (" "    this-syntax-messes-up-future-bindings)
    ;; Control-C " "
    ;; With this in the file, it messes up following attempts to bind
    ;; to C-c, as is done below in mapc. The error generated by the
    ;; mapc below will be the usual
    ;; "Key sequence C-c SPC starts with non-prefix key C-c"
    ;;
    ;; Global-set-key will apparently bind "C-c" to whatever function
    ;; is named in the binding. C-hk describe-key will show that
    ;; C-c is bound to whatever function is named in the binding.
    ;; For example, here is the line that messed up my bindings:
    ;; (" "   completion-at-point)
    ;; C-hk would report that C-c was bound to completion-at-point.

    ("C- "    this-is-no-error-but-is-undefined)
    ;; Control-C Control-SPC
    ;; This won't cause a debug error, but it won't bind anything
    ;; either. Kind of a null operation.

    ("C-SPC"  kbd-likes-this-syntax)
    ;; Control-C Control-SPC
    ;; This syntax works because it is non-white.
    ))

(dolist (pair my-prefix-pairs)
  (global-set-key (kbd (concat "C-c " (car pair))) (cadr pair)))

(mapc
 '(lambda (x) (global-set-key (car x) (car (cdr x))))
 '(
   ("\C-c "     this-syntax-binds-correctly)
   ;; Control-C " "
   ;; This syntax has worked fine for me over many years,
   ;; with several different Emacs implementations. I tried to
   ;; convert it to use with (kbd " "), and lost about 12 hours
   ;; of productivity running down the problems above.
   ))
  • Always use kbd with the same notation that Emacs itself uses (SPC in this instance). The help for kbd directs you to edmacro-mode which explicitly says "whitespace that separates words is ignored. Whitespace [...] must be written explicitly, as in "foo SPC bar"" – phils Jun 26 '16 at 4:28
  • Yep. Apparently so. (kbd (concat "C-c " " ")) => "^C", which is what global-set-key binds. Of course it would be nice if the two space syntaxes (mapc "\C-c " ...) and (kbd "C-c ") could be interchangeable, but they are not. Oh well, it's all history now. On to other things. – Kevin Jun 26 '16 at 6:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.