[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#49931: 28.0.50; `choose-completion' submits incorrect string when mi
From: |
Juri Linkov |
Subject: |
bug#49931: 28.0.50; `choose-completion' submits incorrect string when minibuffer content changes after creation of the *Completions* buffer |
Date: |
Sat, 12 Mar 2022 20:49:58 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (x86_64-pc-linux-gnu) |
[This is continuation of the unfinished fix from bug#34517]
>> Stefan, please advise shouldn't selecting a completion from the
>> *Completions* buffer clear the minibuffer's content before
>> inserting the selected completion?
>
> No, for example when you complete file name "C-x C-f ~/.e TAB" the
> *Completions* buffer will only show ".emacs" so we should clear the
> minibuffer before inserting ".emacs" because that would lose the leading
> "~/". There are other circumstances where trailing text needs to
> be preserved.
Another example that occurred to me is shell-command M-! minibuffer
where TAB can complete on commands and file names.
> The completion code handles this with `completion-base-position` which
> holds the beginning and end of the text that should be replaced when you
> choose an item in *Completions*.
>
>>> 0. emacs -Q
>>> 1. ‘C-h f TAB’ displays a list of completions
>>> 2. type a nonexistent function name, i.e. some random text
>>> in the minibuffer, e.g. “blabla”
>
> The *Completions* content is now "out of date" compared to the minibuffer.
>
>>> 3. click on an existing valid completion in the *Completions* buffer,
>>> e.g. on “append”
>
> completion-base-position was set at step (1) to cover the empty text
> after the prompt, so this empty text (which is now right in front of
> "blabla") is replaced with "append" resulting in "appendblabla".
>
> Obviously, the result is not what we want.
> Now sure how to change which part, tho. Maybe instead of
> completion-base-position we should store the prefix and suffix strings,
> so when you select an entry from *Completions* we just clear the
> minibuffer and replace it with (concat prefix selection suffix)?
Now I tried this, and it works correctly. But not sure how to make
this change as backward-compatible as possible. One variant
would be to save '("prefix" "suffix") instead of '(10 11)
in 'completion-base-position' but this might fail in some existing code.
So maybe better to add a new variable 'completion-base-affixes'.
Then whether to use 'completion-base-position'
or 'completion-base-affixes' could be defined by the new user option
'completion-use-base-affixes'.
Then it can be used in the new command from emacs-devel:
```
(defun minibuffer-completion-choose (&optional arg)
"Run `choose-completion' from the minibuffer in its scrolling window."
(interactive "P")
(with-minibuffer-scroll-window
(let ((completion-use-base-affixes t))
(choose-completion nil arg))))
```
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 0262424b87..4cc050ff86 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -2290,6 +2290,8 @@ minibuffer-completion-help
(let* ((start (or start (minibuffer--completion-prompt-end)))
(end (or end (point-max)))
(string (buffer-substring start end))
+ (base-prefix (buffer-substring (minibuffer--completion-prompt-end)
start))
+ (base-suffix (buffer-substring end (point-max)))
(md (completion--field-metadata start))
(completions (completion-all-completions
string
@@ -2405,11 +2407,16 @@ 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-region (minibuffer-prompt-end)
(point-max))
+ (insert start choice end))
(unless (or (zerop (length prefix))
(equal prefix
(buffer-substring-no-properties
@@ -2418,7 +2425,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 9601e6cd76..bf9d8c8830 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9072,6 +9072,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
@@ -9164,6 +9181,7 @@ choose-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)
(completion-no-auto-exit (if arg t completion-no-auto-exit))
(choice
@@ -9184,7 +9202,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)))))
@@ -9357,9 +9377,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))
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- bug#49931: 28.0.50; `choose-completion' submits incorrect string when minibuffer content changes after creation of the *Completions* buffer,
Juri Linkov <=