]> git.eshelyaron.com Git - emacs.git/commitdiff
Prettify and improve hideshow (bug#78234)
authorElías Gabriel Pérez <eg642616@gmail.com>
Sat, 3 May 2025 04:44:07 +0000 (22:44 -0600)
committerEshel Yaron <me@eshelyaron.com>
Wed, 21 May 2025 06:05:54 +0000 (08:05 +0200)
Buttonize the ellipsis and optionally display in the ellipsis
the total number of hidden lines.
* lisp/progmodes/hideshow.el (hs-display-lines-hidden): New
user option.
(hs-ellipsis): New face.
(hs-make-overlay): Tweak.
(hs--get-ellipsis): New function.
* doc/emacs/programs.texi (Hideshow): Update documentation.
* etc/NEWS: Announce changes.

(cherry picked from commit 8b6e1d8435712a1d312244f9fe3a43d8b346f49a)

doc/emacs/programs.texi
lisp/progmodes/hideshow.el

index 4168519da8d5613a3373282b37bf38d088903868..c62b6c252c60df47ec1ab58536ca4b385a5566cc 100644 (file)
@@ -1631,6 +1631,7 @@ Hide all blocks @var{n} levels below this block
 @end table
 
 @vindex hs-hide-comments-when-hiding-all
+@vindex hs-display-lines-hidden
 @vindex hs-isearch-open
 @vindex hs-special-modes-alist
   These variables can be used to customize Hideshow mode:
@@ -1640,6 +1641,10 @@ Hide all blocks @var{n} levels below this block
 If non-@code{nil}, @kbd{C-c @@ C-M-h} (@code{hs-hide-all}) hides
 comments too.
 
+@item hs-display-lines-hidden
+If non-@code{nil}, display the number of hidden lines next to the
+ellipsis.
+
 @item hs-isearch-open
 This variable specifies the conditions under which incremental search
 should unhide a hidden block when matching text occurs within the
index c1d62fb92ab76eb6ad23004ee1b9dfb0f6367a1c..e7987cab5fbaa81c7c48900312e6858a9792533b 100644 (file)
   :prefix "hs-"
   :group 'languages)
 
+(defface hs-ellipsis
+  '((t :height 0.80 :box (:line-width -1) :inherit default))
+  "Face used for hideshow ellipsis.
+Note: If `selective-display' ellipsis already has a face, hideshow will
+use that face for the ellipsis instead."
+  :version "31.1")
+
 (defcustom hs-hide-comments-when-hiding-all t
   "Hide the comments too when you do an `hs-hide-all'."
   :type 'boolean)
 
+(defcustom hs-display-lines-hidden nil
+  "If non-nil, display the number of hidden lines next to the ellipsis."
+  :type 'boolean
+  :version "31.1")
+
 (defcustom hs-minor-mode-hook nil
   "Hook called when hideshow minor mode is activated or deactivated."
   :type 'hook
@@ -528,8 +540,17 @@ to call with the newly initialized overlay."
         (io (if (eq 'block hs-isearch-open)
                 ;; backward compatibility -- `block'<=>`code'
                 'code
-              hs-isearch-open)))
+              hs-isearch-open))
+        (map (make-sparse-keymap)))
     (overlay-put ov 'invisible 'hs)
+    (define-key map (kbd "<mouse-1>") #'hs-show-block)
+    (overlay-put ov 'display
+                 (propertize
+                  (hs--get-ellipsis b e)
+                  'mouse-face
+                  'highlight
+                  'help-echo "mouse-1: show hidden lines"
+                  'keymap map))
     (overlay-put ov 'hs kind)
     (overlay-put ov 'hs-b-offset b-offset)
     (overlay-put ov 'hs-e-offset e-offset)
@@ -540,6 +561,48 @@ to call with the newly initialized overlay."
     (when hs-set-up-overlay (funcall hs-set-up-overlay ov))
     ov))
 
+(defun hs--get-ellipsis (b e)
+  "Helper function for `hs-make-overlay'.
+This return the ellipsis string to use and its face."
+  (cond*
+   ((bind*
+     (d-t-ellipsis (display-table-slot standard-display-table 'selective-display))
+     (d-t-face ; Get only the first glyph face
+      (if d-t-ellipsis (glyph-face (aref d-t-ellipsis 0))))
+     ;; Convert the ellipsis vector from display-table to a propertized
+     ;; string
+     (ellipsis
+      (cond
+       ((and d-t-ellipsis
+             (not (stringp d-t-ellipsis))
+             ;; Ensure the vector is not empty
+             (not (length= d-t-ellipsis 0)))
+        (let ((string
+               (mapconcat
+                (lambda (g)
+                  (apply #'propertize
+                         (char-to-string (glyph-char g))
+                         (if (glyph-face g)
+                             (list 'face (glyph-face g)))))
+                d-t-ellipsis)))
+          ;; If the ellipsis string has no face, use `hs-ellipsis'
+          (if (get-text-property 0 'face string)
+              string
+            (propertize string 'face 'hs-ellipsis))))
+       ((char-displayable-on-frame-p ?…)
+        (propertize "…" 'face 'hs-ellipsis))
+       (t (propertize "..." 'face 'hs-ellipsis))))))
+   (hs-display-lines-hidden
+    (let ((lines (1- (count-lines b e))))
+      (concat
+       (propertize
+        (concat (number-to-string lines)
+                (if (= lines 1) " line" " lines"))
+        'face (or d-t-face 'hs-ellipsis))
+       ellipsis)))
+   (t
+    ellipsis)))
+
 (defun hs-isearch-show (ov)
   "Delete overlay OV, and set `hs-headline' to nil.