(dabbrev-upcase-means-case-search): Doc fix.
[bpt/emacs.git] / lisp / dabbrev.el
index ed6ef3e..e8bb085 100644 (file)
@@ -1,12 +1,13 @@
 ;;; dabbrev.el --- dynamic abbreviation package
 
-;; Copyright (C) 1985, 1986, 1992, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1994, 1996, 1997, 2000, 2001, 2002,
+;;   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Don Morrison
 ;; Maintainer: Lars Lindberg <Lars.Lindberg@sypro.cap.se>
 ;; Created: 16 Mars 1992
 ;; Lindberg's last update version: 5.7
-;; Keywords: abbrev expand completion
+;; Keywords: abbrev expand completion convenience
 
 ;; This file is part of GNU Emacs.
 
@@ -22,8 +23,8 @@
 
 ;; 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., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -88,7 +89,7 @@
 ;;  [tromey]   Tom Tromey <tromey@busco.lanl.gov>
 ;;  [Rolf]     Rolf Schreiber <rolf@mathematik.uni-stuttgart.de>
 ;;  [Petri]    Petri Raitio <per@tekla.fi>
-;;  [ejb]      Jay Berkenbilt <ejb@ERA.COM>
+;;  [ejb]      Jay Berkenbilt <ejb@ql.org>
 ;;  [hawley]   Bob Hawley <rth1@quartet.mt.att.com>
 ;;  ... and to all the people who have participated in the beta tests.
 
 ;;----------------------------------------------------------------
 ;; Customization variables
 ;;----------------------------------------------------------------
-(defvar dabbrev-backward-only nil
-  "*If non-nil, `dabbrev-expand' only looks backwards.")
 
