unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Philip Kaludercic <philipk@posteo.net>
To: Stefan Kangas <stefankangas@gmail.com>
Cc: Lars Ingebrigtsen <larsi@gnus.org>,  emacs-devel@gnu.org
Subject: Re: Adding a "quick-help" menu
Date: Thu, 13 Oct 2022 14:30:55 +0000	[thread overview]
Message-ID: <87czav3ie8.fsf@posteo.net> (raw)
In-Reply-To: <87fsgnfzb2.fsf@posteo.net> (Philip Kaludercic's message of "Mon,  19 Sep 2022 12:12:17 +0200")

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


(Sorry for the delay, I got distracted)

Philip Kaludercic <philipk@posteo.net> writes:

> Stefan Kangas <stefankangas@gmail.com> writes:
>
>> Philip Kaludercic <philipk@posteo.net> writes:
>>
>>> Lars Ingebrigtsen <larsi@gnus.org> writes:
>>>
>>>> Philip Kaludercic <philipk@posteo.net> writes:
>>>>
>>>>> There is a fork of mg (MicroEmacs)[0] that binds C-h q to a command that
>>>>> pops up a buffer with these contents:
>>>>
>>>> I think having a "cheat sheet" like this would be useful.
>>>
>>> Calling it a "cheat sheet" sounds like a good idea.  I've added
>>> `cheat-sheet' as an alias:
>>
>> Thanks, this looks great.  Some comments after testing it:
>>
>> - I think we should use `help-for-help-header' for the headlines, not
>>   capitalize them, and align them with :align-to.
>
> That can be done.

This has turned out to be more complicated than I had initially assumed,
because way the menu is constructed inserting special properties isn't
that easy.  Do you think that this would be a hard requirement.

>> - Should it be modal, like `C-h C-h'?
>>
>> - If not, I think it would be nice if you could remove it by typing "q"
>>   again.
>>
>>   Perhaps point should be moved to the new buffer by default?  (But then
>>   again, it doesn't do that with "*Help*" by default, sadly.)  So maybe
>>   a repeat-map is appropriate?  Just some ideas.
>
> That depends on how this is to be used.  Is this something a new user
> would use to quickly peek if they don't know how to do something, or
> should it serve as a permanent "cheat sheet" at the bottom of the screen
> (sort of like Nano).

I really think that this should be a persistent menu, so closing the
menu with "q" seems like the wrong thing.  Again, this is not a
which-key alternative, the target audience are people who are struggling
to remember how to open a file or kill a line.

>> - The keys should be linked to the corresponding command docstrings.
>
> This can also be done.

Has been added in the patch below.

>> - Wishlist: It would be great if it had an optional vertical view,
>>   perhaps that you could toggle with both a command and defcustom.
>>   Perhaps the vertical view could even be the default if the window
>>   width is too narrow to fit it all?
>
> I was just thinking about this too.  I implemented this vertically,
> which is more complicated, because that is what the mg fork did too, but
> mg has no horizontal splits, so it had no choice.

I haven't implemented this yet, because I am uncertain if it is worth
the additional complexity.

>> Also, some nits:
>>
>> - "other" should be "other win." or "other window".
>>
>> - "rev. search" should be "search backwards".
>>
>> - "replace" could be "search & replace" or "search&replace"
>
> We can try this, my only concern is that this might use too much
> horizontal space.

Also did this, it seems to be fine.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-a-quick-help-menu.patch --]
[-- Type: text/x-patch, Size: 6388 bytes --]

From aa5e4b0e6f4aa60fed9c5b1dde3c590fc9a62e61 Mon Sep 17 00:00:00 2001
From: Philip Kaludercic <philipk@posteo.net>
Date: Sat, 17 Sep 2022 16:52:01 +0200
Subject: [PATCH] Add a quick-help menu

* lisp/help.el (help-map): Bind 'help-quit-or-quick' instead of 'help-quit'.
(help-quick-sections): Add variable.
(help-quick): Add main command.
(cheat-sheet): Add alias for 'help-quick'.
(help-quit-or-quick): Add auxiliary command.
---
 lisp/help.el | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 133 insertions(+), 1 deletion(-)

diff --git a/lisp/help.el b/lisp/help.el
index b4b9120da3..1d960cf269 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -112,7 +112,7 @@ help-map
     (define-key map "v" 'describe-variable)
     (define-key map "w" 'where-is)
     (define-key map "x" 'describe-command)
-    (define-key map "q" 'help-quit)
+    (define-key map "q" 'help-quit-or-quick)
     map)
   "Keymap for characters following the Help key.")
 
@@ -125,11 +125,143 @@ global-map
 (defvar help-button-cache nil)
 
 \f
+
+(defvar help-quick-sections
+  '(("File"
+     (save-buffers-kill-terminal . "exit")
+     (find-file . "find")
+     (write-file . "write")
+     (save-buffer . "save")
+     (save-some-buffers . "all"))
+    ("Buffer"
+     (kill-buffer . "kill")
+     (list-buffers . "list")
+     (switch-to-buffer . "switch")
+     (goto-line . "goto line")
+     (read-only-mode . "read only"))
+    ("Window"
+     (delete-window . "only other")
+     (delete-other-windows . "only this")
+     (split-window-below . "split vert.")
+     (split-window-right . "split horiz.")
+     (other-window . "other window"))
+    ("Mark & Kill"
+     (set-mark-command . "mark")
+     (kill-line . "kill line")
+     (kill-ring-save . "kill region")
+     (yank . "yank")
+     (exchange-point-and-mark . "swap"))
+    ("Projects"
+     (project-switch-project . "switch")
+     (project-find-file . "find file")
+     (project-find-regexp . "search")
+     (project-query-replace-regexp . "search & replace")
+     (project-compile . "compile"))
+    ("Misc."
+     (undo . "undo")
+     (isearch-forward . "search")
+     (isearch-backward . "reverse search")
+     (query-replace . "search & replace")
+     (fill-paragraph . "reformat"))))
+
+(declare-function prop-match-value "text-property-search" (match))
+
+;; Inspired by a mg fork (https://github.com/troglobit/mg)
+(defun help-quick ()
+  "Display a quick-help buffer."
+  (interactive)
+  (with-current-buffer (get-buffer-create "*Quick Help*")
+    (let ((inhibit-read-only t) (padding 2) blocks)
+
+      ;; Go through every section and prepare a text-rectangle to be
+      ;; inserted later.
+      (dolist (section help-quick-sections)
+        (let ((max-key-len 0) (max-cmd-len 0) keys)
+          (dolist (ent (reverse (cdr section)))
+            (catch 'skip
+              (let* ((bind (where-is-internal (car ent) nil t))
+                     (key (if bind
+                              (propertize
+                               (key-description bind)
+                               'face 'help-key-binding)
+                            (throw 'skip nil))))
+                (setq max-cmd-len (max (length (cdr ent)) max-cmd-len)
+                      max-key-len (max (length key) max-key-len))
+                (push (list key (cdr ent) (car ent)) keys))))
+          (when keys
+            (let ((fmt (format "%%-%ds %%-%ds%s" max-key-len max-cmd-len
+                               (make-string padding ?\s)))
+                  (width (+ max-key-len 1 max-cmd-len padding)))
+              (push `(,width
+                      ,(propertize
+                        (concat
+                         (car section)
+                         (make-string (- width (length (car section))) ?\s))
+                        'face 'bold)
+                      ,@(mapcar (lambda (ent)
+                                  (format fmt
+                                          (propertize
+                                           (car ent)
+                                           'quick-help-cmd
+                                           (caddr ent))
+                                          (cadr ent)))
+                                keys))
+                    blocks)))))
+
+      ;; Insert each rectangle in order until they don't fit into the
+      ;; frame any more, in which case the next sections are inserted
+      ;; in a new "line".
+      (erase-buffer)
+      (dolist (block (nreverse blocks))
+        (when (> (+ (car block) (current-column)) (frame-width))
+          (goto-char (point-max))
+          (newline 2))
+        (save-excursion
+          (insert-rectangle (cdr block)))
+        (end-of-line))
+      (delete-trailing-whitespace)
+
+      (save-excursion
+        (goto-char (point-min))
+        (while-let ((match (text-property-search-forward 'quick-help-cmd)))
+          (make-text-button (prop-match-beginning match)
+                            (prop-match-end match)
+                            'mouse-face 'highlight
+                            'button t
+                            'keymap button-map
+                            'action #'describe-symbol
+                            'button-data (prop-match-value match)))))
+
+    (help-mode)
+
+    ;; Display the buffer at the bottom of the frame...
+    (with-selected-window (display-buffer-at-bottom (current-buffer) '())
+      ;; ... mark it as dedicated to prevent focus from being stolen
+      (set-window-dedicated-p (selected-window) t)
+      ;; ... and shrink it immediately.
+      (fit-window-to-buffer))
+    (message
+     (substitute-command-keys "Toggle the quick help buffer using \\[help-quit-or-quick]."))))
+
+(defalias 'cheat-sheet #'help-quick)
+
 (defun help-quit ()
   "Just exit from the Help command's command loop."
   (interactive)
   nil)
 
+(defun help-quit-or-quick ()
+  "Call `help-quit' or  `help-quick' depending on the context."
+  (interactive)
+  (cond
+   (help-buffer-under-preparation
+    ;; FIXME: There should be a better way to detect if we are in the
+    ;;        help command loop.
+    (help-quit))
+   ((and-let* ((window (get-buffer-window "*Quick Help*")))
+      (quit-window t window)))
+   ((help-quick))))
+
 (defvar help-return-method nil
   "What to do to \"exit\" the help buffer.
 This is a list
-- 
2.37.3


  reply	other threads:[~2022-10-13 14:30 UTC|newest]

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-16 15:43 Adding a "quick-help" menu Philip Kaludercic
2022-09-16 16:11 ` Sean Whitton
2022-09-16 16:24 ` Stefan Kangas
2022-09-16 16:48   ` Philip Kaludercic
2022-09-16 17:03     ` Sławomir Grochowski
2022-09-16 17:22       ` Philip Kaludercic
2022-09-17 12:09         ` Gregor Zattler
2022-09-17 14:44           ` Philip Kaludercic
2022-09-17 17:48             ` Stefan Kangas
2022-09-17 21:45               ` Philip Kaludercic
2022-09-18  0:05                 ` Stefan Kangas
2022-09-18  5:41                   ` Eli Zaretskii
2022-09-18  9:10                   ` Philip Kaludercic
2022-09-18  5:07             ` Visuwesh
2022-09-18  7:51             ` Gregor Zattler
2022-09-17 14:53           ` which-key (was: Adding a "quick-help" menu) Stefan Monnier
2022-09-18  5:12             ` which-key Visuwesh
2022-09-18  8:56               ` which-key Gregory Heytings
2022-09-18  8:58             ` which-key (was: Adding a "quick-help" menu) Gregory Heytings
2022-09-18  9:19               ` which-key Po Lu
2022-09-18  9:53                 ` which-key Gregory Heytings
2022-09-18 10:10                   ` which-key Lars Ingebrigtsen
2022-09-18 13:51                     ` which-key Stefan Monnier
2022-09-18 15:39                       ` which-key Stefan Kangas
2022-09-18 16:43                         ` which-key Gregor Zattler
2022-09-18 16:49                       ` which-key Gregory Heytings
2022-09-19  8:08                         ` which-key Lars Ingebrigtsen
2022-09-19  8:19                           ` which-key Gregory Heytings
2022-09-19 13:26                             ` which-key Corwin Brust
2022-09-19 23:43                               ` which-key Emanuel Berg
2022-09-19  8:06                       ` which-key Lars Ingebrigtsen
2022-09-19  9:08                         ` which-key Stefan Kangas
2022-09-18 11:09                   ` which-key Po Lu
2022-09-17 16:47           ` [External] : Re: Adding a "quick-help" menu Drew Adams
2022-09-16 17:11     ` Stefan Kangas
2022-09-16 17:29       ` Philip Kaludercic
2022-09-16 17:38         ` [External] : " Drew Adams
2022-09-16 17:36       ` Drew Adams
2022-09-16 18:00       ` Stefan Monnier
2022-09-17  1:56       ` Po Lu
2022-09-16 21:03 ` Philip Kaludercic
2022-09-17 14:53   ` Philip Kaludercic
2022-09-17  1:54 ` Po Lu
2022-09-17  2:51   ` Stefan Kangas
2022-09-17  3:28     ` Stefan Monnier
2022-09-17  4:01       ` Visuwesh
2022-09-17  4:50       ` Po Lu
2022-09-17  4:48     ` Po Lu
2022-09-17  6:38       ` Stefan Kangas
2022-09-17  8:24         ` Po Lu
2022-09-17  8:49   ` Philip Kaludercic
2022-09-17 16:45     ` [External] : " Drew Adams
2022-09-17 17:36       ` Philip Kaludercic
2022-09-18 10:11 ` Lars Ingebrigtsen
2022-09-18 10:53   ` Philip Kaludercic
2022-09-18 17:03     ` Bob Rogers
2022-09-18 17:53       ` Philip Kaludercic
2022-09-18 19:25         ` Bob Rogers
2022-09-18 20:38         ` wilnerthomas--- via Emacs development discussions.
2022-09-18 21:21           ` Philip Kaludercic
2022-09-18 22:45             ` Christopher Dimech
2022-09-18 23:00               ` Philip Kaludercic
2022-09-19  1:40                 ` Christopher Dimech
2022-09-19  7:54     ` Lars Ingebrigtsen
2022-09-19  8:26       ` Po Lu
2022-09-19  9:08         ` Stefan Kangas
2022-09-19  9:08     ` Stefan Kangas
2022-09-19 10:12       ` Philip Kaludercic
2022-10-13 14:30         ` Philip Kaludercic [this message]
2022-10-13 19:09           ` Lars Ingebrigtsen
2022-10-13 20:21             ` Philip Kaludercic
2022-10-14 11:03               ` Lars Ingebrigtsen
2022-10-14  7:30             ` Philip Kaludercic
2022-10-14 11:08               ` Lars Ingebrigtsen
2022-10-14 18:10                 ` Philip Kaludercic
2022-10-16  0:29             ` Howard Melman
2022-10-16 16:01               ` Philip Kaludercic
2022-10-16 16:13                 ` Howard Melman
2022-10-16 22:44                   ` Philip Kaludercic
2022-10-17  1:00                     ` Howard Melman
2022-10-17  1:00                     ` [External] : " Drew Adams
2022-10-17  6:17                     ` Eli Zaretskii
2022-10-17  6:29                       ` Philip Kaludercic
2022-10-17  7:00                         ` Eli Zaretskii
2022-10-17  7:12                         ` Stefan Kangas
2022-10-17 15:32                           ` Howard Melman
2022-10-17  5:10         ` Stefan Kangas
2022-10-17  6:31           ` Philip Kaludercic
2022-10-20  5:58             ` Protesilaos Stavrou
2022-10-20  6:37               ` Eli Zaretskii
2022-10-20 11:27                 ` Philip Kaludercic
2022-10-20 12:51                   ` Eli Zaretskii
2022-10-20 16:37                     ` Philip Kaludercic
2022-10-20 16:39                       ` Eli Zaretskii
2022-09-19 15:21     ` Howard Melman

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=87czav3ie8.fsf@posteo.net \
    --to=philipk@posteo.net \
    --cc=emacs-devel@gnu.org \
    --cc=larsi@gnus.org \
    --cc=stefankangas@gmail.com \
    /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).