[comp.emacs] Acronym functions for GNU Emacs

dsill@RELAY.NSWC.NAVY.MIL (02/17/89)

Some time ago, I picked up a file of acronyms off of simtel20, I
believe.  I recently posted my own version of this file to the
unix-sources Internet mailing list.  My copy has almost 2400 entries
now.  The file's in the format:

ACRONYM<TAB>- Expansion Of Acronym

E.g, the entry for ICBM is

ICBM	- InterContinental Ballistic Missile

I also posted a shell script called `whats' that acts as a front-end
for looking up acronyms and adding new ones to the file.

That's all just background.

As an exercise to help me learn elisp, I wrote a similar front-end for
Emacs.  Since this is my first attempt, I'd appreciate any comments on
my code.  Just don't show me how to write the whole thing in less that
10 lines. :-)

;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Emacs-Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;
;; acronyms.el --- Various commands for use with an acronym database
;; Author          : dsill@relay.nswc.navy.mil
;; Created On      : Thu Feb 10 08:33:26 1989
;; Last Modified By: dsill
;; Last Modified On: Thu Feb 16 09:37:50 1989
;; Update Count    : 3
;; Status          : No known bugs.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; History 		
;; 16-Feb-1989		dsill	
;;    Readied for first release.

(defvar acronym-file "~/misc/acron"
  "Acronym database.  Entries are in the form \"ACRONYM\\t- Expansion Of Acronym\".")

(defvar acronym-expansion-buffer "*Acronym Expansion*"
  "Buffer containing the expansion(s) of an acronym.")

(defun look-up-acronym (acronym)
  "Pop up a window containing the expansion(s) of ACRONYM.  If none are found,
the option to call add-acronym is provided."
  (interactive "sAcronym: ")
  (save-excursion
    (let ((buf (get-file-buffer acronym-file))
	  error)
      (if buf
	  (set-buffer buf)
	(setq buf (create-file-buffer acronym-file))
	(set-buffer buf)
	(erase-buffer)
	(insert-file-contents acronym-file t))
      (goto-char (point-min))
      (setq acronym-re (concat "^" (upcase acronym) "	- "))
      (if (re-search-forward acronym-re nil t)
	  (progn
	    (goto-char (point-min))
	    (save-excursion
	      (set-buffer (get-buffer-create acronym-expansion-buffer))
	      (fundamental-mode)
	      (if buffer-read-only (toggle-read-only))
	      (erase-buffer))
	    (while (re-search-forward acronym-re nil t)
	      (let ((beg (point)))
		(end-of-line)
		(copy-region-as-kill beg (point)))
	      (save-excursion
		(set-buffer acronym-expansion-buffer)
		(insert (car kill-ring-yank-pointer) ?\n)))
	    (display-buffer acronym-expansion-buffer t)
	    (set-buffer acronym-expansion-buffer)
	    (toggle-read-only))
	(if (y-or-n-p
	     (concat "Not in database, do you know the expansion of "
		     (upcase acronym) "? "))
	    (add-acronym acronym)
	  (message " "))))))

(defun add-acronym (acronym &optional expansion)
  "Add a new ACRONYM and its EXPANSION to the acronym-file."
  (interactive "sAcronym: ")
  (setq acronym (upcase acronym))
  (setq expansion (read-string (concat "Expansion of " acronym ": ")))
  (if (equal expansion "")
      ()
    (save-excursion
      (let ((buf (get-file-buffer acronym-file))
	    error)
	(if buf
	    (set-buffer buf)
	  (setq buf (create-file-buffer acronym-file))
	  (set-buffer buf)
	  (erase-buffer)
	  (insert-file-contents acronym-file t))
	(goto-char (point-min))
	(setq acronym-re (concat "^" acronym))
	(end-of-buffer)
	(beginning-of-line)
	(insert acronym "	- " expansion ?\n)
	(basic-save-buffer)
	(message (concat acronym " - " expansion))))))

;; finis

lrs@ESL.ESL.COM (Lynn Slater) (02/17/89)

Looks pretty good. I would not reject this if it were posted.  But as
you ask for comments, here goes:

(defvar acronym-file "~/misc/acron"
  "Acronym database.  Entries are in the form \"ACRONYM\\t- Expansion Of Acronym\".")

;; I see that you cause all acronymes to be in upper case.  You may
;; want to consider addinging the line
;;    (case-fold-search nil)
;; to a let statement.  This will dynamically bind that variable for
;; the duration of the let without really changing anything.
;; You can also override buffer-read-only this way without changing
;;   the read only status to the user.  This is a handy way to make
;;   the buffer touched principly by the clean code and to prevent
;;   accidental edits by the user.
;; Dynamic binding has the additional advantage of being canceled with
;;   a control-g while the code to unset something may never be
;;  executed.

(defvar acronym-expansion-buffer "*Acronym Expansion*"
  "Buffer containing the expansion(s) of an acronym.")

;; There should be a defvar for acronyme-re or else it should be in a
;;  let.  As it is, you have set a global and provided no variable
;; documentation. 

(defun look-up-acronym (acronym)
  "Pop up a window containing the expansion(s) of ACRONYM.  If none are found,
the option to call add-acronym is provided."
  (interactive "sAcronym: ")
  (save-excursion
    (let ((buf (get-file-buffer acronym-file))
	  error)
;; find-file-noselect may replace the next 6 lines of code as well as
;; a line above.  See the tags.el for an example.
      (if buf
	  (set-buffer buf)
	(setq buf (create-file-buffer acronym-file))
	(set-buffer buf)
	(erase-buffer)
	(insert-file-contents acronym-file t))
      (goto-char (point-min))
      (setq acronym-re (concat "^" (upcase acronym) "	- "))
      ;; ^^^^^^  this is setting a global 
      (if (re-search-forward acronym-re nil t)
          ;; Is possibly case folded, could get accidents
	  (progn
	    (goto-char (point-min))
	    (save-excursion
	      (set-buffer (get-buffer-create acronym-expansion-buffer))
	      (fundamental-mode)
	      (if buffer-read-only (toggle-read-only))
	      (erase-buffer))
	    (while (re-search-forward acronym-re nil t)
	      (let ((beg (point)))
		(end-of-line)
		(copy-region-as-kill beg (point)))
	      (save-excursion
		(set-buffer acronym-expansion-buffer)
		(insert (car kill-ring-yank-pointer) ?\n)))
         ;; (with-output-to-temp-buffer may replace lots of the above code)
	    (display-buffer acronym-expansion-buffer t)
	    (set-buffer acronym-expansion-buffer)
	    (toggle-read-only))
	(if (y-or-n-p
	     (concat "Not in database, do you know the expansion of "
		     (upcase acronym) "? "))
	    (add-acronym acronym)
	  (message " "))))))

(defun add-acronym (acronym &optional expansion)
  "Add a new ACRONYM and its EXPANSION to the acronym-file."
  (interactive "sAcronym: ")
  (setq acronym (upcase acronym))
  (setq expansion (read-string (concat "Expansion of " acronym ": ")))
  (if (equal expansion "")
      ()
    (save-excursion
      (let ((buf (get-file-buffer acronym-file))
	    error)
	(if buf
	    (set-buffer buf)
	  (setq buf (create-file-buffer acronym-file))
	  (set-buffer buf)
	  (erase-buffer)
	  (insert-file-contents acronym-file t))
	(goto-char (point-min))
	(setq acronym-re (concat "^" acronym))
	(end-of-buffer)
	(beginning-of-line)
	(insert acronym "	- " expansion ?\n)
	(basic-save-buffer)
	(message (concat acronym " - " expansion))))))

;; finis

-*-

An entirely different approach would be to read the buffer once, scan
it and translate it into an alist.  You can then use try-completion
to resolve the names.  Of course, try completion will split the screen
as needed.   I have a quick and dirty issue tracking system with
keyword completion that did this; I can send it if you want it.

Keep up the contributions.  I really like your code summaries.
-- Lynn
===============================================================
Lynn Slater -- lrs@esl.com
ESL/TRW 495 Java Drive, Box 3510, Sunnyvale, Ca 94088-3510
Office (408) 738-2888 x 4482; Home (415) 796-4149 
===============================================================