unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Philip Kaludercic <philipk@posteo.net>
To: emacs-devel@gnu.org
Subject: Suggestions for improvements to the *Completions* buffer
Date: Thu, 09 Dec 2021 17:22:23 +0000	[thread overview]
Message-ID: <87a6h9g0c0.fsf@posteo.net> (raw)

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


Hi,

I'd like to suggest a few modifications to the default behaviour of
the *Completions* buffer.  These are mostly conservative extensions of
the current defaults.

Currently, next-completion (and previous-completion) stops at either the
end or the beginning of a buffer.  This patch would allow for the
command to also wrap around, and if the end has been reached to jump
back to the beginning.  In my experience, the improvement is most
noticeable when choosing between a small number choices, and pressing
tab twice is easier than shift-tab.

Optionally, this could also be extended to only enable cycling when
there are less than n options to select from.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Allow-for-next-completion-to-wrap-around-the-complet.patch --]
[-- Type: text/x-patch, Size: 2725 bytes --]

From 250d743cf53002b4c696ad33eb76a4454c4d254c Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Thu, 9 Dec 2021 17:26:14 +0100
Subject: [PATCH 1/4] Allow for next-completion to wrap around the completion
 buffer

* lisp/simple.el (completion-wrap-movement): Add new option.
(previous-completion): Update docstring.
(next-completion): Respect completion-wrap-movement.
---
 lisp/simple.el | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index 94a459b779..5183a7e053 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9013,25 +9013,38 @@ delete-completion-window
       (if (get-buffer-window buf)
 	  (select-window (get-buffer-window buf))))))
 
