From: Lars Ingebrigtsen Date: Sun, 31 Oct 2021 22:13:52 +0000 (+0100) Subject: Add buttons to outlining and tweak `C-h b' buffer X-Git-Tag: emacs-29.0.90~3671^2~321 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=57030b90d54af1a47508fca032da2634b8c26f4c;p=emacs.git Add buttons to outlining and tweak `C-h b' buffer * lisp/help.el (describe-bindings-outline): Change default to t. (describe-bindings): Tweak the look and remove the explanation. * lisp/outline.el (outline-minor-mode-use-buttons): (outline-minor-mode-buttons): New user options. (outline-hide-subtree): Update buttons. (outline--make-button, outline--make-button-overlay) (outline--insert-open-button, outline--insert-close-button) (outline--fix-up-all-buttons): New functions. --- diff --git a/doc/emacs/text.texi b/doc/emacs/text.texi index dc8ca903b72..53291332d36 100644 --- a/doc/emacs/text.texi +++ b/doc/emacs/text.texi @@ -996,6 +996,13 @@ specific file (@pxref{File Variables}). major mode's special commands. (The variable @code{outline-minor-mode-prefix} controls the prefix used.) +@vindex outline-minor-mode-use-buttons + If @code{outline-minor-mode-use-buttons} is non-@code{nil}, Outline +minor mode will use buttons (at the start of the header lines) in +addition to ellipsis to show that a section is hidden. Using +@kbd{RET} (or clicking on the button with a mouse) will toggle +displaying the section. + @vindex outline-minor-mode-cycle If the @code{outline-minor-mode-cycle} user option is non-@code{nil}, the @kbd{TAB} and @kbd{S-TAB} keys are enabled on the diff --git a/etc/NEWS b/etc/NEWS index e7360d267dc..57c64f7cadb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -48,6 +48,10 @@ time. ** Help +--- +*** 'C-h b' uses outlining by default. +Set 'describe-bindings-outline' to nil to get the old behaviour. + --- *** Jumping to function/variable source now saves mark before moving point. Jumping to source from "*Help*" buffer moves the point when the source @@ -57,6 +61,17 @@ buffer is already open. Now, the old point is pushed to mark ring. *** New key bindings in *Help* buffers: 'n' and 'p'. These will take you (respectively) to the next and previous "page". +** Outline Minor Mode + ++++ +*** New user option 'outline-minor-mode-use-buttons'. +If non-nil, Outline Minor Mode will use buttons to hide/show outlines +in addition to the ellipsis. + +--- +*** New user option 'outline-minor-mode-buttons'. +This is a list of pairs of open/close strings used to display buttons. + ** Fonts --- diff --git a/lisp/help.el b/lisp/help.el index deeb892280f..af68c5717b0 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -561,11 +561,11 @@ To record all your input, use `open-dribble-file'." 'font-lock-face 'help-key-binding 'face 'help-key-binding)) -(defcustom describe-bindings-outline nil +(defcustom describe-bindings-outline t "Non-nil enables outlines in the output buffer of `describe-bindings'." :type 'boolean :group 'help - :version "28.1") + :version "29.1") (defun describe-bindings (&optional prefix buffer) "Display a buffer showing a list of all defined keys, and their definitions. @@ -592,18 +592,19 @@ or a buffer name." (setq-local outline-level (lambda () 1)) (setq-local outline-minor-mode-cycle t outline-minor-mode-highlight t) + (setq-local outline-minor-mode-use-buttons t) (outline-minor-mode 1) (save-excursion + (goto-char (point-min)) (let ((inhibit-read-only t)) - (goto-char (point-min)) - (insert (substitute-command-keys - (concat "\\Type " - "\\[outline-cycle] or \\[outline-cycle-buffer] " - "on headings to cycle their visibility.\n\n"))) ;; Hide the longest body (when (and (re-search-forward "Key translations" nil t) (fboundp 'outline-cycle)) - (outline-cycle)))))))) + (outline-cycle)) + ;; Hide ^Ls. + (while (search-forward "\n\f\n" nil t) + (put-text-property (1+ (match-beginning 0)) (1- (match-end 0)) + 'invisible t)))))))) (defun where-is (definition &optional insert) "Print message listing key sequences that invoke the command DEFINITION. diff --git a/lisp/outline.el b/lisp/outline.el index 52a94b4d9f4..a7f54364f05 100644 --- a/lisp/outline.el +++ b/lisp/outline.el @@ -272,6 +272,21 @@ in the file it applies to.") (defvar outline-font-lock-faces [outline-1 outline-2 outline-3 outline-4 outline-5 outline-6 outline-7 outline-8]) + +(defcustom outline-minor-mode-use-buttons nil + "If non-nil, use clickable buttons on the headings. +The `outline-minor-mode-buttons' variable specifies how the +buttons should look." + :type 'boolean + :version "29.1") + +(defcustom outline-minor-mode-buttons + '(("▶️". "🔽") + ("▶" . "▼")) + "List of close/open pairs to use if using buttons." + :type 'sexp + :version "29.1") + (defvar outline-level #'outline-level "Function of no args to compute a header's nesting level in an outline. @@ -388,6 +403,8 @@ faces to major mode's faces." (goto-char (match-beginning 0)) (not (get-text-property (point) 'face)))) (overlay-put overlay 'face (outline-font-lock-face))) + (when outline-minor-mode-use-buttons + (outline--insert-open-button)) (when outline-minor-mode-cycle (overlay-put overlay 'keymap outline-minor-mode-cycle-map))) (goto-char (match-end 0)))))) @@ -923,11 +940,64 @@ Note that this does not hide the lines preceding the first heading line." (define-obsolete-function-alias 'show-all #'outline-show-all "25.1") -(defun outline-hide-subtree () - "Hide everything after this heading at deeper levels." - (interactive) +(defun outline-hide-subtree (&optional event) + "Hide everything after this heading at deeper levels. +If non-nil, EVENT should be a mouse event." + (interactive (list last-nonmenu-event)) + (mouse-set-point event) + (when (and outline-minor-mode-use-buttons outline-minor-mode) + (outline--insert-close-button)) (outline-flag-subtree t)) +(defun outline--make-button (type) + (cl-loop for (close . open) in outline-minor-mode-buttons + when (and (char-displayable-p (aref close 0)) + (char-displayable-p (aref open 0))) + return (concat (if (eq type 'close) + close + open) + " " (buffer-substring (point) (1+ (point)))))) + +(defun outline--make-button-overlay (type) + (let ((o (seq-find (lambda (o) + (overlay-get o 'outline-button)) + (overlays-at (point))))) + (unless o + (setq o (make-overlay (point) (1+ (point)))) + (overlay-put o 'outline-button t)) + (overlay-put o 'display (outline--make-button type)) + o)) + +(defun outline--insert-open-button () + (save-excursion + (beginning-of-line) + (let ((o (outline--make-button-overlay 'open))) + (overlay-put o 'help-echo "Click to hide") + (overlay-put o 'keymap + (define-keymap + ["RET"] #'outline-hide-subtree + [""] 'mouse-face + [""] #'outline-hide-subtree))))) + +(defun outline--insert-close-button () + (save-excursion + (beginning-of-line) + (let ((o (outline--make-button-overlay 'close))) + (overlay-put o 'help-echo "Click to show") + (overlay-put o 'keymap + (define-keymap + ["RET"] #'outline-show-subtree + [""] 'mouse-face + [""] #'outline-show-subtree))))) + +(defun outline--fix-up-all-buttons () + (outline-map-region + (lambda () + (if (eq (outline--cycle-state) 'show-all) + (outline--insert-open-button) + (outline--insert-close-button))) + (point-min) (point-max))) + (define-obsolete-function-alias 'hide-subtree #'outline-hide-subtree "25.1") (defun outline-hide-leaves () @@ -943,9 +1013,12 @@ Note that this does not hide the lines preceding the first heading line." (define-obsolete-function-alias 'hide-leaves #'outline-hide-leaves "25.1") -(defun outline-show-subtree () +(defun outline-show-subtree (&optional event) "Show everything after this heading at deeper levels." - (interactive) + (interactive (list last-nonmenu-event)) + (mouse-set-point event) + (when (and outline-minor-mode-use-buttons outline-minor-mode) + (outline--insert-open-button)) (outline-flag-subtree nil)) (define-obsolete-function-alias 'show-subtree #'outline-show-subtree "25.1") @@ -1295,7 +1368,9 @@ Return either 'hide-all, 'headings-only, or 'show-all." (t (outline-show-all) (setq outline--cycle-buffer-state 'show-all) - (message "Show all"))))) + (message "Show all"))) + (when outline-minor-mode-use-buttons + (outline--fix-up-all-buttons)))) (defvar outline-navigation-repeat-map (let ((map (make-sparse-keymap)))