(smtpmail-send-queued-mail): Add autoload cookie.
[bpt/emacs.git] / lisp / dabbrev.el
index 297ad59..9dba5d6 100644 (file)
@@ -147,23 +147,41 @@ Any other non-nil version means case is not significant."
 
 (defcustom 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.
+nil 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)
 
+(defcustom dabbrev-case-distinction 'case-replace
+  "*Whether dabbrev treats expansions as the same if they differ in case.
+
+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' 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 "21.4")
+
 (defcustom dabbrev-case-replace 'case-replace
-  "*Controls whether dabbrev preserves case when expanding the abbreviation.
-A value of nil means preserve case.
-A value of `case-replace' means preserve case if `case-replace' is nil.
-Any other non-nil version means do not preserve case.
+  "*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' specifies to ignore case."
   :type '(choice (const :tag "off" nil)
-                (const :tag "like M-x query-replace" case-replace)
+                (const :tag "based on `case-replace'" case-replace)
                 (other :tag "on" t))
   :group 'dabbrev)
 
@@ -241,8 +259,8 @@ 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.")
 
@@ -294,7 +312,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.
@@ -443,7 +461,7 @@ if there is a suitable one already."
      (t
       ;; * String is a common substring completion already.  Make list.
       (message "Making completion list...")
-      (with-output-to-temp-buffer " *Completions*"
+      (with-output-to-temp-buffer "*Completions*"
        (display-completion-list (all-completions init my-obarray)))
       (message "Making completion list...done")))
     (and (window-minibuffer-p (selected-window))
@@ -599,7 +617,9 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
        (progn
          (forward-char -1)
          (while (and (looking-at dabbrev--abbrev-char-regexp)
-                     (not (bobp)))
+                     (not (bobp))
+                     (not (= (point) (field-beginning (point) nil
+                                                      (1- (point))))))
            (forward-char -1))
          (or (looking-at dabbrev--abbrev-char-regexp)
              (forward-char 1))))
@@ -655,21 +675,21 @@ See also `dabbrev-abbrev-char-regexp' and \\[dabbrev-completion]."
        dabbrev--check-other-buffers dabbrev-check-other-buffers))
 
 (defun dabbrev--select-buffers ()
-  "Return a list of all buffers that should be searched for a possible abbrev.
-
-This function makes a list of all the buffers returned by `buffer-list', and
-then filters out every buffer for which `dabbrev-friend-buffer-function',
-if it is bound, returns nil.  The resulting partial list is returned."
-  (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))
-           (not (dabbrev--ignore-buffer-p buffer))
-           (boundp 'dabbrev-friend-buffer-function)
-           (funcall dabbrev-friend-buffer-function buffer))))))
+  "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.
@@ -687,7 +707,11 @@ of the expansion in `dabbrev--last-expansion-location'."
          (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)))
@@ -705,7 +729,8 @@ If IGNORE-CASE is non-nil, accept matches which differ in case."
     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."
@@ -728,93 +753,104 @@ 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."
-  (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
+  (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
+                (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)))))
+
+;; 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 dabbrev--friend-buffer-list))
-                             (not (dabbrev--ignore-buffer-p buffer))))
-                       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.  Remove the current buffer.
-       (when dabbrev--friend-buffer-list
-         (walk-windows (lambda (w)
-                         (unless (eq w (selected-window))
-                           (setq dabbrev--friend-buffer-list
-                                 (cons (window-buffer w)
-                                       (delq (window-buffer w)
-                                             dabbrev--friend-buffer-list))))))
-         (setq dabbrev--friend-buffer-list
-               (delq (current-buffer) dabbrev--friend-buffer-list)))
-       ;; 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)))))
+                        (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)
@@ -936,7 +972,10 @@ Leaves point at the location of the start of the expansion."
                            "\\(" 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
@@ -960,7 +999,8 @@ Leaves point at the location of the start of the expansion."
            ;; We have a truly valid match.  Find the end.
            (re-search-forward pattern2)
            (setq found-string (buffer-substring-no-properties
-                               (match-beginning 1) (match-end 1)))
+                               (match-beginning 0) (match-end 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
@@ -972,16 +1012,12 @@ Leaves point at the location of the start of the expansion."
              (goto-char (match-beginning 0))
            (goto-char (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-no-properties
-                          (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$"