-(defvar dabbrev-limit nil
-  "*Limits region searched by `dabbrev-expand' to this many chars away.")
+(defgroup dabbrev nil
+  "Dynamic Abbreviations."
+  :tag "Dynamic Abbreviations"
+  :group 'abbrev
+  :group 'convenience)
 
-(defvar dabbrev-abbrev-skip-leading-regexp nil
+(defcustom dabbrev-backward-only nil
+  "*If non-nil, `dabbrev-expand' only looks backwards."
+  :type 'boolean
+  :group 'dabbrev)
+
+(defcustom dabbrev-limit nil
+  "*Limits region searched by `dabbrev-expand' to this many chars away."
+  :type '(choice (const :tag "off" nil)
+                integer)
+  :group 'dabbrev)
+
+(defcustom dabbrev-abbrev-skip-leading-regexp nil
   "*Regexp for skipping leading characters of an abbreviation.
 
 Example: Set this to \"\\\\$\" for programming languages
 in which variable names may appear with or without a leading `$'.
-\(For example, in Makefiles.)
+\(For example, in Makefiles.\)
+
+Set this to nil if no characters should be skipped."
+  :type '(choice regexp
+                (const :tag "off" nil))
+  :group 'dabbrev)
 
-Set this to nil if no characters should be skipped.")
+(defcustom dabbrev-eliminate-newlines t
+  "*Non-nil means dabbrev should not insert newlines.
+Instead it converts them to spaces."
+  :type 'boolean
+  :group 'dabbrev)
 
-;; I recommend that you set this to nil.
-(defvar dabbrev-case-fold-search 'case-fold-search
-  "*Non-nil if dabbrev searches should ignore case.
+(defcustom dabbrev-case-fold-search 'case-fold-search
+  "*Control whether dabbrev searches should ignore case.
 A value of nil means case is significant.
+A value of `case-fold-search' means case is significant
+ if `case-fold-search' is nil.
+Any other non-nil version means case is not significant."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "like search" case-fold-search)
+                (other :tag "on" t))
+  :group 'dabbrev)
+
+(defcustom dabbrev-upcase-means-case-search nil
+  "*The significance of an uppercase character in an abbreviation.
+A nil value means case fold search when searching for possible expansions;
+non-nil means case sensitive search.
+
+This variable has an effect only when the value of
+`dabbrev-case-fold-search' says to ignore case."
+  :type 'boolean
+  :group 'dabbrev)
 
-The value of this variable is an expression; it is evaluated
-and the resulting value determines the decision.
-For example: setting this to `case-fold-search' means evaluate that
-variable to see whether its value is nil.")
+(defcustom dabbrev-case-distinction 'case-replace
+  "*Whether dabbrev treats expansions as the same if they differ in case.
 
-(defvar dabbrev-upcase-means-case-search nil
-  "*The significance of an uppercase character in an abbreviation.
-nil means case fold search, non-nil means case sensitive search.
+A value of nil means treat them as different.
+A value of `case-replace' means distinguish them if `case-replace' is nil.
+Any other non-nil value means to treat them as the same.
 
 This variable has an effect only when the value of
-`dabbrev-case-fold-search' evaluates to t.")
-
-;; I recommend that you set this to nil.
-(defvar dabbrev-case-replace 'case-replace
-  "*Non-nil means dabbrev should preserve case when expanding the abbreviation.
-More precisely, it preserves the case pattern of the abbreviation as you
-typed it--as opposed to the case pattern of the expansion that is copied.
-The value of this variable is an expression; it is evaluated
-and the resulting value determines the decision.
-For example, setting this to `case-replace' means evaluate that
-variable to see if its value is t or nil.
+`dabbrev-case-fold-search' specifies to ignore case."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "based on `case-replace'" case-replace)
+                (other :tag "on" t))
+  :group 'dabbrev
+  :version "22.1")
+
+(defcustom dabbrev-case-replace 'case-replace
+  "*Whether dabbrev applies the abbreviations's case pattern to the expansion.
+
+A value of nil means preserve the expansion's case pattern.
+A value of `case-replace' means preserve it if `case-replace' is nil.
+Any other non-nil value means modify the expansion
+by applying the abbreviation's case pattern to it.
 
 This variable has an effect only when the value of
-`dabbrev-case-fold-search' evaluates to t.")
+`dabbrev-case-fold-search' specifies to ignore case."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "based on `case-replace'" case-replace)
+                (other :tag "on" t))
+  :group 'dabbrev)
 
-(defvar dabbrev-abbrev-char-regexp nil
+(defcustom dabbrev-abbrev-char-regexp nil
   "*Regexp to recognize a character in an abbreviation or expansion.
 This regexp will be surrounded with \\\\( ... \\\\) when actually used.
 
@@ -162,9 +205,12 @@ starting with or containing `no-'.  If you set this variable to
 expanding `yes-or-no-' signals an error because `-' is not part of a word;
 but expanding `yes-or-no' looks for a word starting with `no'.
 
-The recommended value is \"\\\\sw\\\\|\\\\s_\".")
+The recommended value is \"\\\\sw\\\\|\\\\s_\"."
+  :type '(choice (const nil)
+                regexp)
+  :group 'dabbrev)
 
-(defvar dabbrev-check-all-buffers t
+(defcustom dabbrev-check-all-buffers t
   "*Non-nil means dabbrev package should search *all* buffers.
 
 Dabbrev always searches the current buffer first.  Then, if
@@ -172,9 +218,26 @@ Dabbrev always searches the current buffer first.  Then, if
 designated by `dabbrev-select-buffers-function'.
 
 Then, if `dabbrev-check-all-buffers' is non-nil, dabbrev searches
-all the other buffers.")
-
-(defvar dabbrev-check-other-buffers t
+all the other buffers, except those named in `dabbrev-ignored-buffer-names',
+or matched by `dabbrev-ignored-regexps'."
+  :type 'boolean
+  :group 'dabbrev)
+
+(defcustom dabbrev-ignored-buffer-names '("*Messages*" "*Buffer List*")
+  "*List of buffer names that dabbrev should not check.
+See also `dabbrev-ignored-buffer-regexps'."
+  :type '(repeat (string :tag "Buffer name"))
+  :group 'dabbrev
+  :version "20.3")
+
+(defcustom dabbrev-ignored-buffer-regexps nil
+  "*List of regexps matching names of buffers that dabbrev should not check.
+See also `dabbrev-ignored-buffer-names'."
+  :type '(repeat regexp)
+  :group 'dabbrev
+  :version "21.1")
+
+(defcustom dabbrev-check-other-buffers t
   "*Should \\[dabbrev-expand] look in other buffers?\
 
 nil: Don't look in other buffers.
@@ -184,7 +247,11 @@ Anything else: When we can't find any more expansions in
 the current buffer, then ask the user whether to look in other
 buffers too.
 
-The default value is t.")
+The default value is t."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "on" t)
+                (other :tag "ask" other))
+  :group 'dabbrev)
 
 ;; I guess setting this to a function that selects all C- or C++-
 ;; mode buffers would be a good choice for a debugging buffer,
@@ -192,12 +259,12 @@ The default value is t.")
 (defvar dabbrev-select-buffers-function 'dabbrev--select-buffers
   "A function that selects buffers that should be searched by dabbrev.
 The function should take no arguments and return a list of buffers to
-search for expansions.  Have a look at `dabbrev--select-buffers' for
-an example.
+search for expansions.  See the source of `dabbrev--select-buffers'
+for an example.
 
 A mode setting this variable should make it buffer local.")
 
-(defvar dabbrev-friend-buffer-function 'dabbrev--same-major-mode-p
+(defcustom dabbrev-friend-buffer-function 'dabbrev--same-major-mode-p
   "*A function to decide whether dabbrev should search OTHER-BUFFER.
 The function should take one argument, OTHER-BUFFER, and return
 non-nil if that buffer should be searched.  Have a look at
@@ -207,13 +274,16 @@ The value of `dabbrev-friend-buffer-function' has an effect only if
 the value of `dabbrev-select-buffers-function' uses it.  The function
 `dabbrev--select-buffers' is one function you can use here.
 
-A mode setting this variable should make it buffer local.")
+A mode setting this variable should make it buffer local."
+  :type 'function
+  :group 'dabbrev)
 
-(defvar dabbrev-search-these-buffers-only nil
+(defcustom dabbrev-search-these-buffers-only nil
   "If non-nil, a list of buffers which dabbrev should search.
 If this variable is non-nil, dabbrev will only look in these buffers.
 It will not even look in the current buffer if it is not a member of
-this list.")
+this list."
+  :group 'dabbrev)
 
 ;;----------------------------------------------------------------
 ;; Internal variables
@@ -243,7 +313,7 @@ this list.")
 ;; The list of remaining buffers with the same mode as current buffer.
 (defvar dabbrev--friend-buffer-list nil)
 
-;; The buffer we looked in last.
+;; The buffer we looked in last, not counting the current buffer.
 (defvar dabbrev--last-buffer nil)
 
 ;; The buffer we found the expansion last time.
@@ -252,8 +322,8 @@ this list.")
 ;; The buffer we last did a completion in.
 (defvar dabbrev--last-completion-buffer nil)
 
-;; Non-nil means we should upcase
-;; when copying successive words.
+;; If non-nil, a function to use when copying successive words.
+;; It should be `upcase' or `downcase'.
 (defvar dabbrev--last-case-pattern nil)
 
 ;; Same as dabbrev-check-other-buffers, but is set for every expand.
@@ -275,24 +345,22 @@ this list.")
 ;; variable ELEMENT, and include it in the result
 ;; if CONDITION evaluates non-nil.
 (defmacro dabbrev-filter-elements (element list condition)
-  (` (let (dabbrev-result dabbrev-tail (, element))
-       (setq dabbrev-tail (, list))
-       (while dabbrev-tail
-        (setq (, element) (car dabbrev-tail))
-        (if (, condition)
-            (setq dabbrev-result (cons (, element) dabbrev-result)))
-        (setq dabbrev-tail (cdr dabbrev-tail)))
-       (nreverse dabbrev-result))))
+  `(let (dabbrev-result dabbrev-tail ,element)
+    (setq dabbrev-tail ,list)
+    (while dabbrev-tail
+      (setq ,element (car dabbrev-tail))
+      (if ,condition
+          (setq dabbrev-result (cons ,element dabbrev-result)))
+      (setq dabbrev-tail (cdr dabbrev-tail)))
+    (nreverse dabbrev-result)))
 
 ;;----------------------------------------------------------------
 ;; Exported functions
 ;;----------------------------------------------------------------
 
-;;;###autoload
-(define-key esc-map "/" 'dabbrev-expand)
+;;;###autoload (define-key esc-map "/" 'dabbrev-expand)
 ;;;??? Do we want this?
-;;;###autoload
-(define-key esc-map [?\C-/] 'dabbrev-completion)
+;;;###autoload (define-key esc-map [?\C-/] 'dabbrev-completion)
 
 ;;;###autoload
 (defun dabbrev-completion (&optional arg)
@@ -305,74 +373,58 @@ function pointed out by `dabbrev-friend-buffer-function' to find the
 completions.
 
 If the prefix argument is 16 (which comes from C-u C-u),
-then it searches *all* buffers.
-
-With no prefix argument, it reuses an old completion list
-if there is a suitable one already."
-
+then it searches *all* buffers."
   (interactive "*P")
   (dabbrev--reset-global-variables)
   (let* ((dabbrev-check-other-buffers (and arg t))
         (dabbrev-check-all-buffers
          (and arg (= (prefix-numeric-value arg) 16)))
         (abbrev (dabbrev--abbrev-at-point))
-        (ignore-case-p  (and (eval dabbrev-case-fold-search)
-                             (or (not dabbrev-upcase-means-case-search)
-                                 (string= abbrev (downcase abbrev)))))
+        (ignore-case-p (and (if (eq dabbrev-case-fold-search 'case-fold-search)
+                                case-fold-search
+                              dabbrev-case-fold-search)
+                            (or (not dabbrev-upcase-means-case-search)
+                                (string= abbrev (downcase abbrev)))))
         (my-obarray dabbrev--last-obarray)
         init)
     (save-excursion
-      (if (and (null arg)
-              my-obarray
-              (or (eq dabbrev--last-completion-buffer (current-buffer))
-                  (and (window-minibuffer-p (selected-window))
-                       (eq dabbrev--last-completion-buffer
-                           (dabbrev--minibuffer-origin))))
-              dabbrev--last-abbreviation
-              (>= (length abbrev) (length dabbrev--last-abbreviation))
-              (string= dabbrev--last-abbreviation
-                       (substring abbrev 0
-                                  (length dabbrev--last-abbreviation)))
-              (setq init (try-completion abbrev my-obarray)))
-         ;; We can reuse the existing completion list.
-         nil
-       ;;--------------------------------
-       ;; New abbreviation to expand.
-       ;;--------------------------------
-       (setq dabbrev--last-abbreviation abbrev)
-       ;; Find all expansion
-       (let ((completion-list
-              (dabbrev--find-all-expansions abbrev ignore-case-p))
-             (completion-ignore-case ignore-case-p))
-         ;; Make an obarray with all expansions
-         (setq my-obarray (make-vector (length completion-list) 0))
-         (or (> (length my-obarray) 0)
-             (error "No dynamic expansion for \"%s\" found%s"
-                    abbrev
-                    (if dabbrev--check-other-buffers "" " in this-buffer")))
-         (cond
-          ((or (not ignore-case-p)
-               (not dabbrev-case-replace))
-           (mapcar (function (lambda (string)
-                               (intern string my-obarray)))
-                   completion-list))
-          ((string= abbrev (upcase abbrev))
-           (mapcar (function (lambda (string)
-                               (intern (upcase string) my-obarray)))
-                   completion-list))
-          ((string= (substring abbrev 0 1)
-                    (upcase (substring abbrev 0 1)))
-           (mapcar (function (lambda (string)
-                               (intern (capitalize string) my-obarray)))
-                   completion-list))
-          (t
-           (mapcar (function (lambda (string)
-                               (intern (downcase string) my-obarray)))
-                   completion-list)))
-         (setq dabbrev--last-obarray my-obarray)
-         (setq dabbrev--last-completion-buffer (current-buffer))
-         ;; Find the longest common string.
-         (setq init (try-completion abbrev my-obarray)))))
+      ;;--------------------------------
+      ;; New abbreviation to expand.
+      ;;--------------------------------
+      (setq dabbrev--last-abbreviation abbrev)
+      ;; Find all expansion
+      (let ((completion-list
+            (dabbrev--find-all-expansions abbrev ignore-case-p))
+           (completion-ignore-case ignore-case-p))
+       ;; Make an obarray with all expansions
+       (setq my-obarray (make-vector (length completion-list) 0))
+       (or (> (length my-obarray) 0)
+           (error "No dynamic expansion for \"%s\" found%s"
+                  abbrev
+                  (if dabbrev--check-other-buffers "" " in this-buffer")))
+       (cond
+        ((or (not ignore-case-p)
+             (not dabbrev-case-replace))
+         (mapc (function (lambda (string)
+                           (intern string my-obarray)))
+               completion-list))
+        ((string= abbrev (upcase abbrev))
+         (mapc (function (lambda (string)
+                           (intern (upcase string) my-obarray)))
+               completion-list))
+        ((string= (substring abbrev 0 1)
+                  (upcase (substring abbrev 0 1)))
+         (mapc (function (lambda (string)
+                           (intern (capitalize string) my-obarray)))
+               completion-list))
+        (t
+         (mapc (function (lambda (string)
+                           (intern (downcase string) my-obarray)))
+               completion-list)))
+       (setq dabbrev--last-obarray my-obarray)
+       (setq dabbrev--last-completion-buffer (current-buffer))
+       ;; Find the longest common string.
+       (setq init (try-completion abbrev my-obarray))))
     ;;--------------------------------
     ;; Let the user choose between the expansions
     ;;--------------------------------
@@ -386,12 +438,13 @@ if there is a suitable one already."
          (message "Repeat `%s' to see all completions"
                   (key-description (this-command-keys)))
        (message "The only possible completion"))
-      (dabbrev--substitute-expansion nil abbrev init))
+      (dabbrev--substitute-expansion nil abbrev init nil))
      (t
       ;; * String is a common substring completion already.  Make list.
       (message "Making completion list...")
-      (with-output-to-temp-buffer " *Completions*"
-       (display-completion-list (all-completions init my-obarray)))
+      (with-output-to-temp-buffer "*Completions*"
+       (display-completion-list (all-completions init my-obarray)
+                                init))
       (message "Making completion list...done")))
     (and (window-minibuffer-p (selected-window))
         (message nil))))
@@ -439,7 +492,7 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
            (setq direction dabbrev--last-direction))
        ;; If the user inserts a space after expanding
        ;; and then asks to expand again, always fetch the next word.
-       (if (and (eq (preceding-char) ?\ )
+       (if (and (eq (preceding-char) ?\s)
                 (markerp dabbrev--last-abbrev-location)
                 (marker-position dabbrev--last-abbrev-location)
                 (= (point) (1+ dabbrev--last-abbrev-location)))
@@ -447,28 +500,27 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
              ;; The "abbrev" to expand is just the space.
              (setq abbrev " ")
              (save-excursion
-               (if dabbrev--last-buffer
-                   (set-buffer dabbrev--last-buffer))
-               ;; Find the end of the last "expansion" word.
-               (if (or (eq dabbrev--last-direction 1)
-                       (and (eq dabbrev--last-direction 0)
-                            (< dabbrev--last-expansion-location (point))))
-                   (setq dabbrev--last-expansion-location
-                         (+ dabbrev--last-expansion-location
-                            (length dabbrev--last-expansion))))
-               (goto-char dabbrev--last-expansion-location)
-               ;; Take the following word, with intermediate separators,
-               ;; as our expansion this time.
-               (re-search-forward
-                (concat "\\(\\(" dabbrev--abbrev-char-regexp "\\)+\\)"))
-               (setq expansion
-                     (buffer-substring dabbrev--last-expansion-location
-                                       (point)))
-               (if dabbrev--last-case-pattern
-                   (setq expansion (upcase expansion)))
-
-               ;; Record the end of this expansion, in case we repeat this.
-               (setq dabbrev--last-expansion-location (point)))
+               (save-restriction
+                 (widen)
+                 (if dabbrev--last-buffer
+                     (set-buffer dabbrev--last-buffer))
+                 ;; Find the end of the last "expansion" word.
+                 (if (or (eq dabbrev--last-direction 1)
+                         (and (eq dabbrev--last-direction 0)
+                              (< dabbrev--last-expansion-location (point))))
+                     (setq dabbrev--last-expansion-location
+                           (+ dabbrev--last-expansion-location
+                              (length dabbrev--last-expansion))))
+                 (goto-char dabbrev--last-expansion-location)
+                 ;; Take the following word, with intermediate separators,
+                 ;; as our expansion this time.
+                 (re-search-forward
+                  (concat "\\(?:" dabbrev--abbrev-char-regexp "\\)+"))
+                 (setq expansion (buffer-substring-no-properties
+                                  dabbrev--last-expansion-location (point)))
+
+                 ;; Record the end of this expansion, in case we repeat this.
+                 (setq dabbrev--last-expansion-location (point))))
              ;; Indicate that dabbrev--last-expansion-location is
              ;; at the end of the expansion.
              (setq dabbrev--last-direction -1))
@@ -488,7 +540,9 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
       (or expansion
          (setq expansion
                (dabbrev--find-expansion abbrev direction
-                                        (and (eval dabbrev-case-fold-search)
+                                        (and (if (eq dabbrev-case-fold-search 'case-fold-search)
+                                                 case-fold-search
+                                               dabbrev-case-fold-search)
                                              (or (not dabbrev-upcase-means-case-search)
                                                  (string= abbrev (downcase abbrev))))))))
     (cond
@@ -504,7 +558,8 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
       (error "No%s dynamic expansion for `%s' found"
             (if old " further" "") abbrev))
      (t
-      (if (not (eq dabbrev--last-buffer dabbrev--last-buffer-found))
+      (if (not (or (eq dabbrev--last-buffer dabbrev--last-buffer-found)
+                  (minibuffer-window-active-p (selected-window))))
          (progn
            (message "Expansion found in '%s'"
                     (buffer-name dabbrev--last-buffer))
@@ -518,18 +573,11 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
                (copy-marker dabbrev--last-expansion-location)))
       ;; Success: stick it in and return.
       (setq buffer-undo-list (cons orig-point buffer-undo-list))
-      (dabbrev--substitute-expansion old abbrev expansion)
-
-      ;; If we are not copying successive words now,
-      ;; set dabbrev--last-case-pattern.
-      (and record-case-pattern
-          (setq dabbrev--last-case-pattern
-                (and (eval dabbrev-case-fold-search)
-                     (not dabbrev-upcase-means-case-search)
-                     (equal abbrev (upcase abbrev)))))
+      (dabbrev--substitute-expansion old abbrev expansion
+                                    record-case-pattern)
 
       ;; Save state for re-expand.
-      (setq dabbrev--last-expansion expansion) 
+      (setq dabbrev--last-expansion expansion)
       (setq dabbrev--last-abbreviation abbrev)
       (setq dabbrev--last-abbrev-location (point-marker))))))
 
@@ -549,14 +597,15 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
 (defun dabbrev--goto-start-of-abbrev ()
   ;; Move backwards over abbrev chars
   (save-match-data
-    (if (not (bobp))
-       (progn
-         (forward-char -1)
-         (while (and (looking-at dabbrev--abbrev-char-regexp)
-                     (not (bobp)))
-           (forward-char -1))
-         (or (looking-at dabbrev--abbrev-char-regexp)
-             (forward-char 1))))
+    (when (> (point) (minibuffer-prompt-end))
+      (forward-char -1)
+      (while (and (looking-at dabbrev--abbrev-char-regexp)
+                 (> (point) (minibuffer-prompt-end))
+                 (not (= (point) (field-beginning (point) nil
+                                                  (1- (point))))))
+       (forward-char -1))
+      (or (looking-at dabbrev--abbrev-char-regexp)
+         (forward-char 1)))
     (and dabbrev-abbrev-skip-leading-regexp
         (while (looking-at dabbrev-abbrev-skip-leading-regexp)
           (forward-char 1)))))
@@ -588,9 +637,9 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
            (error "No possible abbreviation preceding point"))))
     ;; Now find the beginning of that one.
     (dabbrev--goto-start-of-abbrev)
-    (buffer-substring dabbrev--last-abbrev-location
-                     (point))))
-       
+    (buffer-substring-no-properties
+     dabbrev--last-abbrev-location (point))))
+
 ;;; Initializes all global variables
 (defun dabbrev--reset-global-variables ()
   ;; dabbrev--last-obarray and dabbrev--last-completion-buffer
@@ -608,22 +657,28 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
                                        "\\sw\\|\\s_")
        dabbrev--check-other-buffers dabbrev-check-other-buffers))
 
