From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.bugs 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 Organization: LINKOV.NET Message-ID: <86ilsj574h.fsf@mail.linkov.net> References: <874kbydr7m.fsf@mail.linkov.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="24541"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (x86_64-pc-linux-gnu) Cc: 49931@debbugs.gnu.org To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Mar 12 20:14:33 2022 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nT7CC-0006Dx-RX for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 12 Mar 2022 20:14:32 +0100 Original-Received: from localhost ([::1]:59924 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nT7CB-0004Nm-3f for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 12 Mar 2022 14:14:31 -0500 Original-Received: from eggs.gnu.org ([209.51.188.92]:47102) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nT7Bk-0004J5-8o for bug-gnu-emacs@gnu.org; Sat, 12 Mar 2022 14:14:11 -0500 Original-Received: from debbugs.gnu.org ([209.51.188.43]:46974) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1nT7Bi-0005HQ-V0 for bug-gnu-emacs@gnu.org; Sat, 12 Mar 2022 14:14:04 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1nT7Bi-0008Ty-Qc for bug-gnu-emacs@gnu.org; Sat, 12 Mar 2022 14:14:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Juri Linkov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 12 Mar 2022 19:14:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 49931 X-GNU-PR-Package: emacs Original-Received: via spool by 49931-submit@debbugs.gnu.org id=B49931.164711242132562 (code B ref 49931); Sat, 12 Mar 2022 19:14:02 +0000 Original-Received: (at 49931) by debbugs.gnu.org; 12 Mar 2022 19:13:41 +0000 Original-Received: from localhost ([127.0.0.1]:40870 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nT7BN-0008T8-Bu for submit@debbugs.gnu.org; Sat, 12 Mar 2022 14:13:41 -0500 Original-Received: from relay11.mail.gandi.net ([217.70.178.231]:40571) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1nT7BL-0008Se-6N for 49931@debbugs.gnu.org; Sat, 12 Mar 2022 14:13:40 -0500 Original-Received: (Authenticated sender: juri@linkov.net) by mail.gandi.net (Postfix) with ESMTPSA id 1BA2C100002; Sat, 12 Mar 2022 19:13:31 +0000 (UTC) In-Reply-To: <874kbydr7m.fsf@mail.linkov.net> (Juri Linkov's message of "Tue, 10 Aug 2021 10:07:25 +0300") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.io gmane.emacs.bugs:228260 Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit [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)))) ``` --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=completion-base-affixes.patch 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)) --=-=-=--