2

Currently in emacs I have to type SHIFT-[ and SHIFT-] to get { and } respectively. Typing [ and ] yields [ and ] respectively. I want to swap this behaviour in emacs, namely I want to have:

  • [ and ] will yield { and }
  • SHIFT-[ and SHIFT-] will yield [ and ]

This idea is inspired by https://tex.stackexchange.com/a/1985/412

BONUS: I want this behaviour to apply only for certain major modes.

2 Answers 2

1

If you wanted this behavior throughout Emacs, it'd be trivial to achieve it by using key-translation-map, a keymap provided specifically for this purpose. Wanting to use it only in certain major modes complicates things somewhat. The best way I've found so far to do this is to define a minor mode which performs the translation according to a given keymap, and then add a hook to activate that minor mode along with each major mode to which you want it to apply.

Here's the minor mode definition. Drop this into a file swap-braces.el somewhere in your load path.

;;; swap-braces.el - a minor mode to swap square and curly braces

;;; Installation: 

;; Drop it in your load path and (require 'swap-braces).
;; Possibly also (add-hook 'foo-mode-hook 'swap-braces-mode).

;;; Commentary:

;; The swap function explicitly instructs Linum to schedule an update,
;; if Linum mode is enabled; otherwise, Linum does not automatically 
;; update while Swap-Braces mode is enabled.
;; This seems like it should not be necessary, and I'm uncertain whether 
;; it has greater implications regarding interaction between this mode 
;; and others. 
;; (That is, it makes me worry that something about how I've implemented 
;; this makes it screw up other modes using post-command-hook. Caveat user!)

;;; Author

;; Aaron Miller ([email protected])

(setq swap-braces-map (make-sparse-keymap))

(define-key swap-braces-map (kbd "{") "[")
(define-key swap-braces-map (kbd "}") "]")
(define-key swap-braces-map (kbd "[") "{")
(define-key swap-braces-map (kbd "]") "}")

(define-minor-mode swap-braces-mode
  "When active, swap square braces and curly braces, so that e.g. pressing [
elicits '{', and S-[ elicits '['.

The keymap `swap-braces-map' defines this mode's behavior. It is strongly
recommended that you do not define keys in this map which are not self-
inserting characters; the resulting behavior is indeterminate, but almost
certainly not what you intended."
  :init-value nil
  :lighter " [{"
  (if swap-braces-mode
      (add-hook 'post-command-hook
                'swap-braces-mode-swap)
    (remove-hook 'post-command-hook
                 'swap-braces-mode-swap)))

(defun swap-braces-mode-swap ()
  ;; this worries me
  (if (and (boundp 'linum-mode)
           (not (eq nil linum-mode)))
      (linum-schedule))
  (when (and (eq (char-before) last-command-event)
             (not (window-minibuffer-p (selected-window))))
    (let* ((translation (lookup-key swap-braces-map (string (char-before)))))
      (if (stringp translation)
          (progn
            (backward-delete-char 1)
            (insert translation))))))

(provide 'swap-braces)

It's not perfect; note the caveats regarding linum-mode, and what this odd misbehavior may imply about this mode's effects on others which use post-command-hook. I use several such modes, and haven't seen any problems (other than linum not updating) during testing, but your mileage may vary, so be aware. (Oddly enough, using post-self-insert-hook instead made no difference here; I've settled on post-command-hook because post-self-insert-hook is apparently new with Emacs 24, and it offers no difference in behavior worth abandoning backwards compatibility.)

Then, somewhere in your initialization code, (require 'swap-braces); from now on, you can activate the swapping behavior with M-x swap-braces-mode.

Finally, to activate the minor mode along with a major mode, add it to the major mode's load hook. If the major mode you're using is named 'foo-mode', then you'd add the following to your initialization code:

(add-hook 'foo-mode-hook 'swap-braces-mode)

Adjust to taste; in your case, it'll probably be called latex-mode-hook, but check the mode's documentation to make certain.

Edited on 2013-10-09 to apply translation only when the selected window isn't the minibuffer; see comments.

4
  • Can you explain what is the role of linum-mode?
    – Dror
    Aug 21, 2013 at 19:16
  • @Dror It's a (potentially global) minor mode, included in the GNU Emacs standard library, which provides line numbers in the left-hand fringe of windows where it's active. (Linum on EmacsWiki; screenshot from the developer's (rather minimal) site; source.) Aug 21, 2013 at 19:17
  • Seems like this solution messes up the behavior of those keys. For example, when doing a regexp search, things are not stable, or when inserting something to the minibuffer in general... I did not expect it to be such a big problem...
    – Dror
    Oct 9, 2013 at 11:54
  • @Dror Translating keystrokes isn't a big problem; doing it only in certain contexts gets tricky fast. I've just edited swap-braces-mode-swap so as not to translate strokes in the minibuffer; that should give you the behavior you're looking for. I would further strongly advise learning some Emacs Lisp; what I've posted here is more of a starting point than a complete solution, which means you'll probably want to hack it to taste. The language isn't hard to learn, and how forbidding and alien you find Emacs is inversely proportional to how well you know Emacs Lisp. Oct 9, 2013 at 15:18
1

Lets see...

M-x describe-key [
\\    [ runs the command self-insert-command ...
M-x describe-key
\\    { runs the command self-insert-command ...

It looks like we can just swap them naively by adding

(global-set-key (kbd "{") (lambda () (interactive) (insert "[")))

to .emacs. For specific modes, add things like that to the appropriate mode-hook instead of setting them globally. So,

(add-hook 'some-mode-hook
          (lambda ()
             (define-key some-mode-map (kbd "{") (lambda () (interactive) (insert "[")))
             ...))

I get the feeling this isn't really the best solution though. If you use things like autopairs or paredit with those brace styles, Odd Things Will Happen™©.

8
  • Sorry for the downvote, but "naive" understates the depth of the problem here. See my answer, to be posted momentarily. Aug 21, 2013 at 14:42
  • On the other hand, key-translation-map doesn't look like it can be made mode-specific, so that's not an ideal solution either; un-downvoted. (It's still not a good idea to override key behavior this bluntly, though.) Aug 21, 2013 at 14:49
  • At the moment I want to have this swap only in LaTeX-mode. I did not evaluate whether I want it in other modes or not. Thus, the bonus part is somehow important. I'll wait a bit longer.
    – Dror
    Aug 21, 2013 at 14:56
  • @Dror I've just replaced my answer with a minor mode that should do what you want. Aug 21, 2013 at 16:25
  • This solution is light and easy to implement. However, due to @AaronMiller comment it seems like this solution can (I fail to understand how) cause problems. Aaron's solution works as well.
    – Dror
    Aug 21, 2013 at 19:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .