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
next prev 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).