4

I'm using Outline mode (usually the minor mode, but it shouldn't matter) or Org mode. I have a file that looks like this:

    -*-outline-*-
* Chapter 1
** Section 1.1
*** Subsection 1.1.1
foo
*** Subsection 1.1.2
bar
** Section 1.2
baz
* Chapter 2
** Section 2.1
qux
** Section 2.2
wib

I'm editing subsection 1.1.1 (“foo”). I want to focus on this section, so I run C-c C-o (hide-other). This is what I see:

    -*-outline-*-
* Chapter 1
** Section 1.1
*** Subsection 1.1.1
foo...
* Chapter 2...

In the old days of Emacs 19 (the behavior changed after 19.34 and before 20.7), I saw this:

    -*-outline-*-
* Chapter 1
** Section 1.1
*** Subsection 1.1.1
foo
*** Subsection 1.1.2...
** Section 1.2...
* Chapter 2...

The difference is that the headers for Section 1.2 and Subsection 1.1.2 are shown, because they're a sibling of Section 1.1 which contains Subsection 1.1.1 which I'm viewing. I like that. How can I get this behavior in a modern Emacs?

What I'm mainly looking for is a way to make hide-other (or a separate command) show all siblings of all visible headers (if I'm in Subsection 1.1.1, I want to see the headers for Section 1.2 and Subsection 1.1.2, and so on). More generally, I'd like a command outline-show-all-siblings-of-visible-headers. Is there such a thing?

2 Answers 2

2

Since the change was made as part of the Outline rewrite between Emacs 19 and Emacs 20 to use overlays (or close thereto), I had a look at the differences between hide-other from Emacs 19.34 and from Emacs 20.7. The change is easy enough to spot: in the Emacs 20+ definition, the body of the loop that traverses the headings upwards shows the heading it reaches only, while in Emacs 19, it calls show-children. So I tweaked the code of Emacs 23 to call show-children (hot patching with something like flet wouldn't work easily since outline-flag-region is used in many places).

(defun outline-focus ()
  "Hide everything except for the current body and the parent headings.
Unlike `hide-other' since Emacs 20, this function shows all siblings
of visible headers."
  (interactive)
  (hide-sublevels 1)
  (let (outline-view-change-hook)
    (save-excursion
      (outline-back-to-heading t)
      (show-entry)
      (while (condition-case nil (progn (outline-up-heading 1 t) (not (bobp)))
               (error nil))
        (show-children))))
  (run-hooks 'outline-view-change-hook))

In Org mode, org-reveal with a prefix argument (C-u C-x C-r) does what I was looking for: show sibling headers of all headers encountered on the path upwards from the cursor position. Pressing S-tab (org-global-cycle) to get to the “overview” state, or C-u 0 S-tab to get to the “contents” state with minimal depth, followed by C-u C-x C-r gives me the view I wanted.

It's nicer for easy interactive use to mix Outline and Org commands, and call hide-other followed by org-reveal.

(autoload 'org-reveal "org")
(defun gilles/outline-focus-entry ()
  (interactive "@")
  (hide-other)
  (org-reveal t))

This also works in Outline mode, I just need the org-reveal function to be loaded.

1

Here is an modified solution that should reflect the requirements better. Not extensively tested nor optimized.

(defun my-outline-show-near-relatives ()
  "Hides body of all other headings while keeping headers only of siblings and elder relatives."
  (interactive)
  (save-excursion    
    (let ((level (progn
                   (outline-back-to-heading)
                   (funcall outline-level))))
      (hide-other)
      (while (> level 1)
        (outline-up-heading 1)
        (show-children 1)
        (setq level (funcall outline-level))))))

You can see it in action.

screencast of outlining command

First attempt for posterity sake

Here is an attempt that does what I think you want. Not extensively tested

(defun my-outline-show-all-siblings-of-visible-headers ()
  "Hides body of all other headings while keeping headers of
only visible siblings."
  (interactive)
  (save-excursion
    (hide-other)
    (outline-up-heading 1)
    (show-children 1)))

For instance the following layout is outlined as follows depending on where point is.

* Chapter 1
** Section 1.1
foo
** Section 1.2
bar
*** Section 1.2.1
lorem
*** Section 1.2.2
ipsum
** Section 1.3
abracadabra
*** Section 1.3.1
hocus pocus
* Chapter 2
** Section 2.1
qux
** Section 2.2
wib

When point ▌is in Section 1.2.2, it becomes

 * Chapter 1
 ...
 ** Section 1.2
 ...
 *** Section 1.2.1...
 *** Section 1.2.2
 ipsum▌...
 * Chapter 2...

When point is in Section 1.3, it becomes

* Chapter 1
** Section 1.1...
** Section 1.2...
** Section 1.3
abracadabra▌ ...
* Chapter 2...
3
  • This doesn't work when the outline level goes up by more than 1 at some heading. You need to call outline-level again at each iteration. I should go and look at the Emacs 19 code. Oct 16, 2014 at 20:03
  • Yeah, I did not consider that. Nice spot.
    – Vamsi
    Oct 16, 2014 at 22:48
  • In that case, (outline-up-heading 1) will just echo a message when it reaches the root (before level goes to 1). Not the most robust code, but still gets the job done.
    – Vamsi
    Oct 16, 2014 at 23:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.