home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / lisp / packages / dabbrev.el < prev    next >
Encoding:
Text File  |  1992-06-29  |  9.3 KB  |  242 lines

  1. ;; Dynamic abbreviation package for GNU Emacs.
  2. ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 1, or (at your option)
  9. ;; any later version.
  10.  
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;; GNU General Public License for more details.
  15.  
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  18. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21. ; DABBREVS - "Dynamic abbreviations" hack, originally written by Don Morrison
  22. ; for Twenex Emacs.  Converted to mlisp by Russ Fish.  Supports the table
  23. ; feature to avoid hitting the same expansion on re-expand, and the search
  24. ; size limit variable.  Bugs fixed from the Twenex version are flagged by
  25. ; comments starting with ;;; .
  26. ; converted to elisp by Spencer Thomas.
  27. ; Thoroughly cleaned up by Richard Stallman.
  28. ;  
  29. ; If anyone feels like hacking at it, Bob Keller (Keller@Utah-20) first
  30. ; suggested the beast, and has some good ideas for its improvement, but
  31. ; doesn?tknow TECO (the lucky devil...).  One thing that should definitely
  32. ; be done is adding the ability to search some other buffer(s) if you can?t
  33. ; find the expansion you want in the current one.
  34.  
  35. ;; (defun dabbrevs-help ()
  36. ;;   "Give help about dabbrevs."
  37. ;;   (interactive)
  38. ;;   (&info "emacs" "dabbrevs")    ; Select the specific info node.
  39. ;; )
  40. (provide 'dabbrevs)
  41.  
  42. (defvar dabbrevs-limit nil
  43.   "*Limits region searched by dabbrevs-expand to that many chars away (local).")
  44. (make-variable-buffer-local 'dabbrevs-limit)
  45.  
  46. (defvar dabbrevs-backward-only nil
  47.   "*If non-NIL, dabbrevs-expand only looks backwards.")
  48.  
  49. ; State vars for dabbrevs-re-expand.
  50. (defvar last-dabbrevs-table nil
  51.   "Table of expansions seen so far. (local)")
  52. (make-variable-buffer-local 'last-dabbrevs-table)
  53.  
  54. (defvar last-dabbrevs-abbreviation ""
  55.   "Last string we tried to expand.  Buffer-local.")
  56. (make-variable-buffer-local 'last-dabbrevs-abbreviation)
  57.  
  58. (defvar last-dabbrevs-direction 0
  59.   "Direction of last dabbrevs search. (local)")
  60. (make-variable-buffer-local 'last-dabbrevs-direction)
  61.  
  62. (defvar last-dabbrevs-abbrev-location nil
  63.   "Location last abbreviation began (local).")
  64. (make-variable-buffer-local 'last-dabbrevs-abbrev-location)
  65.  
  66. (defvar last-dabbrevs-expansion nil
  67.     "Last expansion of an abbreviation. (local)")
  68. (make-variable-buffer-local 'last-dabbrevs-expansion)
  69.  
  70. (defvar last-dabbrevs-expansion-location nil
  71.   "Location the last expansion was found. (local)")
  72. (make-variable-buffer-local 'last-dabbrevs-expansion-location)
  73.  
  74. (defun dabbrev-expand (arg)
  75.   "Expand previous word \"dynamically\".
  76. Expands to the most recent, preceding word for which this is a prefix.
  77. If no suitable preceding word is found, words following point are considered.
  78.  
  79. If `case-fold-search' and `case-replace' are non-nil (usually true)
  80. then the substituted word may be case-adjusted to match the abbreviation
  81. that you had typed.  This takes place if the substituted word, as found,
  82. is all lower case, or if it is at the beginning of a sentence and only
  83. its first letter was upper case.
  84.  
  85. A positive prefix argument, N, says to take the Nth backward DISTINCT
  86. possibility.  A negative argument says search forward.  The variable
  87. dabbrev-backward-only may be used to limit the direction of search to
  88. backward if set non-nil.
  89.  
  90. If the cursor has not moved from the end of the previous expansion and
  91. no argument is given, replace the previously-made expansion
  92. with the next possible expansion not yet tried."
  93.   (interactive "*P")
  94.   (let (abbrev expansion old which loc n pattern
  95.     (do-case (and case-fold-search case-replace)))
  96.     ;; abbrev -- the abbrev to expand
  97.     ;; expansion -- the expansion found (eventually) or nil until then
  98.     ;; old -- the text currently in the buffer
  99.     ;;    (the abbrev, or the previously-made expansion)
  100.     ;; loc -- place where expansion is found
  101.     ;;    (to start search there for next expansion if requested later)
  102.     ;; do-case -- non-nil if should transform case when substituting.
  103.     (save-excursion
  104.       (if (and (null arg)
  105.            (eq last-command this-command)
  106.            last-dabbrevs-abbrev-location)
  107.       (progn
  108.         (setq abbrev last-dabbrevs-abbreviation)
  109.         (setq old last-dabbrevs-expansion)
  110.         (setq which last-dabbrevs-direction))
  111.     (setq which (if (null arg)
  112.             (if dabbrevs-backward-only 1 0)
  113.                 (prefix-numeric-value arg)))
  114.     (setq loc (point))
  115.     (forward-word -1)
  116.     (setq last-dabbrevs-abbrev-location (point)) ; Original location.
  117.     (setq abbrev (buffer-substring (point) loc))
  118.     (setq old abbrev)
  119.     (setq last-dabbrevs-expansion-location nil)
  120.     (setq last-dabbrev-table nil))      ; Clear table of things seen.
  121.  
  122.       (setq pattern (concat "\\b" (regexp-quote abbrev) "\\(\\sw\\|\\s_\\)+"))
  123.       ;; Try looking backward unless inhibited.
  124.       (if (>= which 0)
  125.       (progn 
  126.         (setq n (max 1 which))
  127.         (if last-dabbrevs-expansion-location
  128.         (goto-char last-dabbrevs-expansion-location))
  129.         (while (and (> n 0)
  130.             (setq expansion (dabbrevs-search pattern t do-case)))
  131.           (setq loc (point-marker))
  132.           (setq last-dabbrev-table (cons expansion last-dabbrev-table))
  133.           (setq n (1- n)))
  134.         (or expansion
  135.         (setq last-dabbrevs-expansion-location nil))
  136.         (setq last-dabbrevs-direction (min 1 which))))
  137.  
  138.       (if (and (<= which 0) (not expansion)) ; Then look forward.
  139.       (progn 
  140.         (setq n (max 1 (- which)))
  141.         (if last-dabbrevs-expansion-location
  142.         (goto-char last-dabbrevs-expansion-location))
  143.         (while (and (> n 0)
  144.             (setq expansion (dabbrevs-search pattern nil do-case)))
  145.           (setq loc (point-marker))
  146.           (setq last-dabbrev-table (cons expansion last-dabbrev-table))
  147.           (setq n (1- n)))
  148.         (setq last-dabbrevs-direction -1))))
  149.  
  150.     (if (not expansion)
  151.     (let ((first (string= abbrev old)))
  152.       (setq last-dabbrevs-abbrev-location nil)
  153.       (if (not first)
  154.           (progn (undo-boundary)
  155.              (delete-backward-char (length old))
  156.              (insert abbrev)))
  157.       (error (if first
  158.              "No dynamic expansion for \"%s\" found."
  159.              "No further dynamic expansions for \"%s\" found.")
  160.          abbrev))
  161.       ;; Success: stick it in and return.
  162.       (undo-boundary)
  163.       (search-backward old)
  164.       ;; Make case of replacement conform to case of abbreviation
  165.       ;; provided (1) that kind of thing is enabled in this buffer
  166.       ;; and (2) the replacement itself is all lower case.
  167.       (replace-match expansion
  168.              (not (and do-case
  169.                    (string= expansion (downcase expansion))))
  170.              'literal)
  171.       ;; Save state for re-expand.
  172.       (setq last-dabbrevs-abbreviation abbrev)
  173.       (setq last-dabbrevs-expansion expansion)
  174.       (setq last-dabbrevs-expansion-location loc))))
  175.  
  176. ;; Search function used by dabbrevs library.  
  177. ;; First arg is string to find as prefix of word.  Second arg is
  178. ;; t for reverse search, nil for forward.  Variable dabbrevs-limit
  179. ;; controls the maximum search region size.
  180.  
  181. ;; Table of expansions already seen is examined in buffer last-dabbrev-table,
  182. ;; so that only distinct possibilities are found by dabbrevs-re-expand.
  183. ;; Note that to prevent finding the abbrev itself it must have been
  184. ;; entered in the table.
  185.  
  186. ;; IGNORE-CASE non-nil means treat case as insignificant while
  187. ;; looking for a match and when comparing with previous matches.
  188. ;; Also if that's non-nil and the match is found at the beginning of a sentence
  189. ;; and is in lower case except for the initial
  190. ;; then it is converted to all lower case for return.
  191.  
  192. ;; Value is the expansion, or nil if not found.  After a successful
  193. ;; search, point is left right after the expansion found.
  194.  
  195. (defun dabbrevs-search (pattern reverse ignore-case)
  196.   (let (missing result (case-fold-search ignore-case))
  197.     (save-restriction         ; Uses restriction for limited searches.
  198.       (if dabbrevs-limit
  199.       (narrow-to-region last-dabbrevs-abbrev-location
  200.                 (+ (point)
  201.                    (* dabbrevs-limit (if reverse -1 1)))))
  202.       ;; Keep looking for a distinct expansion.
  203.       (setq result nil)
  204.       (setq missing nil)
  205.       (while  (and (not result) (not missing))
  206.     ; Look for it, leave loop if search fails.
  207.     (setq missing
  208.           (not (if reverse
  209.                (re-search-backward pattern nil t)
  210.                (re-search-forward pattern nil t))))
  211.  
  212.     (if (not missing)
  213.         (progn
  214.           (setq result (buffer-substring (match-beginning 0)
  215.                          (match-end 0)))
  216.           (let* ((test last-dabbrev-table))
  217.         (while (and test
  218.                 (not
  219.                  (if ignore-case
  220.                  (string= (downcase (car test))
  221.                       (downcase result))
  222.                    (string= (car test) result))))
  223.           (setq test (cdr test)))
  224.         (if test (setq result nil))))))    ; if already in table, ignore
  225.       (if result
  226.       (save-excursion
  227.         (let ((beg (match-beginning 0)))
  228.           (goto-char beg)
  229.           (and ignore-case
  230.            (string= (substring result 1)
  231.                 (downcase (substring result 1)))
  232.            (if (string= paragraph-start
  233.                 (concat "^$\\|" page-delimiter))
  234.                (and (re-search-backward sentence-end nil t)
  235.                 (= (match-end 0) beg))
  236.              (forward-char 1)
  237.              (backward-sentence)
  238.              (= (point) beg))
  239.            (setq result (downcase result))))))
  240.       result)))
  241.