From 2672480e4bd7962f23df07e6beb1a50a23dcfd2b Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Mon, 10 Jun 2024 09:34:15 +0300 Subject: [PATCH] * lisp/outline.el: Improve new feature of preserving outlines after revert. (outline-minor-mode): Move adding hook 'outline-revert-buffer-rehighlight' to the same code branch that calls 'outline-minor-mode-highlight-buffer'. (outline-revert-buffer-rehighlight): Remove same conditions already existing in 'outline-minor-mode'. (outline-hidden-headings-regexp): Remove function. (outline-hidden-headings-paths) (outline-hidden-headings-restore-paths): New functions that save and restore complete paths instead of flat regexps. (outline-revert-buffer-restore-visibility): Use 'outline-hidden-headings-paths' and 'outline-hidden-headings-restore-paths'. (cherry picked from commit 1a5aa16066bb5180eb92d9c0bfc8cb2c0ce4a4d0) --- lisp/outline.el | 72 +++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/lisp/outline.el b/lisp/outline.el index 4d74b30dba4..c19ee9cf0f6 100644 --- a/lisp/outline.el +++ b/lisp/outline.el @@ -574,7 +574,10 @@ See the command `outline-mode' for more information on this mode." (progn (font-lock-add-keywords nil outline-font-lock-keywords t) (font-lock-flush)) - (outline-minor-mode-highlight-buffer))) + (progn + (outline-minor-mode-highlight-buffer) + (add-hook 'revert-buffer-restore-functions + #'outline-revert-buffer-rehighlight nil t)))) (outline--fix-up-all-buttons) ;; Turn off this mode if we change major modes. (add-hook 'change-major-mode-hook @@ -582,8 +585,6 @@ See the command `outline-mode' for more information on this mode." nil t) (add-hook 'revert-buffer-restore-functions #'outline-revert-buffer-restore-visibility nil t) - (add-hook 'revert-buffer-restore-functions - #'outline-revert-buffer-rehighlight nil t) (setq-local line-move-ignore-invisible t) ;; Cause use of ellipses for invisible text. (add-to-invisibility-spec '(outline . t)) @@ -1696,44 +1697,63 @@ LEVEL, decides of subtree visibility according to (point-min) (point-max))) (run-hooks 'outline-view-change-hook)) -(defun outline-hidden-headings-regexp () - "Return a regexp that matches all currently hidden outlines. -This is useful to save the hidden outlines and restore them later, -for example, after reverting the buffer." - (let ((headings)) +(defun outline-hidden-headings-paths () + "Return a hash with headings of currently hidden outlines. +Every hash key is a list whose elements compose a complete path +of headings descending from the top level down to the bottom level. +This is useful to save the hidden outlines and restore them later +after reverting the buffer." + (let ((paths (make-hash-table :test #'equal)) + current-path) (outline-map-region (lambda () - (when (save-excursion - (outline-end-of-heading) - (seq-some (lambda (o) (eq (overlay-get o 'invisible) - 'outline)) - (overlays-at (point)))) - (push (buffer-substring (pos-bol) (pos-eol)) headings))) + (let* ((level (funcall outline-level)) + (heading (buffer-substring-no-properties (pos-bol) (pos-eol))) + path) + (while (and current-path (>= (cdar current-path) level)) + (pop current-path)) + (push (cons heading level) current-path) + (when (save-excursion + (outline-end-of-heading) + (seq-some (lambda (o) (eq (overlay-get o 'invisible) + 'outline)) + (overlays-at (point)))) + (setf (gethash (mapcar #'car current-path) paths) t)))) (point-min) (point-max)) - (when headings - (mapconcat (lambda (heading) - (concat "\\`" (regexp-quote heading) "\\'")) - (nreverse headings) "\\|")))) + paths)) + +(defun outline-hidden-headings-restore-paths (paths) + "Restore hidden outlines from a hash of hidden headings. +This is useful after reverting the buffer to restore the outlines +hidden by `outline-hidden-headings-paths'." + (let (current-path outline-view-change-hook) + (outline-map-region + (lambda () + (let* ((level (funcall outline-level)) + (heading (buffer-substring (pos-bol) (pos-eol))) + path) + (while (and current-path (>= (cdar current-path) level)) + (pop current-path)) + (push (cons heading level) current-path) + (when (gethash (mapcar #'car current-path) paths) + (outline-hide-subtree)))) + (point-min) (point-max)))) (defun outline-revert-buffer-restore-visibility () "Preserve visibility when reverting buffer under `outline-minor-mode'. This function restores the visibility of outlines after the buffer under `outline-minor-mode' is reverted by `revert-buffer'." - (let ((regexp (outline-hidden-headings-regexp))) - (when regexp + (let ((paths (outline-hidden-headings-paths))) + (unless (hash-table-empty-p paths) (lambda () - (outline-hide-by-heading-regexp regexp))))) + (outline-hidden-headings-restore-paths paths))))) (defun outline-revert-buffer-rehighlight () "Rehighlight outlines when reverting buffer under `outline-minor-mode'. This function rehighlights outlines after the buffer under `outline-minor-mode' is reverted by `revert-buffer' when font-lock can't update highlighting for `outline-minor-mode-highlight'." - (when (and outline-minor-mode-highlight - (not (and global-font-lock-mode - (font-lock-specified-p major-mode)))) - (lambda () - (outline-minor-mode-highlight-buffer)))) + (lambda () (outline-minor-mode-highlight-buffer))) ;;; Visibility cycling -- 2.39.2