parenthesis.el

Download

;;; parenthesis.el --- Insert pair of parenthesis

;; Copyright (C) 2007-2008  khiker

;; Author: khiker <khiker.mail+elisp@gmail.com>
;;         plus   <MLB33828@nifty.com>
;; Keywords: lisp

;; This file 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 3, or (at your option)
;; any later version.

;; This file 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, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;; Insert pair of parenthesis.
;; If region is active and transient-mark-mode is not nil, insert
;; enclosing strings at region boundaries.
;; If the letter before the point is a backslash this packages's
;; functions do not work.
;; (This behavior is to make it easy that you write regular expression.)
;; In that case, packages functions work as the normal self-insert-command.

;; Functions:

;; style of {}   : parenthesis-insert-braces
;; style of []   : parenthesis-insert-brackets
;; style of ()   : parenthesis-insert-parens
;; style of ''   : parenthesis-insert-single-quotation
;; style of ""   : parenthesis-insert-double-quotation
;; style of <>   : parenthesis-insert-angle

;; style of `'   : parenthesis-insert-grave-and-quotation

;; style of {  } : parenthesis-insert-braces2
;; style of [  ] : parenthesis-insert-brackets2
;; style of (  ) : parenthesis-insert-parens2
;; style of '  ' : parenthesis-insert-single-quotation2
;; style of "  " : parenthesis-insert-double-quotation2
;; style of <  > : parenthesis-insert-angle2

;; Variables:

;; parenthesis-func-alist :
;;
;;   list of functions.
;;
;; parenthesis-insert-ignore-backslash :
;;
;;   If non-nil, insert pair of parensis even a backslash
;;   exists bofore point.
;;
;; parenthesis-push-mark :
;;
;;   Non-nil means to push mark to end point of close paren
;;   when region has been selected.
;;   Default value is t.

;; Prefix Arg Example:

;; C- - C-4 M-x parenthesis-insert-parens => ((((
;; C-0      M-x parenthesis-insert-parens => (
;; C-4      M-x parenthesis-insert-parens => (((())))

;; Example of Setting:

;; This package provide functions only.
;; So, it is necessary to do key setting by yourself.
;; If you do key setting as a whole, you can use a
;; parenthesis-register-keys function.
;; Usage example of this function is as follows.
;;
;; (add-hook
;;  'scheme-mode-hook
;;  (lambda()
;;    (parenthesis-register-keys "(\"[" scheme-mode-map)))
;;
;; This do key settings for scheme-mode.
;; In this, it insert a group of (, " and [ in a mass.
;; And, if c-mode, it will be as follows.
;;
;; (add-hook
;;  'c-mode-hook
;;  (lambda()
;;    (parenthesis-register-keys "{('\"[" c-mode-map)))
;;
;; In this, it insert a group of {, (, ', " and [ in a mass.
;;
;; And, if you want to insert a <div></div> in a mass,
;; (and the point is just after <div>.)
;; add the following lines in your ~/.emacs.
;;
;; (add-to-list 'parenthesis-func-alist
;;              '(parenthesis-insert-divs "<div>" "</div>"))
;; (parenthesis-init)
;;
;; The point position after inserting can be set.
;; The following setting is the point is not after the linefeed.
;; The point is after the '>'.
;;
;; (add-to-list 'parenthesis-func-alist
;;              '(parenthesis-insert-divs "<div>\n" "</div>" 5))
;; (parenthesis-init)

;; Difference of insert-pair:

;; Main Difference is follows.
;;
;;   - insert-pair is char.
;;   - parenthesis is string.
;;   - 1st argument of insert-pair enclose following arg sexps in
;;     a pair of open and close characters.
;;   - 1st argument of parenthesis repeats arg time.
;;   - insert-pair is Emacs built-in function.
;;   - parenthesis is external elisp package.


;;; Code:

;;; Variables:

(defconst parenthesis-version 0.5 "parenthesis's version")


(defgroup parenthesis nil
  "parenthesis"
  :tag "parenthesis"
  :group 'parenthesis)

(defcustom parenthesis-func-alist
  '((parenthesis-insert-braces "{" "}")
    (parenthesis-insert-braces2 "{ " " }")
    (parenthesis-insert-brackets "[" "]")
    (parenthesis-insert-brackets2 "[ " " ]")
    (parenthesis-insert-parens "(" ")")
    (parenthesis-insert-parens2 "( " " )")
    (parenthesis-insert-single-quotation "'" "'")
    (parenthesis-insert-single-quotation2 "' " " '")
    (parenthesis-insert-double-quotation "\"" "\"")
    (parenthesis-insert-double-quotation2 "\" " " \"")
    (parenthesis-insert-angle "<" ">")
    (parenthesis-insert-angle2 "< " " >")
    (parenthesis-insert-grave-and-quotation "`" "'"))
  "*list of functions for parenthesis."
  :type  '(repeat
           (list :tag "List of functions"
                 (symbol :tag "Name of function.")
                 (string :tag "open")
                 (string :tag "close")
                 (choice :tag "optional argument"
                         (const :tag "end point of open" nil)
                         (number :tag "numeric value of point"))))
  :group 'parenthesis)

