;;; paired-insert.el --- self insert pairs like () or "" depending on mode ;; Copyright (C) 1993 by Free Software Foundation, Inc. ;; Author: Daniel Pfeiffer ;; Keywords: self-insert ;; This file is part of GNU Emacs. ;; GNU Emacs is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; GNU Emacs is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ;;; Commentary: ;; One command and some parameters allowing modes to set up meaningful ;; pairs where a closing symbol gets inserted after the point when its ;; corresponding opening one is typed. ;; Various modes can set this up. The user can totally disable this. ;;; Code: (defvar self-insert-normally t "*If this is non-nil pairing is never attempted. Otherwise those modes that set up self-insert-paired-alist by binding self-insert-maybe-paired to some keys will attempt this.") (defvar self-insert-no-pairing '(lambda ()) "Attempt pairing if this function returns nil, before inserting. This allows for context-sensitive checking whether pairing is appropriate. If this raises an error, no inserting at all is done. function arguments: ()") (defvar self-insert-paired-alist () "An override alist of pairing partners matched against last-command-char. Each alist element is (character string-or-character [ . offset]). If it matches, string-or-character is inserted instead of the default pair, and the point is moved back offset or 1 positions. Elements might be '(?` ?') or '(?` \"`''\" . 2) or '(?( \" )\" . 2)") ;;;###autoload (defun self-insert-maybe-paired (arg) "Insert the character you type ARG times. If self-insert-normally is non-nil this behaves like self-insert-command. With no ARG, and if self-insert-no-pairing returns nil, pairing is performed. If a match is found in self-insert-paired-alist, that is inserted, else the defaults are used. These are (), [], {}, <> and `' for the symmetrical ones, and the same character twice for the others. arguments: (arg)" (interactive "*P") (if (or arg self-insert-normally) (self-insert-command (prefix-numeric-value arg)) (setq arg (or (cdr (or (assq last-command-char self-insert-paired-alist) (assq last-command-char '((?( ?)) (?[ ?]) (?{ ?}) (?< ?>) (?` ?'))))) (list last-command-char))) (or (prog1 (funcall self-insert-no-pairing) (insert last-command-char)) (insert (car arg)) (backward-char (or (cdr arg) 1))))) ;;;###autoload ;; a more serious example can be found in sh-script.el (defun mirror-mode () "This major mode is an amusing little example of paired insertion. All printable characters do a paired self insert, while the others work normally. arguments: ()" (interactive) (kill-all-local-variables) (make-local-variable 'self-insert-normally) (make-local-variable 'self-insert-no-pairing) (make-local-variable 'self-insert-paired-alist) (setq major-mode 'mirror-mode mode-name "Mirror" ;; in the middle column insert one or none if odd window-width self-insert-no-pairing '(lambda () (if (>= (current-column) (/ (window-width) 2)) ;; insert both on next line (next-line 1) ;; insert one or both? (= (* 2 (1+ (current-column))) (window-width)))) ;; mirror these the other way round as well self-insert-paired-alist '((?) ?() (?] ?[) (?} ?{) (?> ?<) (?/ ?\\) (?\\ ?/) (?` "`''" . 2) (?' "'``" . 2)) ;; in this mode we exceptionally ignore the user, else it's no fun self-insert-normally nil) (let ((map (make-keymap)) (i ? )) (use-local-map map) (setq map (car (cdr map))) (while (< i ?\^?) (aset map i 'self-insert-maybe-paired) (setq i (1+ i)))) (run-hooks 'mirror-mode-hook))