(if (eq (car-safe action) 'boundaries)
(cons 'boundaries (completion--sifn-boundaries orig table pred (cdr action)))
(let* ((sifned (substitute-in-file-name orig))
+ (orig-start (car (completion--sifn-boundaries orig table pred "")))
+ (sifned-start (car (completion-boundaries sifned table pred "")))
+ (orig-in-bounds (substring orig orig-start))
+ (sifned-in-bounds (substring sifned sifned-start))
+ (only-need-double-dollars
+ ;; If true, sifn only un-doubled $s in ORIG, so we can fix a
+ ;; completion to match ORIG by just doubling $s again. This
+ ;; preserves more text from the completion, behaving better with
+ ;; non-nil `completion-ignore-case'.
+ (string-equal orig-in-bounds (minibuffer--double-dollars sifned-in-bounds)))
(result (complete-with-action action table sifned pred)))
(cond
((null action) ; try-completion
(if (stringp result)
- ;; Extract the newly added text, quote any dollar signs,
- ;; and append it to ORIG.
- (let ((new-text (substring result (length sifned))))
- (concat orig (minibuffer--double-dollars new-text)))
+ ;; Extract the newly added text, quote any dollar signs, and
+ ;; append it to ORIG.
+ (if only-need-double-dollars
+ (concat (substring orig nil orig-start)
+ (minibuffer--double-dollars (substring result sifned-start)))
+ (let ((new-text (substring result (length sifned))))
+ (concat orig (minibuffer--double-dollars new-text))))
result))
((eq action t) ; all-completions
(mapcar
- (let ((orig-prefix
- (substring orig (car (completion--sifn-boundaries orig table pred ""))))
- (sifned-prefix-length
- (- (length sifned)
- (car (completion-boundaries sifned table pred "")))))
+ (if only-need-double-dollars
+ #'minibuffer--double-dollars
;; Extract the newly added text, quote any dollar signs, and append
;; it to the part of ORIG inside the completion boundaries.
(lambda (compl)
- (let ((new-text (substring compl sifned-prefix-length)))
- (concat orig-prefix (minibuffer--double-dollars new-text)))))
+ (let ((new-text (substring compl (length sifned-in-bounds))))
+ (concat orig-in-bounds (minibuffer--double-dollars new-text)))))
result))
(t result))))))
(when-let ((d (alist-get 'description p)))
(setq single (if single t d))))
minibuffer-completion-predicate)
- (if (stringp single) single
+ (cond
+ ((null single) (user-error "No current predicate"))
+ ((stringp single) single)
+ (t
(completing-read
(format-prompt prompt default)
(completion-table-with-metadata
;; Put latest restriction first.
(reverse descs))))))
'((category . predicate-description)))
- nil t nil nil default))))
+ nil t nil nil default)))))
(defun minibuffer-predicate-description-to-function (desc)
"Return predicate function the DESC describes, or nil."
(should (equal (completion-try-completion input
#'completion--file-name-table
nil (length input))
- (cons output (length output)))))))
+ (cons output (length output)))))
+ ;; Everything also works with `completion-ignore-case'.
+ (let ((completion-ignore-case t))
+ (pcase-dolist (`(,input ,output)
+ '(
+ ("data/M-CTTQ" "data/minibuffer-test-cttq$$tion")
+ ("data/M-CTTQ$$t" "data/minibuffer-test-cttq$$tion")
+ ;; When an env var is in the completion bounds, try-completion
+ ;; won't change letter case.
+ ("lisp/c${CTTQ1}E" "lisp/c${CTTQ1}Et/")
+ ("lisp/ced${CTTQ2}SE-U" "lisp/ced${CTTQ2}SEmantic-utest")
+ ;; If the env var is before the completion bounds, try-completion
+ ;; *will* change letter case.
+ ("lisp/c${CTTQ1}et/SE-U" "lisp/c${CTTQ1}et/semantic-utest")
+ ("lis/c${CTTQ1}/SE-U" "lisp/c${CTTQ1}et/semantic-utest")
+ ))
+ (should (equal (car (completion-try-completion input
+ #'completion--file-name-table
+ nil (length input)))
+ output))))))
(ert-deftest completion--insert-strings-faces ()
(with-temp-buffer