]> code.delx.au - gnu-emacs/blobdiff - lisp/complete.el
(normal-splash-screen, fancy-splash-screens-1): Add a reference to the Lisp
[gnu-emacs] / lisp / complete.el
index 337af81de71281eae848484441ec8b15a5a347f1..6620db860c319e7a898b043b2a546e79b25e83ce 100644 (file)
@@ -1,7 +1,7 @@
 ;;; complete.el --- partial completion mechanism plus other goodies
 
-;; Copyright (C) 1990, 1991, 1992, 1993, 1999, 2000, 2003, 2005
-;;  Free Software Foundation, Inc.
+;; Copyright (C) 1990, 1991, 1992, 1993, 1999, 2000, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Dave Gillespie <daveg@synaptics.com>
 ;; Keywords: abbrev convenience
@@ -21,8 +21,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:
 
@@ -94,7 +94,7 @@
   :group 'convenience)
 
 (defcustom PC-first-char 'find-file
-  "*Control how the first character of a string is to be interpreted.
+  "Control how the first character of a string is to be interpreted.
 If nil, the first character of a string is not taken literally if it is a word
 delimiter, so that \".e\" matches \"*.e*\".
 If t, the first character of a string is always taken literally even if it is a
@@ -107,13 +107,13 @@ completion."
   :group 'partial-completion)
 
 (defcustom PC-meta-flag t
-  "*If non-nil, TAB means PC completion and M-TAB means normal completion.
+  "If non-nil, TAB means PC completion and M-TAB means normal completion.
 Otherwise, TAB means normal completion and M-TAB means Partial Completion."
   :type 'boolean
   :group 'partial-completion)
 
 (defcustom PC-word-delimiters "-_. "
-  "*A string of characters treated as word delimiters for completion.
+  "A string of characters treated as word delimiters for completion.
 Some arcane rules:
 If `]' is in this string, it must come first.
 If `^' is in this string, it must not come first.
@@ -124,13 +124,13 @@ expression (not containing character ranges like `a-z')."
   :group 'partial-completion)
 
 (defcustom PC-include-file-path '("/usr/include" "/usr/local/include")
-  "*A list of directories in which to look for include files.
+  "A list of directories in which to look for include files.
 If nil, means use the colon-separated path in the variable $INCPATH instead."
   :type '(repeat directory)
   :group 'partial-completion)
 
 (defcustom PC-disable-includes nil
-  "*If non-nil, include-file support in \\[find-file] is disabled."
+  "If non-nil, include-file support in \\[find-file] is disabled."
   :type 'boolean
   :group 'partial-completion)
 
@@ -141,8 +141,6 @@ If nil, means use the colon-separated path in the variable $INCPATH instead."
   "A list of the environment variable names and values.")
 
 \f
-(defvar PC-old-read-file-name-internal nil)
-
 (defun PC-bindings (bind)
   (let ((completion-map minibuffer-local-completion-map)
        (must-match-map minibuffer-local-must-match-map))
@@ -203,31 +201,48 @@ other file in that directory begin with that sequence of characters.
 Unless `PC-disable-includes' is non-nil, the `<...>' sequence is interpreted
 specially in \\[find-file].  For example,
 \\[find-file] <sys/time.h> RET finds the file `/usr/include/sys/time.h'.
-See also the variable `PC-include-file-path'."
+See also the variable `PC-include-file-path'.
+
+Partial Completion mode extends the meaning of `completion-auto-help' (which
+see), so that if it is neither nil nor t, Emacs shows the `*Completions*'
+buffer only on the second attempt to complete.  That is, if TAB finds nothing
+to complete, the first TAB just says \"Next char not unique\" and the
+second TAB brings up the `*Completions*' buffer."
   :global t :group 'partial-completion
   ;; Deal with key bindings...
   (PC-bindings partial-completion-mode)
   ;; Deal with include file feature...
   (cond ((not partial-completion-mode)
-        (remove-hook 'find-file-not-found-hooks 'PC-look-for-include-file))
+        (remove-hook 'find-file-not-found-functions 'PC-look-for-include-file))
        ((not PC-disable-includes)
-        (add-hook 'find-file-not-found-hooks 'PC-look-for-include-file)))
+        (add-hook 'find-file-not-found-functions 'PC-look-for-include-file)))
   ;; ... with some underhand redefining.
