neitzel@infbs.UUCP (Martin Neitzel) (05/17/89)
[a description of gin-mode follows the copyright stuff.]
Please note:
This is my first self-made minor-mode. It runs quite smoothly here
for some weeks now, but some parts of the code at least *look* arkward
to me. Everything is based on the suggestions given in the old '88
version of the elisp manual. It was a big help. If something with
gin-mode.el is wrong, it might be wise to extend the manual, but any
blame goes to me, of course.
Martin Neitzel
;; gin-mode.el -- Set up minor mode with guess-indent stuff.
;; Copyright (C) Martin Neitzel, May 1989
;; This file is not yet part of GNU Emacs.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY. No author or distributor
;; accepts responsibility to anyone for the consequences of using it
;; or for whether it serves any particular purpose or works at all,
;; unless he says so in writing. Refer to the GNU Emacs General Public
;; License for full details.
;; Everyone is granted permission to copy, modify and redistribute
;; GNU Emacs, but only under the conditions described in the
;; GNU Emacs General Public License. A copy of this license is
;; supposed to have been given to you along with GNU Emacs so you
;; can know your rights and responsibilities. It should be in a
;; file named COPYING. Among other things, the copyright notice
;; and this notice must be preserved on all copies.
;; SUMMARY
;;
;; Gnu Emacs supports filling of paragraphs and wrapping of lines with a
;; settable string to be used for the left margin, the variable
;; ``fill-prefix''. Setting this variable by hand is fine, but can
;; become mildly annoying if it has to be changed often in a document.
;; However, the appropriate value for fill-prefix can be derived from
;; the layout of the current line in almost all cases.
;;
;; This is a minor mode that ``guesses'' the indentation to be used
;; for (auto-) filling. It has proven to be very handy in all text-mode
;; variants. It uses a simple but effective heuristic to guess a
;; fill-prefix based on the current line and two (configurable) regular
;; expressions. I almost never have to use "^X." explicitly anymore.
;;
;; The two regexps control
;;
;; * what line beginnings have to be taken as "fill-prefix" (my
;; standard setup recognizes initial white space and typical
;; mail-prefixes like ">" or "name> ").
;;
;; * what line beginnings are really hanging indents. The
;; standard setup recognizes the stars used right here,
;; enumerations, and some more...
;; The guessing stuff
(provide 'gin-mode)
(defvar gin-left-hang-indent-re
"\\s *\\([-*]\\|([a-zA-Z0-9])\\|[a-zA-Z0-9]\\.?:]?\\)\\s +"
"*Regexp that defines a hanging indent of a paragraph.
If it is seen by gin-guess-prefix, the next lines are indented with
white space beyond the hanging indent. Setting this variable makes
it buffer-local.")
(defvar gin-retain-indent-re
"[a-zA-Z]*>+[ \t]*\\|[ \t]+"
"*Regexp that defines how a fill-prefix can look like.
If such a string is seen by gin-guess-prefix in the current line,
the next line will be indented with it, too. Setting this variable
makes it buffer-local.")
(defun gin-guess-prefix ()
"Try to figure out the prefix for the next line."
(save-excursion
(beginning-of-line)
(cond ((looking-at gin-left-hang-indent-re)
(let ((beg (point))
indent-size
(indent-prefix ""))
(re-search-forward gin-left-hang-indent-re)
(setq indent-size (current-column))
;; First gather tabs as needed ...
(if indent-tabs-mode
(while (>= indent-size tab-width)
(setq indent-prefix (concat indent-prefix "\t"))
(setq indent-size (- indent-size tab-width))))
;; ... then append the rest as spaces:
(while (> indent-size 0)
(setq indent-prefix (concat indent-prefix " "))
(setq indent-size (1- indent-size)))
indent-prefix))
((looking-at gin-retain-indent-re)
(buffer-substring (match-beginning 0) (match-end 0)))
(t ""))))
;; Replacements for old functions dealing with the fill-prefix.
;; Their function values are stuffed into the original symbols.
(defun gin-fill-paragraph (arg)
"fill-paragraph in Gin mode, tries to guess the appropriate fill-prefix.
With arg, also justify."
(interactive "P")
(if gin-mode
(let ((fill-prefix (gin-guess-prefix)))
(funcall 'gin-old-fill-paragraph arg))
(funcall 'gin-old-fill-paragraph arg)))
(defun gin-do-auto-fill()
(if gin-mode
(let ((fill-prefix (gin-guess-prefix)))
(funcall 'gin-old-do-auto-fill))
(funcall 'gin-old-do-auto-fill)))
;; When loaded for the first time, install our minor mode indicator
(defconst gin-old-fill-paragraph nil
"Keeps the true fill-paragraph function during Gin mode.")
(defconst gin-old-do-auto-fill nil
"Keeps the true do-auto-fill function during Gin mode.")
(defun gin-overlay-functions()
"Undermine emacs with Gin stuff."
(fset 'fill-paragraph (symbol-function 'gin-fill-paragraph))
(fset 'do-auto-fill (symbol-function 'gin-do-auto-fill)))
(defun gin-restore-originals ()
"Throw gin-mode functions out everywhere."
(fset 'fill-paragraph (symbol-function 'gin-old-fill-paragraph))
(fset 'do-auto-fill (symbol-function 'gin-old-do-auto-fill)))
(if (boundp 'gin-mode)
nil
(setq minor-mode-alist (cons '(gin-mode " Gin")
minor-mode-alist))
(make-variable-buffer-local 'gin-mode)
(set-default 'gin-mode nil)
(make-variable-buffer-local 'gin-left-hang-indent-re)
(make-variable-buffer-local 'gin-retain-indent-re)
(fset 'gin-old-fill-paragraph (symbol-function 'fill-paragraph))
(fset 'gin-old-do-auto-fill (symbol-function 'do-auto-fill))
(gin-overlay-functions))
(defun gin-mode (arg)
"Minor mode to guess indentations.
Toggle gin-mode, or turn it on iff optional ARG is positiv.
Gin mode adds the capability to \"guess\" a suitable indent for
filling based on the current line. The line is matched against the
two regexps 'gin-left-hang-indent-re' and 'gin-retain-indent-re', see
their documentation.
When Gin mode is active, auto-filling and fill-paragraph will both use
a \"guessed\" value as fill-prefix."
(interactive "P")
(setq gin-mode
(if (null arg) (not gin-mode)
(> (prefix-numeric-value arg) 0)))
(set-buffer-modified-p (buffer-modified-p)))