Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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 http://tex.stackexchange.com/a/1985/412

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

share|improve this question

2 Answers 2

up vote 1 down vote accepted

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 (me@aaron-miller.me)

(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.

share|improve this answer
    
Can you explain what is the role of linum-mode? –  Dror Aug 21 '13 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.) –  Aaron Miller Aug 21 '13 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 '13 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. –  Aaron Miller Oct 9 '13 at 15:18

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™©.

share|improve this answer
    
Sorry for the downvote, but "naive" understates the depth of the problem here. See my answer, to be posted momentarily. –  Aaron Miller Aug 21 '13 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.) –  Aaron Miller Aug 21 '13 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 '13 at 14:56
    
@Dror I've just replaced my answer with a minor mode that should do what you want. –  Aaron Miller Aug 21 '13 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 '13 at 19:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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