-  (cond ((and (not partial-completion-mode)
-             (functionp PC-old-read-file-name-internal))
-        (fset 'read-file-name-internal PC-old-read-file-name-internal))
-       ((and (not PC-disable-includes) (not PC-old-read-file-name-internal))
-        (setq PC-old-read-file-name-internal
-              (symbol-function 'read-file-name-internal))
-        (fset 'read-file-name-internal
-              'PC-read-include-file-name-internal)))
-    (when (and partial-completion-mode (null PC-env-vars-alist))
-      (setq PC-env-vars-alist
-           (mapcar (lambda (string)
-                     (let ((d (string-match "=" string)))
-                       (cons (concat "$" (substring string 0 d))
-                             (and d (substring string (1+ d))))))
-                   process-environment))))
+  (cond ((not partial-completion-mode)
+         (ad-disable-advice 'read-file-name-internal 'around 'PC-include-file)
+         (ad-activate 'read-file-name-internal))
+       ((not PC-disable-includes)
+         (ad-enable-advice 'read-file-name-internal 'around 'PC-include-file)
+         (ad-activate 'read-file-name-internal)))
+  ;; Adjust the completion selection in *Completion* buffers to the way
+  ;; we work.  The default minibuffer completion code only completes the
+  ;; text before point and leaves the text after point alone (new in
+  ;; Emacs-22).  In contrast we use the whole text and we even sometimes
+  ;; move point to a place before EOB, to indicate the first position where
+  ;; there's a difference, so when the user uses choose-completion, we have
+  ;; to trick choose-completion into replacing the whole minibuffer text
+  ;; rather than only the text before point.  --Stef
+  (funcall
+   (if partial-completion-mode 'add-hook 'remove-hook)
+   'choose-completion-string-functions
+   (lambda (&rest x) (goto-char (point-max)) nil))
+  ;; Build the env-completion and mapping table.
+  (when (and partial-completion-mode (null PC-env-vars-alist))
+    (setq PC-env-vars-alist
+          (mapcar (lambda (string)
+                    (let ((d (string-match "=" string)))
+                      (cons (concat "$" (substring string 0 d))
+                            (and d (substring string (1+ d))))))
+                  process-environment))))
 
 \f
 (defun PC-complete ()
@@ -254,8 +269,7 @@ Word-delimiters for the purposes of Partial Completion are \"-\", \"_\",
       ;; and this command is repeated, scroll that window.
       (if (and window (window-buffer window)
               (buffer-name (window-buffer window)))
-         (save-excursion
-           (set-buffer (window-buffer window))
+         (with-current-buffer (window-buffer window)
            (if (pos-visible-in-window-p (point-max) window)
                (set-window-start window (point-min) nil)
              (scroll-other-window)))
@@ -339,11 +353,8 @@ See `PC-complete' for details."
 (defvar PC-delims-list nil)
 
 (defvar PC-completion-as-file-name-predicate
-  (function
-   (lambda ()
-     (memq minibuffer-completion-table
-          '(read-file-name-internal read-directory-name-internal))))
-   "A function testing whether a minibuffer completion now will work filename-style.
+  (lambda () minibuffer-completing-file-name)
+  "A function testing whether a minibuffer completion now will work filename-style.
 The function takes no arguments, and typically looks at the value
 of `minibuffer-completion-table' and the minibuffer contents.")
 
@@ -610,8 +621,7 @@ of `minibuffer-completion-table' and the minibuffer contents.")
                                    (insert (substring prefix i (1+ i)))
                                    (setq end (1+ end)))
                                  (setq i (1+ i)))
-                               (or pt (equal (point) beg)
-                                   (setq pt (point)))
+                               (or pt (setq pt (point)))
                                (looking-at PC-delim-regex))
                              (setq skip (concat skip
                                                 (regexp-quote prefix)
@@ -658,8 +668,7 @@ of `minibuffer-completion-table' and the minibuffer contents.")
                        (eq mode 'help))
                    (with-output-to-temp-buffer "*Completions*"
                      (display-completion-list (sort helpposs 'string-lessp))
-                     (save-excursion
-                       (set-buffer standard-output)
+                     (with-current-buffer standard-output
                        ;; Record which part of the buffer we are completing
                        ;; so that choosing a completion from the list
                        ;; knows how much old text to replace.
@@ -725,16 +734,12 @@ Otherwise, all symbols with function definitions, values
 or properties are considered."
   (interactive)
   (let* ((end (point))
-        (buffer-syntax (syntax-table))
-        (beg (unwind-protect
-                 (save-excursion
-                   (if lisp-mode-syntax-table
-                       (set-syntax-table lisp-mode-syntax-table))
-                   (backward-sexp 1)
-                   (while (= (char-syntax (following-char)) ?\')
-                     (forward-char 1))
-                   (point))
-               (set-syntax-table buffer-syntax)))
+        (beg (save-excursion
+                (with-syntax-table lisp-mode-syntax-table
+                  (backward-sexp 1)
+                  (while (= (char-syntax (following-char)) ?\')
+                    (forward-char 1))
+                  (point))))
         (minibuffer-completion-table obarray)
         (minibuffer-completion-predicate
          (if (eq (char-after (1- beg)) ?\()
@@ -760,16 +765,21 @@ or properties are considered."
      (goto-char end)
      (PC-do-completion nil beg end)))
 
-;;; Use the shell to do globbing.
-;;; This could now use file-expand-wildcards instead.
+;; Use the shell to do globbing.
+;; This could now use file-expand-wildcards instead.
 
 (defun PC-expand-many-files (name)
-  (save-excursion
-    (set-buffer (generate-new-buffer " *Glob Output*"))
+  (with-current-buffer (generate-new-buffer " *Glob Output*")
     (erase-buffer)
     (shell-command (concat "echo " name) t)
     (goto-char (point-min))
-    (if (looking-at ".*No match")
+    ;; CSH-style shells were known to output "No match", whereas
+    ;; SH-style shells tend to simply output `name' when no match is found.
+    (if (looking-at (concat ".*No match\\|\\(^\\| \\)\\("
+                           (regexp-quote name)
+                           "\\|"
+                           (regexp-quote (expand-file-name name))
+                           "\\)\\( \\|$\\)"))
        nil
       (insert "(\"")
       (while (search-forward " " nil t)
@@ -792,14 +802,21 @@ or properties are considered."
                          "\\)\\'")))
        (setq p nil)
        (while files
-         (or (string-match PC-ignored-regexp (car files))
+          ;; This whole process of going through to shell, to echo, and
+          ;; finally parsing the output is a hack.  It breaks as soon as
+          ;; there are spaces in the file names or when the no-match
+          ;; message changes.  To make up for it, we check that what we read
+          ;; indeed exists, so we may miss some files, but we at least won't
+          ;; list non-existent ones.
+         (or (not (file-exists-p (car files)))
+             (string-match PC-ignored-regexp (car files))
              (setq p (cons (car files) p)))
          (setq files (cdr files)))
        p))))
 
-;;; Facilities for loading C header files.  This is independent from the
-;;; main completion code.  See also the variable `PC-include-file-path'
-;;; at top of this file.
+;; Facilities for loading C header files.  This is independent from the
+;; main completion code.  See also the variable `PC-include-file-path'
+;; at top of this file.
 
 (defun PC-look-for-include-file ()
   (if (string-match "[\"<]\\([^\"<>]*\\)[\">]?$" (buffer-file-name))
@@ -810,8 +827,7 @@ or properties are considered."
            new-buf)
        (kill-buffer (current-buffer))
        (if (equal name "")
-           (save-excursion
-             (set-buffer (car (buffer-list)))
+           (with-current-buffer (car (buffer-list))
              (save-excursion
                (beginning-of-line)
                (if (looking-at
@@ -848,8 +864,7 @@ or properties are considered."
              (if path
                  (setq name (concat (file-name-as-directory (car path)) name))
                (error "No such include file: <%s>" name)))
-         (let ((dir (save-excursion
-                      (set-buffer (car (buffer-list)))
+         (let ((dir (with-current-buffer (car (buffer-list))
                       default-directory)))
            (if (file-exists-p (concat dir name))
                (setq name (concat dir name))
@@ -858,8 +873,7 @@ or properties are considered."
        (if new-buf
            ;; no need to verify last-modified time for this!
            (set-buffer new-buf)
-         (setq new-buf (create-file-buffer name))
-         (set-buffer new-buf)
+         (set-buffer (create-file-buffer name))
          (erase-buffer)
          (insert-file-contents name t))
        ;; Returning non-nil with the new buffer current
@@ -878,7 +892,7 @@ or properties are considered."
                env (substring env 0 pos)))
        path)))
 
-;;; This is adapted from lib-complete.el, by Mike Williams.
+;; This is adapted from lib-complete.el, by Mike Williams.
 (defun PC-include-file-all-completions (file search-path &optional full)
   "Return all completions for FILE in any directory on SEARCH-PATH.
 If optional third argument FULL is non-nil, returned pathnames should be
@@ -925,24 +939,26 @@ absolute rather than relative to some directory on the SEARCH-PATH."
          (setq sorted (cdr sorted)))
        compressed))))
 
-(defun PC-read-include-file-name-internal (string dir action)
-  (if (string-match "<\\([^\"<>]*\\)>?$" string)
-      (let* ((name (substring string (match-beginning 1) (match-end 1)))
+(defadvice read-file-name-internal (around PC-include-file disable)
+  (if (string-match "<\\([^\"<>]*\\)>?\\'" (ad-get-arg 0))
+      (let* ((string (ad-get-arg 0))
+             (action (ad-get-arg 2))
+             (name (substring string (match-beginning 1) (match-end 1)))
             (str2 (substring string (match-beginning 0)))
             (completion-table
-             (mapcar (function (lambda (x) (list (format "<%s>" x))))
+             (mapcar (lambda (x) (format "<%s>" x))
                      (PC-include-file-all-completions
                       name (PC-include-file-path)))))
-       (cond
-        ((not completion-table) nil)
-        ((eq action nil) (try-completion str2 completion-table nil))
-        ((eq action t) (all-completions str2 completion-table nil))
-        ((eq action 'lambda)
-         (eq (try-completion str2 completion-table nil) t))))
-    (funcall PC-old-read-file-name-internal string dir action)))
+        (setq ad-return-value
+              (cond
+               ((not completion-table) nil)
+               ((eq action 'lambda) (test-completion str2 completion-table nil))
+               ((eq action nil) (try-completion str2 completion-table nil))
+               ((eq action t) (all-completions str2 completion-table nil)))))
+    ad-do-it))
 \f
 
 (provide 'complete)
 
-;;; arch-tag: fc7e2768-ff44-4e22-b579-4d825b968458
+;; arch-tag: fc7e2768-ff44-4e22-b579-4d825b968458
 ;;; complete.el ends here