unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: sbaugh@catern.com
To: emacs-devel@gnu.org
Subject: Re: Updating *Completions* as you type
Date: Mon, 16 Oct 2023 08:16:15 -0400	[thread overview]
Message-ID: <874jiqyd80.fsf@catern.com> (raw)
In-Reply-To: 87h6mryj5o.fsf@catern.com

[-- Attachment #1: Type: text/plain, Size: 354 bytes --]

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.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Keep-point-on-the-same-completion-in-the-completions.patch --]
[-- Type: text/x-patch, Size: 12752 bytes --]

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


  parent reply	other threads:[~2023-10-16 12:16 UTC|newest]

Thread overview: 107+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-12 23:53 Updating *Completions* as you type sbaugh
2023-10-13  6:31 ` Eli Zaretskii
2023-10-13 18:01   ` Spencer Baugh
2023-10-14  7:09     ` Eli Zaretskii
2023-10-14 19:26       ` Björn Bidar
     [not found]       ` <874jit2ef7.fsf@>
2023-10-14 19:38         ` Eli Zaretskii
2023-10-14 16:51     ` Juri Linkov
2023-10-14 17:56       ` sbaugh
2023-10-14 19:51       ` Dmitry Gutov
2023-10-13  6:34 ` Juri Linkov
2023-10-13 19:04   ` Spencer Baugh
2023-10-14 16:58     ` Juri Linkov
2023-10-14 20:05       ` sbaugh
2023-10-15  6:06         ` Eli Zaretskii
2023-10-15 15:55           ` sbaugh
2023-10-16 11:38             ` Eli Zaretskii
2023-10-16 14:50               ` Michael Albinus
2023-10-16 15:58                 ` [External] : " Drew Adams
2023-10-16 12:16             ` sbaugh [this message]
2023-10-17 18:23               ` Juri Linkov
2023-10-18 23:27                 ` Spencer Baugh
2023-10-15  7:32         ` Juri Linkov
2023-10-16 19:28           ` Rudolf Adamkovič
2023-10-17 18:38             ` Juri Linkov
2023-10-15 20:31         ` Eshel Yaron
2023-10-16  3:18           ` [External] : " Drew Adams
2023-10-16 16:54           ` Juri Linkov
2023-10-17 13:48         ` sbaugh
2023-10-17 18:35           ` Juri Linkov
2023-10-17 22:57             ` Spencer Baugh
2023-10-18  3:04               ` [External] : " Drew Adams
2023-10-18  6:56               ` Juri Linkov
2023-10-18 12:25                 ` Spencer Baugh
2023-10-18 17:32                   ` Juri Linkov
2023-10-18 23:33                     ` Spencer Baugh
2023-10-19  2:29                       ` Spencer Baugh
2023-10-19  6:55                         ` Juri Linkov
2023-11-19 19:22                           ` sbaugh
2023-11-20  7:51                             ` Juri Linkov
2023-11-20 15:24                               ` Spencer Baugh
2023-11-20 17:47                                 ` Juri Linkov
2023-11-20 18:50                                   ` Spencer Baugh
2023-11-21  7:58                                     ` Juri Linkov
2023-11-21 12:40                                       ` sbaugh
2023-11-21 17:09                                         ` Juri Linkov
2023-11-21 20:45                                           ` Spencer Baugh
2023-11-22  7:51                                             ` Juri Linkov
2023-11-22 16:11                                               ` Spencer Baugh
2023-11-23  7:58                                                 ` Juri Linkov
2023-11-23 12:36                                                   ` sbaugh
2023-11-24  7:58                                                     ` Juri Linkov
2023-11-25 16:44                                                       ` Spencer Baugh
2023-11-25 18:31                                                         ` Juri Linkov
2023-11-26 13:33                                                           ` sbaugh
2023-11-27  7:28                                                             ` Juri Linkov
2023-11-28 14:38                                                               ` Spencer Baugh
2023-11-28 15:03                                                                 ` Eli Zaretskii
2023-11-28 17:13                                                                   ` Juri Linkov
2023-11-28 17:36                                                                     ` Eli Zaretskii
2023-11-29  7:11                                                                       ` Juri Linkov
2023-11-29 13:09                                                                         ` Eli Zaretskii
2023-11-29 14:14                                                                           ` Spencer Baugh
2023-11-29 14:54                                                                             ` Eli Zaretskii
2023-11-29 15:21                                                                               ` Spencer Baugh
2023-11-29 15:52                                                                                 ` Eli Zaretskii
2023-11-29 19:17                                                                                   ` Spencer Baugh
2023-11-30  6:12                                                                                     ` Eli Zaretskii
2023-11-30 12:33                                                                                       ` Spencer Baugh
2023-11-30 14:10                                                                                         ` Eli Zaretskii
2023-11-28 23:56                                                                   ` Spencer Baugh
2023-11-29  3:33                                                                     ` Eli Zaretskii
2023-12-03 17:25                                                                     ` Juri Linkov
2023-12-03 17:56                                                                       ` Eli Zaretskii
2023-12-06 17:17                                                                         ` Juri Linkov
2023-11-28 17:16                                                                 ` Juri Linkov
2023-11-28 23:36                                                                   ` Turning completion table lambdas into symbols Spencer Baugh
2023-11-28 23:51                                                                     ` Dmitry Gutov
2023-11-29 19:26                                                                       ` Spencer Baugh
2023-12-01  0:36                                                                         ` Dmitry Gutov
2023-11-29  7:18                                                                     ` Juri Linkov
2023-11-21 12:54                                       ` Updating *Completions* as you type John Yates
2023-11-21 17:03                                         ` Juri Linkov
2023-11-21 22:27                                           ` John Yates
2023-10-20  6:49         ` Juri Linkov
2023-10-17 15:01       ` sbaugh
2023-10-17 18:20         ` Juri Linkov
2023-10-17 23:37           ` Spencer Baugh
2023-10-17 23:44             ` Spencer Baugh
2023-10-18  6:51             ` Juri Linkov
2023-10-18 12:47               ` Spencer Baugh
2023-10-18 17:28                 ` Juri Linkov
2023-10-18 23:32                   ` Spencer Baugh
2023-10-16  3:19   ` [External] : " Drew Adams
2023-10-20  9:35   ` zcomplete Philip Kaludercic
2023-10-22 17:28     ` zcomplete Juri Linkov
2023-10-23  5:00       ` zcomplete Protesilaos Stavrou
2023-10-23  6:45         ` zcomplete Juri Linkov
2023-10-13 18:11 ` Updating *Completions* as you type Daniel Semyonov
2023-10-13 18:48   ` Spencer Baugh
2023-10-16  3:16     ` [External] : " Drew Adams
2023-10-16  9:25       ` Philip Kaludercic
2023-10-16 16:03         ` Drew Adams
2023-10-20  7:45           ` Philip Kaludercic
2023-10-20 16:10             ` Drew Adams
2023-10-16 22:55         ` Emanuel Berg
2023-10-17  6:09           ` Emanuel Berg
2023-10-17  0:44 ` Michael Heerdegen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874jiqyd80.fsf@catern.com \
    --to=sbaugh@catern.com \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).