-;;; Find all buffers that are considered "friends" according to the
-;;; function pointed out by dabbrev-friend-buffer-function.
 (defun dabbrev--select-buffers ()
-  (save-excursion
-    (and (window-minibuffer-p (selected-window))
-        (set-buffer (dabbrev--minibuffer-origin)))
-    (let ((orig-buffer (current-buffer)))
-      (dabbrev-filter-elements
-       buffer (buffer-list)
-       (and (not (eq orig-buffer buffer))
-           (boundp 'dabbrev-friend-buffer-function)
-           (funcall dabbrev-friend-buffer-function buffer))))))
-
-;;; Search for ABBREV, N times, normally looking forward,
-;;; but looking in reverse instead if REVERSE is non-nil.
+  "Return a list of other buffers to search for a possible abbrev.
+The current buffer is not included in the list.
+
+This function makes a list of all the buffers returned by `buffer-list',
+then discards buffers whose names match `dabbrev-ignored-buffer-names'
+or `dabbrev-ignored-buffer-regexps'.  It also discards buffers for which
+`dabbrev-friend-buffer-function', if it is bound, returns nil when called
+with the buffer as argument.
+It returns the list of the buffers that are not discarded."
+  (dabbrev-filter-elements
+   buffer (buffer-list)
+   (and (not (eq (current-buffer) buffer))
+       (not (dabbrev--ignore-buffer-p buffer))
+       (boundp 'dabbrev-friend-buffer-function)
+       (funcall dabbrev-friend-buffer-function buffer))))
+
 (defun dabbrev--try-find (abbrev reverse n ignore-case)
+  "Search for ABBREV, backwards if REVERSE, N times.
+If IGNORE-CASE is non-nil, ignore case while searching.
+Return the expansion found, and save the location of the start
+of the expansion in `dabbrev--last-expansion-location'."
   (save-excursion
     (save-restriction
       (widen)
@@ -635,14 +690,19 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
          (while (and (> count 0)
                      (setq expansion (dabbrev--search abbrev
                                                       reverse
-                                                      ignore-case)))
+                                                      (and ignore-case
+                                                           (if (eq dabbrev-case-distinction 'case-replace)
+                                                               case-replace
+                                                             dabbrev-case-distinction))
+                                                      )))
            (setq count (1- count))))
        (and expansion
             (setq dabbrev--last-expansion-location (point)))
        expansion))))
 
-;;; Find all expansions of ABBREV
 (defun dabbrev--find-all-expansions (abbrev ignore-case)
+  "Return a list of all possible expansions of ABBREV.
+If IGNORE-CASE is non-nil, accept matches which differ in case."
   (let ((all-expansions nil)
        expansion)
     (save-excursion
@@ -652,137 +712,224 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
     all-expansions))
 
 (defun dabbrev--scanning-message ()
-  (message "Scanning `%s'" (buffer-name (current-buffer))))
+  (unless (window-minibuffer-p (selected-window))
+    (message "Scanning `%s'" (buffer-name (current-buffer)))))
+
+(defun dabbrev--ignore-buffer-p (buffer)
+  "Return non-nil if BUFFER should be ignored by dabbrev."
+  (let ((bn (buffer-name buffer)))
+    (or (member bn dabbrev-ignored-buffer-names)
+       (let ((tail dabbrev-ignored-buffer-regexps)
+             (match nil))
+         (while (and tail (not match))
+           (setq match (string-match (car tail) bn)
+                 tail (cdr tail)))
+         match))))
 
-;;; Find one occasion of ABBREV.
-;;; DIRECTION > 0 means look that many times backwards.
-;;; DIRECTION < 0 means look that many times forward.
-;;; DIRECTION = 0 means try both backward and forward.
-;;; IGNORE-CASE non-nil means ignore case when searching.
 (defun dabbrev--find-expansion (abbrev direction ignore-case)
-  (let (expansion)
-    (save-excursion
-      (cond
-       (dabbrev--last-buffer
-       (set-buffer dabbrev--last-buffer)
-       (dabbrev--scanning-message))
-       ((and (not dabbrev-search-these-buffers-only)
-            (window-minibuffer-p (selected-window)))
-       (set-buffer (dabbrev--minibuffer-origin))
-       ;; In the minibuffer-origin buffer we will only search from
-       ;; the top and down.
-       (goto-char (point-min))
-       (setq direction -1)
-       (dabbrev--scanning-message)))
-      (cond
-       ;; ------------------------------------------
-       ;; Look backwards
-       ;; ------------------------------------------
-       ((and (not dabbrev-search-these-buffers-only)
-            (>= direction 0)
-            (setq dabbrev--last-direction (min 1 direction))
-            (setq expansion (dabbrev--try-find abbrev t
-                                               (max 1 direction)
-                                               ignore-case)))
-       expansion)
-       ;; ------------------------------------------
-       ;; Look forward
-       ;; ------------------------------------------
-       ((and (or (not dabbrev-search-these-buffers-only)
-                dabbrev--last-buffer)
-            (<= direction 0)
-            (setq dabbrev--last-direction -1)
-            (setq expansion (dabbrev--try-find abbrev nil
-                                               (max 1 (- direction))
-                                               ignore-case)))
-       expansion)
-       ;; ------------------------------------------
-       ;; Look in other buffers.
-       ;; Start at (point-min) and look forward.
-       ;; ------------------------------------------
-       (t
-       (setq dabbrev--last-direction -1)
-       ;; Make sure that we should check other buffers
-       (or dabbrev--friend-buffer-list
-           dabbrev--last-buffer
-           (setq dabbrev--friend-buffer-list
-                 (mapcar (function get-buffer)
-                         dabbrev-search-these-buffers-only))
-           (not dabbrev--check-other-buffers)
-           (not (or (eq dabbrev--check-other-buffers t)
-                    (progn
-                      (setq dabbrev--check-other-buffers
-                            (y-or-n-p "Scan other buffers also? ")))))
-           (let* (friend-buffer-list non-friend-buffer-list)
-             (setq dabbrev--friend-buffer-list
-                   (funcall dabbrev-select-buffers-function))
-             (if dabbrev-check-all-buffers
-                 (setq non-friend-buffer-list
-                       (nreverse
-                        (dabbrev-filter-elements
-                         buffer (buffer-list)
-                         (not (memq buffer dabbrev--friend-buffer-list))))
-                       dabbrev--friend-buffer-list
-                       (append dabbrev--friend-buffer-list
-                               non-friend-buffer-list)))))
-       ;; Move buffers that are visible on the screen
-       ;; to the front of the list.
-       (if dabbrev--friend-buffer-list
-           (let ((w (next-window (selected-window))))
-             (while (not (eq w (selected-window)))
-               (setq dabbrev--friend-buffer-list
-                     (cons (window-buffer w)
-                           (delq (window-buffer w) dabbrev--friend-buffer-list)))
-               (setq w (next-window w)))))
-       ;; Walk through the buffers
-       (while (and (not expansion) dabbrev--friend-buffer-list)
-         (setq dabbrev--last-buffer
-               (car dabbrev--friend-buffer-list))
-         (setq dabbrev--friend-buffer-list
-               (cdr dabbrev--friend-buffer-list))
-         (set-buffer dabbrev--last-buffer)
-         (dabbrev--scanning-message)
-         (setq dabbrev--last-expansion-location (point-min))
-         (setq expansion (dabbrev--try-find abbrev nil 1 ignore-case)))
-       expansion)))))
+  "Find one occurrence of ABBREV, and return the expansion.
+DIRECTION > 0 means look that many times backwards.
+DIRECTION < 0 means look that many times forward.
+DIRECTION = 0 means try both backward and forward.
+IGNORE-CASE non-nil means ignore case when searching.
+This sets `dabbrev--last-direction' to 1 or -1 according
+to the direction in which the occurrence was actually found.
+It sets `dabbrev--last-expansion-location' to the location
+of the start of the occurrence."
+  (save-excursion
+    ;; If we were scanning something other than the current buffer,
+    ;; continue scanning there.
+    (when dabbrev--last-buffer
+      (set-buffer dabbrev--last-buffer)
+      (dabbrev--scanning-message))
+    (or
+     ;; ------------------------------------------
+     ;; Look backward in current buffer.
+     ;; ------------------------------------------
+     (and (not dabbrev-search-these-buffers-only)
+         (>= direction 0)
+         (setq dabbrev--last-direction (min 1 direction))
+         (dabbrev--try-find abbrev t
+                            (max 1 direction)
+                            ignore-case))
+     ;; ------------------------------------------
+     ;; Look forward in current buffer
+     ;; or whatever buffer we were last scanning.
+     ;; ------------------------------------------
+     (and (or (not dabbrev-search-these-buffers-only)
+             dabbrev--last-buffer)
+         (<= direction 0)
+         (setq dabbrev--last-direction -1)
+         (dabbrev--try-find abbrev nil
+                            (max 1 (- direction))
+                            ignore-case))
+     ;; ------------------------------------------
+     ;; Look in other buffers.
+     ;; Always start at (point-min) and look forward.
+     ;; ------------------------------------------
+     (progn
+       (setq dabbrev--last-direction -1)
+       (unless dabbrev--last-buffer
+        ;; If we have just now begun to search other buffers,
+        ;; determine which other buffers we should check.
+        ;; Put that list in dabbrev--friend-buffer-list.
+        (or dabbrev--friend-buffer-list
+            (setq dabbrev--friend-buffer-list
+                  (dabbrev--make-friend-buffer-list))))
+       ;; Walk through the buffers till we find a match.
+       (let (expansion)
+        (while (and (not expansion) dabbrev--friend-buffer-list)
+          (setq dabbrev--last-buffer (pop dabbrev--friend-buffer-list))
+          (set-buffer dabbrev--last-buffer)
+          (dabbrev--scanning-message)
+          (setq dabbrev--last-expansion-location (point-min))
+          (setq expansion (dabbrev--try-find abbrev nil 1 ignore-case)))
+        expansion)))))
+
+;; Compute the list of buffers to scan.
+;; If dabbrev-search-these-buffers-only, then the current buffer
+;; is included in this list if it should be searched.
+;; Otherwise, the current buffer is searched first specially.,
+;; and it is not included in this list.
+(defun dabbrev--make-friend-buffer-list ()
+  (let ((list (mapcar (function get-buffer)
+                     dabbrev-search-these-buffers-only)))
+    (when (and (null dabbrev-search-these-buffers-only)
+              dabbrev--check-other-buffers
+              (or (eq dabbrev--check-other-buffers t)
+                  (setq dabbrev--check-other-buffers
+                        (y-or-n-p "Scan other buffers also? "))))
+      (setq list (funcall dabbrev-select-buffers-function))
+      ;; If dabbrev-check-all-buffers, tack on all the other
+      ;; buffers at the end of the list, except those which are
+      ;; specifically to be ignored.
+      (if dabbrev-check-all-buffers
+         (setq list
+               (append list
+                       (dabbrev-filter-elements
+                        buffer (buffer-list)
+                        (and (not (memq buffer list))
+                             (not (dabbrev--ignore-buffer-p buffer)))))))
+      ;; Remove the current buffer.
+      (setq list (delq (current-buffer) list)))
+    ;; Move buffers in the list that are visible on the screen
+    ;; to the front of the list, but don't add anything to the list.
+    (if list
+       (walk-windows (lambda (w)
+                       (unless (eq w (selected-window))
+                         (if (memq (window-buffer w) list)
+                             (setq list
+                                   (cons (window-buffer w)
+                                         (delq (window-buffer w)
+                                               list))))))))
+    ;; In a minibuffer, search the buffer it was activated from,
+    ;; first after the minibuffer itself.  Unless we aren't supposed
+    ;; to search the current buffer either.
+    (if (and (window-minibuffer-p (selected-window))
+            (not dabbrev-search-these-buffers-only))
+       (setq list
+             (cons (dabbrev--minibuffer-origin)
+                   (delq (dabbrev--minibuffer-origin) list))))
+    list))
 
 (defun dabbrev--safe-replace-match (string &optional fixedcase literal)
   (if (eq major-mode 'picture-mode)
-      (picture-replace-match string fixedcase literal)
+      (with-no-warnings
+       (picture-replace-match string fixedcase literal))
     (replace-match string fixedcase literal)))
 
 ;;;----------------------------------------------------------------
-;;; Substitute the current string in buffer with the expansion
-;;; OLD is nil or the last expansion substring.
-;;; ABBREV is the abbreviation we are working with.
-;;; EXPANSION is the expansion substring.
-(defun dabbrev--substitute-expansion (old abbrev expansion)
+(defun dabbrev--substitute-expansion (old abbrev expansion record-case-pattern)
+  "Replace OLD with EXPANSION in the buffer.
+OLD is text currently in the buffer, perhaps the abbreviation
+or perhaps another expansion that was tried previously.
+ABBREV is the abbreviation we are expanding.
+It is \" \" if we are copying subsequent words.
+EXPANSION is the expansion substring to be used this time.
+RECORD-CASE-PATTERN, if non-nil, means set `dabbrev--last-case-pattern'
+to record whether we upcased the expansion, downcased it, or did neither."
   ;;(undo-boundary)
-  (let ((use-case-replace (and (eval dabbrev-case-fold-search)
+  (let ((use-case-replace (and (if (eq dabbrev-case-fold-search 'case-fold-search)
+                                  case-fold-search
+                                dabbrev-case-fold-search)
                               (or (not dabbrev-upcase-means-case-search)
                                   (string= abbrev (downcase abbrev)))
-                              (eval dabbrev-case-replace))))
-    (and nil use-case-replace
-        (setq old (concat abbrev (or old "")))
-        (setq expansion (concat abbrev expansion)))
-    ;; If the given abbrev is mixed case and its case pattern
+                              (if (eq dabbrev-case-replace 'case-replace)
+                                  case-replace
+                                dabbrev-case-replace))))
+
+    ;; If we upcased or downcased the original expansion,
+    ;; do likewise for the subsequent words when we copy them.
+    ;; Don't do any of the usual case processing, though.
+    (when (equal abbrev " ")
+      (if dabbrev--last-case-pattern
+         (setq expansion
+               (funcall dabbrev--last-case-pattern expansion)))
+      (setq use-case-replace nil))
+
+    ;; If the expansion has mixed case
+    ;; and it is not simply a capitalized word,
+    ;; or if the abbrev has mixed case,
+    ;; and if the given abbrev's case pattern
     ;; matches the start of the expansion,
     ;; copy the expansion's case
     ;; instead of downcasing all the rest.
-    (if (and (string= abbrev
-                     (substring expansion 0 (length abbrev)))
-            (not (string= abbrev (downcase abbrev)))
-            (not (string= abbrev (upcase abbrev))))
-       (setq use-case-replace nil))
-    (if (equal abbrev " ")
+    ;;
+    ;; Treat a one-capital-letter (possibly with preceding non-letter
+    ;; characters) abbrev as "not all upper case", so as to force
+    ;; preservation of the expansion's pattern if the expansion starts
+    ;; with a capital letter.
+    (let ((expansion-rest (substring expansion 1))
+         (first-letter-position (string-match "[[:alpha:]]" abbrev)))
+      (if (or (null first-letter-position)
+             (and (not (and (or (string= expansion-rest (downcase expansion-rest))
+                                (string= expansion-rest (upcase expansion-rest)))
+                            (or (string= abbrev (downcase abbrev))
+                                (and (string= abbrev (upcase abbrev))
+                                     (> (- (length abbrev) first-letter-position)
+                                        1)))))
+                  (string= abbrev
+                           (substring expansion 0 (length abbrev)))))
+         (setq use-case-replace nil)))
+
+    ;; If the abbrev and the expansion are both all-lower-case
+    ;; then don't do any conversion.  The conversion would be a no-op
+    ;; for this replacement, but it would carry forward to subsequent words.
+    ;; The goal of this is to prevent that carrying forward.
+    (if (and (string= expansion (downcase expansion))
+            (string= abbrev (downcase abbrev)))
        (setq use-case-replace nil))
+
     (if use-case-replace
        (setq expansion (downcase expansion)))
+
+    ;; In case we insert subsequent words,
+    ;; record if we upcased or downcased the first word,
+    ;; in order to do likewise for subsequent words.
+    (and record-case-pattern
+        (setq dabbrev--last-case-pattern
+              (and use-case-replace
+                   (cond ((equal abbrev (upcase abbrev)) 'upcase)
+                         ((equal abbrev (downcase abbrev)) 'downcase)))))
+
+    ;; Convert whitespace to single spaces.
+    (if dabbrev-eliminate-newlines
+       (let ((pos
+              (if (equal abbrev " ") 0 (length abbrev))))
+         ;; If ABBREV is real, search after the end of it.
+         ;; If ABBREV is space and we are copying successive words,
+         ;; search starting at the front.
+         (while (string-match "[\n \t]+" expansion pos)
+           (setq pos (1+ (match-beginning 0)))
+           (setq expansion (replace-match " " nil nil expansion)))))
+
     (if old
        (save-excursion
          (search-backward old))
-      ;;(store-match-data (list (point-marker) (point-marker)))
-      (search-backward abbrev))
+      ;;(set-match-data (list (point-marker) (point-marker)))
+      (search-backward abbrev)
+      (search-forward abbrev))
+
     ;; Make case of replacement conform to case of abbreviation
     ;; provided (1) that kind of thing is enabled in this buffer
     ;; and (2) the replacement itself is all lower case.
@@ -794,28 +941,33 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
 ;;;----------------------------------------------------------------
 ;;; Search function used by dabbrevs library.
 
-;;; ABBREV is string to find as prefix of word.  Second arg, REVERSE,
-;;; is t for reverse search, nil for forward.  Variable dabbrev-limit
-;;; controls the maximum search region size.  Third argument IGNORE-CASE
-;;; non-nil means treat case as insignificant while looking for a match
-;;; and when comparing with previous matches.  Also if that's non-nil
-;;; and the match is found at the beginning of a sentence and is in
-;;; lower case except for the initial then it is converted to all lower
-;;; case for return.
-
-;;; Table of expansions already seen is examined in buffer
-;;; `dabbrev--last-table' so that only distinct possibilities are found
-;;; by dabbrev-re-expand.
-
-;;; Value is the expansion, or nil if not found.
 
 (defun dabbrev--search (abbrev reverse ignore-case)
+  "Search for something that could be used to expand ABBREV.
+
+Second arg, REVERSE, is t for reverse search, nil for forward.
+The variable `dabbrev-limit' controls the maximum search region size.
+Third argument IGNORE-CASE non-nil means treat case as insignificant while
+looking for a match and when comparing with previous matches.  Also if
+that's non-nil and the match is found at the beginning of a sentence
+and is in lower case except for the initial then it is converted to
+all lower case for return.
+
+Table of expansions already seen is examined in buffer
+`dabbrev--last-table' so that only distinct possibilities are found
+by dabbrev-re-expand.
+
+Returns the expansion found, or nil if not found.
+Leaves point at the location of the start of the expansion."
   (save-match-data
     (let ((pattern1 (concat (regexp-quote abbrev)
                            "\\(" dabbrev--abbrev-char-regexp "\\)"))
          (pattern2 (concat (regexp-quote abbrev)
                           "\\(\\(" dabbrev--abbrev-char-regexp "\\)+\\)"))
-         (found-string nil))
+         ;; This makes it possible to find matches in minibuffer prompts
+         ;; even when they are "inviolable".
+         (inhibit-point-motion-hooks t)
+         found-string result)
       ;; Limited search.
       (save-restriction
        (and dabbrev-limit
@@ -838,8 +990,8 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
              nil
            ;; We have a truly valid match.  Find the end.
            (re-search-forward pattern2)
-           (setq found-string
-                 (buffer-substring (match-beginning 1) (match-end 1)))
+           (setq found-string (match-string-no-properties 0))
+           (setq result found-string)
            (and ignore-case (setq found-string (downcase found-string)))
            ;; Ignore this match if it's already in the table.
            (if (dabbrev-filter-elements
@@ -847,21 +999,21 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
                 (string= found-string table-string))
                (setq found-string nil)))
          ;; Prepare to continue searching.
-         (if reverse
-             (goto-char (match-beginning 0))
-           (goto-char (match-end 0))))
+         (goto-char (if reverse (match-beginning 0) (match-end 0))))
        ;; If we found something, use it.
-       (if found-string
-           ;; Put it into `dabbrev--last-table'
-           ;; and return it (either downcased, or as is).
-           (let ((result
-                  (buffer-substring (match-beginning 0) (match-end 0))))
-             (setq dabbrev--last-table
-                   (cons found-string dabbrev--last-table))
-             (if (and ignore-case (eval dabbrev-case-replace))
-                 result
-               result)))))))
+       (when found-string
+         ;; Put it into `dabbrev--last-table'
+         ;; and return it (either downcased, or as is).
+         (setq dabbrev--last-table
+               (cons found-string dabbrev--last-table))
+         result)))))
+
+(dolist (mess '("^No dynamic expansion for .* found$"
+               "^No further dynamic expansion for .* found$"
+               "^No possible abbreviation preceding point$"))
+  (add-to-list 'debug-ignored-errors mess))
 
 (provide 'dabbrev)
 
+;;; arch-tag: 29e58596-f080-4306-a409-70296cf9d46f
 ;;; dabbrev.el ends here