diff options
Diffstat (limited to 'lisp/complete.el')
-rw-r--r-- | lisp/complete.el | 206 |
1 files changed, 96 insertions, 110 deletions
diff --git a/lisp/complete.el b/lisp/complete.el index aca28af4a5b..cbc678de977 100644 --- a/lisp/complete.el +++ b/lisp/complete.el @@ -153,11 +153,8 @@ If nil, means use the colon-separated path in the variable $INCPATH instead." (define-key completion-map " " 'minibuffer-complete-word) (define-key completion-map "?" 'minibuffer-completion-help) - (define-key must-match-map "\t" 'minibuffer-complete) - (define-key must-match-map " " 'minibuffer-complete-word) (define-key must-match-map "\r" 'minibuffer-complete-and-exit) (define-key must-match-map "\n" 'minibuffer-complete-and-exit) - (define-key must-match-map "?" 'minibuffer-completion-help) (define-key global-map [remap lisp-complete-symbol] nil)) (PC-default-bindings @@ -173,17 +170,11 @@ If nil, means use the colon-separated path in the variable $INCPATH instead." (define-key completion-map "\e\n" 'PC-force-complete-and-exit) (define-key completion-map "\e?" 'PC-completion-help) - (define-key must-match-map "\t" 'PC-complete) - (define-key must-match-map " " 'PC-complete-word) (define-key must-match-map "\r" 'PC-complete-and-exit) (define-key must-match-map "\n" 'PC-complete-and-exit) - (define-key must-match-map "?" 'PC-completion-help) - (define-key must-match-map "\e\t" 'PC-complete) - (define-key must-match-map "\e " 'PC-complete-word) (define-key must-match-map "\e\r" 'PC-complete-and-exit) (define-key must-match-map "\e\n" 'PC-complete-and-exit) - (define-key must-match-map "\e?" 'PC-completion-help) (define-key global-map [remap lisp-complete-symbol] 'PC-lisp-complete-symbol))))) @@ -231,13 +222,6 @@ second TAB brings up the `*Completions*' buffer." (remove-hook 'find-file-not-found-functions 'PC-look-for-include-file)) ((not PC-disable-includes) (add-hook 'find-file-not-found-functions 'PC-look-for-include-file))) - ;; ... with some underhand redefining. - (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 @@ -344,14 +328,24 @@ See `PC-complete' for details." (PC-do-complete-and-exit))) (defun PC-do-complete-and-exit () - (if (= (point-max) (minibuffer-prompt-end)) ; Duplicate the "bug" that Info-menu relies on... - (exit-minibuffer) + (cond + ((= (point-max) (minibuffer-prompt-end)) + ;; Duplicate the "bug" that Info-menu relies on... + (exit-minibuffer)) + ((eq minibuffer-completion-confirm 'confirm-only) + (if (or (eq last-command this-command) + (test-completion (field-string) + minibuffer-completion-table + minibuffer-completion-predicate)) + (exit-minibuffer) + (PC-temp-minibuffer-message " [Confirm]"))) + (t (let ((flag (PC-do-completion 'exit))) (and flag (if (or (eq flag 'complete) (not minibuffer-completion-confirm)) (exit-minibuffer) - (PC-temp-minibuffer-message " [Confirm]")))))) + (PC-temp-minibuffer-message " [Confirm]"))))))) (defun PC-completion-help () @@ -387,9 +381,9 @@ of `minibuffer-completion-table' and the minibuffer contents.") ;; Returns the sequence of non-delimiter characters that follow regexp in string. (defun PC-chunk-after (string regexp) (if (not (string-match regexp string)) - (let ((message (format "String %s didn't match regexp %s" string regexp))) - (message message) - (error message))) + (let ((message "String %s didn't match regexp %s")) + (message message string regexp) + (error message string regexp))) (let ((result (substring string (match-end 0)))) ;; result may contain multiple chunks (if (string-match PC-delim-regex result) @@ -439,7 +433,9 @@ point-max (as is appropriate for completing a file name). If GOTO-END is non-nil, however, it instead replaces up to END." (or beg (setq beg (minibuffer-prompt-end))) (or end (setq end (point-max))) - (let* ((table minibuffer-completion-table) + (let* ((table (if (eq minibuffer-completion-table 'read-file-name-internal) + 'PC-read-file-name-internal + minibuffer-completion-table)) (pred minibuffer-completion-predicate) (filename (funcall PC-completion-as-file-name-predicate)) (dirname nil) ; non-nil only if a filename is being completed @@ -454,6 +450,7 @@ GOTO-END is non-nil, however, it instead replaces up to END." env-on regex p offset + abbreviated (poss nil) helpposs (case-fold-search completion-ignore-case)) @@ -518,7 +515,7 @@ GOTO-END is non-nil, however, it instead replaces up to END." "*" (substring pat p)) p (+ p 2))) - (setq files (PC-expand-many-files (concat pat "*"))) + (setq files (file-expand-wildcards (concat pat "*"))) (if files (let ((dir (file-name-directory (car files))) (p files)) @@ -532,11 +529,11 @@ GOTO-END is non-nil, however, it instead replaces up to END." (insert str) (setq end (+ beg (length str))))) (if origstr - ;; If the wildcards were introduced by us, it's possible - ;; that read-file-name-internal (especially our - ;; PC-include-file advice) can still find matches for the - ;; original string even if we couldn't, so remove the - ;; added wildcards. + ;; If the wildcards were introduced by us, it's + ;; possible that PC-read-file-name-internal can + ;; still find matches for the original string + ;; even if we couldn't, so remove the added + ;; wildcards. (setq str origstr) (setq filename nil table nil pred nil))))) @@ -590,17 +587,43 @@ GOTO-END is non-nil, however, it instead replaces up to END." pred nil)) ;; Find an initial list of possible completions - (if (not (setq p (string-match (concat PC-delim-regex + (unless (setq p (string-match (concat PC-delim-regex (if filename "\\|\\*" "")) str - (+ (length dirname) offset)))) + (+ (length dirname) offset))) ;; Minibuffer contains no hyphens -- simple case! - (setq poss (all-completions (if env-on - basestr str) + (setq poss (all-completions (if env-on basestr str) table pred)) - + (unless (or poss (string-equal str "")) + ;; Try completion as an abbreviation, e.g. "mvb" -> + ;; "m-v-b" -> "multiple-value-bind", but only for + ;; non-empty strings. + (setq origstr str + abbreviated t) + (if filename + (cond + ;; "alpha" or "/alpha" -> expand whole path. + ((string-match "^/?\\([A-Za-z0-9]+\\)$" str) + (setq + basestr "" + p nil + poss (file-expand-wildcards + (concat "/" + (mapconcat #'list (match-string 1 str) "*/") + "*")) + beg (1- beg))) + ;; Alphanumeric trailer -> expand trailing file + ((string-match "^\\(.+/\\)\\([A-Za-z0-9]+\\)$" str) + (setq regex (concat "\\`" + (mapconcat #'list + (match-string 2 str) + "[A-Za-z0-9]*[^A-Za-z0-9]")) + p (1+ (length (match-string 1 str)))))) + (setq regex (concat "\\`" (mapconcat #'list str "[^-]*-")) + p 1)))) + (when p ;; Use all-completions to do an initial cull. This is a big win, ;; since all-completions is written in C! (let ((compl (all-completions (if env-on @@ -609,12 +632,24 @@ GOTO-END is non-nil, however, it instead replaces up to END." table pred))) (setq p compl) + (when (and compl abbreviated) + (if filename + (progn + (setq p nil) + (dolist (x compl) + (when (string-match regex x) + (push x p))) + (setq basestr (try-completion "" p))) + (setq basestr (mapconcat 'list str "-")) + (delete-region beg end) + (setq end (+ beg (length basestr))) + (insert basestr)))) (while p (and (string-match regex (car p)) (progn (set-text-properties 0 (length (car p)) '() (car p)) (setq poss (cons (car p) poss)))) - (setq p (cdr p))))) + (setq p (cdr p)))) ;; If table had duplicates, they can be here. (delete-dups poss) @@ -648,6 +683,7 @@ GOTO-END is non-nil, however, it instead replaces up to END." (and p (setq poss p)))) ;; Now we have a list of possible completions + (cond ;; No valid completions found @@ -657,6 +693,9 @@ GOTO-END is non-nil, however, it instead replaces up to END." (let ((PC-word-failed-flag t)) (delete-backward-char 1) (PC-do-completion 'word)) + (when abbreviated + (delete-region beg end) + (insert origstr)) (beep) (PC-temp-minibuffer-message (if ambig " [Ambiguous dir name]" @@ -793,13 +832,18 @@ GOTO-END is non-nil, however, it instead replaces up to END." (setq completion-base-size (if dirname dirlength (- beg prompt-end)))))) - (PC-temp-minibuffer-message " [Next char not unique]")) - nil))))) + (PC-temp-minibuffer-message " [Next char not unique]")) + ;; Expansion of filenames is not reversible, + ;; so just keep the prefix. + (when (and abbreviated filename) + (delete-region (point) end)) + nil))))) ;; Only one possible completion (t (if (and (equal basestr (car poss)) - (not (and env-on filename))) + (not (and env-on filename)) + (not abbreviated)) (if (null mode) (PC-temp-minibuffer-message " [Sole completion]")) (delete-region beg end) @@ -825,7 +869,7 @@ GOTO-END is non-nil, however, it instead replaces up to END." (defun PC-temp-minibuffer-message (message) "A Lisp version of `temp_minibuffer_message' from minibuf.c." (cond (PC-not-minibuffer - (message message) + (message "%s" message) (sit-for 2) (message "")) ((fboundp 'temp-minibuffer-message) @@ -857,13 +901,11 @@ only symbols with function definitions are considered. Otherwise, all symbols with function definitions, values or properties are considered." (interactive) - (let* ((end (point)) - ;; To complete the word under point, rather than just the portion - ;; before point, use this: -;;; (save-excursion -;;; (with-syntax-table lisp-mode-syntax-table -;;; (forward-sexp 1) -;;; (point)))) + (let* ((end + (save-excursion + (with-syntax-table lisp-mode-syntax-table + (skip-syntax-forward "_w") + (point)))) (beg (save-excursion (with-syntax-table lisp-mode-syntax-table (backward-sexp 1) @@ -921,67 +963,12 @@ or properties are considered." (point-min) t) (+ (point) 2) (point-min))) - (minibuffer-completion-table 'read-file-name-internal) + (minibuffer-completion-table 'PC-read-file-name-internal) (minibuffer-completion-predicate "") (PC-not-minibuffer t)) (goto-char end) (PC-do-completion nil beg end))) -;; Use the shell to do globbing. -;; This could now use file-expand-wildcards instead. - -(defun PC-expand-many-files (name) - (with-current-buffer (generate-new-buffer " *Glob Output*") - (erase-buffer) - (when (and (file-name-absolute-p name) - (not (file-directory-p default-directory))) - ;; If the current working directory doesn't exist `shell-command' - ;; signals an error. So if the file names we're looking for don't - ;; depend on the working directory, switch to a valid directory first. - (setq default-directory "/")) - (shell-command (concat "echo " name) t) - (goto-char (point-min)) - ;; 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) - (delete-backward-char 1) - (insert "\" \"")) - (goto-char (point-max)) - (delete-backward-char 1) - (insert "\")") - (goto-char (point-min)) - (let ((files (read (current-buffer))) (p nil)) - (kill-buffer (current-buffer)) - (or (equal completion-ignored-extensions PC-ignored-extensions) - (setq PC-ignored-regexp - (concat "\\(" - (mapconcat - 'regexp-quote - (setq PC-ignored-extensions - completion-ignored-extensions) - "\\|") - "\\)\\'"))) - (setq p nil) - (while 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. @@ -1107,24 +1094,23 @@ absolute rather than relative to some directory on the SEARCH-PATH." (setq sorted (cdr sorted))) compressed)))) -(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 (match-string 1 string)) +(defun PC-read-file-name-internal (string dir action) + "Extend `read-file-name-internal' to handle include files. +This is only used by " + (if (string-match "<\\([^\"<>]*\\)>?\\'" string) + (let* ((name (match-string 1 string)) (str2 (substring string (match-beginning 0))) (completion-table (mapcar (lambda (x) (format (if (string-match "/\\'" x) "<%s" "<%s>") x)) (PC-include-file-all-completions name (PC-include-file-path))))) - (setq ad-return-value (cond ((not completion-table) nil) ((eq action 'lambda) (test-completion str2 completion-table nil)) ((eq action nil) (PC-try-completion str2 completion-table nil)) - ((eq action t) (all-completions str2 completion-table nil))))) - ad-do-it)) + ((eq action t) (all-completions str2 completion-table nil)))) + (read-file-name-internal string dir action))) (provide 'complete) |