From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Spencer Baugh via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#74019: [PATCH] Optionally preserve selected candidate across *Completions* update Date: Tue, 29 Oct 2024 12:25:15 -0400 Message-ID: References: Reply-To: Spencer Baugh 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="33834"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: 74019@debbugs.gnu.org, Juri Linkov To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Oct 29 17:26:32 2024 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 1t5p37-0008Y6-MW for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 29 Oct 2024 17:26:30 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t5p2m-0008HB-Em; Tue, 29 Oct 2024 12:26:08 -0400 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 1t5p2j-0008EV-Hs for bug-gnu-emacs@gnu.org; Tue, 29 Oct 2024 12:26:05 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1t5p2g-0008Dm-Rb for bug-gnu-emacs@gnu.org; Tue, 29 Oct 2024 12:26:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:References:In-Reply-To:From:To:Subject; bh=UdjG3HU+5yLJNBIIdC3p8jSSD2SvDhiWAS6FoMartfI=; b=MofSte2rSw+DyVmHrzMAK30fX5nLl5fCHHexGIBkcAy8yNWBFbSKTAfTkxDIx6ePEQHUjITzOP9fE9zy5JFLOWcsBHHJiV213y0p0QsaQMdGh737XXHD32K6fD8quQLiRG+V9+lVKZeziutlq8L+8U0NKdi4KyRNR+UPbsvqgyGJ4Wuba8v0iDTwhRlZOEpdoZBsE/MB3r8VH3WBLIl+e2q9ZPpSMlhQQh/MwgRWNFKVh/+7iWUI3YLpeOvKaUlCHfWAxRg97TEIpwBrR9OI3LbGPAyXinr8sFfIi34u5+zpAvL5xyg3GxTLJ0NciNvf5/9+c0n/ZXMcnw33mA1pxA==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1t5p2g-0001zr-MH for bug-gnu-emacs@gnu.org; Tue, 29 Oct 2024 12:26:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Spencer Baugh Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 29 Oct 2024 16:26:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 74019 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 74019-submit@debbugs.gnu.org id=B74019.17302191247638 (code B ref 74019); Tue, 29 Oct 2024 16:26:02 +0000 Original-Received: (at 74019) by debbugs.gnu.org; 29 Oct 2024 16:25:24 +0000 Original-Received: from localhost ([127.0.0.1]:57269 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t5p24-0001z8-0e for submit@debbugs.gnu.org; Tue, 29 Oct 2024 12:25:24 -0400 Original-Received: from mxout1.mail.janestreet.com ([38.105.200.78]:54085) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1t5p21-0001yq-Ng for 74019@debbugs.gnu.org; Tue, 29 Oct 2024 12:25:22 -0400 In-Reply-To: (Stefan Monnier's message of "Mon, 28 Oct 2024 22:53:59 -0400") DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=waixah; t=1730219115; bh=UdjG3HU+5yLJNBIIdC3p8jSSD2SvDhiWAS6FoMartfI=; h=From:To:Cc:Subject:In-Reply-To:References:Date; b=tx7EtmlisUb0opJW2YlRkqO2zqUOZH7pXymZfGYsrS5lFRKHRUtATz48vYz8v+6uY 6js4RPkGnOqH+SFn7/c4xy98NGjrMx63KAhxPnZjkFOw5A+Sa38A3p/cmuvUD07qY6 bBry9TwlWpctjs9BUJCC93wPChFMDDSCndKP8N564fhD0N2Z7TAscnPIi/amePXg+J MZvKQl5+0NF/zOP87bakGJLS9fUBJ08UeYCP/ePhRGZzjox1NA/g2usCu/KhtMlDOk gWLsd9BrXi4xxovZleC6G3eM1Kh5ZrSzFcAhfq+/mWRl66IVNsfgHVpN4LmjbRTNqj S6naN4mIY227Q== 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-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:294506 Archived-At: --=-=-= Content-Type: text/plain Stefan Monnier writes: >> Or maybe instead of a buffer-local, we could have >> minibuffer-hide-completions do (goto-char (point-min)) so no >> completion is selected anymore. Then it becomes harmless to reuse >> that *Completions* buffer. > > Either way works for me. OK, updated patch with this and other feedback: --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Preserve-selected-candidate-across-Completions-updat.patch >From c9b1336692c095e4f8423797e58aac9fe55325fb Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Tue, 29 Oct 2024 12:16:31 -0400 Subject: [PATCH] Preserve selected candidate across *Completions* update When *Completions* is updated and point was on some completion candidate, move point to the same candidate after the update. Also, a selected completion in *Completions* is now always highlighted, even if it was selected by the user or other code moving point rather than by minibuffer-next-completion, because cursor-face-highlight-nonselected-window is now set in completion-setup-function. Other completion UIs (e.g. ido, vertico, etc) effectively have this behavior: whenever they update the list of completions, they preserve whatever candidate is selected. This matters a lot when completions are auto-updated, but is still useful without auto-updating. Including this behavior is a step towards supporting auto-updating in the default completion UI. * lisp/minibuffer.el (minibuffer-completion-help): Preserve the selected completion candidate across updates. (bug#74019) (minibuffer-hide-completions): Move point to BOB. (minibuffer-next-completion): Don't set cursor-face-highlight-nonselected-window. * lisp/simple.el (completions--start-of-candidate-at) (choose-completion): Extract the current-completion-finding code into a separate function. (completion-setup-function): Set cursor-face-highlight-nonselected-window. * etc/NEWS: Announce new behavior. --- etc/NEWS | 8 ++++++++ lisp/minibuffer.el | 29 +++++++++++++++++++++++------ lisp/simple.el | 39 ++++++++++++++++++++++++--------------- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 18b6678dce9..ad85bbf116e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -86,6 +86,14 @@ different values for completion-affecting variables like applies for the styles configuration in 'completion-category-overrides' and 'completion-category-defaults'. +--- +*** Selected completion candidate is preserved across *Completions* updates. +When point is on a completion candidate in the *Completions* buffer +(because of 'minibuffer-next-completion' or for any other reason), point +will still be on that candidate after *Completions* is updated with a +new list of completions. The candidate is automatically deselected when +the *Completions* buffer is hidden. + ** Windows +++ diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 44d07557f48..9b498615926 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2624,6 +2624,12 @@ minibuffer-completion-help (sort-fun (completion-metadata-get all-md 'display-sort-function)) (group-fun (completion-metadata-get all-md 'group-function)) (mainbuf (current-buffer)) + (current-candidate-and-offset + (when-let* ((buffer (get-buffer "*Completions*")) + (window (get-buffer-window buffer 0))) + (with-current-buffer buffer + (when-let* ((beg (completions--start-of-candidate-at (window-point window)))) + (cons (get-text-property beg 'completion--string) (- (point) beg)))))) ;; If the *Completions* buffer is shown in a new ;; window, mark it as softly-dedicated, so bury-buffer in ;; minibuffer-hide-completions will know whether to @@ -2647,7 +2653,7 @@ minibuffer-completion-help ,(when temp-buffer-resize-mode '(preserve-size . (nil . t))) (body-function - . ,#'(lambda (_window) + . ,#'(lambda (window) (with-current-buffer mainbuf (when completion-auto-deselect (add-hook 'after-change-functions #'completions--after-change nil t)) @@ -2737,7 +2743,16 @@ minibuffer-completion-help (if (eq (car bounds) (length result)) 'exact 'finished)))))) - (display-completion-list completions nil group-fun))))) + (display-completion-list completions nil group-fun) + (when current-candidate-and-offset + (with-current-buffer standard-output + (when-let* ((match (text-property-search-forward + 'completion--string (car current-candidate-and-offset) t))) + (goto-char (prop-match-beginning match)) + ;; Preserve the exact offset for the sake of + ;; `choose-completion-deselect-if-after'. + (forward-char (cdr current-candidate-and-offset)) + (set-window-point window (point))))))))) nil))) nil)) @@ -2746,8 +2761,12 @@ minibuffer-hide-completions ;; FIXME: We could/should use minibuffer-scroll-window here, but it ;; can also point to the minibuffer-parent-window, so it's a bit tricky. (interactive) - (let ((win (get-buffer-window "*Completions*" 0))) - (if win (with-selected-window win (bury-buffer))))) + (when-let* ((win (get-buffer-window "*Completions*" 0))) + (with-selected-window win + ;; Move point off any completions, so we don't move point there + ;; again the next time `minibuffer-completion-help' is called. + (goto-char (point-min)) + (bury-buffer)))) (defun exit-minibuffer () "Terminate this minibuffer argument." @@ -4905,8 +4924,6 @@ minibuffer-next-completion (interactive "p") (let ((auto-choose minibuffer-completion-auto-choose)) (with-minibuffer-completions-window - (when completions-highlight-face - (setq-local cursor-face-highlight-nonselected-window t)) (if vertical (next-line-completion (or n 1)) (next-completion (or n 1))) diff --git a/lisp/simple.el b/lisp/simple.el index 2ffd6e86e56..3a142ef14b3 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10246,6 +10246,23 @@ choose-completion-deselect-if-after This makes `completions--deselect' effective.") +(defun completions--start-of-candidate-at (position) + "Return the start position of the completion candidate at POSITION." + (save-excursion + (goto-char position) + (let (beg) + (cond + ((and (not (eobp)) + (get-text-property (point) 'completion--string)) + (setq beg (1+ (point)))) + ((and (not (bobp)) + (get-text-property (1- (point)) 'completion--string)) + (setq beg (point)))) + (when beg + (or (previous-single-property-change + beg 'completion--string) + beg))))) + (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. @@ -10269,21 +10286,11 @@ choose-completion (or (get-text-property (posn-point (event-start event)) 'completion--string) (error "No completion here")) - (save-excursion - (goto-char (posn-point (event-start event))) - (let (beg) - (cond - ((and (not (eobp)) - (get-text-property (point) 'completion--string)) - (setq beg (1+ (point)))) - ((and (not (bobp)) - (get-text-property (1- (point)) 'completion--string)) - (setq beg (point))) - (t (error "No completion here"))) - (setq beg (or (previous-single-property-change - beg 'completion--string) - beg)) - (get-text-property beg 'completion--string)))))) + (if-let* ((candidate-start + (completions--start-of-candidate-at + (posn-point (event-start event))))) + (get-text-property candidate-start 'completion--string) + (error "No completion here"))))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) @@ -10451,6 +10458,8 @@ completion-setup-function (let ((base-position completion-base-position) (insert-fun completion-list-insert-choice-function)) (completion-list-mode) + (when completions-highlight-face + (setq-local cursor-face-highlight-nonselected-window t)) (setq-local completion-base-position base-position) (setq-local completion-list-insert-choice-function insert-fun)) (setq-local completion-reference-buffer mainbuf) -- 2.39.3 --=-=-=--