[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#48356: 28.0.50; choose-completion discards the suffix after the comp
From: |
Juri Linkov |
Subject: |
bug#48356: 28.0.50; choose-completion discards the suffix after the completion boundary |
Date: |
Sun, 13 Mar 2022 19:56:50 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (x86_64-pc-linux-gnu) |
forcemerge 48356 49931
thanks
> When selecting a candidate the suffix after the completion boundary is
> discarded by `choose-completion`/`choose-completion-string`.
> `choose-completion` is invoked when a candidate in the *Completions*
> buffer is selected with the mouse or RET.
>
> For example when completing a file path "~/emacs/master/li|/calc", where
> "|" is the cursor, and then the candidate "lisp" is selected in the
> *Completions* buffer, the result is "~/emacs/master/lisp/". The prefix
> "~/emacs/master/" is prepended to the selected candidate, but the suffix
> "/calc" is discarded.
>
> `choose-completion-string` contains logic which checks if the resulting
> string equals the car of the completion boundary. In that case the
> minibuffer is not exited.
Strange, in your test case above, the minibuffer is not exited already.
> I propose the following change to the existing logic: When
> selecting a candidate with `choose-completion` and a suffix is present,
> the minibuffer should not be exited (completion continues) and the
> suffix is preserved.
Here is a better patch than was posted to bug#49931
to preserve the suffix.
It correctly handles at least three different cases:
1. When manually adding a suffix in the minibuffer after completions
were displayed, choose-completion discards that suffix.
2. In file name completion in the above case the suffix is preserved.
3. 'M-! command filename TAB' and choosing a completion preserves both
prefix and suffix.
This works only after customizing 'completion-use-base-affixes' to t:
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 36b8d80841..5685f078ad 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2227,6 +2312,8 @@ minibuffer-completion-help
(let* ((last (last completions))
(base-size (or (cdr last) 0))
(prefix (unless (zerop base-size) (substring string 0 base-size)))
+ (base-prefix (buffer-substring
(minibuffer--completion-prompt-end) (+ start base-size)))
+ (base-suffix (buffer-substring (point) (point-max)))
(all-md (completion--metadata (buffer-substring-no-properties
start (point))
base-size md
@@ -2320,11 +2407,18 @@ minibuffer-completion-help
;; completion-all-completions does not give
us the
;; necessary information.
end))
+ (setq-local completion-base-affixes (list base-prefix
base-suffix))
(setq-local completion-list-insert-choice-function
(let ((ctable minibuffer-completion-table)
(cpred minibuffer-completion-predicate)
(cprops completion-extra-properties))
(lambda (start end choice)
+ (if (and (stringp start) (stringp end))
+ (progn
+ (delete-minibuffer-contents)
+ (insert start choice)
+ ;; Keep point after completion before
suffix
+ (save-excursion (insert end)))
(unless (or (zerop (length prefix))
(equal prefix
(buffer-substring-no-properties
@@ -2333,7 +2427,7 @@ minibuffer-completion-help
start)))
(message "*Completions* out of date"))
;; FIXME: Use `md' to do quoting&terminator
here.
- (completion--replace start end choice)
+ (completion--replace start end choice))
(let* ((minibuffer-completion-table ctable)
(minibuffer-completion-predicate cpred)
(completion-extra-properties cprops)
diff --git a/lisp/simple.el b/lisp/simple.el
index accc119e2b..52cf54c563 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9071,6 +9075,19 @@ completion-base-position
where the completion should be inserted and END (if non-nil) is the end
of the text to replace. If END is nil, point is used instead.")
+(defvar completion-base-affixes nil
+ "Base context of the text corresponding to the shown completions.
+This variable is used in the *Completions* buffers.
+Its value is a list of the form (PREFIX SUFFIX) where PREFIX is the text
+before the place where completion should be inserted and SUFFIX is the text
+after the completion.")
+
+(defcustom completion-use-base-affixes nil
+ "Non-nil means to restore original prefix and suffix in the minibuffer."
+ :type 'boolean
+ :version "29.1"
+ :group 'completion)
+
(defvar completion-list-insert-choice-function #'completion--replace
"Function to use to insert the text chosen in *Completions*.
Called with three arguments (BEG END TEXT), it should replace the text
@@ -9151,6 +9168,7 @@ next-completion
(with-current-buffer (window-buffer (posn-window (event-start event)))
(let ((buffer completion-reference-buffer)
(base-position completion-base-position)
+ (base-affixes completion-base-affixes)
(insert-function completion-list-insert-choice-function)
(choice
(save-excursion
@@ -9184,7 +9203,8 @@ choose-completion
(with-current-buffer buffer
(choose-completion-string
choice buffer
- (or base-position
+ (or (and completion-use-base-affixes base-affixes)
+ base-position
;; If all else fails, just guess.
(list (choose-completion-guess-base-position choice)))
insert-function)))))
@@ -9344,9 +9372,11 @@ completion-setup-function
(buffer-substring (minibuffer-prompt-end) (point)))))))
(with-current-buffer standard-output
(let ((base-position completion-base-position)
+ (base-affixes completion-base-affixes)
(insert-fun completion-list-insert-choice-function))
(completion-list-mode)
(setq-local completion-base-position base-position)
+ (setq-local completion-base-affixes base-affixes)
(setq-local completion-list-insert-choice-function insert-fun))
(setq-local completion-reference-buffer mainbuf)
(if base-dir (setq default-directory base-dir))
- bug#48356: 28.0.50; choose-completion discards the suffix after the completion boundary,
Juri Linkov <=