Function: completion--try-word-completion
completion--try-word-completion is a byte-compiled function defined in
minibuffer.el.gz.
Signature
(completion--try-word-completion STRING TABLE PREDICATE POINT MD)
Source Code
;; Defined in /usr/src/emacs/lisp/minibuffer.el.gz
(defun completion--try-word-completion (string table predicate point md)
(let ((comp (completion-try-completion string table predicate point md)))
(if (not (consp comp))
comp
;; If completion finds next char not unique,
;; consider adding a space or a hyphen.
(when (= (length string) (length (car comp)))
;; Mark the added char with the `completion-word' property, so it
;; can be handled specially by completion styles such as
;; partial-completion.
;; We used to remove `partial-completion' from completion-styles
;; instead, but it was too blunt, leading to situations where SPC
;; was the only insertable char at point but minibuffer-complete-word
;; refused inserting it.
(let ((exts (mapcar (lambda (str) (propertize str 'completion-try-word t))
'(" " "-")))
(before (substring string 0 point))
(after (substring string point))
tem)
;; If both " " and "-" lead to completions, prefer " " so SPC behaves
;; a bit more like a self-inserting key (bug#17375).
(while (and exts (not (consp tem)))
(setq tem (completion-try-completion
(concat before (pop exts) after)
table predicate (1+ point) md)))
(if (consp tem) (setq comp tem))))
;; Completing a single word is actually more difficult than completing
;; as much as possible, because we first have to find the "current
;; position" in `completion' in order to find the end of the word
;; we're completing. Normally, `string' is a prefix of `completion',
;; which makes it trivial to find the position, but with fancier
;; completion (plus env-var expansion, ...) `completion' might not
;; look anything like `string' at all.
(let* ((comppoint (cdr comp))
(completion (car comp))
(before (substring string 0 point))
(combined (concat before "\n" completion)))
;; Find in completion the longest text that was right before point.
(when (string-match "\\(.+\\)\n.*?\\1" combined)
(let* ((prefix (match-string 1 before))
;; We used non-greedy match to make `rem' as long as possible.
(rem (substring combined (match-end 0)))
;; Find in the remainder of completion the longest text
;; that was right after point.
(after (substring string point))
(suffix (if (string-match "\\`\\(.+\\).*\n.*\\1"
(concat after "\n" rem))
(match-string 1 after))))
;; The general idea is to try and guess what text was inserted
;; at point by the completion. Problem is: if we guess wrong,
;; we may end up treating as "added by completion" text that was
;; actually painfully typed by the user. So if we then cut
;; after the first word, we may throw away things the
;; user wrote. So let's try to be as conservative as possible:
;; only cut after the first word, if we're reasonably sure that
;; our guess is correct.
;; Note: a quick survey on emacs-devel seemed to indicate that
;; nobody actually cares about the "word-at-a-time" feature of
;; minibuffer-complete-word, whose real raison-d'être is that it
;; tries to add "-" or " ". One more reason to only cut after
;; the first word, if we're really sure we're right.
(when (and (or suffix (zerop (length after)))
(string-match (concat
;; Make submatch 1 as small as possible
;; to reduce the risk of cutting
;; valuable text.
".*" (regexp-quote prefix) "\\(.*?\\)"
(if suffix (regexp-quote suffix) "\\'"))
completion)
;; The new point in `completion' should also be just
;; before the suffix, otherwise something more complex
;; is going on, and we're not sure where we are.
(eq (match-end 1) comppoint)
;; (match-beginning 1)..comppoint is now the stretch
;; of text in `completion' that was completed at point.
(string-match "\\W" completion (match-beginning 1))
;; Is there really something to cut?
(> comppoint (match-end 0)))
;; Cut after the first word.
(let ((cutpos (match-end 0)))
(setq completion (concat (substring completion 0 cutpos)
(substring completion comppoint)))
(setq comppoint cutpos)))))
(cons completion comppoint)))))