summaryrefslogtreecommitdiff
path: root/lisp/minibuffer.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/minibuffer.el')
-rw-r--r--lisp/minibuffer.el257
1 files changed, 160 insertions, 97 deletions
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 41399f3f141..f3d92b18722 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -58,12 +58,9 @@
;;; Todo:
+;; - for M-x, cycle-sort commands that have no key binding first.
;; - Make things like icomplete-mode or lightning-completion work with
;; completion-in-region-mode.
-;; - completion-insert-complete-hook (called after inserting a complete
-;; completion), typically used for "complete-abbrev" where it would expand
-;; the abbrev. Tho we'd probably want to provide it from the
-;; completion-table.
;; - extend `boundaries' to provide various other meta-data about the
;; output of `all-completions':
;; - preferred sorting order when displayed in *Completions*.
@@ -74,10 +71,6 @@
;; - indicate how to turn all-completion's output into
;; try-completion's output: e.g. completion-ignored-extensions.
;; maybe that could be merged with the "quote" operation above.
-;; - completion hook to run when the completion is
-;; selected/inserted (maybe this should be provided some other
-;; way, e.g. as text-property, so `try-completion can also return it?)
-;; both for when it's inserted via TAB or via choose-completion.
;; - indicate that `all-completions' doesn't do prefix-completion
;; but just returns some list that relates in some other way to
;; the provided string (as is the case in filecache.el), in which
@@ -87,18 +80,6 @@
;; \n into something else, add special boundaries between
;; completions). E.g. when completing from the kill-ring.
-;; - make partial-completion-mode obsolete:
-;; - (?) <foo.h> style completion for file names.
-;; This can't be done identically just by tweaking completion,
-;; because partial-completion-mode's behavior is to expand <string.h>
-;; to /usr/include/string.h only when exiting the minibuffer, at which
-;; point the completion code is actually not involved normally.
-;; Partial-completion-mode does it via a find-file-not-found-function.
-;; - special code for C-x C-f <> to visit the file ref'd at point
-;; via (require 'foo) or #include "foo". ffap seems like a better
-;; place for this feature (supplemented with major-mode-provided
-;; functions to find the file ref'd at point).
-
;; - case-sensitivity currently confuses two issues:
;; - whether or not a particular completion table should be case-sensitive
;; (i.e. whether strings that differ only by case are semantically
@@ -562,7 +543,8 @@ candidates than this number."
(if completion-show-inline-help
(minibuffer-message msg)))
-(defun completion--do-completion (&optional try-completion-function)
+(defun completion--do-completion (&optional try-completion-function
+ expect-exact)
"Do the completion and return a summary of what happened.
M = completion was performed, the text was Modified.
C = there were available Completions.
@@ -576,7 +558,11 @@ E = after completion we now have an Exact match.
100 4 ??? impossible
101 5 ??? impossible
110 6 some completion happened
- 111 7 completed to an exact completion"
+ 111 7 completed to an exact completion
+
+TRY-COMPLETION-FUNCTION is a function to use in place of `try-completion'.
+EXPECT-EXACT, if non-nil, means that there is no need to tell the user
+when the buffer's text is already an exact match."
(let* ((beg (field-beginning))
(end (field-end))
(string (buffer-substring beg end))
@@ -595,7 +581,9 @@ E = after completion we now have an Exact match.
(minibuffer--bitset nil nil nil))
((eq t comp)
(minibuffer-hide-completions)
- (goto-char (field-end))
+ (goto-char end)
+ (completion--done string 'finished
+ (unless expect-exact "Sole completion"))
(minibuffer--bitset nil nil t)) ;Exact and unique match.
(t
;; `completed' should be t if some completion was done, which doesn't
@@ -619,12 +607,12 @@ E = after completion we now have an Exact match.
;; whether this is a unique completion or not, so try again using
;; the real case (this shouldn't recurse again, because the next
;; time try-completion will return either t or the exact string).
- (completion--do-completion try-completion-function)
+ (completion--do-completion try-completion-function expect-exact)
;; It did find a match. Do we match some possibility exactly now?
(let ((exact (test-completion completion
- minibuffer-completion-table
- minibuffer-completion-predicate))
+ minibuffer-completion-table
+ minibuffer-completion-predicate))
(comps
;; Check to see if we want to do cycling. We do it
;; here, after having performed the normal completion,
@@ -658,7 +646,13 @@ E = after completion we now have an Exact match.
;; We could also decide to refresh the completions,
;; if they're displayed (and assuming there are
;; completions left).
- (minibuffer-hide-completions))
+ (minibuffer-hide-completions)
+ (if exact
+ ;; If completion did not put point at end of field,
+ ;; it's a sign that completion is not finished.
+ (completion--done completion
+ (if (< comp-pos (length completion))
+ 'exact 'unknown))))
;; Show the completion table, if requested.
((not exact)
(if (case completion-auto-help
@@ -669,8 +663,12 @@ E = after completion we now have an Exact match.
;; If the last exact completion and this one were the same, it
;; means we've already given a "Complete, but not unique" message
;; and the user's hit TAB again, so now we give him help.
- ((eq this-command last-command)
- (if completion-auto-help (minibuffer-completion-help))))
+ (t
+ (if (and (eq this-command last-command) completion-auto-help)
+ (minibuffer-completion-help))
+ (completion--done completion 'exact
+ (unless expect-exact
+ "Complete, but not unique"))))
(minibuffer--bitset completed t exact))))))))
@@ -705,10 +703,6 @@ scroll the window of possible completions."
t)
(t (case (completion--do-completion)
(#b000 nil)
- (#b001 (completion--message "Sole completion")
- t)
- (#b011 (completion--message "Complete, but not unique")
- t)
(t t)))))
(defun completion--flush-all-sorted-completions (&rest _ignore)
@@ -742,10 +736,11 @@ scroll the window of possible completions."
;; Prefer recently used completions.
;; FIXME: Additional sorting ideas:
;; - for M-x, prefer commands that have no key binding.
- (let ((hist (symbol-value minibuffer-history-variable)))
- (setq all (sort all (lambda (c1 c2)
- (> (length (member c1 hist))
- (length (member c2 hist)))))))
+ (when (minibufferp)
+ (let ((hist (symbol-value minibuffer-history-variable)))
+ (setq all (sort all (lambda (c1 c2)
+ (> (length (member c1 hist))
+ (length (member c2 hist))))))))
;; Cache the result. This is not just for speed, but also so that
;; repeated calls to minibuffer-force-complete can cycle through
;; all possibilities.
@@ -763,14 +758,21 @@ Repeated uses step through the possible completions."
;; ~/src/emacs/trunk/ and throws away lisp/minibuffer.el.
(let* ((start (field-beginning))
(end (field-end))
- (all (completion-all-sorted-completions)))
- (if (not (consp all))
+ (all (completion-all-sorted-completions))
+ (base (+ start (or (cdr (last all)) 0))))
+ (cond
+ ((not (consp all))
(completion--message
- (if all "No more completions" "No completions"))
+ (if all "No more completions" "No completions")))
+ ((not (consp (cdr all)))
+ (let ((mod (equal (car all) (buffer-substring-no-properties base end))))
+ (if mod (completion--replace base end (car all)))
+ (completion--done (buffer-substring-no-properties start (point))
+ 'finished (unless mod "Sole completion"))))
+ (t
(setq completion-cycling t)
- (goto-char end)
- (insert (car all))
- (delete-region (+ start (cdr (last all))) end)
+ (completion--replace base end (car all))
+ (completion--done (buffer-substring-no-properties start (point)) 'sole)
;; If completing file names, (car all) may be a directory, so we'd now
;; have a new set of possible completions and might want to reset
;; completion-all-sorted-completions to nil, but we prefer not to,
@@ -778,7 +780,7 @@ Repeated uses step through the possible completions."
;; through the previous possible completions.
(let ((last (last all)))
(setcdr last (cons (car all) (cdr last)))
- (setq completion-all-sorted-completions (cdr all))))))
+ (setq completion-all-sorted-completions (cdr all)))))))
(defvar minibuffer-confirm-exit-commands
'(minibuffer-complete minibuffer-complete-word PC-complete PC-complete-word)
@@ -850,7 +852,7 @@ If `minibuffer-completion-confirm' is `confirm-after-completion',
(t
;; Call do-completion, but ignore errors.
(case (condition-case nil
- (completion--do-completion)
+ (completion--do-completion nil 'expect-exact)
(error 1))
((#b001 #b011) (exit-minibuffer))
(#b111 (if (not minibuffer-completion-confirm)
@@ -954,10 +956,6 @@ Return nil if there is no valid completion, else t."
(interactive)
(case (completion--do-completion 'completion--try-word-completion)
(#b000 nil)
- (#b001 (completion--message "Sole completion")
- t)
- (#b011 (completion--message "Complete, but not unique")
- t)
(t t)))
(defface completions-annotations '((t :inherit italic))
@@ -1157,6 +1155,21 @@ the completions buffer."
(run-hooks 'completion-setup-hook)))
nil)
+(defvar completion-extra-properties nil
+ "Property list of extra properties of the current completion job.
+These include:
+`:annotation-function': Function to add annotations in the completions buffer.
+ The function takes a completion and should either return nil, or a string
+ that will be displayed next to the completion. The function can access the
+ completion data via `minibuffer-completion-table' and related variables.
+`:exit-function': Function to run after completion is performed.
+ The function takes at least 2 parameters (STRING and STATUS) where STRING
+ is the text to which the field was completed and STATUS indicates what
+ kind of operation happened: if text is now complete it's `finished', if text
+ cannot be further completed but completion is not finished, it's `sole', if
+ text is a valid completion but may be further completed, it's `exact', and
+ other STATUSes may be added in the future.")
+
(defvar completion-annotate-function
nil
;; Note: there's a lot of scope as for when to add annotations and
@@ -1173,6 +1186,27 @@ The function takes a completion and should either return nil, or a string that
will be displayed next to the completion. The function can access the
completion table and predicates via `minibuffer-completion-table' and related
variables.")
+(make-obsolete-variable 'completion-annotate-function
+ 'completion-extra-properties "24.1")
+
+(defun completion--done (string &optional finished message)
+ (let* ((exit-fun (plist-get completion-extra-properties :exit-function))
+ (pre-msg (and exit-fun (current-message))))
+ (assert (memq finished '(exact sole finished unknown)))
+ ;; FIXME: exit-fun should receive `finished' as a parameter.
+ (when exit-fun
+ (when (eq finished 'unknown)
+ (setq finished
+ (if (eq (try-completion string
+ minibuffer-completion-table
+ minibuffer-completion-predicate)
+ t)
+ 'finished 'exact)))
+ (funcall exit-fun string finished))
+ (when (and message
+ ;; Don't output any message if the exit-fun already did so.
+ (equal pre-msg (and exit-fun (current-message))))
+ (completion--message message))))
(defun minibuffer-completion-help ()
"Display a list of possible completions of the current minibuffer contents."
@@ -1187,44 +1221,77 @@ variables.")
minibuffer-completion-predicate
(- (point) (field-beginning)))))
(message nil)
- (if (and completions
- (or (consp (cdr completions))
- (not (equal (car completions) string))))
- (let* ((last (last completions))
- (base-size (cdr last))
- ;; If the *Completions* buffer is shown in a new
- ;; window, mark it as softly-dedicated, so bury-buffer in
- ;; minibuffer-hide-completions will know whether to
- ;; delete the window or not.
- (display-buffer-mark-dedicated 'soft))
- (with-output-to-temp-buffer "*Completions*"
- ;; Remove the base-size tail because `sort' requires a properly
- ;; nil-terminated list.
- (when last (setcdr last nil))
- (setq completions (sort completions 'string-lessp))
- (when completion-annotate-function
- (setq completions
- (mapcar (lambda (s)
- (let ((ann
- (funcall completion-annotate-function s)))
- (if ann (list s ann) s)))
- completions)))
- (with-current-buffer standard-output
- (set (make-local-variable 'completion-base-position)
- (list (+ start base-size)
- ;; FIXME: We should pay attention to completion
- ;; boundaries here, but currently
- ;; completion-all-completions does not give us the
- ;; necessary information.
- end)))
- (display-completion-list completions)))
-
- ;; If there are no completions, or if the current input is already the
- ;; only possible completion, then hide (previous&stale) completions.
- (minibuffer-hide-completions)
- (ding)
- (minibuffer-message
- (if completions "Sole completion" "No completions")))
+ (if (or (null completions)
+ (and (not (consp (cdr completions)))
+ (equal (car completions) string)))
+ (progn
+ ;; If there are no completions, or if the current input is already
+ ;; the sole completion, then hide (previous&stale) completions.
+ (minibuffer-hide-completions)
+ (ding)
+ (minibuffer-message
+ (if completions "Sole completion" "No completions")))
+
+ (let* ((last (last completions))
+ (base-size (cdr last))
+ (prefix (unless (zerop base-size) (substring string 0 base-size)))
+ (global-af (or (plist-get completion-extra-properties
+ :annotation-function)
+ completion-annotate-function))
+ ;; If the *Completions* buffer is shown in a new
+ ;; window, mark it as softly-dedicated, so bury-buffer in
+ ;; minibuffer-hide-completions will know whether to
+ ;; delete the window or not.
+ (display-buffer-mark-dedicated 'soft))
+ (with-output-to-temp-buffer "*Completions*"
+ ;; Remove the base-size tail because `sort' requires a properly
+ ;; nil-terminated list.
+ (when last (setcdr last nil))
+ (setq completions (sort completions 'string-lessp))
+ (setq completions
+ (cond
+ (global-af
+ (mapcar (lambda (s)
+ (let ((ann (funcall global-af s)))
+ (if ann (list s ann) s)))
+ completions))
+ (t completions)))
+
+ (with-current-buffer standard-output
+ (set (make-local-variable 'completion-base-position)
+ (list (+ start base-size)
+ ;; FIXME: We should pay attention to completion
+ ;; boundaries here, but currently
+ ;; completion-all-completions does not give us the
+ ;; necessary information.
+ end))
+ (set (make-local-variable 'completion-list-insert-choice-function)
+ (let ((ctable minibuffer-completion-table)
+ (cpred minibuffer-completion-predicate)
+ (cprops completion-extra-properties))
+ (lambda (start end choice)
+ (unless
+ (or (zerop (length prefix))
+ (equal prefix
+ (buffer-substring-no-properties
+ (max (point-min) (- start (length prefix)))
+ start)))
+ (message "*Completions* out of date"))
+ ;; FIXME: Use `md' to do quoting&terminator here.
+ (completion--replace start end choice)
+ (let* ((minibuffer-completion-table ctable)
+ (minibuffer-completion-predicate cpred)
+ (completion-extra-properties cprops)
+ (result (concat prefix choice))
+ (bounds (completion-boundaries
+ result ctable cpred "")))
+ ;; If the completion introduces a new field, then
+ ;; completion is not finished.
+ (completion--done result
+ (if (eq (car bounds) (length result))
+ 'exact 'finished)))))))
+
+ (display-completion-list completions))))
nil))
(defun minibuffer-hide-completions ()
@@ -1364,9 +1431,9 @@ or a list of the form (START END COLLECTION &rest PROPS) where
START and END delimit the entity to complete and should include point,
COLLECTION is the completion table to use to complete it, and
PROPS is a property list for additional information.
-Currently supported properties are:
- `:predicate' a predicate that completion candidates need to satisfy.
- `:annotation-function' the value to use for `completion-annotate-function'.")
+Currently supported properties are all the properties that can appear in
+`completion-extra-properties' plus:
+ `:predicate' a predicate that completion candidates need to satisfy.")
(defvar completion--capf-misbehave-funs nil
"List of functions found on `completion-at-point-functions' that misbehave.")
@@ -1403,9 +1470,7 @@ The completion method is determined by `completion-at-point-functions'."
(pcase res
(`(,_ . ,(and (pred functionp) f)) (funcall f))
(`(,hookfun . (,start ,end ,collection . ,plist))
- (let* ((completion-annotate-function
- (or (plist-get plist :annotation-function)
- completion-annotate-function))
+ (let* ((completion-extra-properties plist)
(completion-in-region-mode-predicate
(lambda ()
;; We're still in the same completion field.
@@ -1428,9 +1493,7 @@ The completion method is determined by `completion-at-point-functions'."
(`(,hookfun . (,start ,end ,collection . ,plist))
(let* ((minibuffer-completion-table collection)
(minibuffer-completion-predicate (plist-get plist :predicate))
- (completion-annotate-function
- (or (plist-get plist :annotation-function)
- completion-annotate-function))
+ (completion-extra-properties plist)
(completion-in-region-mode-predicate
(lambda ()
;; We're still in the same completion field.
@@ -2029,7 +2092,7 @@ from lowercase to uppercase characters).")
(defun completion-pcm--prepare-delim-re (delims)
(setq completion-pcm--delim-wild-regex (concat "[" delims "*]")))
-(defcustom completion-pcm-word-delimiters "-_./: "
+(defcustom completion-pcm-word-delimiters "-_./:| "
"A string of characters treated as word delimiters for completion.
Some arcane rules:
If `]' is in this string, it must come first.