Is there any option or other customization to keep the outline of an org-mode buffer (uncollapsed parts of the tree) after the buffer has been reverted (org-mode 9.0.1, emacs 25.3.2)? In my case only the top headings are displayed after reverting. This is quite annoying and time-consuming in a setup, where one constantly switches between git branches e.g.
1 Answer
The correct answer was provided on the mailing list:
http://lists.gnu.org/archive/html/emacs-orgmode/2018-01/msg00336.html
Quotation of the relevant part of that message:
Org provides two functions to save and restore visibility (and a macro that does both, but isn't useful in your case):
org-outline-overlay-data
andorg-set-outline-overlay-data
.You may want to use them within
before-revert-hook
andafter-revert-hook
.
The following is useful for implementing it:
Note that the functions org-outline-overlay-data
and org-set-outline-overlay-data
do not exist anymore in Orgmode 9.2.
Citation of the incompatible changes of Orgmode 9.2:
Removed commands and functions
org-outline-overlay-data
Use
org-save-outline-visibility
instead.
org-set-outline-overlay-data
Use
org-save-outline-visibility
instead.
Possible Implementation
There follows Elisp code that preserves the outline state of headings over revert-buffer
. It includes the definitions of org-outline-overlay-data
and org-set-outline-overlay-data
that have been deleted from Orgmode 9.2.
(defun org-outline-overlay-data (&optional use-markers)
"Return a list of the locations of all outline overlays.
These are overlays with the `invisible' property value `outline'.
The return value is a list of cons cells, with start and stop
positions for each overlay.
If USE-MARKERS is set, return the positions as markers."
(let (beg end)
(org-with-wide-buffer
(delq nil
(mapcar (lambda (o)
(when (eq (overlay-get o 'invisible) 'outline)
(setq beg (overlay-start o)
end (overlay-end o))
(and beg end (> end beg)
(if use-markers
(cons (copy-marker beg)
(copy-marker end t))
(cons beg end)))))
(overlays-in (point-min) (point-max)))))))
(defun org-set-outline-overlay-data (data)
"Create visibility overlays for all positions in DATA.
DATA should have been made by `org-outline-overlay-data'."
(org-with-wide-buffer
(org-show-all)
(dolist (c data) (org-flag-region (car c) (cdr c) t 'outline))))
(defvar-local my-org-outline-state nil
"Place for saving org outline state before reverting the buffer.")
(put 'my-org-outline-state 'permanent-local t)
(defun my-org-save-outline-state ()
"Save org outline state in `my-org-outline-state'.
It can be recovered afterwards with `my-org-recover-outline-state'."
(setq my-org-outline-state (org-outline-overlay-data t)))
(defun my-org-restore-outline-state ()
"Save org outline state in `my-org-outline-state'.
It can be recovered afterwards with `my-org-recover-outline-state'."
(when my-org-outline-state
(org-set-outline-overlay-data my-org-outline-state)
(setq my-org-outline-state nil)))
(defun my-org-install-save-outline-state ()
"Configure org to preserve the outline state at revert-buffer."
(add-hook 'before-revert-hook #'my-org-save-outline-state nil t)
(add-hook 'after-revert-hook #'my-org-restore-outline-state nil t))
(add-hook 'org-mode-hook #'my-org-install-save-outline-state)
org-startup-folded
's docstring, which might be the variable you're looking for.