(defcustom parenthesis-insert-ignore-backslash nil
  "*If non-nil, insert pair of parensis even a backslash exists bofore point."
  :type  'symbol
  :group 'parenthesis)

(defcustom parenthesis-push-mark t
  "*Non-nil means to push mark to end point of close paren
when region has been selected.
Default value is t."
  :type  'symbol
  :group 'parenthesis)


;;; Functions:

(defun parenthesis-init ()
  "Define the functions that insert pair of parenthesis."
  (interactive)
  (mapc
   (lambda (x)
     (fset (car x)
           `(lambda (rep)
              (interactive "p")
              (parenthesis-insert-internal
               rep ,(nth 1 x) ,(nth 2 x) ,(nth 3 x)))))
   parenthesis-func-alist))

(defun parenthesis-insert-internal (rep open close &optional pos)
  (if (or parenthesis-insert-ignore-backslash
          (bobp)
          (/= (char-before) ?\\))
      (cond
       ((> rep 0)
        (save-excursion
          (save-restriction
            (if (and transient-mark-mode mark-active)
                (narrow-to-region (region-beginning) (region-end))
              (narrow-to-region (point) (point)))
            (goto-char (point-min))
            (insert (parenthesis-repeat-string rep open))
            (goto-char (point-max))
            (insert (parenthesis-repeat-string rep close))))
        (when (and mark-active transient-mark-mode)
          (let ((p (region-beginning)))
            (when parenthesis-push-mark
              ;; push mark to end point of close paren.
              (push-mark (+ (region-end) (* (length close) rep))))
            (goto-char p)))
        ;; pos is non-nil: pos + length_of_open * (rep - 1)
        ;; pos is nil: lenght_of_open * rep
        (forward-char (+ (if (numberp pos) pos 0)
                         (* (length open) (if (numberp pos) (1- rep) rep)))))
       (t
        (insert (parenthesis-repeat-string (if (= rep 0) 1 (- rep)) open))))
    (self-insert-command rep)))

(defun parenthesis-repeat-string (rep str)
  "Return a string which STR times REP is repeated."
  (mapconcat 'identity (make-vector rep str) ""))

(defun parenthesis-register-keys (str map &optional spc)
  "Register keys to local-map."
  (mapc
   (lambda (x)
     (mapc
      (lambda (y)
        (when (string-equal (nth 1 x) (concat y (and spc " ")))
          (define-key map y (car x))))
      (split-string str "" t)))
   parenthesis-func-alist))


(make-variable-buffer-local 'parenthesis-insert-ignore-backslash)
(parenthesis-init)


(provide 'parenthesis)

;;; parenthesis.el ends here