<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>subtree on
A Scripter's Notes</title><link>https://scripter.co/tags/subtree/</link><description>Recent content in subtree
on A Scripter's Notes</description><language>en-us</language><managingEditor>kaushal.modi@gmail.com (Kaushal Modi)</managingEditor><webMaster>kaushal.modi@gmail.com (Kaushal Modi)</webMaster><lastBuildDate>Wed, 22 Apr 2026 08:24:58 -0400</lastBuildDate><generator>Hugo -- gohugo.io</generator><docs>https://validator.w3.org/feed/docs/rss2.html</docs><atom:link href="https://scripter.co/tags/subtree/index.xml" rel="self" type="application/rss+xml"/><item><title>Org: Show only Post subtree headings</title><link>https://scripter.co/org-show-only-post-subtree-headings/</link><description>&lt;blockquote>How to define a custom &lt;code>org-global-cycle&lt;/code>-like command that collapses
only the Org subtrees with specific properties.&lt;/blockquote>&lt;div class="ox-hugo-toc toc">
&lt;div class="heading">Table of Contents&lt;/div>
&lt;ul>
&lt;li>&lt;a href="#org-global-cycle">Org Global Cycle&lt;/a>&lt;/li>
&lt;li>&lt;a href="#skeleton-of-only-post-headings">Skeleton of only Post headings&lt;/a>&lt;/li>
&lt;li>&lt;a href="#the-collapse-all-posts-function">The &amp;ldquo;Collapse All Posts&amp;rdquo; function&lt;/a>&lt;/li>
&lt;li>&lt;a href="#binding-with-c-u-c-c-tab">Binding with &lt;code>C-u C-c TAB&lt;/code>&lt;/a>&lt;/li>
&lt;li>&lt;a href="#result">Result&lt;/a>&lt;/li>
&lt;/ul>
&lt;/div>
&lt;!--endtoc-->
&lt;p>I start this post by introducing what the Org mode global cycling
command does, what kind of subtree folding I actually need, and then
share the solution with code snippets.&lt;/p>
&lt;h2 id="org-global-cycle">Org Global Cycle&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#org-global-cycle">#&lt;/a>&lt;/h2>
&lt;p>Org mode has a built-in &lt;code>org-global-cycle&lt;/code> command that you might be
familiar with. It&amp;rsquo;s bound by default to the &lt;code>S-TAB&lt;/code> key. Each time
this command is called, the Org buffer will cycle through these
states:&lt;/p>
&lt;ol>
&lt;li>Overview: Show only the Level 1 headings and collapse everything
underneath.&lt;/li>
&lt;li>Contents: Show only the Org headings and collapse all the content.&lt;/li>
&lt;li>Show All: Expand all the headings and show their contents too.&lt;/li>
&lt;/ol>
&lt;p>If a numeric prefix &lt;em>N&lt;/em> is used with this command, it will show only
the Org headings up to Level &lt;em>N&lt;/em>. For example, &lt;code>C-2 S-TAB&lt;/code> will show
only the headings up to Level 2.&lt;/p>
&lt;p>This is a really helpful command, but I needed something different ..&lt;/p>
&lt;h2 id="skeleton-of-only-post-headings">Skeleton of only Post headings&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#skeleton-of-only-post-headings">#&lt;/a>&lt;/h2>
&lt;p>I maintain most of this website&amp;rsquo;s content in a single Org file. I have
dozens of blog posts organized in Org subtrees, which I further
organize under &amp;ldquo;category&amp;rdquo; headings .. It kind of looks like the below
mock-up:
&lt;span class="sidenote-number">&lt;small class="sidenote">
It&amp;rsquo;s amazing how many features PlantUML has. If you are interested in
creating diagrams like these, check out the &lt;a href="https://plantuml.com/salt">PlantUML Salt&lt;/a> syntax.
&lt;/small>&lt;/span>&lt;/p>
&lt;p>&lt;a id="figure--post-subtrees-collapsed-mockup">&lt;/a>&lt;/p>
&lt;figure>
&lt;img src="https://scripter.co/org-show-only-post-subtree-headings/post-subtrees.svg" alt="Figure 1: Post Subtrees at arbitrary heading levels"/> &lt;figcaption>
&lt;p>
&lt;span class="figure-number">Figure 1: &lt;/span>Post Subtrees at arbitrary heading levels
&lt;/p>
&lt;/figcaption>&lt;/figure>
&lt;p>As we can see,&lt;/p>
&lt;ul>
&lt;li>All the post subtrees are not at Level 1 headings.&lt;/li>
&lt;li>They are also not at a fixed Level &lt;em>N&lt;/em>.&lt;/li>
&lt;li>The heading level of the post depends on how many parent categories
that post has (and that will also change over time).&lt;/li>
&lt;/ul>
&lt;p>I needed to basically show everything leading up to a post subtree
heading, and then collapse all the content under that post; even the
sub-headings.&lt;/p>
&lt;h2 id="the-collapse-all-posts-function">The &amp;ldquo;Collapse All Posts&amp;rdquo; function&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#the-collapse-all-posts-function">#&lt;/a>&lt;/h2>
&lt;p>The &lt;code>modi/org-hugo-collapse-all-posts&lt;/code> function defined below meets
the above requirement:&lt;/p>
&lt;ol>
&lt;li>It first widens the whole buffer and expands all the headings.&lt;/li>
&lt;li>Then it loops through all the headings and collapses all the &lt;em>post
subtrees&lt;/em> i.e. all the subtrees that have the &lt;code>EXPORT_FILE_NAME&lt;/code>
property set. This is where I use the &lt;a href="https://scripter.co/looping-through-org-mode-headings/">&lt;code>org-map-entries&lt;/code>&lt;/a> magic.&lt;/li>
&lt;li>Finally it looks for Org headings that begin with &amp;ldquo;Footnotes&amp;rdquo; or
&amp;ldquo;COMMENT&amp;rdquo; and collapses them as well.&lt;/li>
&lt;/ol>
&lt;p>I am using the development version of Org mode (version 9.6, yet to be
released as of &lt;span class="timestamp-wrapper">&lt;span class="timestamp">&amp;lt;2022-06-15 Wed&amp;gt;&lt;/span>&lt;/span>) which has the new &lt;code>org-fold&lt;/code>
library. This library obsoletes the use of &lt;code>outline.el&lt;/code> library and
other &lt;em>code-folding&lt;/em> related functions in Org mode. So &lt;code>cl-flet&lt;/code> is
used to create function symbol aliases that use the &lt;code>org-fold-*&lt;/code>
functions if available, otherwise they fall back to the legacy
functions.&lt;/p>
&lt;p>&lt;a id="code-snippet--collapse-all-posts-fn">&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="hl">&lt;span class="lnt">19
&lt;/span>&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="hl">&lt;span class="lnt">23
&lt;/span>&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-emacs-lisp" data-lang="emacs-lisp">&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nb">defun&lt;/span> &lt;span class="nv">modi/org-hugo-collapse-all-posts&lt;/span> &lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Collapse all post subtrees in the current buffer.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">Also collapse the Footnotes subtree and COMMENT subtrees if
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">present.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">A post subtree is one that has the EXPORT_FILE_NAME property
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">set.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">interactive&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">cl-flet&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="nv">show-all&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">fboundp&lt;/span> &lt;span class="ss">&amp;#39;org-fold-show-all&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">org-fold-show-all&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">org-show-all&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nv">hide-subtree&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">fboundp&lt;/span> &lt;span class="ss">&amp;#39;org-fold-hide-subtree&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">org-fold-hide-subtree&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">outline-hide-subtree&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">widen&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nv">show-all&lt;/span> &lt;span class="o">&amp;#39;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">headings&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">;; Collapse all the post subtrees (ones with EXPORT_FILE_NAME&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">;; property set).&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nv">org-map-entries&lt;/span> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">hide-subtree&lt;/span> &lt;span class="s">&amp;#34;EXPORT_FILE_NAME&amp;lt;&amp;gt;\&amp;#34;\&amp;#34;&amp;#34;&lt;/span> &lt;span class="ss">&amp;#39;file&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">;; Also hide Footnotes and comments.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">save-excursion&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nf">goto-char&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">point-min&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">re-search-forward&lt;/span> &lt;span class="s">&amp;#34;^\\(\\* Footnotes\\|\\*+ COMMENT\\)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="no">nil&lt;/span> &lt;span class="nb">:noerror&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nv">hide-subtree&lt;/span>&lt;span class="p">)))))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;div class="src-block-caption">
&lt;span class="src-block-number">&lt;a href="#code-snippet--collapse-all-posts-fn">Code Snippet 1&lt;/a>:&lt;/span>
Function that collapses all the post subtrees in the current buffer
&lt;/div>
&lt;h2 id="binding-with-c-u-c-c-tab">Binding with &lt;code>C-u C-c TAB&lt;/code>&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#binding-with-c-u-c-c-tab">#&lt;/a>&lt;/h2>
&lt;p>The function is ready, but let&amp;rsquo;s now add a bit of convenience to it.&lt;/p>
&lt;p>If a point is under a subtree, &lt;code>C-c TAB&lt;/code> will collapse that subtree
while showing only Level 1 headings, and if a numeric prefix is used,
it will show only those many levels of headings. I decided to bind the
above function to &lt;code>C-u C-c TAB&lt;/code> because,&lt;/p>
&lt;ol>
&lt;li>The behavior of &lt;code>modi/org-hugo-collapse-all-posts&lt;/code> falls in the
same category as that of &lt;code>C-c TAB&lt;/code>.&lt;/li>
&lt;li>The &lt;code>C-u C-c ..&lt;/code> binding rolls off the fingers pretty
nicely 😃.&lt;/li>
&lt;/ol>
&lt;p>This &lt;em>binding&lt;/em> is achieved using one of my favorite Emacs features
.. the &lt;strong>advice&lt;/strong> system. The &lt;code>:before-until&lt;/code> &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html" title="Emacs Lisp: (info &amp;quot;(elisp) Advice Combinators&amp;quot;)">Advice Combinator&lt;/a> is used
here, which means that if the &lt;em>advising&lt;/em> function (below) returns a
&lt;em>nil&lt;/em>, the &lt;em>advised&lt;/em> or the original function &lt;code>org-ctrl-c-tab&lt;/code> is not
called.&lt;/p>
&lt;p>The &lt;em>advising&lt;/em> function below detects if the &lt;code>C-u&lt;/code> prefix argument is
used. If it is, the &lt;code>modi/org-hugo-collapse-all-posts&lt;/code> function is
called, otherwise the original &lt;code>org-ctrl-c-tab&lt;/code> function is called.&lt;/p>
&lt;p>&lt;a id="code-snippet--collapse-all-posts-binding">&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="hl">&lt;span class="lnt">4
&lt;/span>&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-emacs-lisp" data-lang="emacs-lisp">&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nb">defun&lt;/span> &lt;span class="nv">modi/org-ctrl-c-tab-advice&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kp">&amp;amp;rest&lt;/span> &lt;span class="nv">args&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Run &lt;/span>&lt;span class="ss">`modi/org-hugo-collapse-all-posts&amp;#39;&lt;/span>&lt;span class="s"> when
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">doing \\[universal-argument] \\[org-ctrl-c-tab].&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">let&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="nv">do-not-run-orig-fn&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nf">equal&lt;/span> &lt;span class="o">&amp;#39;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nv">current-prefix-arg&lt;/span>&lt;span class="p">)))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nb">when&lt;/span> &lt;span class="nv">do-not-run-orig-fn&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span>&lt;span class="nv">modi/org-hugo-collapse-all-posts&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">do-not-run-orig-fn&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">(&lt;/span>&lt;span class="nv">advice-add&lt;/span> &lt;span class="ss">&amp;#39;org-ctrl-c-tab&lt;/span> &lt;span class="nb">:before-until&lt;/span> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">modi/org-ctrl-c-tab-advice&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;div class="src-block-caption">
&lt;span class="src-block-number">&lt;a href="#code-snippet--collapse-all-posts-binding">Code Snippet 2&lt;/a>:&lt;/span>
Bind &lt;code>C-u C-c TAB&lt;/code> to call &lt;code>modi/org-hugo-collapse-all-posts&lt;/code>
&lt;/div>
&lt;h2 id="result">Result&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#result">#&lt;/a>&lt;/h2>
&lt;p>After evaluating the above two snippets, when I do &lt;code>C-u C-c TAB&lt;/code> in
my &amp;ldquo;blog posts&amp;rdquo; Org buffer, I see this:&lt;/p>
&lt;p>&lt;a id="figure--post-subtrees-collapsed">&lt;/a>&lt;/p>
&lt;figure>
&lt;a href="post-subtrees-collapsed.png">
&lt;img src="https://scripter.co/org-show-only-post-subtree-headings/post-subtrees-collapsed.png" alt="Figure 2: My &amp;ldquo;blog posts&amp;rdquo; Org buffer showing only the Post subtree headings"/> &lt;/a>&lt;figcaption>
&lt;p>
&lt;span class="figure-number">Figure 2: &lt;/span>My &amp;ldquo;blog posts&amp;rdquo; Org buffer showing only the Post subtree headings
&lt;/p>
&lt;/figcaption>&lt;/figure>
&lt;p>It matches &lt;a href="#figure--post-subtrees-collapsed-mockup">that earlier mockup&lt;/a> &amp;mdash; Mission accomplished! 💯&lt;/p></description><author>Kaushal.Modi@fakeEmailToMakeValidatorHappy.com (Kaushal Modi)</author><category domain="https://scripter.co/categories/emacs">emacs</category><category domain="https://scripter.co/categories/org">org</category><category domain="https://scripter.co/categories/elisp">elisp</category><category domain="https://scripter.co/tags/100daystooffload">100DaysToOffload</category><category domain="https://scripter.co/tags/subtree">subtree</category><category domain="https://scripter.co/tags/looping">looping</category><category domain="https://scripter.co/tags/advice">advice</category><guid>https://scripter.co/org-show-only-post-subtree-headings/</guid><pubDate>Thu, 16 Jun 2022 00:21:00 -0400</pubDate></item></channel></rss>