From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Spencer Baugh Newsgroups: gmane.emacs.devel Subject: Re: Navigating completions from minibuffer Date: Wed, 29 Nov 2023 00:20:00 +0000 (UTC) Message-ID: <874jh5v2bd.fsf@catern.com> References: <86fs1c3yml.fsf@mail.linkov.net> <864jhokelp.fsf@mail.linkov.net> <86il62tbfa.fsf@mail.linkov.net> <861qcpu0ft.fsf@mail.linkov.net> <861qcorh4c.fsf@mail.linkov.net> <87jzqen5h0.fsf@catern.com> <86sf52tf0b.fsf@mail.linkov.net> <878r6tn6uf.fsf@catern.com> <874jhck2rn.fsf@catern.com> <8634wvk2me.fsf@mail.linkov.net> <87sf4tj1xw.fsf@catern.com> <86jzq521qs.fsf@mail.linkov.net> <87ttp8vb37.fsf@catern.com> <86il5niukm.fsf@mail.linkov.net> <87leaiue78.fsf@catern.com> <86msuxiyla.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="34120"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Juri Linkov Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Nov 29 01:21:03 2023 Return-path: Envelope-to: ged-emacs-devel@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 1r88K5-0008fg-Vo for ged-emacs-devel@m.gmane-mx.org; Wed, 29 Nov 2023 01:21:02 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1r88JE-0005FG-SL; Tue, 28 Nov 2023 19:20:08 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1r88JD-0005Eq-Is for emacs-devel@gnu.org; Tue, 28 Nov 2023 19:20:07 -0500 Original-Received: from s.wfbtzhsv.outbound-mail.sendgrid.net ([159.183.224.104]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1r88JA-00053h-7C for emacs-devel@gnu.org; Tue, 28 Nov 2023 19:20:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=catern.com; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: cc:content-type:from:subject:to; s=s1; bh=TxHxuxbeb6P2nOTrPPhh8k32/sN+RmJ/pk27EHxhSXc=; b=sDAhRvyLtcvfXJU3qbw2BMYYxMbUFx3y796clv/nnccJtBjBhGRc2HRYr21M9i8SC5xl cj32ir6tDa39lvihkYfEMBvhiMAjgi5ibVFda7q+xEX4SsMjb/eYrEWSQJezHMl1NsBShZ yR8SjUff0ej6mF3s9RytPQtgMaUlJanJNilbVez4f/ppKKKxJS8IOTWDNLKKElk4uot51W zJnOA7qJ8/OfJ0j6A8HbtxNNuui+OgdoXoiOkdbwiHsZMLpwLdkv7GVBk/jKvZqccRe72J f5ZzMyhC+htoRptVCIn9A50lymepGPOxWYcQJiahab83piubmZPiP241FwNEEhWQ== Original-Received: by filterdrecv-656b5b4c75-6h76l with SMTP id filterdrecv-656b5b4c75-6h76l-1-656683B0-30 2023-11-29 00:20:00.770264639 +0000 UTC m=+3649211.871783294 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-49 (SG) with ESMTP id MOPgh5MXSg6O5Sk7oWfRQg Wed, 29 Nov 2023 00:20:00.647 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=74.101.51.129; helo=localhost; envelope-from=sbaugh@catern.com; receiver=linkov.net Original-Received: from localhost (unknown [74.101.51.129]) by earth.catern.com (Postfix) with ESMTPSA id 1D73863E4B; Tue, 28 Nov 2023 19:19:19 -0500 (EST) In-Reply-To: <86msuxiyla.fsf@mail.linkov.net> X-SG-EID: =?us-ascii?Q?GW3oCMoYnalRiojMOuLzE6x2H5kORXvlCdz1UwQVRMVT4fbh9ODEfCogOe74cO?= =?us-ascii?Q?rI4e0V+MFZgakz9Re5a6=2FCgnHo8VR+8PXI8MYpr?= =?us-ascii?Q?k2h1C0rIgLO1hO8nbFRr7NI2vr7hh4xbFTnbb8B?= =?us-ascii?Q?uXwEtBDLFRrEn4FxHlPvYzyNOZ8mxGbXmPiANjV?= =?us-ascii?Q?20IgPzbmp3MjGsgeWs2NjfT0a=2FH=2FZFYZtzR8o3A?= =?us-ascii?Q?y7ExQfbGKVhOJlVA4Tto1wWEV6nS6W75Fsc5=2FU?= X-Entity-ID: d/0VcHixlS0t7iB1YKCv4Q== Received-SPF: pass client-ip=159.183.224.104; envelope-from=bounces+21787432-489d-emacs-devel=gnu.org@em8926.catern.com; helo=s.wfbtzhsv.outbound-mail.sendgrid.net X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, UNPARSEABLE_RELAY=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:313343 Archived-At: --=-=-= Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Juri Linkov writes: >>> then point is moved before the suffix "(C-x *)", >>> and after editing it is selected on RET. >> >> Ah, good catch. Fixed (by using 'completion--string to detect whether >> point is on a completion rather 'mouse-face) > > Thank, now this works nicely. > Maybe this deserves a NEWS entry as well? Added. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Deselect-the-selected-completion-candidate-when-typi.patch >From e92d36a643df166406a8f4d9ca321213c6bb0704 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Thu, 23 Nov 2023 13:37:29 +0000 Subject: [PATCH] Deselect the selected completion candidate when typing minibuffer-choose-completion-or-exit submits the selected completion candidate, if any, ignoring the contents of the minibuffer. But a user might select a completion candidate and then want to type something else in the minibuffer and submit what they typed. Now typing will automatically deselect the selected completion candidate so that minibuffer-choose-completion-or-exit will not choose it. minibuffer-choose-completion has the same behavior as before, and is not affected by the deselection. * lisp/minibuffer.el (completion-auto-deselect, completions--deselect) (completions--after-change): Add. (minibuffer-completion-help): Add completions--after-change hook. (minibuffer-next-completion): Bind completion-auto-deselect to nil to avoid immediately deselecting the completion. (minibuffer-choose-completion-or-exit): Bind choose-completion-deselect-if-after so deselection takes effect. (display-completion-list): Guarantee a newline at the beginning of *Completions* to avoid ambiguity about candidate selection. * lisp/simple.el (choose-completion-deselect-if-after): Add. (choose-completion): Check choose-completion-deselect-if-after. * etc/NEWS: Announce. --- etc/NEWS | 9 +++++++++ lisp/minibuffer.el | 43 +++++++++++++++++++++++++++++++++++++++---- lisp/simple.el | 11 ++++++++++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 6661ac70e1b..b785b91cb4b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -626,6 +626,15 @@ completions window. When the completions window is not visible, then all these keys have their usual meaning in the minibuffer. This option is supported for in-buffer completion as well. +*** Selected completion candidates are deselected on typing. +When a user types, point in the *Completions* window will be moved off +any completion candidates. 'minibuffer-choose-completion' ('M-RET') +will still choose a previously-selected completion candidate, but the +new command 'minibuffer-choose-completion-or-exit' (bound by +'minibuffer-visible-completions') will exit with the minibuffer +contents instead. The deselection behavior can be controlled with the +new user option 'completion-auto-deselect'. + ** Pcomplete --- diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 5c12d9fc914..382d4458e26 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2310,8 +2310,11 @@ display-completion-list (with-current-buffer standard-output (goto-char (point-max)) - (when completions-header-format - (insert (format completions-header-format (length completions)))) + (if completions-header-format + (insert (format completions-header-format (length completions))) + (unless completion-show-help + ;; Ensure beginning-of-buffer isn't a completion. + (insert (propertize "\n" 'face '(:height 0))))) (completion--insert-strings completions group-fun))) (run-hooks 'completion-setup-hook) @@ -2378,6 +2381,33 @@ completions--fit-window-to-buffer (resize-temp-buffer-window win)) (fit-window-to-buffer win completions-max-height))) +(defcustom completion-auto-deselect t + "If non-nil, deselect the selected completion candidate when you type. + +A non-nil value means that after typing, point in *Completions* +will be moved off any completion candidates. This means +`minibuffer-choose-completion-or-exit' will exit with the +minibuffer's current contents, instead of a completion candidate." + :type '(choice (const :tag "Candidates in *Completions* stay selected as you type" nil) + (const :tag "Typing deselects any completion candidate in *Completions*" t)) + :version "30.1") + +(defun completions--deselect () + "If point is in a completion candidate, move to just after the end of it. + +The candidate will still be chosen by `choose-completion' unless +`choose-completion-deselect-if-after' is non-nil." + (when (get-text-property (point) 'completion--string) + (goto-char (or (next-single-property-change (point) 'completion--string) + (point-max))))) + +(defun completions--after-change (_start _end _old-len) + "Update displayed *Completions* buffer after change in buffer contents." + (when completion-auto-deselect + (when-let (window (get-buffer-window "*Completions*" 0)) + (with-selected-window window + (completions--deselect))))) + (defun minibuffer-completion-help (&optional start end) "Display a list of possible completions of the current minibuffer contents." (interactive) @@ -2400,6 +2430,7 @@ minibuffer-completion-help ;; If there are no completions, or if the current input is already ;; the sole completion, then hide (previous&stale) completions. (minibuffer-hide-completions) + (remove-hook 'after-change-functions #'completions--after-change t) (if completions (completion--message "Sole completion") (unless completion-fail-discreetly @@ -2460,6 +2491,8 @@ minibuffer-completion-help (body-function . ,#'(lambda (_window) (with-current-buffer mainbuf + (when completion-auto-deselect + (add-hook 'after-change-functions #'completions--after-change t)) ;; Remove the base-size tail because `sort' requires a properly ;; nil-terminated list. (when last (setcdr last nil)) @@ -4673,7 +4706,8 @@ minibuffer-next-completion (next-line-completion (or n 1)) (next-completion (or n 1))) (when auto-choose - (let ((completion-use-base-affixes t)) + (let ((completion-use-base-affixes t) + (completion-auto-deselect nil)) (choose-completion nil t t)))))) (defun minibuffer-previous-completion (&optional n) @@ -4721,7 +4755,8 @@ minibuffer-choose-completion-or-exit contents." (interactive "P") (condition-case nil - (minibuffer-choose-completion no-exit no-quit) + (let ((choose-completion-deselect-if-after t)) + (minibuffer-choose-completion no-exit no-quit)) (error (minibuffer-complete-and-exit)))) (defun minibuffer-complete-history () diff --git a/lisp/simple.el b/lisp/simple.el index 35bce6ab4b8..67d04032e64 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10092,6 +10092,11 @@ next-line-completion (if pos (goto-char pos)))) (setq n (1+ n))))) +(defvar choose-completion-deselect-if-after nil + "If non-nil, don't choose a completion candidate if point is right after it. + +This makes `completions--deselect' effective.") + (defun choose-completion (&optional event no-exit no-quit) "Choose the completion at point. If EVENT, use EVENT's position to determine the starting position. @@ -10112,6 +10117,10 @@ choose-completion (insert-function completion-list-insert-choice-function) (completion-no-auto-exit (if no-exit t completion-no-auto-exit)) (choice + (if choose-completion-deselect-if-after + (if-let ((str (get-text-property (posn-point (event-start event)) 'completion--string))) + (substring-no-properties str) + (error "No completion here")) (save-excursion (goto-char (posn-point (event-start event))) (let (beg) @@ -10127,7 +10136,7 @@ choose-completion beg 'completion--string) beg)) (substring-no-properties - (get-text-property beg 'completion--string)))))) + (get-text-property beg 'completion--string))))))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) -- 2.42.1 --=-=-=--