Package: emacs;
Reported by: James Cherti <contact <at> jamescherti.com>
Date: Thu, 21 Aug 2025 18:10:02 UTC
Severity: normal
View this message in rfc822 format
From: James Cherti <contact <at> jamescherti.com> To: Rahguzar <rahguzar <at> mailbox.org> Cc: 79286 <at> debbugs.gnu.org Subject: bug#79286: outline-mode: attempting to open folded sections does not work as expected inside a deeply nested header Date: Thu, 21 Aug 2025 15:09:19 -0400
On 2025-08-21 14:34, Rahguzar wrote: > Hi James, Hi Rahguzar, > James Cherti <contact <at> jamescherti.com> writes: > >> When using outline-mode or outline-minor-mode, attempting to >> open folded sections (outline-show-entry) does not work as >> expected when the cursor is positioned inside a deeply >> nested header. >> >> Steps to Reproduce: >> ------------------- >> 1. Open an outline-mode buffer with multiple >> nested headers, for example: >> >> Level 1 >> ** Level 2 >> *** Level 3 >> **** Level 4: A >> Some content here >> Some content here >> Some content here >> Some content here >> **** Level 4: B >> Some content here >> Some content here >> Some content here >> Some content here >> **** Level 4: C >> Some content here >> Some content here< PUT THE CURSOR HERE >> Some content here >> Some content here >> **** Level 4: D >> Some content here >> Some content here >> Some content here >> Some content here >> Some content here >> **** Level 4: E >> Some content here >> Some content here >> Some content here >> >> 2. Put the cursor before `< PUT THE CURSOR HERE` >> >> 3. Collapse all folds with: (hide-sublevels 1) >> >> 6. Show entry: (outline-show-entry) >> >> The folds fail to expand fully in nested hierarchies, leaving all >> content hidden except for `level 4: C`. >> >> Screenshot: >> https://github.com/user-attachments/assets/2ea6c3bd-0284-40a7-90e5-1619bdf3acc5 >> >> Expected Behavior: >> ------------------ >> The expected behavior is that only the heading at point (and >> its associated content) should be expanded, while all >> ancestor headings remain collapsed. (Similar to other editors.) >> >> Actual Behavior: >> ---------------- >> Only the heading at point expands, while other headings >> remain invisible, which is confusing. In some cases, these >> hidden headings cannot be revealed until the parent heading >> is first collapsed and then expanded again. > > I have encountered this with isearch and was able to fix this > with in my init file. > > ```emacs-lisp > (defun +outline-reveal (pos) > (let ((heading-pos nil)) > (while (not (eq heading-pos (progn (outline-back-to-heading) (point)))) > (setq heading-pos (point)) > (outline-show-children) > (goto-char pos)) > (outline-show-entry) > (goto-char pos))) > > (defun +outline-invsible-open (&optional _) > (when (and outline-minor-mode > (outline-invisible-p)) > (+outline-reveal (point)))) > > (setq outline-isearch-open-invisible-function #'+outline-invsible-open) > ``` > With an interactive spec the function +outline-reveal can be used as an > alternative to outline-show-entry without this problem but I can't > imagine a scenario where that might be needed. > Unfortunately, neither `+outline-reveal` nor `+outline-invisible-open` resolves this issue. I wrote the following Elisp code to fix this issue: --8<---------------cut here---------------start------------->8--- ;; Author James Cherti ;; GitHub: https://github.com/jamescherti (defun my-outline-show-entry () "Show the body directly following this heading. Show the heading too, if it is currently invisible." (interactive) ;; Show previous headers (unless (derived-mode-p 'outline-indent-minor-mode) (save-excursion (let ((func-invisible-p (cond ((and (derived-mode-p 'org-mode) (fboundp 'org-invisible-p)) 'org-invisible-p) ((and (or (derived-mode-p 'outline-mode) (derived-mode-p 'outline-minor-mode)) (fboundp 'outline-invisible-p)) 'outline-invisible-p) (t 'invisible-p))) (initial-point (point)) (visual-point nil) (visual-init-point nil)) ;; Unfolding loop (while (and ;; Folded? (save-excursion (end-of-line) (funcall func-invisible-p (point))) ;; When the real point differs from the visual point, it indicates ;; that the cursor is still located within a hidden header. ;; ;; This prevents infinite loops if the unfolding stops changing ;; the cursor position. (or (not visual-init-point) (not visual-point) (/= visual-init-point visual-point))) (save-excursion (outline-back-to-heading) (beginning-of-line) (setq visual-point (point)) (with-no-warnings (show-children)) ;; Go back to point (goto-char initial-point) (outline-back-to-heading) (beginning-of-line) (setq visual-init-point (point)))) ;; Previous version of `outline-show-entry' (save-excursion (outline-back-to-heading t) (outline-flag-region (1- (point)) (progn (outline-next-preface) (if (= 1 (- (point-max) (point))) (point-max) (point))) nil)))))) (advice-add 'outline-show-entry :override #'my-outline-show-entry) --8<---------------cut here---------------start------------->8--- This could likely be simplified using built-in functions. I welcome any suggestions for improvement. >> Environment: >> ------------ >> * Emacs version: 30.2 and master branch >> (ade6608e2587452c8ea565ce3057879379ebd0b5) >> >> -- >> James Cherti >> GitHub: https://github.com/jamescherti >> Website: https://www.jamescherti.com/ > > Rahguzar -- James Cherti GitHub: https://github.com/jamescherti Website: https://www.jamescherti.com/
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.