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.
Can you explain what is the role of
linum-mode
? – Dror – 2013-08-21T19:16:11.917@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 – 2013-08-21T19:17:24.833Seems 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 – 2013-10-09T11:54:06.670
@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 – 2013-10-09T15:18:32.557