[comp.emacs] whist

gh@bdblues.inria.fr (gilbert harrus) (12/16/88)

Below is a small elisp package for editing history messages. More infos can
be found after the copyleft.

Enjoy whist!

Gilbert Harrus
Gip-Altair/INRIA                                       gh@bdblues.altair.fr
Domaine de Voluceau                              ...!mcvax!inria!bdblues!gh
BP105 Rocquencourt
78153 Le Chesnay Cedex                        phone: (33)-(1)-39-63-54-63
France

<----------------------------cut here------------------------------>
;; edition of modification history  : whist 
;; Copyright (C) 1988 Free Software Foundation, Inc.

;; This file is 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.

;;;	This file provides a 'whist' function for editing history
;;;	messages. It is derived from an Gossling-emacs implementation
;;;	of the same function. I just translated it to elisp, and
;;;	rewrote some parts.
;;;     If you find an improvement, please send it to me.
;;;     If you find a bug, please report it to me (along with the fix...).
;;;
;;;     December 1988, Gilbert Harrus (gh@bdblues.altair.fr).
;;;	

;;; Installation
;;;	
;;;	1- Change the default value of whist-site to the appropriate value.
;;;	
;;;	2- Put the file whist.el in the standard emacs-lisp directory
;;;	
;;;	3- Add this line to your .emacs
;;;		(autoload 'whist "whist.el" "" t)
;;;	
;;; Man
;;;	
;;;	Just type: M-x whist<CR> 
;;;	Error messages should be self-explanatory.
;;;	To add new types, you have to modify the whist-types-alist and
;;;	whist-prefix-alist constants, and the whist-help-message function.
;;;	The modifications should be straightforward.
;;;	
;;; Examples
;;; 
;;; 11-Dec-88  gilbert harrus (gh@bdblues.altair.fr)
;;;	This is another example of history message.
;;;
;;; 10-Dec-88  gilbert harrus (gh@bdblues.altair.fr)
;;;	This is an example of history message. Note that is the first I
;;;	entered, but this is also the last you read. 

;;; Site: change this at will!

(defvar whist-site "bdblues.altair.fr")

;;; Constants

;; As default type is text (no comment prefix), we do not list corresponding
;; extensions (like .txt etc).

(defconst whist-types-alist (mapcar 'purecopy
			      '(("\\.[chy]$" . "c")
				("\\.tex$" . "tex")
				("\\.el$" . "lisp")
 				("\\.l$" . "lisp")
				("\\.lisp$" . "lisp")
				("akefile"  . "makefile")
				("\\.p$" . "pascal")
				("\\.f$" . "fortran")
				("\\.[nt]$" . "ntroff")
				("\\.TeX$" . "tex")
				("\\.sty$" . "tex")
				("\\.bbl$" . "tex")
				("\\.bib$" . "tex")
				("\\.lsp$" . "lisp")
				("\\.ml$" . "lisp")
				("\\.ll$" . "lisp")
				("\\.lh$" . "lisp")
				("\\.bc$" . "bc")
				("\\.cc$" . "c++")
				("\\..*sh$" . "shell")
				("\\.ada$" . "ada")
				("\\.tbl$" . "ntroff")
				("\\.eqn$" . "ntroff")
				; site dependent types
				("\\.a$"   . "tex")
				))
"Alist of filename patterns with corresponding (whist) types, and is used by
whist to make guess about your file types.
Each element looks like (REGEXP . TYPE), for example (""\\.c$"" . ""c"").
See also the whist-prefix variable.")

;; prefix by types
;; 
(defconst whist-prefix-alist (mapcar 'purecopy
			       '(
				 ("ada"      . "--")
				 ("bc"       . " *")
				 ("c"        . " *")
				 ("c++"      . " *")
				 ("fortran"  . "C")
				 ("lisp"     . ";;;")
				 ("makefile" . "#")
				 ("pascal"   . " *")
				 ("ntroff"   . ".""")
				 ("shell"    . "#")
				 ("tex"      . "%%")
				 ("text"     . "")
				 ("yacc"     . " *")
				 ))
  "Alist of whist types with corresponding prefix for comment continuation.
Each element looks like (TYPE . PREFIX), for example (""c"" . "" *"").
Type must be an existing type in whist-types-alist")


(defun whist()
  "Add some comments line on the history part of the file.
Somewhere in the buffer, insert a comment with HISTORY,
History or history inside."
  (interactive)
  (catch 'this-way (whist-internal))
  )

(defun whist-abort () 
  "To abort whist ..."
  (throw 'this-way t)
  )

(defun whist-internal()
  (save-excursion
    (if (not buffer-file-name)
	(error-message "There is no file associated to this buffer"))
    (let
	((whist-file-name (file-name-nondirectory buffer-file-name))
	 (alist whist-types-alist)
	 (whist-file-type nil)
	 (prefix nil))
      (beginning-of-buffer)
      (if (or (< (buffer-size) 10)
	      ; I am not so good with regexp ...
	      (not (re-search-forward "HISTORY\\|History\\|history"
				      (buffer-size) t)))
	  (error-message "Please add a comment containing HISTORY.")
	(set-mark (point))
	)
      (end-of-line)
      (if (eobp) (insert-string "\n") (forward-char))
      (exchange-point-and-mark)
      ;	We left the mark at the beginning of the line
      ; 	that follows the one containing HISTORY.

      ; What is the type of the file ? We use our own list

      (while (and (not whist-file-type) alist)
	(if (string-match (car (car alist)) whist-file-name)
	    (setq whist-file-type (cdr (car alist))))
	(setq alist (cdr alist)))
      (if (not whist-file-type) (setq whist-file-type "text"))
      ;
      ;	It is time to check our guess and define the format
      ;	of the comment.
      ;
      (save-window-excursion
	(while (not prefix)
	  (setq whist-file-type		; check our guess.
		(get-arg "Type of file ?"
			 whist-file-type))
	  (cond
	   ((string-equal whist-file-type ".")
	    (error-message "Bye."))
	   ((string-equal whist-file-type "special")
	    (setq prefix
		  (get-arg "Enter prefix string: " "")))
	   (t ; let's go for the real search
	    (setq alist whist-prefix-alist)
	    (while (and (not prefix) alist)
	      ;; take care to compare with string-equal, not string-match
	      (if (string-equal (car (car alist)) whist-file-type)
		  (setq prefix (cdr (car alist))))
	      (setq alist (cdr alist)))
	    ;
	    (if (and (not prefix)
		     (or (string-equal whist-file-type "?")
			 (string-equal (ml-substring
					(get-arg (concat whist-file-type
					    " is unknown, do you want a list?")
						 "yes") 0 1) "y")))
		(whist-help-message))))))

      ;
      ;	Now is time to enter the message ...
      ;
      (save-window-excursion
	(pop-to-buffer "*whist*" 1)
	(erase-buffer)
	(setq mode-line-format
	      (concat "History message for " whist-file-name " ("
		      whist-file-type ") %M" ))
	(setq fill-column 65)
	(setq left-margin 0)
	(auto-fill-mode 1)
	(setq keep-going t)
	(while keep-going
	  (message "%s" (substitute-command-keys
			 "Enter text. \\[exit-recursive-edit] when done.")
		   (recursive-edit)    ; enter the message in the whist buffer
		   (setq action (ml-substring (get-arg
					       (concat "Action? (a[bort], e[dit], u[pdate]):")
					       "update") 0 1))
		   (cond
		    ((string-equal action "e")
		     ); continue edition
		    ((string-equal action "a")
		     (kill-buffer "*whist*")
		     (error-message "Aborted")) ; abort
		    ((string-equal action "u")
		     (setq keep-going nil)) ; update
		    (t
		     (message "%s" "Don't you read ? ")
		     (sit-for 2 t)) ; Yes, don't you read ?
		    )))

	; updating
	(beginning-of-buffer)
	(if (zerop (buffer-size))
	    (error-message "Must be non-empty!")
	  (beginning-of-buffer))
	(set-mark (point))
	(setq time-string (current-time-string))
	(insert (concat prefix " "
			(if (string-equal whist-file-type "shell") """ " "")
			(ml-substring time-string 8 10)
			"-"
			(ml-substring time-string 4 7)
			"-"
			(ml-substring time-string -2 2)
			"  "
			(user-full-name)
			" ("
			(user-login-name) "@" whist-site ")"
			"\n"
			))
	(replace-regexp   "^" (concat prefix "\t"))
	(end-of-buffer)
	(if (not (equal (preceding-char) 10)) (insert-string "\n"))
	)
      (exchange-dot-and-mark)	; back to the line following HISTORY.
      (insert-buffer-substring "*whist*" nil nil)
      (kill-buffer "*whist*")
      (message "%s" "Done")
      )
    )
  )


;; Misc. functions

(defun whist-help-message()
  (with-output-to-temp-buffer "*Help*"
    (princ "The following file-types are recognized:\n")
    (princ "ada         bc          c         c++\n")
    (princ "fortran     lisp        makefile  ntroff\n")
    (princ "pascal      shell       tex       text\n")
    (princ "yacc\n\n")
    (princ "You may also specify ""special"" ")
    (princ "to enter a prefix string, or . to abort.\n\n")
    (princ "Contact your local emacs guru for adding types.\n")
    )
  (message "%s" "Hit return to continue")
  (read-char)
)

(defun get-arg(arg1 arg2)
  "Reads in the minibuffer an answer [string] to the question ARG1 with a
default answer ARG2 (just type <RETURN>)"
  (setq return-argum (read-string (concat arg1 " [" arg2 "] ")))
  (if (string-equal return-argum "") (setq return-argum arg2))
  return-argum
  )

(defun error-message(str)
  (message "%s" str)
  (sit-for 1 t)
  (whist-abort))

(defun ml-substring(str pos n)
  " Returns the substring of string str starting at position
pos  (numbering from 1) and running for n characters.  
If pos is less than 0, then length of the string is added to  it; 
the  same  is  done  for  n. "
  (if (>= pos 0)
      (substring str pos n)
    (substring str pos (+ (+ (length str) pos) n))))

Gilbert Harrus
Gip-Altair/INRIA                                       gh@bdblues.altair.fr
Domaine de Voluceau                              ...!mcvax!inria!bdblues!gh
BP105 Rocquencourt
78153 Le Chesnay Cedex                        phone: (33)-(1)-39-63-54-63
France