mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-06-14 04:21:24 +00:00
Add outline-show-entry-and-parents to reveal entry hierarchy
* lisp/outline.el (outline-mode-prefix-map): Rebind 'C-e' from 'outline-show-entry' to 'outline-show-entry-and-parents'. (outline-mode-menu-bar-map): Use 'outline-show-entry-and-parents' instead of 'outline-show-entry'. (outline-isearch-open-invisible): Use the new command instead of the 'outline-show-entry' primitive. This prevents unintended side effects for packages relying on the base API and avoids the 'isolated item' effect. (outline-show-entry-and-parents): New function to climb the tree, reveal parent headings, and unfold the current entry (bug#79286).
This commit is contained in:
parent
971fa88a58
commit
e7e9c55ba7
2 changed files with 71 additions and 4 deletions
6
etc/NEWS
6
etc/NEWS
|
|
@ -88,6 +88,12 @@ This means it won't get in your way even if it's slow for your
|
|||
repository. As such, the 'vc-dir-show-outgoing-count' option is now
|
||||
obsolete.
|
||||
|
||||
** Outline mode
|
||||
|
||||
*** New command 'outline-show-entry-and-parents'.
|
||||
It is bound to 'C-e' and reveals the current entry
|
||||
with its parent hierarchy.
|
||||
|
||||
|
||||
* New Modes and Packages in Emacs 32.1
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ imitate the function `looking-at'.")
|
|||
"C-t" #'outline-hide-body
|
||||
"C-a" #'outline-show-all
|
||||
"C-c" #'outline-hide-entry
|
||||
"C-e" #'outline-show-entry
|
||||
"C-e" #'outline-show-entry-and-parents
|
||||
"C-l" #'outline-hide-leaves
|
||||
"C-k" #'outline-show-branches
|
||||
"C-q" #'outline-hide-sublevels
|
||||
|
|
@ -130,8 +130,8 @@ imitate the function `looking-at'.")
|
|||
(define-key map [show outline-show-branches]
|
||||
'(menu-item "Show Branches" outline-show-branches
|
||||
:help "Show all subheadings of this heading, but not their bodies"))
|
||||
(define-key map [show outline-show-entry]
|
||||
'(menu-item "Show Entry" outline-show-entry
|
||||
(define-key map [show outline-show-entry-and-parents]
|
||||
'(menu-item "Show Entry" outline-show-entry-and-parents
|
||||
:help "Show the body directly following this heading"))
|
||||
(define-key map [show outline-show-all]
|
||||
'(menu-item "Show All" outline-show-all
|
||||
|
|
@ -1095,7 +1095,7 @@ If FLAG is nil then text is shown, while if FLAG is t the text is hidden."
|
|||
;; `outline-flag-region').
|
||||
(defun outline-isearch-open-invisible (_overlay)
|
||||
;; We rely on the fact that isearch places point on the matched text.
|
||||
(outline-show-entry))
|
||||
(outline-show-entry-and-parents))
|
||||
|
||||
(defun outline-hide-entry ()
|
||||
"Hide the body directly following this heading."
|
||||
|
|
@ -1123,6 +1123,67 @@ Show the heading too, if it is currently invisible."
|
|||
|
||||
(define-obsolete-function-alias 'show-entry #'outline-show-entry "25.1")
|
||||
|
||||
(defun outline-show-entry-and-parents ()
|
||||
"Reveal the current entry and its parent hierarchy.
|
||||
This command ensures that the current entry, all of its ancestor
|
||||
headings, and their immediate sibling headings are visible.
|
||||
|
||||
The function iteratively unfolds the children and body of the target
|
||||
entry until it is fully revealed. If invoked when the point is inside
|
||||
a completely hidden subtree, it manages the visibility state to avoid
|
||||
leaving the buffer in an inconsistent layout. This guarantees a safe
|
||||
and predictable visual expansion."
|
||||
(interactive)
|
||||
;; Wrap in `save-match-data' because outline functions use regular
|
||||
;; expressions. Without this, calling `outline-show-entry-and-parents'
|
||||
;; programmatically would clobber the caller's match data, leading to
|
||||
;; subtle, hard-to-trace bugs.
|
||||
(save-match-data
|
||||
;; Repeatedly expand the outline structure at point from the outside
|
||||
;; in until the target text is fully visible.
|
||||
;;
|
||||
;; Think of this block as manually opening nested folds:
|
||||
;; - It checks whether the heading at point is folded.
|
||||
;; - If it is folded, it moves backward to that parent heading.
|
||||
;; - It opens the heading to reveal its text and subheadings.
|
||||
;; - It repeats this process layer by layer down to the target.
|
||||
(let (heading-point
|
||||
prior-heading-point)
|
||||
(while (condition-case nil
|
||||
(save-excursion
|
||||
;; Workaround: `outline-back-to-heading' throws an
|
||||
;; `outline-before-first-heading' error if the
|
||||
;; heading is on the first line (e.g., in
|
||||
;; `markdown-ts-mode') and point is deep within the
|
||||
;; hidden body of that folded first heading.
|
||||
(vertical-motion 0)
|
||||
;; Navigate backward to the nearest visible heading
|
||||
(outline-back-to-heading)
|
||||
(setq heading-point (point))
|
||||
;; Break the loop if we stop making progress,
|
||||
;; preventing infinite recursion
|
||||
(if (eq heading-point prior-heading-point)
|
||||
;; Break out of the loop
|
||||
nil
|
||||
(setq prior-heading-point heading-point)
|
||||
;; Check if the heading is folded by inspecting the
|
||||
;; end of the line
|
||||
(when (invisible-p (pos-eol))
|
||||
;; Ignore errors to guarantee the target entry is
|
||||
;; still revealed via `outline-show-entry' even
|
||||
;; if a buggy third-party `outline-level'
|
||||
;; function fails during child expansion.
|
||||
(ignore-errors (outline-show-children))
|
||||
|
||||
;; Show the body directly following this heading
|
||||
(outline-show-entry)
|
||||
|
||||
;; Return t to continue drilling down to the next
|
||||
;; layer of the outline hierarchy
|
||||
t)))
|
||||
(outline-before-first-heading
|
||||
nil))))))
|
||||
|
||||
(defun outline-hide-body ()
|
||||
"Hide all body lines in buffer, leaving all headings visible.
|
||||
Note that this does not hide the lines preceding the first heading line."
|
||||
|
|
|
|||
Loading…
Reference in a new issue