aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElías Gabriel Pérez2025-12-12 15:45:09 -0600
committerJuri Linkov2025-12-20 20:09:41 +0200
commite93a9a905799b2e1e371fe6292a003e6f5480e95 (patch)
treeed9e5a64422f7e431605ddd0023d6771dc0d6abc
parentc989d096f19d875a9a96ba56bfc479af4b14f700 (diff)
downloademacs-e93a9a905799b2e1e371fe6292a003e6f5480e95.tar.gz
emacs-e93a9a905799b2e1e371fe6292a003e6f5480e95.zip
hideshow: Support nested comment block in 'hs-hide-level-recursive'
bug#80009 * doc/emacs/programs.texi (Hideshow): Update documentation. * lisp/progmodes/hideshow.el (hs-hide-level-recursive): Rework. (hs-get-first-block-on-line): Minor changes. (hs--add-indicators, hs-hide-comments-when-hiding-all) (hs-minor-mode-menu, hs-hide-level, hs-cycle): Update code. * test/lisp/progmodes/hideshow-tests.el (hideshow-hide-levels-with-comments-1): New test.
-rw-r--r--doc/emacs/programs.texi4
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/progmodes/hideshow.el75
-rw-r--r--test/lisp/progmodes/hideshow-tests.el49
4 files changed, 98 insertions, 35 deletions
diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index 6acd04d0bae..1e487120272 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -1747,8 +1747,8 @@ Either hide or show all the blocks in the current buffer. (@code{hs-toggle-all})
1747 1747
1748@table @code 1748@table @code
1749@item hs-hide-comments-when-hiding-all 1749@item hs-hide-comments-when-hiding-all
1750If non-@code{nil}, @kbd{C-c @@ C-M-h} (@code{hs-hide-all}) hides 1750If non-@code{nil}, @code{hs-hide-all}, @code{hs-cycle} and
1751comments too. 1751@code{hs-hide-level} hide comments too.
1752 1752
1753@item hs-hide-block-behavior 1753@item hs-hide-block-behavior
1754This variable controls how @code{hs-hide-block} and 1754This variable controls how @code{hs-hide-block} and
diff --git a/etc/NEWS b/etc/NEWS
index e3ea4557355..7e8dbf44b9f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1169,6 +1169,11 @@ FORWARD-SEXP-FUNC, etc., major mode authors should set the corresponding
1169buffer-local variables 'hs-block-start-regexp', 'hs-c-start-regexp', 1169buffer-local variables 'hs-block-start-regexp', 'hs-c-start-regexp',
1170'hs-forward-sexp-function', etc. 1170'hs-forward-sexp-function', etc.
1171 1171
1172+++
1173*** 'hs-hide-level' and 'hs-cycle' can now hide comments too.
1174This is controlled by 'hs-hide-comments-when-hiding-all'.
1175
1176
1172** C-ts mode 1177** C-ts mode
1173 1178
1174+++ 1179+++
diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el
index 41e804ae3d0..688f2e7cdff 100644
--- a/lisp/progmodes/hideshow.el
+++ b/lisp/progmodes/hideshow.el
@@ -83,7 +83,8 @@
83;; Hideshow provides the following user options: 83;; Hideshow provides the following user options:
84;; 84;;
85;; - `hs-hide-comments-when-hiding-all' 85;; - `hs-hide-comments-when-hiding-all'
86;; self-explanatory! 86;; If non-nil, `hs-hide-all', `hs-cycle' and `hs-hide-level' will hide
87;; comments too.
87;; - `hs-hide-all-non-comment-function' 88;; - `hs-hide-all-non-comment-function'
88;; If non-nil, after calling `hs-hide-all', this function is called 89;; If non-nil, after calling `hs-hide-all', this function is called
89;; with no arguments. 90;; with no arguments.
@@ -322,7 +323,9 @@ a block), `hs-show-all' and `hs-show-block'."
322 :version "31.1") 323 :version "31.1")
323 324
324(defcustom hs-hide-comments-when-hiding-all t 325(defcustom hs-hide-comments-when-hiding-all t
325 "Hide the comments too when you do an `hs-hide-all'." 326 "Whether the comments should be hidden.
327If non-nil, `hs-hide-all', `hs-cycle' and `hs-hide-level' will hide
328comments too."
326 :type 'boolean) 329 :type 'boolean)
327 330
328(defcustom hs-hide-block-behavior 'after-bol 331(defcustom hs-hide-block-behavior 'after-bol
@@ -560,7 +563,8 @@ This is only used if `hs-indicator-type' is set to `margin' or nil."
560 ["Hide comments when hiding all" 563 ["Hide comments when hiding all"
561 (setq hs-hide-comments-when-hiding-all 564 (setq hs-hide-comments-when-hiding-all
562 (not hs-hide-comments-when-hiding-all)) 565 (not hs-hide-comments-when-hiding-all))
563 :help "If t also hide comment blocks when doing `hs-hide-all'" 566 :help "\
567If t also hide comment blocks when doing `hs-hide-all', `hs-cycle' or `hs-hide-level'"
564 :style toggle :selected hs-hide-comments-when-hiding-all] 568 :style toggle :selected hs-hide-comments-when-hiding-all]
565 ("Reveal on isearch" 569 ("Reveal on isearch"
566 ["Code blocks" (setq hs-isearch-open 'code) 570 ["Code blocks" (setq hs-isearch-open 'code)
@@ -693,12 +697,13 @@ to find the beginning of the current block.")
693 "Function used to do `hs-find-next-block'. 697 "Function used to do `hs-find-next-block'.
694It should reposition point at next block start. 698It should reposition point at next block start.
695 699
696It is called with three arguments REGEXP, BOUND, and COMMENTS. 700It is called with three arguments REGEXP, BOUND, and COMMENTS. REGEXP
697REGEXP is a regexp representing block start. When block start is found, 701is a regexp representing block start. When block start is found,
698`match-data' should be set using REGEXP. BOUND is a buffer position 702`match-data' should be set using REGEXP. BOUND is a buffer position
699that limits the search. When COMMENTS is non-nil, REGEXP matches not 703that limits the search. When COMMENTS is non-nil, REGEXP matches not
700only beginning of a block but also beginning of a comment. In this 704only beginning of a block but also beginning of a comment. In this
701case, the function should find nearest block or comment. 705case, the function should find nearest block or comment and return
706non-nil.
702 707
703Specifying this function is necessary for languages such as Python, 708Specifying this function is necessary for languages such as Python,
704where regexp search is not enough to find the beginning of the next 709where regexp search is not enough to find the beginning of the next
@@ -871,7 +876,8 @@ line and returns the start position of the first block found.
871Otherwise, if no block is found, it returns nil. 876Otherwise, if no block is found, it returns nil.
872 877
873If INCLUDE-COMMENTS is non-nil, also search for a comment block." 878If INCLUDE-COMMENTS is non-nil, also search for a comment block."
874 (let ((regexp (if include-comments 879 (let ((bk-point (point))
880 (regexp (if include-comments
875 (concat "\\(" hs-block-start-regexp "\\)" 881 (concat "\\(" hs-block-start-regexp "\\)"
876 "\\|\\(" hs-c-start-regexp "\\)") 882 "\\|\\(" hs-c-start-regexp "\\)")
877 hs-block-start-regexp)) 883 hs-block-start-regexp))
@@ -887,6 +893,7 @@ If INCLUDE-COMMENTS is non-nil, also search for a comment block."
887 (if (and beg (hs-hideable-region-p beg end)) 893 (if (and beg (hs-hideable-region-p beg end))
888 (setq exit (point)) 894 (setq exit (point))
889 t))))) 895 t)))))
896 (unless exit (goto-char bk-point))
890 exit)) 897 exit))
891 898
892(defun hs-get-near-block (&optional include-comment) 899(defun hs-get-near-block (&optional include-comment)
@@ -929,21 +936,21 @@ commands."
929 (goto-char beg) 936 (goto-char beg)
930 (while (not (>= (point) end)) 937 (while (not (>= (point) end))
931 (when-let* ((_ (not (invisible-p (point)))) ; Skip invisible lines 938 (when-let* ((_ (not (invisible-p (point)))) ; Skip invisible lines
932 (block (save-excursion 939 (b-start (hs-get-first-block-on-line include-comments)))
933 (hs-get-first-block-on-line include-comments)))) 940 (goto-char b-start)
934 (goto-char (match-beginning 0)) 941 (let ((comment (and include-comments (funcall hs-inside-comment-predicate)))
935 (if (> arg 1) 942 (code (hs-block-positions)))
936 ;; Find a block recursively according to ARG. 943 ;; Find a block recursively according to ARG.
937 (pcase-let ((`(,beg ,end) (or (and include-comments 944 (if (> arg 1)
938 (funcall hs-inside-comment-predicate)) 945 ;; Nested comment blocks in a comment block are impossible,
939 (hs-block-positions)))) 946 ;; so skip them.
940 (hs-hide-level-recursive (1- arg) beg end include-comments)) 947 (if comment
941 ;; Now hide the block we found. 948 (goto-char (cadr comment))
942 (if func (funcall func) 949 (pcase-let ((`(,beg ,end) code))
943 (hs-hide-block-at-point 950 (hs-hide-level-recursive (1- arg) beg end include-comments)))
944 (and include-comments (funcall hs-inside-comment-predicate)))) 951 ;; Now hide the block we found.
945 (when progress 952 (if func (funcall func) (hs-hide-block-at-point comment))
946 (progress-reporter-update progress (point))))) 953 (when progress (progress-reporter-update progress (point))))))
947 (forward-line 1)) 954 (forward-line 1))
948 (goto-char end)) 955 (goto-char end))
949 956
@@ -1086,10 +1093,9 @@ the overlay: `invisible' `hs'. Also, depending on variable
1086 (remove-overlays beg end 'hs-indicator t) 1093 (remove-overlays beg end 'hs-indicator t)
1087 1094
1088 (while (not (>= (point) end)) 1095 (while (not (>= (point) end))
1089 (save-excursion 1096 (when-let* ((_ (not (invisible-p (point)))) ; Skip invisible lines
1090 (when-let* ((_ (not (invisible-p (point)))) ; Skip invisible lines 1097 (b-beg (hs-get-first-block-on-line)))
1091 (b-beg (hs-get-first-block-on-line))) 1098 (hs--make-indicators-overlays b-beg))
1092 (hs--make-indicators-overlays b-beg)))
1093 ;; Only 1 indicator per line 1099 ;; Only 1 indicator per line
1094 (forward-line)) 1100 (forward-line))
1095 `(jit-lock-bounds ,beg . ,end)) 1101 `(jit-lock-bounds ,beg . ,end))
@@ -1354,14 +1360,14 @@ The hook `hs-hide-hook' is run; see `run-hooks'."
1354 (message "Hiding blocks ...") 1360 (message "Hiding blocks ...")
1355 (if (hs-get-near-block) 1361 (if (hs-get-near-block)
1356 ;; Hide block if we are looking at one. 1362 ;; Hide block if we are looking at one.
1357 (apply #'hs-hide-level-recursive arg 1363 (pcase-let ((`(,beg ,end) (hs-block-positions)))
1358 (hs-block-positions)) 1364 (hs-hide-level-recursive arg beg end hs-hide-comments-when-hiding-all))
1359 ;; Otherwise hide all the blocks in the current buffer 1365 ;; Otherwise hide all the blocks in the current buffer
1360 (hs-hide-level-recursive 1366 (hs-hide-level-recursive
1361 ;; Increment ARG by 1, avoiding it acts like 1367 ;; Increment ARG by 1, avoiding it acts like
1362 ;; `hs-hide-all' 1368 ;; `hs-hide-all'
1363 (1+ arg) 1369 (1+ arg) (point-min) (point-max)
1364 (point-min) (point-max))) 1370 hs-hide-comments-when-hiding-all))
1365 (message "Hiding blocks ... done")) 1371 (message "Hiding blocks ... done"))
1366 (run-hooks 'hs-hide-hook))) 1372 (run-hooks 'hs-hide-hook)))
1367 1373
@@ -1422,8 +1428,9 @@ only blocks which are that many levels below the level of point."
1422 (hs-toggle-hiding) 1428 (hs-toggle-hiding)
1423 (message "Toggle visibility")) 1429 (message "Toggle visibility"))
1424 ((> level 1) 1430 ((> level 1)
1425 (apply #'hs-hide-level-recursive level 1431 (pcase-let ((`(,beg ,end) (hs-block-positions)))
1426 (hs-block-positions)) 1432 (hs-hide-level-recursive
1433 level beg end hs-hide-comments-when-hiding-all))
1427 (message "Hide %d level" level)) 1434 (message "Hide %d level" level))
1428 (t 1435 (t
1429 (let* (hs-allow-nesting 1436 (let* (hs-allow-nesting
@@ -1440,7 +1447,9 @@ only blocks which are that many levels below the level of point."
1440 ;; Hide the children blocks if the parent block is hidden 1447 ;; Hide the children blocks if the parent block is hidden
1441 ((and (= (overlay-start ov) (car block)) 1448 ((and (= (overlay-start ov) (car block))
1442 (= (overlay-end ov) (cadr block))) 1449 (= (overlay-end ov) (cadr block)))
1443 (apply #'hs-hide-level-recursive 1 block) 1450 (hs-hide-level-recursive
1451 1 (car block) (cadr block)
1452 hs-hide-comments-when-hiding-all)
1444 (message "Hide first nested blocks")) 1453 (message "Hide first nested blocks"))
1445 ;; Otherwise show all in the parent block, we cannot use 1454 ;; Otherwise show all in the parent block, we cannot use
1446 ;; `hs-show-block' here because we already know the 1455 ;; `hs-show-block' here because we already know the
diff --git a/test/lisp/progmodes/hideshow-tests.el b/test/lisp/progmodes/hideshow-tests.el
index 49f661a2390..cf13a064f39 100644
--- a/test/lisp/progmodes/hideshow-tests.el
+++ b/test/lisp/progmodes/hideshow-tests.el
@@ -281,6 +281,55 @@ main(int argc, char **argv)
281} 281}
282")))) 282"))))
283 283
284(ert-deftest hideshow-hide-levels-with-comments-1 ()
285 "Should hide 2nd and then 3rd level blocks including comment blocks."
286 (hideshow-tests-with-temp-buffer
287 lisp-data-mode
288 ;; 2nd
289 "
290;; comment
291;; comment
292;; comment
293
294(list
295 ;; comment2
296 ;; comment2
297 (list
298 ;; comment3
299 ;; comment3
300 '(lv3
301 lv3)))
302"
303 (hs-hide-level-recursive 2 (point-min) (point-max) :comments)
304 (should (string=
305 (hideshow-tests-visible-string)
306 "
307;; comment
308;; comment
309;; comment
310
311(list
312 ;; comment2
313 (list))
314"))
315 ;; 3rd
316 (hs-show-all)
317 (hs-hide-level-recursive 3 (point-min) (point-max) :comments)
318 (should (string=
319 (hideshow-tests-visible-string)
320 "
321;; comment
322;; comment
323;; comment
324
325(list
326 ;; comment2
327 ;; comment2
328 (list
329 ;; comment3
330 '(lv3)))
331"))))
332
284(ert-deftest hideshow-toggle-hiding-1 () 333(ert-deftest hideshow-toggle-hiding-1 ()
285 "Should toggle hiding/showing of a block." 334 "Should toggle hiding/showing of a block."
286 (let ((contents " 335 (let ((contents "