I'm attempting to override a mode-specific key binding, but my attempt so far hasn't been able to reassign it.

I use the M-j,k,i,l to navigate instead of the regular C-n, C-p etc. I find it to be a lot faster.

However, M-j is bound automatically to c-indent-new-comment-line when editing in any C-like language. I'd like for M-j to be bound to backward-char.

Here are my attempt so far to rebind this function:

(add-hook 'c-mode-common-hook t
          ;; rebind key
          (lambda () (global-set-key (kbd "M-j") 'backward-char)))

Does anyone know what I'm doing wrong?

  • 2
    In general, a user may remove a mode-specific binding by setting it to nil, instead of trying to trump it with global. Major trumps global, and minor trumps major. In this particular case, however, perhaps something else is needed and one of the local forum experts can teach us all a thing or two. The current key is bound by the following code: (substitute-key-definition 'indent-new-comment-line 'c-indent-new-comment-line c-mode-base-map global-map) Perhaps simply creating a major mode binding is sufficient?: (define-key c-mode-base-map (kbd "M-j") 'backward-char)
    – lawlist
    Jun 7 '15 at 3:21
  • The define-key worked! Thanks for the great explanation. If you move this to an answer I'll accept it.
    – David
    Jun 7 '15 at 5:12
  • 2
    In your example, the arguments are out of order, having t before the function actually adds t to the hook list not the function, effectively doing nothing. Jul 7 '15 at 20:27

global-set-key, as the name suggests, changes a global key binding. Local bindings, determined by the buffer's mode override global bindings. See the Emacs manual for an introduction to multiple keymaps and the Elisp manual for the full story. What you're doing here is each time you open a file in C mode, change the global binding for M-j, which doesn't make sense.

Since you want to change the binding of M-j in the CC mode familiy, you need to change it in c-mode-base-map (that's what c-mode-map is based on). You can check that c-mode-base-map is indeed where M-j is bound, to c-indent-new-comment-line.

To override that binding, use the define-key function. You need to invoke it after c-mode-base-map is defined, which is done when cc-mode is loaded. Use with-eval-after-load in Emacs ≥24.4, or eval-after-load in older versions.

(defun my-after-load-cc-mode ()
  (define-key c-mode-base-map (kbd "M-j") 'backward-char))
(eval-after-load "cc-mode" 'my-after-load-cc-mode)

If you want M-j to be bound to backward-char all the time, then you need to define it as a global binding, and to stop major modes from overriding it. To remove a binding from a keymap, bind the key to nil.

(global-set-key "M-j" 'backward-char)
(defun my-after-load-cc-mode ()
  (define-key c-mode-base-map (kbd "M-j") nil))
(eval-after-load "cc-mode" 'my-after-load-cc-mode)
  • It looks like you've been scheming a little too recently. Jul 7 '15 at 20:29
  • @JordonBiondo cvs log .sawfishrc |grep '^date' as a matter of fact, yes. Did I get them all? Jul 7 '15 at 20:37

As spotted by Jordon, your function is actually ignored because you pass your arguments in the wrong order. That's the first problem, so first rewrite:

(add-hook 'c-mode-common-hook
          ;; rebind key
          (lambda () (global-set-key (kbd "M-j") 'backward-char))

Note that the t arg is probably of no importance here anyway and you can likely drop it. Of course, this still won't work, since it will just repeatedly change the global binding of M-j to backward-char but I suspect that this is already the binding you gave it elsewhere, so the hook function wil end up not changing anything: you can to remove/override the local binding, not change the global binding. So just remove the local binding instead:

(add-hook 'c-mode-common-hook
          ;; rebind key
          (lambda () (local-set-key (kbd "M-j") nil)))

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.