9

I'm trying to use just a few functions from paredit, without loading all the keybindings. Looking at paredit.el, the only keymap I found was paredit-mode-map, so I tried this.

(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)

It didn't change the keybinding (As checked with C-h k), but the variable paredit-mode-map was changed.

I also tried

(eval-after-load "paredit"
  '(progn
     (setq paredit-mode-map (make-sparse-keymap))
     (define-key paredit-mode-map (kbd "<C-M-left>") 'paredit-backward)))

and then turning paredit on and off, with the same result.

Previously, making changes to a keymap directly has always worked for me. What is going on here?

Edit:

I succeeded in changing the keymap by doing this:

; Remove old paredit bindings
(defun take-from-list (condp list)
  "Returns elements in list satisfying condp"
  (delq nil
    (mapcar (lambda (x) (and (funcall condp x) x)) list)))
(setq minor-mode-map-alist 
      (take-from-list 
        (lambda (x) (not (eq (car x) 'paredit-mode))) 
        minor-mode-map-alist))

; Create new paredit-mode-map
(setq paredit-mode-map (make-sparse-keymap))
(define-key paredit-mode-map (kbd "<C-kp-enter>") 'paredit-backward)

; Add the new paredit-mode-map to minor-mode-map-alist
(setq minor-mode-map-alist (append
                (list (append (list 'paredit-mode) paredit-mode-map))
                minor-mode-map-alist))

So it seems minor-mode-map-alist is a the variable used for lookup. I'm sure there are more elegant ways to change the keybindings, but I wanted to understand more of how keybindings work in emacs.

snowape
  • 1,274
  • 10
  • 23
  • You may want to look at [Smartparens](https://github.com/Fuco1/smartparens). It covers pretty much all of Paredit (and more), and doesn't enforce specific keybindings. You have the choice between two built-in sets of bindings, but you can easily define [your own](https://github.com/lunaryorn/stante-pede/blob/76310ff6666afe9898b9de428806ebb24fca4a48/init.el#L623). –  May 17 '13 at 16:33

3 Answers3

5

Paredit uses a different way of defining the keymap. Whereas most minor modes define the keymap in the variable definition, Paredit calls paredit-define-keys on top-level, and thus forcibly initializes the keymap.

In other words, you cannot prevent Paredit from setting up its bindings. You need to remove all keybindings in the keymap with (define-key paredit-mode-map … nil) to get rid of these.

Edit: You cannot “reset” keymaps by assigning a new keymap to the variable. (setq paredit-mode-map …) will change the variable paredit-mode-map, it will not change the actual keymap being used by Paredit mode.

The binding of this variable is only evaluated once at definition time, i.e. during the evaluation of define-minor-mode. This macro internally calls add-minor-mode, and passes to this function the current value of the keymap variable. All future use of the mode refers to this keymap only. The keymap variable is never again evaluated by the minor mode, thus changing its binding has no effect whatsoever.

If you want to change the keymap, you have to re-bind the variable before define-minor-mode is evaluated, i.e. before the corresponding library is loaded. Changing it in an eval-after-load form is hence completely useless.

Normally, changing the keymap variable before the library is loaded works well, because most modes define the keymap within the body of defvar. defvar however will not change the value of a variable if it already has a value. Thus, if the variable already has a keymap, it won't be touched.

However, as I said, Paredit doesn't respect this pattern, and instead forcibly add its bindings to the keymap. Thus changing it is pointless, because Paredit will add its bindings anyway.

As I said, you have to manually clear the existing keymap by un-defining every single of its keys.

TL;DR: Use Smartparens, really! It covers all of Paredit, it's flexible, it's powerful, it's extensible, in short it's just good. And it lets you choose whatever keybindings you want.

  • But looking at paredit-define-keys, all it does is using `(define-key paredit-mode-map ...)` to set up the keys. So why doesn't the keybindings disappear when paredit-mode-map is empty? How can the keybindings work when paredit-mode-map is empty? – snowape May 17 '13 at 17:26
  • To put it another way: I understand that I cant prevent keybindings from being set up, but I don't understand why I cant change them afterwards. – snowape May 17 '13 at 17:37
  • You cannot reset keymaps with `setq`. I have updated my answer to clarify this point. –  May 17 '13 at 22:10
  • 3
    Smartparens is philosophically different to paredit. Paredit changes your mindset to be sexp centric. Smartparens does not seem to care. Personally, I had great difficulty adjusting to paredit's philosophy, but now that I have, I will never go back. – event_jr May 18 '13 at 04:12
  • @event_jr Say rather that Smartparens does not force a philosophy upon the user. The built-in keybindings do not force you into Sexp-centric editing, but merely enhance the editor to provide sexp-centric editing at your wish. By choosing a proper set of keybindings, however, you can use Smartparens just exactly like Paredit. I have replaced Paredit with Smartparens, and found no loss of convenience. But of course, YMMV. –  May 18 '13 at 09:03
  • 3
    "force" is accurate. I benefitted from having been forced though. – event_jr May 18 '13 at 14:23
4

Read lunaryorn's answer first. This is just a clarification.

what exactly is broken with your code

(setq paredit-mode-map (make-sparse-keymap))

This will not work with any already loaded mode. paredit is not special.

Paredit's disrespect of defvar does mean that it's very difficult to unbind all keys as you wish.

event_jr
  • 17,467
  • 4
  • 47
  • 62
  • You are mistaken: Smartparens does **not** define keys the same way as Paredit. In fact, it does **not** define any keys **at all** by default, until you call one of the keybindings functions **explicitly** in your init file. As I said in my comment to the question, you can completely ignore the built-in commands, and define your own keymap. I have done so. –  May 18 '13 at 09:05
3

Why don't you just create your own minor mode? All that Paredit Mode does is provide key bindings, so if you clobber its keymap it does nothing for you. The paredit commands are available whether you use Paredit Mode or not. (Nobody `forces' key bindings on you!)

(defvar snowape-mode-map (make-sparse-keymap))
(define-minor-mode snowape-mode
  "Minor mode for snowape's favorite pareditoid key bindings.
\\<snowape-mode-map>"
  :lighter " Snowape")
(define-key snowape-mode-map (kbd "C-M-<left>") 'paredit-backward)
...

Alternatively, you could just use local-set-key in your favorite mode hooks:

(add-hook 'lisp-mode-hook
  (defun lisp-mode-snowape-setup ()
    (local-set-key (kbd "C-M-<left>") 'paredit-backward)))
  • Yes, I use local-set-key like this. The reason I created the question was mostly because I was curious how keybindings in emacs works. – snowape Jun 13 '13 at 14:38
  • 1
    According to emacswiki *"ParEdit helps keep parentheses balanced"* so this answer is probably incorrect. – The Unfun Cat Feb 19 '15 at 13:34