;;; 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
;; 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:
: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
: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.
: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)
"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))
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 ()
;; 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)))
(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.")
(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)
(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.
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)) ?\()
(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)
"\\)\\'")))
(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))
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
(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))
(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
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
(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