From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: sbaugh@catern.com Newsgroups: gmane.emacs.devel Subject: Re: Updating *Completions* as you type Date: Mon, 16 Oct 2023 08:16:15 -0400 Message-ID: <874jiqyd80.fsf@catern.com> References: <87bkd3z9bi.fsf@catern.com> <86cyxjyr1y.fsf@mail.linkov.net> <ier34ye4a3x.fsf@janestreet.com> <86r0lxm7um.fsf@mail.linkov.net> <87sf6dx954.fsf@catern.com> <8334ycqv0g.fsf@gnu.org> <87h6mryj5o.fsf@catern.com> 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="7878"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) To: emacs-devel@gnu.org Cancel-Lock: sha1:HF2OFaZhDQvBG1bhEj9KUdQULiY= Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Mon Oct 16 14:40:33 2023 Return-path: <emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org> 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 <emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org>) id 1qsMtd-0001oS-3j for ged-emacs-devel@m.gmane-mx.org; Mon, 16 Oct 2023 14:40:33 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from <emacs-devel-bounces@gnu.org>) id 1qsMsn-00048f-5e; Mon, 16 Oct 2023 08:39:41 -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 <ged-emacs-devel@m.gmane-mx.org>) id 1qsMWN-0003xf-Up for emacs-devel@gnu.org; Mon, 16 Oct 2023 08:16:32 -0400 Original-Received: from ciao.gmane.io ([116.202.254.214]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <ged-emacs-devel@m.gmane-mx.org>) id 1qsMWK-0001s2-CV for emacs-devel@gnu.org; Mon, 16 Oct 2023 08:16:30 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from <ged-emacs-devel@m.gmane-mx.org>) id 1qsMWH-000AMa-Hd for emacs-devel@gnu.org; Mon, 16 Oct 2023 14:16:25 +0200 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=ged-emacs-devel@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -15 X-Spam_score: -1.6 X-Spam_bar: - X-Spam_report: (-1.6 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.25, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Mon, 16 Oct 2023 08:39:37 -0400 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." <emacs-devel.gnu.org> List-Unsubscribe: <https://lists.gnu.org/mailman/options/emacs-devel>, <mailto:emacs-devel-request@gnu.org?subject=unsubscribe> List-Archive: <https://lists.gnu.org/archive/html/emacs-devel> List-Post: <mailto:emacs-devel@gnu.org> List-Help: <mailto:emacs-devel-request@gnu.org?subject=help> List-Subscribe: <https://lists.gnu.org/mailman/listinfo/emacs-devel>, <mailto:emacs-devel-request@gnu.org?subject=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:311519 Archived-At: <http://permalink.gmane.org/gmane.emacs.devel/311519> --=-=-= Content-Type: text/plain sbaugh@catern.com writes: > But actually, even without completions-auto-update, it would be > generally useful to not lose the location of point in *Completions*. > So I'll just implement that as a separate patch. Here's this; it's independently useful and independently installable. Should be a nice, if a bit niche, improvement to behavior. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Keep-point-on-the-same-completion-in-the-completions.patch >From 64c08696755c29d2d9125734865ef93af6833fef Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh@catern.com> Date: Sun, 15 Oct 2023 16:47:16 -0400 Subject: [PATCH] Keep point on the same completion in the completions buffer Currently if the user re-runs minibuffer-completion-help, point is reset to the beginning of the buffer. This throws away information unnecessarily; let's keep point on the same completion the user previously selected. We move setting cursor-face-highlight-nonselected-window to completion-setup-function so that the selected completion continues to be highlighted after minibuffer-completion-help, which creates a new *Completions* buffer. * lisp/minibuffer.el (completion--insert-strings) (completion--selected-posn, completion--insert-horizontal) (completion--insert-vertical, completion--insert-one-column) (completion--insert, display-completion-list): Add SELECTED argument. (minibuffer-next-completion): Don't set cursor-face-highlight-nonselected-window. (minibuffer-completion-help): Calculate current-completion and pass it to display-completion-list. * lisp/simple.el (completions--get-posn): Add. (choose-completion): Call completions--get-posn. (completion-setup-function): Set cursor-face-highlight-nonselected-window. --- lisp/minibuffer.el | 64 +++++++++++++++++++++++++++++++--------------- lisp/simple.el | 41 ++++++++++++++++------------- 2 files changed, 66 insertions(+), 39 deletions(-) diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 2120e31775e..998ef9f05a9 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2034,12 +2034,17 @@ completions-header-format (string :tag "Format string for heading line")) :version "29.1") -(defun completion--insert-strings (strings &optional group-fun) +(defvar completion--selected-posn) + +(defun completion--insert-strings (strings &optional group-fun selected) "Insert a list of STRINGS into the current buffer. The candidate strings are inserted into the buffer depending on the completions format as specified by the variable `completions-format'. Runs of equal candidate strings are eliminated. GROUP-FUN is a -`group-function' used for grouping the completion candidates." +`group-function' used for grouping the completion candidates. + +If SELECTED exists in STRINGS, point is set to its first +instance; otherwise, it's set to `point-min'." (when (consp strings) (let* ((length (apply #'max (mapcar (lambda (s) @@ -2055,18 +2060,20 @@ completion--insert-strings ;; Don't allocate more columns than we can fill. ;; Windows can't show less than 3 lines anyway. (max 1 (/ (length strings) 2)))) - (colwidth (/ wwidth columns))) + (colwidth (/ wwidth columns)) + completion--selected-posn) (unless (or tab-stop-list (null completion-tab-width) (zerop (mod colwidth completion-tab-width))) ;; Align to tab positions for the case ;; when the caller uses tabs inside prefix. (setq colwidth (- colwidth (mod colwidth completion-tab-width)))) (funcall (intern (format "completion--insert-%s" completions-format)) - strings group-fun length wwidth colwidth columns)))) + strings group-fun length wwidth colwidth columns selected) + (goto-char (or completion--selected-posn (point-min)))))) (defun completion--insert-horizontal (strings group-fun length wwidth - colwidth _columns) + colwidth _columns selected) (let ((column 0) (first t) (last-title nil) @@ -2103,7 +2110,7 @@ completion--insert-horizontal `(display (space :align-to ,column))) nil)) (setq first nil) - (completion--insert str group-fun) + (completion--insert str group-fun selected) ;; Next column to align to. (setq column (+ column ;; Round up to a whole number of columns. @@ -2111,7 +2118,7 @@ completion--insert-horizontal (defun completion--insert-vertical (strings group-fun _length _wwidth - colwidth columns) + colwidth columns selected) (while strings (let ((group nil) (column 0) @@ -2155,13 +2162,15 @@ completion--insert-vertical (insert " \t") (set-text-properties (1- (point)) (point) `(display (space :align-to ,column)))) - (completion--insert str group-fun) + (completion--insert str group-fun selected) (if (> column 0) (forward-line) (insert "\n")) (setq row (1+ row))))))) -(defun completion--insert-one-column (strings group-fun &rest _) +(defun completion--insert-one-column (strings group-fun + _length _wwidth + _colwidth _columns selected) (let ((last-title nil) (last-string nil)) (dolist (str strings) (unless (equal last-string str) ; Remove (consecutive) duplicates. @@ -2172,11 +2181,14 @@ completion--insert-one-column (setq last-title title) (when title (insert (format completions-group-format title) "\n"))))) - (completion--insert str group-fun) + (completion--insert str group-fun selected) (insert "\n"))) (delete-char -1))) -(defun completion--insert (str group-fun) +(defun completion--insert (str group-fun selected) + (when (and (not completion--selected-posn) + (equal (or (car-safe str) str) selected)) + (setq completion--selected-posn (point))) (if (not (consp str)) (add-text-properties (point) @@ -2197,7 +2209,7 @@ completion--insert (let ((beg (point)) (end (progn (insert prefix) (point)))) (add-text-properties beg end `(mouse-face nil completion--string ,(car str))))) - (completion--insert (car str) group-fun) + (completion--insert (car str) group-fun selected) (let ((beg (point)) (end (progn (insert suffix) (point)))) (add-text-properties beg end `(mouse-face nil completion--string ,(car str))) @@ -2267,7 +2279,7 @@ completion-hilit-commonality completions) base-size)))) -(defun display-completion-list (completions &optional common-substring group-fun) +(defun display-completion-list (completions &optional common-substring group-fun selected) "Display the list of completions, COMPLETIONS, using `standard-output'. Each element may be just a symbol or string or may be a list of two strings to be printed as if concatenated. @@ -2276,6 +2288,8 @@ display-completion-list `standard-output' must be a buffer. The actual completion alternatives, as inserted, are given `mouse-face' properties of `highlight'. +If SELECTED exists in COMPLETIONS, point is set to its first +instance; otherwise, it's set to `point-min'. At the end, this runs the normal hook `completion-setup-hook'. It can find the completion buffer in `standard-output'. GROUP-FUN is a `group-function' used for grouping the completion @@ -2299,9 +2313,15 @@ display-completion-list (goto-char (point-max)) (when completions-header-format (insert (format completions-header-format (length completions)))) - (completion--insert-strings completions group-fun))) - - (run-hooks 'completion-setup-hook) + (completion--insert-strings completions group-fun selected))) + + ;; Make sure point stays at SELECTED. + (let ((marker + (when (bufferp standard-output) + (with-current-buffer standard-output (point-marker))))) + (run-hooks 'completion-setup-hook) + (when marker + (with-current-buffer standard-output (goto-char marker)))) nil) (defvar completion-extra-properties nil @@ -2421,7 +2441,10 @@ minibuffer-completion-help ;; window, mark it as softly-dedicated, so bury-buffer in ;; minibuffer-hide-completions will know whether to ;; delete the window or not. - (display-buffer-mark-dedicated 'soft)) + (display-buffer-mark-dedicated 'soft) + (current-completion + (when-let ((buf (get-buffer "*Completions*"))) + (with-current-buffer buf (completions--get-posn (point)))))) (with-current-buffer-window "*Completions*" ;; This is a copy of `display-buffer-fallback-action' @@ -2440,7 +2463,7 @@ minibuffer-completion-help ,(when temp-buffer-resize-mode '(preserve-size . (nil . t))) (body-function - . ,#'(lambda (_window) + . ,#'(lambda (window) (with-current-buffer mainbuf ;; Remove the base-size tail because `sort' requires a properly ;; nil-terminated list. @@ -2527,7 +2550,8 @@ 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 current-completion) + (set-window-point window (with-current-buffer standard-output (point))))))) nil))) nil)) @@ -4496,8 +4520,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)) (next-completion (or n 1)) (when auto-choose (let ((completion-use-base-affixes t)) diff --git a/lisp/simple.el b/lisp/simple.el index ec14bec9e07..3ab8b783659 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10000,6 +10000,25 @@ next-completion (when (/= 0 n) (switch-to-minibuffer)))) +(defun completions--get-posn (position) + "Return the completion at POSITION as a string." + (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 + (setq beg (or (previous-single-property-change + beg 'completion--string) + beg)) + (substring-no-properties + (get-text-property beg 'completion--string)))))) + (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. @@ -10019,24 +10038,8 @@ choose-completion (base-affixes completion-base-affixes) (insert-function completion-list-insert-choice-function) (completion-no-auto-exit (if no-exit t completion-no-auto-exit)) - (choice - (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)) - (substring-no-properties - (get-text-property beg 'completion--string)))))) - + (choice (or (completions--get-posn (posn-point (event-start event))) + (error "No completion here")))) (unless (buffer-live-p buffer) (error "Destination buffer is dead")) (unless no-quit @@ -10208,6 +10211,8 @@ completion-setup-function (base-affixes completion-base-affixes) (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-base-affixes base-affixes) (setq-local completion-list-insert-choice-function insert-fun)) -- 2.41.0 --=-=-=--