<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>looping on
A Scripter's Notes</title><link>https://scripter.co/tags/looping/</link><description>Recent content in looping
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/looping/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><item><title>Looping through Org mode headings</title><link>https://scripter.co/looping-through-org-mode-headings/</link><description>&lt;blockquote>Using the &lt;code>org-map-entries&lt;/code> API to loop through selected or all
headings in an Org file.&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-map-entries-api">&lt;code>org-map-entries&lt;/code> API&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#match-strings">&lt;em>MATCH&lt;/em> strings&lt;/a>&lt;/li>
&lt;li>&lt;a href="#comparison-types">Comparison Types&lt;/a>&lt;/li>
&lt;li>&lt;a href="#other-notes">Other notes&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#example-modifying-a-property-in-all-headings">Example: Modifying a property in all headings&lt;/a>&lt;/li>
&lt;li>&lt;a href="#org-map-entries-references">&lt;code>org-map-entries&lt;/code> References&lt;/a>&lt;/li>
&lt;/ul>
&lt;/div>
&lt;!--endtoc-->
&lt;p>&lt;a href="https://framapiaf.org/@postroutine/108313152514542145">Below question&lt;/a> on Mastodon by the user &lt;a href="https://framapiaf.org/@postroutine">@postroutine&lt;/a> inspired me to
write this post:&lt;/p>
&lt;blockquote>
&lt;p>I got a lot of Org-Mode headings and I want to modify their properties
(add, remove, edit). Is there a function to do the same modifications
on each heading?&lt;/p>
&lt;/blockquote>
&lt;p>I think that the best solution to that question is using the
&lt;strong>org-map-entries&lt;/strong> function.&lt;/p>
&lt;p>But somehow when replying to that question then, that wasn&amp;rsquo;t what
first came to my mind! .. when ironically that function is the &lt;a href="https://github.com/kaushalmodi/ox-hugo/blob/2b169e5e83d608e80f4faee9d681b98d87041f58/ox-hugo.el#L4781-L4788">main
function&lt;/a> that enables my preferred &lt;em>subtree-based flow&lt;/em> in &lt;code>ox-hugo&lt;/code>
😆. So I am writing this post to better ingrain the following
concept in myself ..&lt;/p>
&lt;div class="note">
&lt;p>If you need to loop through headings in an Org buffer, and especially
if you &lt;strong>need to modify that buffer&lt;/strong> in the process, use
&lt;strong>org-map-entries&lt;/strong>&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>.&lt;/p>
&lt;/div>
&lt;p>Next,&lt;/p>
&lt;ol>
&lt;li>I will give a give introduction to the &lt;code>org-map-entries&lt;/code> API.&lt;/li>
&lt;li>Then provide a super-short solution to the above question.&lt;/li>
&lt;/ol>
&lt;h2 id="org-map-entries-api">&lt;code>org-map-entries&lt;/code> API&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#org-map-entries-api">#&lt;/a>&lt;/h2>
&lt;p>I will give only a broad level overview on how to use this function. I
would encourage the reader to refer to the resources at the end of
this post to learn more about it.&lt;/p>
&lt;p>So let&amp;rsquo;s start by looking at this function&amp;rsquo;s signature:&lt;/p>
&lt;p>&lt;a id="code-snippet--org-map-entries-signature">&lt;/a>&lt;/p>
&lt;div class="highlight">&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="nv">org-map-entries&lt;/span> &lt;span class="nv">FUNC&lt;/span> &lt;span class="kp">&amp;amp;optional&lt;/span> &lt;span class="nv">MATCH&lt;/span> &lt;span class="nv">SCOPE&lt;/span> &lt;span class="kp">&amp;amp;rest&lt;/span> &lt;span class="nv">SKIP&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="src-block-caption">
&lt;span class="src-block-number">&lt;a href="#code-snippet--org-map-entries-signature">Code Snippet 1&lt;/a>:&lt;/span>
Signature of the &lt;code>org-map-entries&lt;/code> function
&lt;/div>
&lt;p>The &lt;code>org-map-entries&lt;/code> function iterates through all the headings
meeting the &lt;em>MATCH&lt;/em> criteria in the determined &lt;em>SCOPE&lt;/em>, and then calls
the specified function &lt;em>FUNC&lt;/em> at each of those headings.&lt;/p>
&lt;ul>
&lt;li>The &lt;code>FUNC&lt;/code> function accepts &lt;strong>no&lt;/strong> arguments and is called at the
beginning of each Org heading.&lt;/li>
&lt;li>The optional second argument &lt;em>MATCH&lt;/em> is either &lt;em>nil&lt;/em>, &lt;code>t&lt;/code> or a
&lt;em>search string&lt;/em>.
&lt;ul>
&lt;li>If &lt;em>MATCH&lt;/em> is &lt;em>nil&lt;/em> or &lt;code>t&lt;/code>, &lt;strong>all&lt;/strong> headings will be visited by the
iteration and &lt;em>FUNC&lt;/em> will be called on all of them.&lt;/li>
&lt;li>But if &lt;em>MATCH&lt;/em> is a string, the headings will first be filtered
based on that string and then the &lt;em>FUNC&lt;/em> will be called on only
those.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>For explanations on the optional &lt;em>SCOPE&lt;/em> and &lt;em>SKIP&lt;/em> arguments, see
&lt;a href="https://orgmode.org/manual/Using-the-Mapping-API.html" title="Emacs Lisp: (info &amp;quot;(org) Using the Mapping API&amp;quot;)">Org Info: Using the Mapping API&lt;/a> or &lt;kbd>C-h&lt;/kbd> &lt;kbd>f&lt;/kbd> &lt;code>org-map-entries&lt;/code> from
within Emacs.&lt;/li>
&lt;/ul>
&lt;p>Here&amp;rsquo;s a typical &lt;code>org-map-entries&lt;/code> call that loops through &lt;strong>all&lt;/strong> the
headings in the &lt;strong>visible&lt;/strong> buffer: &lt;code class="code-inline language-emacs-lisp">&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">some-function&lt;/span>&lt;span class="p">)&lt;/span>&lt;/code> where all the optional
argument values are &lt;em>nil&lt;/em>. Next, we&amp;rsquo;ll see some examples of
string-type &lt;em>MATCH&lt;/em> arguments used for filtering the headings.&lt;/p>
&lt;h3 id="match-strings">&lt;em>MATCH&lt;/em> strings&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#match-strings">#&lt;/a>&lt;/h3>
&lt;p>Below table shows few examples of match string patterns.&lt;/p>
&lt;p>&lt;a id="table--org-map-entries-search-strings">&lt;/a>&lt;/p>
&lt;div class="table-caption">
&lt;span class="table-number">&lt;a href="#table--org-map-entries-search-strings">Table 1&lt;/a>:&lt;/span>
String-type &lt;i>MATCH&lt;/i> argument examples for &lt;code>org-map-entries&lt;/code>
&lt;/div>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Search string&lt;/th>
&lt;th>Description&lt;/th>
&lt;th>Example&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TAG&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Tag name&lt;/td>
&lt;td>&lt;code>&amp;quot;foo&amp;quot;&lt;/code> matches all headings with that tag&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;{TAG REGEXP}&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Regexp matching tags&lt;/td>
&lt;td>&lt;code>&amp;quot;{f.*}&amp;quot;&lt;/code> matches all headings whose tags match that regexp&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TAG1+TAG2+..&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Tag set intersection&lt;/td>
&lt;td>&lt;code>&amp;quot;foo+bar&amp;quot;&lt;/code> matches all headings with both of those tags&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TAG1-TAG2+..&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Tag set difference&lt;/td>
&lt;td>&lt;code>&amp;quot;foo-bar&amp;quot;&lt;/code> matches all headings with &lt;code>foo&lt;/code> tag but without &lt;code>bar&lt;/code> tag&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TAG1&lt;/code>|​&lt;code>TAG2&lt;/code>|​&lt;code>..&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Tag set union or boolean &lt;em>OR&lt;/em>&lt;/td>
&lt;td>&lt;code>&amp;quot;foo&lt;/code>​|​&lt;code>bar&amp;quot;&lt;/code> matches all headings with either of those tags&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TAG1&amp;amp;TAG2&amp;amp;..&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Tag set intersection or boolean &lt;em>AND&lt;/em>&lt;/td>
&lt;td>&lt;code>&amp;quot;foo&amp;amp;bar&amp;quot;&lt;/code> is same as &lt;code>&amp;quot;foo+bar&amp;quot;&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;PROP&lt;/code>​=​&lt;code>\&amp;quot;STRVAL\&amp;quot;&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Specified property value matching a string&lt;/td>
&lt;td>&lt;code>&amp;quot;color&lt;/code>​=​&lt;code>\&amp;quot;blue\&amp;quot;&amp;quot;&lt;/code> matches all headings where &lt;code>color&lt;/code> property is &lt;code>blue&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;PROP&amp;lt;&amp;gt;\&amp;quot;STRVAL\&amp;quot;&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Specified property value not matching a string&lt;/td>
&lt;td>&lt;code>&amp;quot;color&amp;lt;&amp;gt;\&amp;quot;blue\&amp;quot;&amp;quot;&lt;/code> matches all headings where &lt;code>color&lt;/code> property is not &lt;code>blue&lt;/code>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;PROP&lt;/code>​=​&lt;code>{VAL REGEXP}&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Specified property value matching a regexp&lt;/td>
&lt;td>&lt;code>&amp;quot;color={b.*}&amp;quot;&lt;/code> matches all headings where &lt;code>color&lt;/code> property value matches &amp;lsquo;&lt;code>b.*&lt;/code>&amp;rsquo; regexp&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;PROP[OP]NUMVAL&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Specified property value compared with a numeric value&lt;/td>
&lt;td>&lt;code>&amp;quot;some_num&lt;/code>​&amp;gt;=​&lt;code>10&amp;quot;&lt;/code> matches all headings where &lt;code>some_num&lt;/code> property is &amp;gt;=10&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;LEVEL[OP]VAL&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Check value of headline&amp;rsquo;s special property &lt;em>LEVEL&lt;/em>&lt;/td>
&lt;td>&lt;code>&amp;quot;level&amp;gt;2&amp;quot;&lt;/code> matches all headlines at levels greater than 2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>&lt;code>&amp;quot;TODO[OP]\&amp;quot;STRVAL\&amp;quot;&amp;quot;&lt;/code>&lt;/strong>&lt;/td>
&lt;td>Check value of headline&amp;rsquo;s &lt;em>TODO&lt;/em> state&lt;/td>
&lt;td>&lt;code>&amp;quot;TODO&lt;/code>​=​&lt;code>\&amp;quot;DONE\&amp;quot;&amp;quot;&lt;/code> matches all headlines with &lt;em>TODO&lt;/em> state set to &amp;lsquo;DONE&amp;rsquo;&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="comparison-types">Comparison Types&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#comparison-types">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>If the comparison value is a plain number, a numerical comparison is
done, and the allowed operators are &amp;lsquo;&amp;lt;&amp;rsquo;, &amp;lsquo;=​&amp;rsquo;, &amp;lsquo;&amp;gt;&amp;rsquo;, &amp;lsquo;&amp;lt;=​&amp;rsquo;, &amp;lsquo;&amp;gt;=​&amp;rsquo;,
and &amp;lsquo;&amp;lt;&amp;gt;&amp;rsquo;.&lt;/li>
&lt;li>If the comparison value is enclosed in double quotes, a string
comparison is done, and the same operators are allowed.&lt;/li>
&lt;li>If the comparison value is enclosed in curly braces, a regexp match
is performed. For this comparison, only &amp;lsquo;=​&amp;rsquo; (regexp matches) and
&amp;lsquo;&amp;lt;&amp;gt;&amp;rsquo; (regexp does not match) operators are allowed.&lt;/li>
&lt;li>Comparison with dates and &lt;a href="https://orgmode.org/manual/Tag-Hierarchy.html" title="Emacs Lisp: (info &amp;quot;(org) Tag Hierarchy&amp;quot;)">Group Tags&lt;/a> is also possible. See
&lt;a href="https://orgmode.org/manual/Matching-tags-and-properties.html" title="Emacs Lisp: (info &amp;quot;(org) Matching tags and properties&amp;quot;)">Org Info: Matching tags and properties&lt;/a> for more details.&lt;/li>
&lt;/ul>
&lt;h3 id="other-notes">Other notes&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#other-notes">#&lt;/a>&lt;/h3>
&lt;ul>
&lt;li>The property names are case-insensitive. So these all work the
same: &lt;code>&amp;quot;COLOR&amp;lt;&amp;gt;\&amp;quot;blue\&amp;quot;&amp;quot;&lt;/code>, &lt;code>&amp;quot;color&amp;lt;&amp;gt;\&amp;quot;blue\&amp;quot;&amp;quot;&lt;/code>,
&lt;code>&amp;quot;Color&amp;lt;&amp;gt;\&amp;quot;blue\&amp;quot;&amp;quot;&lt;/code>.&lt;/li>
&lt;li>The &amp;ldquo;tag&amp;rdquo; and &amp;ldquo;property&amp;rdquo; matches can be mixed up using the boolean
&amp;lsquo;&lt;code>&amp;amp;&lt;/code>&amp;rsquo;, &amp;lsquo;&lt;code>|&lt;/code>&amp;rsquo;, &amp;lsquo;&lt;code>+&lt;/code>&amp;rsquo; and &amp;lsquo;&lt;code>-&lt;/code>​&amp;rsquo; operators. So searching
&amp;lsquo;&lt;code>+LEVEL=3+boss-TODO​=&amp;quot;DONE&amp;quot;&lt;/code>&amp;rsquo; lists all level three headlines
that have the tag &amp;lsquo;boss&amp;rsquo; and are &lt;span class="underline">not&lt;/span> marked with the TODO
keyword &amp;lsquo;DONE&amp;rsquo;.&lt;/li>
&lt;li>&amp;lsquo;&lt;code>&amp;amp;&lt;/code>&amp;rsquo; binds more strongly than &amp;lsquo;&lt;code>|&lt;/code>&amp;rsquo;.&lt;/li>
&lt;li>Grouping of match expressions using parentheses is not
supported.&lt;/li>
&lt;/ul>
&lt;h2 id="example-modifying-a-property-in-all-headings">Example: Modifying a property in all headings&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#example-modifying-a-property-in-all-headings">#&lt;/a>&lt;/h2>
&lt;p>Below is an example solution to the &lt;a href="https://framapiaf.org/@postroutine/108313152514542145">Mastoson question&lt;/a> that I
referenced in the beginning of this post.&lt;/p>
&lt;p>&lt;a id="code-snippet--set-props-all-headings">&lt;/a>&lt;/p>
&lt;div class="highlight">&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">test/set-property-at-heading&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;Function to be called at the beginning of an Org heading.&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">let&lt;/span> &lt;span class="p">((&lt;/span>&lt;span class="nv">el&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">org-element-at-point&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">org-set-property&lt;/span> &lt;span class="s">&amp;#34;foo&amp;#34;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">org-element-property&lt;/span> &lt;span class="nb">:title&lt;/span> &lt;span class="nv">el&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">org-map-entries&lt;/span> &lt;span class="nf">#&amp;#39;&lt;/span>&lt;span class="nv">test/set-property-at-heading&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="src-block-caption">
&lt;span class="src-block-number">&lt;a href="#code-snippet--set-props-all-headings">Code Snippet 2&lt;/a>:&lt;/span>
Dummy example showing how to set a property for all Org headings using &lt;code>org-map-entries&lt;/code>
&lt;/div>
&lt;ul>
&lt;li>It defines a function that parses the Org element at point using
&lt;code>org-element-at-point&lt;/code>, gets the &lt;code>title&lt;/code> property of the element
&lt;span class="sidenote-number">&lt;small class="sidenote">
This function is designed to be called by &lt;code>org-map-entries&lt;/code> and so
the point at the time of calling this function will always be on a
heading.
&lt;/small>&lt;/span>
, and sets that to the &lt;em>headline&lt;/em> element&amp;rsquo;s &lt;code>foo&lt;/code> property.&lt;/li>
&lt;li>The &lt;code>org-map-entries&lt;/code> call now simply calls this function on each
heading in the visible scope of the Org buffer.&lt;/li>
&lt;/ul>
&lt;h2 id="org-map-entries-references">&lt;code>org-map-entries&lt;/code> References&amp;nbsp;&lt;a class="headline-hash no-text-decoration" href="#org-map-entries-references">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>&lt;kbd>C-h&lt;/kbd> &lt;kbd>f&lt;/kbd> &lt;code>org-map-entries&lt;/code>&lt;/li>
&lt;li>&lt;a href="https://orgmode.org/manual/Using-the-Mapping-API.html" title="Emacs Lisp: (info &amp;quot;(org) Using the Mapping API&amp;quot;)">Org Info: Using the Mapping API&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://orgmode.org/manual/Matching-tags-and-properties.html" title="Emacs Lisp: (info &amp;quot;(org) Matching tags and properties&amp;quot;)">Org Info: Matching tags and properties&lt;/a>&lt;/li>
&lt;/ul>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>Org mode has another popular mapping/looping API function
&lt;strong>org-element-map&lt;/strong>. I won&amp;rsquo;t go into much detail about that in this post
&amp;mdash; I&amp;rsquo;ll just mention that &lt;code>org-element-map&lt;/code> is not the best choice if
you need to modify the original Org buffer. It&amp;rsquo;s main use is to loop
through a parsed &lt;abbr aria-label="Abstract Syntax Tree" tabindex=0>AST&lt;/abbr> of an Org buffer
and optional modify those elements &lt;em>in memory&lt;/em>.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></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/looping">looping</category><category domain="https://scripter.co/tags/100daystooffload">100DaysToOffload</category><guid>https://scripter.co/looping-through-org-mode-headings/</guid><pubDate>Wed, 18 May 2022 23:29:00 -0400</pubDate></item></channel></rss>