+(defcustom completion-wrap-movement t
+  "Non-nil means to wrap around when selecting completion options.
+This affects the commands `next-completion' and
+`previous-completion'."
+  :type 'boolean
+  :version "29.1"
+  :group 'completion)
+
 (defun previous-completion (n)
-  "Move to the previous item in the completion list."
+  "Move to the previous item in the completion list.
+With prefix argument N, move back N items (negative N means move
+forward)."
   (interactive "p")
   (next-completion (- n)))
 
 (defun next-completion (n)
   "Move to the next item in the completion list.
-With prefix argument N, move N items (negative N means move backward)."
+With prefix argument N, move N items (negative N means move
+backward)."
   (interactive "p")
   (let ((beg (point-min)) (end (point-max)))
-    (while (and (> n 0) (not (eobp)))
+    (while (> n 0)
       ;; If in a completion, move to the end of it.
       (when (get-text-property (point) 'mouse-face)
 	(goto-char (next-single-property-change (point) 'mouse-face nil end)))
+      (when (and (eobp) completion-wrap-movement)
+        (goto-char (point-min)))
       ;; Move to start of next one.
       (unless (get-text-property (point) 'mouse-face)
 	(goto-char (next-single-property-change (point) 'mouse-face nil end)))
       (setq n (1- n)))
-    (while (and (< n 0) (not (bobp)))
+    (while (< n 0)
       (let ((prop (get-text-property (1- (point)) 'mouse-face)))
 	;; If in a completion, move to the start of it.
 	(when (and prop (eq prop (get-text-property (point) 'mouse-face)))
@@ -9041,6 +9054,8 @@ next-completion
 	(unless (or (bobp) (get-text-property (1- (point)) 'mouse-face))
 	  (goto-char (previous-single-property-change
 		      (point) 'mouse-face nil beg)))
+        (when (and (bobp) completion-wrap-movement)
+          (goto-char (point-max)))
 	;; Move to the start of that one.
 	(goto-char (previous-single-property-change
 		    (point) 'mouse-face nil beg))
-- 
2.34.0


[-- Attachment #3: Type: text/plain, Size: 387 bytes --]


Currently, as soon as the minibuffer cannot expand the completion any
further, tab becomes a noop and the user is caught in a state that they
have to exit with some other command (M-v, C-g, ...).  Again, just like
above, I prefer to stay on the same key, so this patch introduces a user
option to automatically switch to the completion buffer, as soon as it
pops up, to just "tab on".


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: 0002-Allow-for-the-completion-buffer-to-be-automatically-.patch --]
[-- Type: text/x-patch, Size: 1412 bytes --]

From 4bc0d69c00cc650ec2be437ac7d45ccad7926ea1 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Thu, 9 Dec 2021 17:34:54 +0100
Subject: [PATCH 2/4] Allow for the completion buffer to be automatically
 selected

* lisp/simple.el (completion-auto-select): Add new option.
(completion-setup-function): Respect completion-auto-select.
---
 lisp/simple.el | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index 5183a7e053..b5f5122153 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -9227,6 +9227,12 @@ completion-show-help
   :version "22.1"
   :group 'completion)
 
+(defcustom completion-auto-select t
+  "Non-nil means to automatically select the completions buffer."
+  :type 'boolean
+  :version "29.1"
+  :group 'completion)
+
 ;; This function goes in completion-setup-hook, so that it is called
 ;; after the text of the completion list buffer is written.
 (defun completion-setup-function ()
@@ -9263,7 +9269,9 @@ completion-setup-function
 	    (insert "Click on a completion to select it.\n"))
 	(insert (substitute-command-keys
 		 "In this buffer, type \\[choose-completion] to \
-select the completion near point.\n\n"))))))
+select the completion near point.\n\n")))))
+  (when completion-auto-select
+    (switch-to-completions)))
 
 (add-hook 'completion-setup-hook #'completion-setup-function)
 
-- 
2.34.0


[-- Attachment #5: Type: text/plain, Size: 438 bytes --]


When exiting the *Completions* buffer, C-g and q seem not to send the
user back to minibuffer.  This introduces friction via uncertainty,
because you don't know where the active point will land, so you have to
manually switch back.  This command adds and binds command that ensure
the minibuffer is always selected once it is closed or unfocused.  I
think this is an absolute improvement, so there is no option to reset
this behaviour.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #6: 0003-Switch-back-to-minibuffer-when-quitting-completion-b.patch --]
[-- Type: text/x-patch, Size: 1822 bytes --]

From 8f2433d70eadef47772b01b71ff44f5010c0935b Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Thu, 9 Dec 2021 17:36:14 +0100
Subject: [PATCH 3/4] Switch back to minibuffer when quitting  completion
 buffer

* lisp/simple.el (completion-quit): Add new command
(completion-kill-buffer): Add new command
(completion-list-mode-map): Bind completion-quit and
rebind kill-current-buffer to completion-kill-buffer
---
 lisp/simple.el | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index b5f5122153..5ca8142548 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8957,6 +8957,18 @@ set-variable
 \f
 ;; Define the major mode for lists of completions.
 
+(defun completion-quit ()
+  "Close the completion buffer and return to the minibuffer."
+  (interactive)
+  (quit-window)
+  (switch-to-minibuffer))
+
+(defun completion-kill-buffer ()
+  "Close the completion buffer and return to the minibuffer."
+  (interactive)
+  (kill-buffer "*Completions*")
+  (switch-to-minibuffer))
+
 (defvar completion-list-mode-map
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map special-mode-map)
@@ -8970,10 +8982,12 @@ completion-list-mode-map
     (define-key map [right] 'next-completion)
     (define-key map [?\t] 'next-completion)
     (define-key map [backtab] 'previous-completion)
-    (define-key map "z" 'kill-current-buffer)
     (define-key map "n" 'next-completion)
     (define-key map "p" 'previous-completion)
     (define-key map "\M-g\M-c" 'switch-to-minibuffer)
+    (define-key map "z" #'completion-kill-buffer)
+    (define-key map [remap keyboard-quit] #'completion-quit)
+    (define-key map [remap quit-window] #'switch-to-minibuffer)
     map)
   "Local map for completion list buffers.")
 
-- 
2.34.0


[-- Attachment #7: Type: text/plain, Size: 409 bytes --]


In the *Completions*, self-insert-command is not bound so that "q", "n",
"p", "z", ... can be used.  This patch would add "s" (for
isearch-forward) and "S" (for isearch-forward-regexp) to the default
bunch.  This is my most recent change, that I am least certain about.
If I played around with it for a bit longer, maybe this could also be
extended to an interactive narrowing along the lines of icomplete.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #8: 0004-Bind-modifier-less-isearch-commands-in-the-completio.patch --]
[-- Type: text/x-patch, Size: 958 bytes --]

From 4f311034fac33698534090c35fb7e662f1cef47a Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Thu, 9 Dec 2021 17:37:44 +0100
Subject: [PATCH 4/4] Bind modifier-less isearch commands in the completion
 buffer

* lisp/simple.el (completion-list-mode-map): Bind isearch-forward and
isearch-forward-regexp
---
 lisp/simple.el | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/lisp/simple.el b/lisp/simple.el
index 5ca8142548..cb2d4cd7f4 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8982,6 +8982,8 @@ completion-list-mode-map
     (define-key map [right] 'next-completion)
     (define-key map [?\t] 'next-completion)
     (define-key map [backtab] 'previous-completion)
+    (define-key map "s" #'isearch-forward)
+    (define-key map "S" #'isearch-forward-regexp)
     (define-key map "n" 'next-completion)
     (define-key map "p" 'previous-completion)
     (define-key map "\M-g\M-c" 'switch-to-minibuffer)
-- 
2.34.0


[-- Attachment #9: Type: text/plain, Size: 453 bytes --]


So, any opinions on these suggestions?  I get the impression that many
people avoid the default completion system because of small
peculiarities such as the ones I describe above.  Protesilaos Stavrou's
recent library MCT (https://gitlab.com/protesilaos/mct) demonstrates
that it doesn't take much to fix these issues, but I think that the
above already does a lot, with a lot less code (mostly because this is
not a package).

-- 
	Philip Kaludercic


             reply	other threads:[~2021-12-09 17:22 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-09 17:22 Philip Kaludercic [this message]
2021-12-09 17:49 ` [External] : Suggestions for improvements to the *Completions* buffer Drew Adams
2021-12-09 18:05   ` Philip Kaludercic
2021-12-09 19:21     ` Stefan Monnier
2021-12-09 18:27 ` Manuel Uberti
2021-12-09 19:49 ` Juri Linkov
2021-12-09 20:07   ` Philip Kaludercic
2021-12-09 20:21     ` Juri Linkov
2021-12-13 19:16       ` Philip Kaludercic
2021-12-09 21:16     ` Stefan Kangas
2021-12-13 19:13       ` Philip Kaludercic
2021-12-13 21:36 ` Philip Kaludercic
2021-12-14 21:13   ` Juri Linkov
2021-12-17 11:27     ` Philip Kaludercic
2021-12-17 15:00       ` Philip Kaludercic
2021-12-18 12:22       ` Philip Kaludercic
2021-12-18 12:31         ` Po Lu
2021-12-18 13:39           ` Philip Kaludercic
2021-12-20  1:13             ` Po Lu
2021-12-18 17:41         ` Juri Linkov
2021-12-19 14:55           ` Philip Kaludercic
2021-12-19 17:18             ` Juri Linkov
2021-12-19 23:58               ` Philip Kaludercic
2021-12-20  9:03                 ` Philip Kaludercic
2021-12-21 19:02                 ` Juri Linkov
2021-12-21 21:32                   ` Philip Kaludercic
2021-12-22  7:54                     ` Daniel Semyonov
2021-12-22  9:04                       ` Juri Linkov
2021-12-22  9:56                         ` Daniel Semyonov
2021-12-22 17:42                           ` Juri Linkov
2021-12-22 12:27                     ` Eli Zaretskii
2021-12-18 17:40       ` Juri Linkov

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=87a6h9g0c0.fsf@posteo.net \
    --to=philipk@posteo.net \
    --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).