0
0
Fork 1
mirror of https://git.savannah.gnu.org/git/emacs/org-mode.git synced 2024-08-24 10:19:14 +00:00

org-fold-core: New API to fold/restore buffer folding state

* lisp/org-fold-core.el (org-fold-core-get-regions): New function to
retrieve the list of folded regions in buffer.
(org-fold-core-regions): New function to set folding state in buffer
according to the list returned by `org-fold-core-get-regions'.
(org-fold-core-save-visibility): New macro, equivalent to
`org-fold-save-outline-visibility'.
This commit is contained in:
Ihor Radchenko 2022-08-13 14:59:01 +08:00
parent 687d5702d2
commit 15658b8665
No known key found for this signature in database
GPG key ID: 6470762A7DA11D8B

View file

@ -932,6 +932,55 @@ Move point right after the end of the region, to LIMIT, or
(set-match-data (list (set-marker (make-marker) (car region) (current-buffer))
(set-marker (make-marker) (cdr region) (current-buffer))))))))))
(cl-defun org-fold-core-get-regions (&key specs from to with-markers relative)
"Find all the folded regions in current buffer.
Each element of the returned list represent folded region boundaries
and the folding spec: (BEG END SPEC).
Search folds intersecting with (FROM TO) buffer region if FROM and TO
are provided.
If FROM is non-nil and TO is nil, search the folded regions at FROM.
When SPECS is non-nil it should be a list of folding specs or a symbol.
Only return the matching fold types.
When WITH-MARKERS is non-nil, use markers to represent region
boundaries.
When RELATIVE is a buffer position, regions boundaries are given
relative to that position.
When RELATIVE is t, use FROM as the position.
WITH-MARKERS must be nil when RELATIVE is non-nil."
(when (and relative with-markers)
(error "Cannot use markers in non-absolute region boundaries"))
(when (eq relative t) (setq relative from))
(unless (listp specs) (setq specs (list specs)))
(let (regions region mk-region)
(org-with-wide-buffer
(when (and from (not to)) (setq to (point-max)))
(when (and from (< from (point-min))) (setq from (point-min)))
(when (and to (> to (point-max))) (setq to (point-max)))
(unless from (setq from (point-min)))
(dolist (spec (or specs (org-fold-core-folding-spec-list)) regions)
(goto-char from)
(catch :exit
(while (or (not to) (< (point) to))
(when (org-fold-core-get-folding-spec spec)
(setq region (org-fold-core-get-region-at-point spec))
(when relative
(cl-decf (car region) relative)
(cl-decf (cdr region) relative))
(if (not with-markers)
(setq mk-region `(,(car region) ,(cdr region) ,spec))
(setq mk-region `(,(make-marker) ,(make-marker) ,spec))
(move-marker (nth 0 mk-region) (car region))
(move-marker (nth 1 mk-region) (cdr region)))
(push mk-region regions))
(unless to (throw :exit nil))
(goto-char (org-fold-core-next-folding-state-change spec nil to))))))))
;;;; Changing visibility
;;;;; Region visibility
@ -999,6 +1048,43 @@ If SPEC-OR-ALIAS is omitted and FLAG is nil, unfold everything in the region."
(jit-lock-refontify from to)
(save-match-data (font-lock-fontify-region from to)))))))))))
(cl-defmacro org-fold-core-regions (regions &key override clean-markers relative)
"Fold every region in REGIONS list in current buffer.
Each region in the list is a list (BEG END SPEC-OR-ALIAS) describing
region and folding spec to be applied.
When optional argument OVERRIDE is non-nil, clear folding state in the
buffer first.
When optional argument CLEAN-MARKERS is non-nil, clear markers used to
mark region boundaries in REGIONS.
When optional argument RELATIVE is non-nil, it must be a buffer
position. REGION boundaries are then treated as relative distances
from that position."
`(org-with-wide-buffer
(when ,override (org-fold-core-region (point-min) (point-max) nil))
(pcase-dolist (`(,beg ,end ,spec) (delq nil ,regions))
(if ,relative
(org-fold-core-region (+ ,relative beg) (+ ,relative end) t spec)
(org-fold-core-region beg end t spec))
(when ,clean-markers
(when (markerp beg) (set-marker beg nil))
(when (markerp end) (set-marker end nil))))))
(defmacro org-fold-core-save-visibility (use-markers &rest body)
"Save and restore folding state around BODY.
If USE-MARKERS is non-nil, use markers for the positions. This
means that the buffer may change while running BODY, but it also
means that the buffer should stay alive during the operation,
because otherwise all these markers will point to nowhere."
(declare (debug (form body)) (indent 1))
(org-with-gensyms (regions)
`(let* ((,regions ,(org-fold-core-get-regions :with-markers use-markers)))
(unwind-protect (progn ,@body)
(org-fold-core-regions ,regions :override t :clean-markers t)))))
;;; Make isearch search in some text hidden via text propertoes
(defvar org-fold-core--isearch-overlays nil