X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c4ca64dbae24a2206cbc35273258ed3a9e165a63..9edfb3d2a1d7480ed6566c5e7b25036d9c47eb19:/lisp/dabbrev.el diff --git a/lisp/dabbrev.el b/lisp/dabbrev.el index a5a37c3d20..c9591950f5 100644 --- a/lisp/dabbrev.el +++ b/lisp/dabbrev.el @@ -1,6 +1,6 @@ ;;; dabbrev.el --- dynamic abbreviation package -;; Copyright (C) 1985, 86, 92, 94, 96, 1997, 2000, 2001 +;; Copyright (C) 1985, 86, 92, 94, 96, 1997, 2000, 01, 2003 ;; Free Software Foundation, Inc. ;; Author: Don Morrison @@ -128,6 +128,12 @@ Set this to nil if no characters should be skipped." (const :tag "off" nil)) :group 'dabbrev) +(defcustom dabbrev--eliminate-newlines t + "*Non-nil means dabbrev should not insert newlines. +Instead it converts them to spaces." + :type 'boolean + :group 'dabbrev) + (defcustom dabbrev-case-fold-search 'case-fold-search "*Control whether dabbrev searches should ignore case. A value of nil means case is significant. @@ -141,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) @@ -235,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.") @@ -288,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. @@ -333,11 +357,9 @@ this list.") ;; 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) @@ -437,7 +459,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)) @@ -589,14 +611,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))))) @@ -648,22 +671,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) @@ -675,14 +704,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 @@ -692,113 +726,133 @@ 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 + "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 + (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) - (let ((bn (buffer-name buffer))) - (and (not (member bn dabbrev-ignored-buffer-names)) - (not (memq buffer dabbrev--friend-buffer-list)) - (not - (let ((tail dabbrev-ignored-buffer-regexps) - (match nil)) - (while (and tail (not match)) - (setq match (string-match (car tail) bn) - tail (cdr tail))) - match))))) - 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) - (picture-replace-match string fixedcase literal) + (with-no-warnings + (picture-replace-match string fixedcase literal)) (replace-match string fixedcase literal))) ;;;---------------------------------------------------------------- @@ -823,10 +877,12 @@ to record whether we upcased the expansion, downcased it, or did neither." ;; If we upcased or downcased the original expansion, ;; do likewise for the subsequent words when we copy them. - (and (equal abbrev " ") - dabbrev--last-case-pattern - (setq expansion - (funcall dabbrev--last-case-pattern expansion))) + ;; 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, @@ -847,8 +903,15 @@ to record whether we upcased the expansion, downcased it, or did neither." (string= abbrev (substring expansion 0 (length abbrev)))) (setq use-case-replace nil))) - (if (equal abbrev " ") + + ;; 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 preven 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))) @@ -856,16 +919,27 @@ to record whether we upcased the expansion, downcased it, or did neither." ;; 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 + (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 + ;; Start searching at end of ABBREV so that any whitespace + ;; carried over from the existing text is not changed. + (let ((pos (length abbrev))) + (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)) ;;(set-match-data (list (point-marker) (point-marker))) - (search-backward abbrev)) + (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. @@ -877,28 +951,33 @@ to record whether we upcased the expansion, downcased it, or did neither." ;;;---------------------------------------------------------------- ;;; 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 @@ -922,7 +1001,8 @@ to record whether we upcased the expansion, downcased it, or did neither." ;; 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 @@ -934,16 +1014,12 @@ to record whether we upcased the expansion, downcased it, or did neither." (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$" @@ -952,4 +1028,5 @@ to record whether we upcased the expansion, downcased it, or did neither." (provide 'dabbrev) +;;; arch-tag: 29e58596-f080-4306-a409-70296cf9d46f ;;; dabbrev.el ends here