From 56e998c5776f4a8fb16ea2be1a05c5675f129b8b Mon Sep 17 00:00:00 2001 From: 45mg <45mm.cartridge421@slmail.me> Date: Mon, 20 May 2024 18:23:46 +0000 Subject: [PATCH] fix(fold): properly handle recursive folds With four folding systems in play, there are numerous ways to create nested folds (eg. hideshow folds inside folded outline headings with `+fold/close-all`). So `+fold/open-rec' needs to be able to open all kinds of folds within the newly unfolded region. It can't stop at unfolding the type of fold it was called on. --- modules/editor/fold/autoload/fold.el | 70 ++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/modules/editor/fold/autoload/fold.el b/modules/editor/fold/autoload/fold.el index c130bf7ed..9009de7d9 100644 --- a/modules/editor/fold/autoload/fold.el +++ b/modules/editor/fold/autoload/fold.el @@ -59,6 +59,69 @@ (end-of-line) ,@body)) +(defun +fold--union () + "Get the combined region covered by all folds at point." + ;; We are supporting four folding systems that weren't really designed to work + ;; together. No doubt users will find novel, unanticipated ways to nest + ;; different types of folds (especially easy to do with `outline-minor-mode'). + ;; So, we need code that can deal with any arbitrary overlap. + (cl-reduce + (lambda (&optional acc cur) + (when (and acc cur) + (cons (min (car acc) (car cur)) + (max (cdr acc) (cdr cur))))) + (nconc + (when (+fold--vimish-fold-p) + (mapcar (lambda (ov) + (cons (overlay-start ov) (overlay-end ov))) + (seq-filter #'vimish-fold--vimish-overlay-p + (or (overlays-at (point)) '())))) + (when (+fold--outline-fold-p) + (save-excursion + (let ((beg (progn (outline-back-to-heading) (point))) + (end (progn (outline-end-of-subtree) (point)))) + (list (cons beg end))))) + (when-let ((start (+fold--hideshow-fold-p))) + ;; `start' could be start of the block, or 't' if that wasn't found. + ;; In either case, we know the fold is on the same line. + (let* ((start (or (and (numberp start) start) + (line-beginning-position))) + (end (line-end-position)) + (ov (hs-overlay-at start))) + (while (and (not ov) (< start end)) + (setq start (next-overlay-change start) + ov (hs-overlay-at start))) + (when ov + (list (cons (overlay-start ov) (overlay-end ov)))))) + (when (+fold--ts-fold-p) + (when-let* ((node (ts-fold--foldable-node-at-pos)) + (beg (tsc-node-start-position node)) + (end (tsc-node-end-position node))) + (list (cons beg end))))))) + +(defun +fold--open-rec-between (beg end) + "Recursively open all folds betwen BEG and END." + (when (featurep 'vimish-fold) + ;; from `vimish-fold-unfold-all' + (mapc #'vimish-fold--unfold + (vimish-fold--folds-in + (point-min) + (point-max)))) + (and (+fold--outline-fold-p) + (outline-show-subtree)) + (hs-life-goes-on + ;; from `hs-show-all' + (let ((hs-allow-nesting nil)) + (hs-discard-overlays beg end)) + (run-hooks 'hs-show-hook)) + (when (bound-and-true-p ts-fold-mode) + ;; from `ts-fold-open-all' + (ts-fold--ensure-ts + (thread-last (overlays-in (point-min) (point-max)) + (seq-filter + (lambda (ov) + (eq (overlay-get ov 'invisible) 'ts-fold))) + (mapc #'delete-overlay))))) ;; ;;; Commands @@ -84,11 +147,8 @@ Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." Targets `vimmish-fold', `hideshow', `ts-fold' and `outline' folds." (interactive) - (save-excursion - (cond ((+fold--vimish-fold-p) (vimish-fold-unfold)) - ((+fold--outline-fold-p) (outline-show-subtree)) - ((+fold--hideshow-fold-p) (+fold-from-eol (hs-show-block))) - ((+fold--ts-fold-p) (ts-fold-open))))) + (cl-destructuring-bind (beg . end) (+fold--union) + (+fold--open-rec-between beg end))) ;;;###autoload (defun +fold/open ()