<?xml version="1.0" encoding="utf-8"?> 
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us">
    <generator uri="https://gohugo.io/" version="0.136.5">Hugo</generator><title type="html"><![CDATA[Emacs on Stéfan's blog]]></title>
    
    
    
            <link href="https://mentat.za.net/blog/tags/emacs/" rel="alternate" type="text/html" title="html" />
            <link href="https://mentat.za.net/blog/tags/emacs/atom.xml" rel="self" type="application/atom" title="atom" />
    <updated>2026-03-13T20:18:35+00:00</updated>
    
    
    
    
        <id>https://mentat.za.net/blog/tags/emacs/</id>
    
        
        <entry>
            <title type="html"><![CDATA[org-mode Day Planning with Time Blocks]]></title>
            <link href="https://mentat.za.net/blog/2026/01/27/org-mode-time-blocks/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2025/01/08/pomodoros-with-org-timer/?utm_source=atom_feed" rel="related" type="text/html" title="Pomodoros with org-timer" />
                <link href="https://mentat.za.net/blog/2026/01/26/gemini-for-code-patches-in-emacs/?utm_source=atom_feed" rel="related" type="text/html" title="Using Gemini for Code Patches in Emacs" />
                <link href="https://mentat.za.net/blog/2024/11/13/exporting-chromium-tabs/?utm_source=atom_feed" rel="related" type="text/html" title="Exporting List of Chromium Tabs" />
                <link href="https://mentat.za.net/blog/2023/01/12/google-tasks-to-org/?utm_source=atom_feed" rel="related" type="text/html" title="Google Tasks to Org" />
                <link href="https://mentat.za.net/blog/2020/04/28/voice-capture-org-tasks-on-android/?utm_source=atom_feed" rel="related" type="text/html" title="Voice capture org-mode tasks on Android" />
            
                <id>https://mentat.za.net/blog/2026/01/27/org-mode-time-blocks/</id>
            
            
            <published>2026-01-27T00:00:00+00:00</published>
            <updated>2026-01-27T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p>I&rsquo;ve discovered, over the years, that setting a clear intention is closely
correlated to a day well spent.  I know that, when I decide what I want
to do early in the morning—before being overwhelmed by email, Slack,
Zulip, Discord, and all the other little attention grabbers—that I
have a better chance of doing something I <em>care</em> about.</p>
<p>It seems like, in 2026, slow, intentional work is <em>en vogue</em>, with
books like Burkeman&rsquo;s &ldquo;Meditations for Mortals&rdquo; and Cal Newport&rsquo;s
&ldquo;Slow Productivity&rdquo; doing the rounds.  As my friends know, I am
fascinated (and inspired) by the Stoics and enjoy listening to the various teachers
on <a href="https://www.wakingup.com/">Waking Up</a>, many of whom echo the
same idea: that mindful, focused effort is vastly more satisfying than
responding to whatever seems urgent.</p>
<h2 id="time-blocking">
  Time-blocking
<a class="anchor" href="#time-blocking">#</a>
</h2>
<p>How we set intention is personal, and recommending any specific system
feels trite. However, I have found that, <em>for me</em>, planning a rough
schedule for the day—often called <em>time-blocking</em>—is a great way to
think about <em>what</em> I want to do, <em>how much</em> of it I want to do, and
<em>when</em> I want to do it.</p>
<p>Trying to follow such a schedule brings home many realities quickly:</p>
<ul>
<li>That the hours go by more quickly than one tends to think.
For me, this is a reminder that the day is precious.</li>
<li>That we often do a poor job at estimating how long work will take.
Typically, we imagine we can do much more in a day than is realistic.</li>
<li>That unscheduled interruptions are common. And others, like breaks for
exercise, eating, etc., should be taken into consideration.</li>
</ul>
<h2 id="implementation">
  Implementation
<a class="anchor" href="#implementation">#</a>
</h2>
<p>I use <code>org-mode</code> to outline my day, and have capture templates for each
<em>week</em> and each <em>day</em>. For this year, I have a file <code>2026.org</code> in which I
capture all those entries.</p>
<p>The day planner template is most relevant here:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-org" data-lang="org"><span class="line"><span class="cl"><span class="gu">**</span> %u
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Scan [[<span class="na">mu4e:query:maildir:/INBOX flag:flagged</span>][<span class="nt">pinned emails</span>]] for new tasks (max 10 mins)
</span></span><span class="line"><span class="cl"><span class="k">- [ ]</span> Scan [[<span class="na">https://github.com/notifications</span>][<span class="nt">GitHub</span>]] for new tasks (max 10 mins)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">***</span> Plan
</span></span><span class="line"><span class="cl">**** 
</span></span><span class="line"><span class="cl"><span class="gu">****</span> Lunch + walk &lt;%&lt;%Y-%m-%d %a 13:00-13:45&gt;&gt;
</span></span><span class="line"><span class="cl">**** 
</span></span><span class="line"><span class="cl"><span class="gu">****</span> Tidy up &lt;%&lt;%Y-%m-%d %a 16:45-17:00&gt;&gt;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">***</span> Notes
</span></span></code></pre></div><p>It is then hooked up to my <a href="https://orgmode.org/manual/Capture-templates.html"><code>org-capture-templates</code></a>.
I use <a href="https://orgmode.org/manual/Org-Indent-Mode.html">org-indent mode</a>, so all those heading stars collapse.</p>
<p>The part I&rsquo;d like to discuss in this post is the &ldquo;Plan&rdquo; section, where I outline my work for the day.</p>
<p>The time stamps in <code>org-mode</code> are neat: you&rsquo;ll see the lunch entry
goes from 13:00 to 13:45 (and this is how it is stored on disk), but
when modifying it in <code>org-mode</code> it is displayed for editing in the
minibuffer as <code>13:00+0:45</code>. This makes it very easy to adjust the
<em>duration</em> of an event. Note that the day timestamp (<code>%u</code>) is
<a href="https://orgmode.org/manual/Timestamps.html#index-timestamp_002c-inactive">inactive</a>,
whereas the time blocks are active, so that only the latter appear in
today&rsquo;s Agenda view.</p>








<figure>
    <img
        
            sizes="(min-width: 35em) 1200px, 100vw"
              
            srcset='
            
                   https://mentat.za.net/blog/2026/01/27/org-mode-time-blocks/2026-01-27-timeblocks_hu8531388192944842114.png 480w,
            
                   https://mentat.za.net/blog/2026/01/27/org-mode-time-blocks/2026-01-27-timeblocks_hu1905747191668622867.png 800w,
            
                   
            
                   
            '

            
            
            src="https://mentat.za.net/blog/2026/01/27/org-mode-time-blocks/2026-01-27-timeblocks_hu1905747191668622867.png"
            

        
            alt="A screenshot of my time block planning in Emacs for 2026-01-27"/> <figcaption>
            <h4>My time block planning for 2026-01-27, showing active timestamps following one another.</h4>
        </figcaption>
</figure>

<h3 id="elisp-functions">
  Elisp functions
<a class="anchor" href="#elisp-functions">#</a>
</h3>
<p>The above template is sufficient for doing time blocking in
org-mode. However, we can reduce some friction in how we <em>use</em> it by
adding some utility functions for common activities.</p>
<p>Here are three such functions that help me to craft and modify my
daily plan smoothly:</p>
<ol>
<li>
<p><strong>Quickly navigate to today&rsquo;s plan</strong></p>
<p>This command is invoked inside <code>2026.org</code>, and navigates to the current week, then day, then to the end of the &ldquo;Plan&rdquo; entry.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-jump-to-today-plan</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Jump to the end of the &#39;Plan&#39; heading under today&#39;s date headline.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">today</span> <span class="p">(</span><span class="nf">regexp-quote</span> <span class="p">(</span><span class="nf">format-time-string</span> <span class="p">(</span><span class="nv">org-time-stamp-format</span> <span class="no">nil</span> <span class="no">t</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">today-re</span> <span class="p">(</span><span class="nf">concat</span> <span class="s">&#34;^\\*+ .*?&#34;</span> <span class="nv">today</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">goto-char</span> <span class="p">(</span><span class="nf">point-min</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nv">not</span> <span class="p">(</span><span class="nf">re-search-forward</span> <span class="nv">today-re</span> <span class="no">nil</span> <span class="no">t</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">message</span> <span class="s">&#34;Heading matching %s not found.&#34;</span> <span class="nv">today</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nv">org-reveal</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nb">save-restriction</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nv">org-narrow-to-subtree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">goto-char</span> <span class="p">(</span><span class="nf">point-min</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="c1">;; Matches &#39;Plan&#39; heading and optional trailing tags</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nf">re-search-forward</span> <span class="s">&#34;^\\*+ Plan\\(?:[ \t]*\\(:[[:alnum:]_@:]+:\\)\\)?[ \t]*$&#34;</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nv">org-end-of-subtree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nf">widen</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nf">message</span> <span class="s">&#34;No exact &#39;Plan&#39; heading found under today&#39;s date.&#34;</span><span class="p">))))))</span>
</span></span></code></pre></div><p>It specifically searches for a <code>* Plan</code> heading, so if you modify the
template be sure to update the regexp accordingly.</p>
</li>
<li>
<p><strong>Add a new planner entry, which follows the previous</strong></p>
<p>This function takes the <em>end</em> time of the previous entry, and uses it as the <em>start</em> time for a new entry.</p>
<p>It tries to be somewhat clever at guessing your intention:</p>
<ul>
<li>If you invoke it on a blank line, it searches upward for the previous timestamp, and turns the current line into a heading.</li>
<li>If invoked inside a section that already has a timestamp, it turns the <em>next</em> line into a timestamped heading.</li>
<li>If invoked on a heading line without a timestamp, it adds the timestamp to the end, preserving cursor position.
<p></p>
</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-plan-next</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Create a new day plan entry following on the current or previous lines&#39;s active timestamp.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">ts-found</span> <span class="p">(</span><span class="nb">save-excursion</span>
</span></span><span class="line"><span class="cl">                     <span class="p">(</span><span class="nf">end-of-line</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                     <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nf">re-search-backward</span> <span class="nv">org-ts-regexp0</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                       <span class="p">(</span><span class="nb">let</span> <span class="p">((</span><span class="nv">ctx</span> <span class="p">(</span><span class="nv">org-element-context</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">                         <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nf">eq</span> <span class="p">(</span><span class="nv">org-element-type</span> <span class="nv">ctx</span><span class="p">)</span> <span class="ss">&#39;timestamp</span><span class="p">)</span> <span class="nv">ctx</span><span class="p">)))))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">is-blank</span> <span class="p">(</span><span class="nv">string-blank-p</span> <span class="p">(</span><span class="nf">buffer-substring</span> <span class="p">(</span><span class="nf">line-beginning-position</span><span class="p">)</span> <span class="p">(</span><span class="nf">line-end-position</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">is-header</span> <span class="p">(</span><span class="nv">org-at-heading-p</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="c1">;; Check if the found timestamp is actually on the current line</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">on-current-line</span> <span class="p">(</span><span class="nb">and</span> <span class="nv">ts-found</span>
</span></span><span class="line"><span class="cl">                               <span class="p">(</span><span class="nf">&gt;=</span> <span class="p">(</span><span class="nv">org-element-property</span> <span class="nb">:begin</span> <span class="nv">ts-found</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                                   <span class="p">(</span><span class="nf">line-beginning-position</span><span class="p">)))))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">if</span> <span class="p">(</span><span class="nv">not</span> <span class="nv">ts-found</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="ne">user-error</span> <span class="s">&#34;No timestamp found above point&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nb">cond</span>
</span></span><span class="line"><span class="cl">       <span class="c1">;; Already has TS OR is plain text -&gt; new heading below</span>
</span></span><span class="line"><span class="cl">       <span class="p">((</span><span class="nb">or</span> <span class="nv">on-current-line</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nv">not</span> <span class="nv">is-blank</span><span class="p">)</span> <span class="p">(</span><span class="nv">not</span> <span class="nv">is-header</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">end-of-line</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nv">org-insert-heading</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">save-excursion</span> <span class="p">(</span><span class="nv">stefanv/insert-formatted-org-ts</span> <span class="nv">ts-found</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">       <span class="c1">;; Current line is blank -&gt; turn into heading here</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">is-blank</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nv">org-insert-heading</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">save-excursion</span> <span class="p">(</span><span class="nv">stefanv/insert-formatted-org-ts</span> <span class="nv">ts-found</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">       <span class="c1">;; Current line is a header (no TS) -&gt; append TS and return cursor</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="no">t</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">save-excursion</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nf">end-of-line</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nv">stefanv/insert-formatted-org-ts</span> <span class="nv">ts-found</span><span class="p">)))))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/insert-formatted-org-ts</span> <span class="p">(</span><span class="nv">ts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Helper to insert formatted timestamp with exactly one preceding space.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">just-one-space</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nf">insert</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;&lt;%s %02d:%02d&gt;&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">org-format-timestamp</span> <span class="nv">ts</span> <span class="s">&#34;%Y-%m-%d %a&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">org-element-property</span> <span class="nb">:hour-end</span> <span class="nv">ts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">org-element-property</span> <span class="nb">:hour-start</span> <span class="nv">ts</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">org-element-property</span> <span class="nb">:minute-end</span> <span class="nv">ts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">org-element-property</span> <span class="nb">:minute-start</span> <span class="nv">ts</span><span class="p">)</span> <span class="mi">0</span><span class="p">))))</span>
</span></span></code></pre></div><p>If you use it often, you can bind the function to a key:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nv">keymap-set</span> <span class="nv">org-mode-map</span> <span class="s">&#34;C-c C-x p&#34;</span> <span class="nf">#&#39;</span><span class="nv">stefanv/org-plan-next</span><span class="p">)</span>
</span></span></code></pre></div></li>
<li>
<p>Move all timestamps in a region forward by N minutes.</p>
<p>Sometimes, a day runs away from us, or we get carried away and miss the end of a timeblock.
At that point, you&rsquo;d likely want to shift your entire day forward.
The following function lets you select several planner items and shift them all by N minutes (positive or negative).
If no region is selected, operate on the current line.</p>
<p>There&rsquo;s some fancy footwork to ensure that the surrounding org buffer
is re-rendered, especially when using
<a href="https://github.com/minad/org-modern"><code>org-modern</code></a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-shift-timestamps-in-region</span> <span class="p">(</span><span class="nv">minutes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Shift all active timestamps in the region (or current line) forward by MINUTES minutes.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span> <span class="s">&#34;nMinutes to shift: &#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">let*</span> <span class="p">((</span><span class="nv">region-active</span> <span class="p">(</span><span class="nv">use-region-p</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">beg</span> <span class="p">(</span><span class="nb">if</span> <span class="nv">region-active</span> <span class="p">(</span><span class="nf">region-beginning</span><span class="p">)</span> <span class="p">(</span><span class="nf">line-beginning-position</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">end</span> <span class="p">(</span><span class="nf">copy-marker</span> <span class="p">(</span><span class="nb">if</span> <span class="nv">region-active</span> <span class="p">(</span><span class="nf">region-end</span><span class="p">)</span> <span class="p">(</span><span class="nf">line-end-position</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">         <span class="c1">;; Regex for active timestamps: matches &lt; followed by anything until &gt;</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">active-ts-re</span> <span class="s">&#34;&lt;\\([0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.*?\\)&gt;&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="c1">;; Allow undoing everything in one step</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">atomic-change-group</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nb">save-excursion</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">goto-char</span> <span class="nv">beg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1">;; Shift active timestamps</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">while</span> <span class="p">(</span><span class="nf">re-search-forward</span> <span class="nv">active-ts-re</span> <span class="nv">end</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nb">save-excursion</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nf">goto-char</span> <span class="p">(</span><span class="nf">match-beginning</span> <span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nv">org-timestamp-change</span> <span class="nv">minutes</span> <span class="ss">&#39;minute</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nf">fboundp</span> <span class="ss">&#39;org-element-cache-refresh</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">              <span class="p">(</span><span class="nv">org-element-cache-refresh</span> <span class="p">(</span><span class="nf">point</span><span class="p">)))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">;; Re-align tags for any headlines in the range</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">goto-char</span> <span class="nv">beg</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nb">while</span> <span class="p">(</span><span class="nf">re-search-forward</span> <span class="nv">org-outline-regexp-bol</span> <span class="nv">end</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nv">org-align-tags</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">;; Refresh</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">font-lock-flush</span> <span class="nv">beg</span> <span class="nv">end</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">set-marker</span> <span class="nv">end</span> <span class="no">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">message</span> <span class="s">&#34;Shifted active timestamps by %s minutes.&#34;</span> <span class="nv">minutes</span><span class="p">)))</span>
</span></span></code></pre></div></li>
</ol>
<h2 id="conclusion">
  Conclusion
<a class="anchor" href="#conclusion">#</a>
</h2>
<p>I&rsquo;ve presented three utility functions that help me quickly plan and
organize my day. I&rsquo;d love to hear from you how you plan yours!</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="productivity" label="productivity" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Using Gemini for Code Patches in Emacs]]></title>
            <link href="https://mentat.za.net/blog/2026/01/26/gemini-for-code-patches-in-emacs/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2025/01/08/pomodoros-with-org-timer/?utm_source=atom_feed" rel="related" type="text/html" title="Pomodoros with org-timer" />
                <link href="https://mentat.za.net/blog/2018/10/31/using-org-mode-with-neomutt/?utm_source=atom_feed" rel="related" type="text/html" title="Linking to emails in org-mode (using neomutt)" />
                <link href="https://mentat.za.net/blog/2016/12/15/org-mode-header-search/?utm_source=atom_feed" rel="related" type="text/html" title="Search headers in org-mode" />
                <link href="https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/?utm_source=atom_feed" rel="related" type="text/html" title="Adobe&#39;s new free font: Source Code Pro" />
                <link href="https://mentat.za.net/blog/2012/09/25/emacs-package-management/?utm_source=atom_feed" rel="related" type="text/html" title="Emacs package management" />
            
                <id>https://mentat.za.net/blog/2026/01/26/gemini-for-code-patches-in-emacs/</id>
            
            
            <published>2026-01-26T00:00:00+00:00</published>
            <updated>2026-01-26T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p>To ensure that my skepticism of LLMs did not blind me to progress,
and to keep my finger on the pulse, I&rsquo;ve been incorporating them into
my Emacs config, starting with
<a href="https://github.com/karthink/gptel">gptel</a> and, more recently,
<a href="https://github.com/kmontag/macher">macher</a>. In December, I took
another look at Gemini, and noticed a <em>significant</em> improvement over
Flash 2.5 with the arrival of Flash 3 Preview.</p>
<p>In this post, I share the configuration I currently use, and
mention some open questions I still hope to address.</p>
<h2 id="tools">
  Tools
<a class="anchor" href="#tools">#</a>
</h2>
<p><code>gptel</code> is a beautifully clean and simple interface for LLM chat.
Despite its simplicity, it actually has fairly advanced functionality,
which includes MCP integration, introspection of queries, multi-modal
input (such as images), and tool usage (extending LLMs with access to
elisp functions of your choosing).</p>
<p><code>macher</code> runs on top of <code>gptel</code>. It provides a &ldquo;pseudo-agentic&rdquo;
workflow, in which you provide the LLM context about your current
project, such as the list of files. It also defines several tools that
the LLM can use, such as the ability to read files. You can use
<code>macher</code> to generate a patch, which you then review, apply the
parts you like, or ask <code>macher</code> for further improvements.</p>
<h2 id="configuration">
  Configuration
<a class="anchor" href="#configuration">#</a>
</h2>
<p>The <code>macher</code> installation simply follows the recommendations in its README:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">use-package</span> <span class="nv">macher</span>
</span></span><span class="line"><span class="cl">  <span class="nb">:custom</span>
</span></span><span class="line"><span class="cl">  <span class="c1">;; better folding and source block highlighting of the reasoning process</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">macher-action-buffer-ui</span> <span class="ss">&#39;org</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="nb">:config</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">macher-install</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">macher-enable</span><span class="p">))</span>
</span></span></code></pre></div><p>And here is the basic <code>gptel</code> configuration, ensuring that <code>macher</code> is pre-loaded:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">use-package</span> <span class="nv">gptel</span>
</span></span><span class="line"><span class="cl">  <span class="nb">:commands</span> <span class="p">(</span><span class="nv">gptel</span> <span class="nv">gptel-mode</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="nb">:config</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">require</span> <span class="ss">&#39;macher</span><span class="p">))</span>
</span></span></code></pre></div><p>Now the model definition for Gemini, to access the latest 3.0 models:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="c1">;; https://ai.google.dev/gemini-api/docs/models</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">setq</span>
</span></span><span class="line"><span class="cl">  <span class="nv">gptel-model</span> <span class="ss">&#39;gemini-3-flash-preview</span>
</span></span><span class="line"><span class="cl">  <span class="nv">gptel-backend</span> <span class="p">(</span><span class="nv">gptel-make-gemini</span> <span class="s">&#34;Gemini&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="nb">:key</span> <span class="s">&#34;&lt;Get your key at aistudio.google.com&gt;&#34;</span>
</span></span><span class="line"><span class="cl">                  <span class="nb">:stream</span> <span class="no">t</span>
</span></span><span class="line"><span class="cl">                  <span class="nb">:models</span> <span class="o">&#39;</span><span class="p">(</span><span class="nv">gemini-3-flash-preview</span>
</span></span><span class="line"><span class="cl">                            <span class="nv">gemini-3-pro-preview</span>
</span></span><span class="line"><span class="cl">                            <span class="nv">gemini-2.5-flash</span>
</span></span><span class="line"><span class="cl">                            <span class="nv">gemini-2.5-pro</span><span class="p">)))</span>
</span></span></code></pre></div><p>Note how you list the models you want to choose from, and then pick the default.</p>
<p>You will need an API key, which you can generate at
<a href="https://aistudio.google.com">https://aistudio.google.com</a>.  I&rsquo;m pretty sure you also need to
activate billing to access <code>gemini-3-flash-preview</code>, but let me know
if you succeed without doing that. My total cost, after playing around
with it a bunch this week, was ~3 USD.</p>
<p>If your Emacs config lives in a public repository or on an untrusted
machine, you&rsquo;ll want to be careful in adding the token to it.  <code>gptel</code>
<a href="https://github.com/karthink/gptel?tab=readme-ov-file#optional-securing-api-keys-with-authinfo">automatically uses tokens listed in <code>~/.authinfo</code></a>.
See <a href="https://www.masteringemacs.org/article/keeping-secrets-in-emacs-gnupg-auth-sources">Mastering Emacs</a>
for more on
<a href="https://www.gnu.org/software/emacs/manual/html_mono/auth.html">auth-source</a>.</p>
<h3 id="adding-google-search">
  Adding Google search
<a class="anchor" href="#adding-google-search">#</a>
</h3>
<p><strong>EDIT: I&rsquo;ve since noticed that, while adding the search tool this way works, it also messes up macher. So, don&rsquo;t try this yet until #750 is resolved.</strong></p>
<p>The above configuration works fine, but I noticed that some answers
were outdated.  Gemini supports &ldquo;grounding&rdquo; via Google Search. For
example, instead of telling you that TypeScript 5.3 is the newest
release (which it was, at the time of its training), it can use Google
Search to verify that, in fact, the latest version is 5.9.</p>
<p><a href="https://github.com/karthink/gptel/issues/750">gptel#750</a> tracks the
issue, but in the meantime you can manually adjust the query sent to
Google, and tell it to enable <a href="https://ai.google.dev/gemini-api/docs/google-search">Grounding with Google Search</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="c1">;; Enable Google Search capability for gemini</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">cl-defmethod</span> <span class="nv">gptel--request-data</span> <span class="nb">:around</span> <span class="p">((</span><span class="nv">backend</span> <span class="nv">gptel-gemini</span><span class="p">)</span> <span class="nv">prompts</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Add search ability to Gemini requests.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nf">plist-put</span> <span class="p">(</span><span class="nv">cl-call-next-method</span><span class="p">)</span> <span class="nb">:tools</span> <span class="p">(</span><span class="nf">append</span> <span class="o">&#39;</span><span class="p">(</span><span class="nb">:google_search</span> <span class="p">()))))</span>
</span></span></code></pre></div><p>This is obviously just a temporary hack, until #750 can be resolved.</p>
<p>Grounding with Search may incur additional costs, as per the <a href="https://ai.google.dev/gemini-api/docs/pricing">Gemini API docs</a>:</p>
<blockquote>
<p>5,000 prompts per month (free), then (Coming soon**) $14 / 1,000 search queries</p>
</blockquote>
<h2 id="usage">
  Usage
<a class="anchor" href="#usage">#</a>
</h2>
<p>To generate a patch on your current project, you must do two things:</p>
<ol>
<li>
<p><strong>Select project:</strong> Tell <code>macher</code> which project you&rsquo;re working
on. The easiest way to do this is to open a gptel buffer (which you
can give any name you like, e.g. <code>gemini:add-tests</code>) and then <code>M-x cd</code> (change directory) into your project.</p>
<p>I haven&rsquo;t checked, but I suspect this requires the project to be
under version control.</p>
</li>
<li>
<p><strong>Activate macher:</strong> As part of your query, mention <code>@macher</code>
anywhere to enable it. E.g., <code>@macher add unit test scaffolding</code>. <code>C-c &lt;enter&gt;</code> executes the query.</p>
<p>If you type <code>@macher</code> and it does not get highlighted with a little
box surrounding the text, then <code>macher</code> isn&rsquo;t correctly
installed. Try running <code>M-: (macher-install)</code> manually.</p>
<p>You can add additional context to a query (e.g., a programming
guidance document outside of the project) using <code>gptel-add</code> (this
is standard <code>gptel</code> functionality).</p>
</li>
</ol>
<p>While the query is executing, it displays a folded reasoning
block. You can type TAB to unfold it, and watch the various steps the
LLM takes. After a while, a patch will be generated in a separate
window.</p>
<p>You can apply the entire patch using <code>diff-apply-buffer</code>, or single
parts of the patch with <code>diff-apply-hunk</code>.</p>
<h2 id="issues-to-resolve">
  Issues to resolve
<a class="anchor" href="#issues-to-resolve">#</a>
</h2>
<p>With my configuration, <code>diff-apply-buffer</code> works fine as long as only
existing files are modified. When new files need to be created, it
misunderstands the file prefix in the patch, and fails to
auto-complete its name. I filed an issue to discuss that with the
macher author at
<a href="https://github.com/kmontag/macher/issues/45">macher#45</a>, and
hopefully can post an update soon.</p>
<h2 id="conclusion">
  Conclusion
<a class="anchor" href="#conclusion">#</a>
</h2>
<p>LLMs recently seem to have undergone a phase change in coding
ability.  Of course, even in this phase any code generated needs to be
very carefully reviewed and tested. <a href="https://x.com/karpathy/status/2015883857489522876">Andrej Karpathy&rsquo;s tweet earlier
today</a> summarizes
where we stand quite well (I recommend reading the top comments too).</p>
<p>E.g., when talking about the new capability, he also warns:</p>
<blockquote>
<p>The nearest neighbor really is some kind of a junior engineer. Its
ideas about what experiments to run [&hellip;] have been
surprisingly bad, but its execution on ideas I&rsquo;ve given it have been
surprisingly good. — <a href="https://x.com/karpathy/status/2015888674739912910">https://x.com/karpathy/status/2015888674739912910</a></p>
</blockquote>
<blockquote>
<p>The mistakes have changed a lot - they are not simple syntax errors
anymore, they are subtle conceptual errors that a slightly sloppy,
hasty junior dev might do. The most common category is that the
models make wrong assumptions on your behalf and just run along with
them without checking. They also don&rsquo;t manage their confusion, they
don&rsquo;t seek clarifications, they don&rsquo;t surface inconsistencies, they
don&rsquo;t present tradeoffs, they don&rsquo;t push back when they should, and
they are still a little too sycophantic. — <a href="https://x.com/karpathy/status/2015883857489522876">https://x.com/karpathy/status/2015883857489522876</a></p>
</blockquote>
<p>So, while we should tread with care, there are exciting avenues to explore. I&rsquo;ve been developing open source computational libraries for a long time, and as <a href="https://scientific-python.org">our ecosystem</a> grows I notice myself spending more and more time on maintenance, and less and less time on reading papers and developing new features. My hope is that LLMs will free our small communities—who have very limited time and resources—from repetitive, tiring maintenance tasks, so we may return to what we love to do: crafting intuitive APIs around innovative algorithms that, in turn, enable real-world science.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="llms" label="LLMs" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Pomodoros with org-timer]]></title>
            <link href="https://mentat.za.net/blog/2025/01/08/pomodoros-with-org-timer/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2024/11/13/exporting-chromium-tabs/?utm_source=atom_feed" rel="related" type="text/html" title="Exporting List of Chromium Tabs" />
                <link href="https://mentat.za.net/blog/2023/01/12/google-tasks-to-org/?utm_source=atom_feed" rel="related" type="text/html" title="Google Tasks to Org" />
                <link href="https://mentat.za.net/blog/2020/04/28/voice-capture-org-tasks-on-android/?utm_source=atom_feed" rel="related" type="text/html" title="Voice capture org-mode tasks on Android" />
                <link href="https://mentat.za.net/blog/2018/10/31/using-org-mode-with-neomutt/?utm_source=atom_feed" rel="related" type="text/html" title="Linking to emails in org-mode (using neomutt)" />
                <link href="https://mentat.za.net/blog/2016/12/15/org-mode-header-search/?utm_source=atom_feed" rel="related" type="text/html" title="Search headers in org-mode" />
            
                <id>https://mentat.za.net/blog/2025/01/08/pomodoros-with-org-timer/</id>
            
            
            <published>2025-01-08T00:00:00+00:00</published>
            <updated>2025-01-08T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p><em>A New Year! Create the <code>2025.org</code> journal file, channel all that post-break energy, and get ready to be Super Productive™! 💪 Oh, what&rsquo;s this&hellip; <a href="https://charlbotha.com/til/Show-Emacs-org-timer-countdown-in-macOS-menubar">a post on how to track Pomodoros using org mode</a>. 👀 Of course, I didn&rsquo;t bite. Of course not.</em></p>
<p>Productivity people sure spend a lot of time writing a lot about little; and the <strong>Pomodoro technique</strong> is no exception. It can be summarized as:</p>
<blockquote>
<p>Set a timer, get to work, take a break. Repeat, take a break.</p>
</blockquote>
<p>There&rsquo;s way too much productivity literature out there, and much of it comes down to: <em>find a way to get your butt in the seat and start [writing/typing/reading/editing/&hellip;]</em>. The new wave of productivity literature, or <a href="https://www.oliverburkeman.com/">&ldquo;anti-productivity&rdquo; literature</a>, tells us to face the facts: you&rsquo;re never going to finish your TODO list, so give up already, be in the present, and focus on what&rsquo;s most important (or, whatever, just <a href="https://www.wakingup.com/">be present</a>).</p>
<p>Sometimes, I get in the flow easily, and don&rsquo;t need any tricks. But other times, especially with those slightly-mundane-tasks-that-still-need-to-get-done, I need a little nudge not get started and not get distracted (by something more interesting which, in this case, may well be everything).</p>
<p>For me, the Pomodoro method is helpful for that purpose. And, <strong>because distraction abounds</strong>, it&rsquo;s helpful to <strong>have the timer as well as the topic</strong> you&rsquo;re supposed to be focused on <strong>displayed somewhere visible</strong>.</p>
<p>When I saw Charl&rsquo;s post, I was delighted because:</p>
<ol>
<li>It relies on <code>org-mode</code>, which I already use;</li>
<li>it does everything I used <code>org-pomodoro</code> for, but more simply;</li>
<li>it provides an easy path towards integration with <a href="https://github.com/Alexays/Waybar">waybar</a> (he uses xbar for macOS, but same idea); and,</li>
<li>as observed by Charl, it does not interfere with other org clocks.</li>
</ol>
<p>So, what follows here is a slight modification of <a href="https://charlbotha.com/til/Show-Emacs-org-timer-countdown-in-macOS-menubar">Charl&rsquo;s method</a>, which in turn combines previous approaches by
<a href="https://systemcrafters.net/emacs-shorts/pomodoro-timer/">David Wilson (System Crafters)</a> and <a href="https://xiangji.me/2020/12/27/displaying-orgmode-clock-in-menu-bar/">Xiang Ji</a>.</p>
<h2 id="emacs-configuration-basic">
  Emacs configuration: basic
<a class="anchor" href="#emacs-configuration-basic">#</a>
</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nf">require</span> <span class="ss">&#39;org-timer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">;; If you want sound when the pomodoro is over</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">setq</span> <span class="nv">org-clock-sound</span> <span class="p">(</span><span class="nv">expand-file-name</span> <span class="s">&#34;~/sounds/bell.wav&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">;; And if you&#39;d like to have a keyboard shortcut for starting a Pomodoro</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">org-timer-start-pomodoro</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">setq</span> <span class="nv">current-prefix-arg</span> <span class="mi">25</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">call-interactively</span> <span class="ss">&#39;org-timer-set-timer</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">global-set-key</span> <span class="p">(</span><span class="nv">kbd</span> <span class="s">&#34;C-c P&#34;</span><span class="p">)</span> <span class="ss">&#39;org-timer-start-pomodoro</span><span class="p">)</span>
</span></span></code></pre></div><p>Now, when you press <code>C-c P</code>, a new pomodoro timer is started (you&rsquo;ll see it in the mode line). You can also start it with <code>org-timer-set-timer</code>. After 25 minutes, when the Pomodoro is done, a system notification is displayed. Tada!</p>
<h2 id="display-pomodoro-status-on-waybar">
  Display pomodoro status on waybar
<a class="anchor" href="#display-pomodoro-status-on-waybar">#</a>
</h2>
<p>To display org-timer&rsquo;s status on waybar, we&rsquo;ll query emacs (via emacsclient<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>) for its current value.</p>
<p>Here&rsquo;s the function, <code>org-timer-waybar-repr</code>, which generates the status text:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">html-escape-string</span> <span class="p">(</span><span class="nc">string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Escape special characters in STRING for HTML.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">result</span> <span class="s">&#34;&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">dolist</span> <span class="p">(</span><span class="nf">char</span> <span class="p">(</span><span class="nv">string-to-list</span> <span class="nc">string</span><span class="p">)</span> <span class="nv">result</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="k">setq</span> <span class="nv">result</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="nv">concat</span> <span class="nv">result</span>
</span></span><span class="line"><span class="cl">                    <span class="p">(</span><span class="nv">pcase</span> <span class="nf">char</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">?\&amp;</span> <span class="s">&#34;&amp;amp;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">?\&lt;</span> <span class="s">&#34;&amp;lt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">?\&gt;</span> <span class="s">&#34;&amp;gt;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">?\&#34;</span> <span class="s">&#34;&amp;quot;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">?\&#39;</span> <span class="s">&#34;&amp;#39;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">_</span> <span class="p">(</span><span class="nv">char-to-string</span> <span class="nf">char</span><span class="p">))))))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">org-timer-minutes-to-string</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Remaining org-timer minutes, rounded up to nearest minute, as string.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">time-string</span> <span class="p">(</span><span class="nv">org-timer-value-string</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">parts</span> <span class="p">(</span><span class="nv">split-string</span> <span class="nv">time-string</span> <span class="s">&#34;:&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">hours</span> <span class="p">(</span><span class="nv">string-to-number</span> <span class="p">(</span><span class="nf">nth</span> <span class="mi">0</span> <span class="nv">parts</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">minutes</span> <span class="p">(</span><span class="nv">string-to-number</span> <span class="p">(</span><span class="nf">nth</span> <span class="mi">1</span> <span class="nv">parts</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">seconds</span> <span class="p">(</span><span class="nv">string-to-number</span> <span class="p">(</span><span class="nf">nth</span> <span class="mi">2</span> <span class="nv">parts</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">total-minutes</span> <span class="p">(</span><span class="nf">+</span> <span class="p">(</span><span class="nf">*</span> <span class="nv">hours</span> <span class="mi">60</span><span class="p">)</span> <span class="nv">minutes</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">seconds</span> <span class="mf">60.0</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">number-to-string</span> <span class="p">(</span><span class="nf">ceiling</span> <span class="nv">total-minutes</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">org-timer-waybar-repr</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Format org-timer status for waybar&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nf">not</span> <span class="p">(</span><span class="nf">boundp</span> <span class="ss">&#39;org-timer-countdown-timer</span><span class="p">))</span> <span class="p">(</span><span class="nf">not</span> <span class="nv">org-timer-countdown-timer</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;🤗&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">html-escape-string</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nv">concat</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;🍅 &#34;</span><span class="p">(</span><span class="nv">org-timer-minutes-to-string</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;  🎯 &#34;</span> <span class="p">(</span><span class="nv">org-link-display-format</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">substring-no-properties</span> <span class="nv">org-timer-countdown-timer-title</span><span class="p">))))))</span>
</span></span></code></pre></div><p>Next, we need a script, say <code>org-timer-remaining</code>, to access this text:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1">#/bin/sh</span>
</span></span><span class="line"><span class="cl">emacsclient --eval <span class="s1">&#39;(org-timer-waybar-repr)&#39;</span> <span class="p">|</span> sed <span class="s1">&#39;s/&#34;//g&#39;</span>
</span></span></code></pre></div><p>(That <code>sed</code> bit is to strip the surrounding quotes from the resulting string.)</p>
<p>To display it in waybar, we need to tell waybar to call the script at a regular interval. In <code>~/.config/waybar/config</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="err">...,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;modules-left&#34;</span><span class="p">:</span> <span class="p">[</span><span class="err">...</span><span class="p">,</span> <span class="s2">&#34;custom/org_timer&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="err">...,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;custom/org_timer&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;~/scripts/org-timer-remaining&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;interval&#34;</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="nt">&#34;signal&#34;</span><span class="p">:</span> <span class="mi">8</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Now, after starting a timer, you should see something like:</p>
<p><img src="waybar-org-timer.png" alt="Waybar displaying org-timer status"></p>
<p>One little trick 🪄: do you notice the <code>&quot;signal&quot;: 8</code> above? You don&rsquo;t need it, but it&rsquo;s a mechanism provided by <code>waybar</code> for externally refreshing a widget. In this case, if we send a specific kill signal, the org-timer display will reload:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pkill -RTMIN+8 waybar
</span></span></code></pre></div><p>You can therefore add the following to your emacs configuration to refresh <code>waybar</code> the moment a pomodoro is created:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-timer-set-hook</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">start-process</span> <span class="s">&#34;waybar-timer-trigger&#34;</span> <span class="no">nil</span> <span class="s">&#34;pkill&#34;</span> <span class="s">&#34;-RTMIN+8&#34;</span> <span class="s">&#34;waybar&#34;</span><span class="p">)))</span>
</span></span></code></pre></div><h2 id="things-that-didnt-work">
  Things that didn&rsquo;t work
<a class="anchor" href="#things-that-didnt-work">#</a>
</h2>
<p>I&rsquo;d have liked a tomato-themed notification for when my pomodoro expired. I can use <code>notify-send</code> to make that happen:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">pomo-notify</span> <span class="p">(</span><span class="nv">MSG</span> <span class="k">&amp;optional</span> <span class="nv">TIMEOUT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;&#34;&#34;Display pomodoro notification with notify-send&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nf">apply</span>
</span></span><span class="line"><span class="cl">    <span class="ss">&#39;start-process</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;notify-send&#34;</span> <span class="no">nil</span> <span class="s">&#34;notify-send&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="o">`</span><span class="p">(</span><span class="o">,@</span><span class="p">(</span><span class="nb">when</span> <span class="nv">TIMEOUT</span> <span class="p">(</span><span class="nc">list</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;--expire-time=%d&#34;</span> <span class="p">(</span><span class="nf">*</span> <span class="mi">1000</span> <span class="nv">TIMEOUT</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">       <span class="o">,</span><span class="nv">MSG</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-timer-done-hook</span> <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nv">pomo-notify</span> <span class="s">&#34;🍅 org-timer done!&#34;</span><span class="p">)))</span>
</span></span></code></pre></div><p>However, now I have <em>two</em> notifications popping up: mine, and the org-timer one.
I tried to silence the org-timer notification using <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">suppress-org-notify</span> <span class="p">(</span><span class="nv">orig-fun</span> <span class="k">&amp;rest</span> <span class="nv">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">cl-letf</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">             <span class="p">((</span><span class="nf">symbol-function</span> <span class="ss">&#39;org-show-notification</span><span class="p">)</span> <span class="p">(</span><span class="nb">lambda</span> <span class="p">(</span><span class="k">&amp;rest</span> <span class="nv">_</span><span class="p">)</span> <span class="p">(</span><span class="k">ignore</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">           <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">apply</span> <span class="nv">orig-fun</span> <span class="nv">args</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">advice-add</span> <span class="ss">&#39;org-timer--run-countdown-timer</span> <span class="ss">:around</span> <span class="nf">#&#39;</span><span class="nv">suppress-org-notify</span><span class="p">)</span>
</span></span></code></pre></div><p>Alas, my advice fell on deaf ears. Do you perhaps know how to make it work? Let me know!</p>
<h2 id="the-end">
  The end
<a class="anchor" href="#the-end">#</a>
</h2>
<p>En dit is dit. Geniet die tamaties!</p>
<hr>
<h2 id="updates">
  Updates
<a class="anchor" href="#updates">#</a>
</h2>
<h3 id="waybar-poll-during-timer-only">
  Waybar: poll during timer only
<a class="anchor" href="#waybar-poll-during-timer-only">#</a>
</h3>
<p>I didn&rsquo;t like that the monitoring script talked to emacs every 30s, regardless of whether the timer is running. So, here is a modified version that triggers waybar updates only when the timer is started, and pauses them when the timer ends:</p>
<p><code>org-timer-remaining</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl"><span class="c1">#/bin/sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">function</span> print_status<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="nv">REPR</span><span class="o">=</span><span class="sb">`</span>emacsclient --eval <span class="s1">&#39;(org-timer-waybar-repr)&#39;</span> <span class="p">|</span> sed <span class="s1">&#39;s/&#34;//g&#39;</span><span class="sb">`</span>
</span></span><span class="line"><span class="cl">  <span class="nb">echo</span> <span class="nv">$REPR</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">print_status
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">MONITORING</span><span class="o">=</span><span class="s2">&#34;no&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">trap</span> <span class="s1">&#39;MONITORING=&#34;yes&#34;&#39;</span> USR1
</span></span><span class="line"><span class="cl"><span class="nb">trap</span> <span class="s1">&#39;MONITORING=&#34;no&#34;; print_status&#39;</span> USR2
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> true<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="o">[</span> <span class="nv">$MONITORING</span> <span class="o">==</span> <span class="s2">&#34;yes&#34;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    print_status
</span></span><span class="line"><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="cl">  sleep <span class="m">30</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="cl">  <span class="nb">wait</span> <span class="nv">$!</span>
</span></span><span class="line"><span class="cl"><span class="k">done</span>
</span></span></code></pre></div><p>Because the script now does the polling internally, you invoke it slightly differently from waybar:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl">    <span class="s2">&#34;custom/org_timer&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;exec&#34;</span><span class="p">:</span> <span class="s2">&#34;~/scripts/org-timer-remaining&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span></code></pre></div><p>And, because the script handles the signals (instead of waybar), we need to update our hooks too:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-timer-set-hook</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">start-process</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;waybar-monitor-start&#34;</span> <span class="no">nil</span> <span class="s">&#34;pkill&#34;</span> <span class="s">&#34;-USR1&#34;</span> <span class="s">&#34;-f&#34;</span> <span class="s">&#34;sh .*org-timer-remaining&#34;</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-timer-done-hook</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">start-process</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;waybar-monitor-pause&#34;</span> <span class="no">nil</span> <span class="s">&#34;pkill&#34;</span> <span class="s">&#34;-USR2&#34;</span> <span class="s">&#34;-f&#34;</span> <span class="s">&#34;sh .*org-timer-remaining&#34;</span><span class="p">)))</span>
</span></span></code></pre></div><h3 id="reporting-pomodoros">
  Reporting pomodoros
<a class="anchor" href="#reporting-pomodoros">#</a>
</h3>
<p>It can be useful to see how many pomodoros were spent on any given
project. With the modification below, we add a LOGBOOK entry to the
TODO header on which the pomodoro was started upon its completion:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lisp" data-lang="lisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defvar</span> <span class="nv">stefanv/pomodoro-start-time</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Stores the start time of the Pomodoro timer.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defvar</span> <span class="nv">stefanv/pomodoro-start-mark</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Stores a marker to the starting point of the Pomodoro.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-timer-start-pomodoro</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Start a Pomodoro timer and record the starting point and time.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nf">string-equal</span> <span class="nv">major-mode</span> <span class="s">&#34;org-mode&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="k">setq</span> <span class="nv">stefanv/pomodoro-start-time</span> <span class="p">(</span><span class="nv">current-time</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="k">setq</span> <span class="nv">stefanv/pomodoro-start-mark</span> <span class="p">(</span><span class="nv">point-marker</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">  <span class="c1">;; Call org-timer-set-timer with a 1 (25 min) prefix argument</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">current-prefix-arg</span> <span class="mi">1</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">call-interactively</span> <span class="nf">#&#39;</span><span class="nv">org-timer-set-timer</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-log-pomodoro-duration</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Logs the duration of the completed Pomodoro to the item where it was started.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">end-time</span> <span class="p">(</span><span class="nv">current-time</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">duration</span> <span class="p">(</span><span class="nv">float-time</span> <span class="p">(</span><span class="nv">time-subtract</span> <span class="nv">end-time</span> <span class="nv">stefanv/pomodoro-start-time</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">duration-mins</span> <span class="p">(</span><span class="nf">floor</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">duration</span> <span class="mi">60</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">log-entry</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;- 🍅: %dm completed %s&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="nv">duration-mins</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">format-time-string</span> <span class="s">&#34;%Y-%m-%d %H:%M&#34;</span> <span class="nv">end-time</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/org-log-pomodoro-duration</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;Logs the duration of the completed Pomodoro to the item where it was started.&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">end-time</span> <span class="p">(</span><span class="nv">current-time</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">duration</span> <span class="p">(</span><span class="nv">float-time</span> <span class="p">(</span><span class="nv">time-subtract</span> <span class="nv">end-time</span> <span class="nv">stefanv/pomodoro-start-time</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">duration-mins</span> <span class="p">(</span><span class="nf">floor</span> <span class="p">(</span><span class="nf">/</span> <span class="nv">duration</span> <span class="mi">60</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="nv">log-entry</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;- 🍅: %dm completed %s&#34;</span>
</span></span><span class="line"><span class="cl">                      <span class="nv">duration-mins</span>
</span></span><span class="line"><span class="cl">                      <span class="p">(</span><span class="nv">format-time-string</span> <span class="s">&#34;%Y-%m-%d %H:%M&#34;</span> <span class="nv">end-time</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nb">when</span> <span class="nv">stefanv/pomodoro-start-time</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nv">org-with-point-at</span> <span class="nv">stefanv/pomodoro-start-mark</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nv">save-excursion</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="nv">org-back-to-heading</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">          <span class="c1">;; Find LOGBOOK or create it after heading/meta-data</span>
</span></span><span class="line"><span class="cl">          <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">drawer-regexp</span> <span class="s">&#34;^:LOGBOOK:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">(</span><span class="nv">subtree-end</span> <span class="p">(</span><span class="nv">save-excursion</span>
</span></span><span class="line"><span class="cl">                               <span class="p">(</span><span class="nv">org-end-of-subtree</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                               <span class="p">(</span><span class="nv">point</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">            <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nv">re-search-forward</span> <span class="nv">drawer-regexp</span> <span class="nv">subtree-end</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="c1">;; Drawer exists: insert after :LOGBOOK: line</span>
</span></span><span class="line"><span class="cl">                <span class="p">(</span><span class="k">progn</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">forward-line</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">insert</span> <span class="nv">log-entry</span> <span class="s">&#34;\n&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">              <span class="c1">;; Drawer does not exist: create it after meta-data</span>
</span></span><span class="line"><span class="cl">              <span class="p">(</span><span class="nv">org-end-of-meta-data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">              <span class="p">(</span><span class="nv">insert</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;:LOGBOOK:\n%s\n:END:\n&#34;</span> <span class="nv">log-entry</span><span class="p">)))))))</span>
</span></span><span class="line"><span class="cl">  <span class="c1">;; Cleanup</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">set-marker</span> <span class="nv">stefanv/pomodoro-start-mark</span> <span class="no">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="k">setq</span> <span class="nv">stefanv/pomodoro-start-time</span> <span class="no">nil</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-timer-done-hook</span> <span class="nf">#&#39;</span><span class="nv">stefanv/org-log-pomodoro-duration</span><span class="p">)</span>
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Since Emacs 29, the emacsclient server is started automatically! 🙌&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="elisp" label="elisp" />
                             
                                <category scheme="taxonomy:Tags" term="productivity" label="productivity" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Linking to emails in org-mode (using neomutt)]]></title>
            <link href="https://mentat.za.net/blog/2018/10/31/using-org-mode-with-neomutt/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2016/12/15/org-mode-header-search/?utm_source=atom_feed" rel="related" type="text/html" title="Search headers in org-mode" />
                <link href="https://mentat.za.net/blog/2012/09/25/emacs-package-management/?utm_source=atom_feed" rel="related" type="text/html" title="Emacs package management" />
                <link href="https://mentat.za.net/blog/2016/10/20/websockets-in-python/?utm_source=atom_feed" rel="related" type="text/html" title="WebSockets in Python (and some Redux)" />
                <link href="https://mentat.za.net/blog/2016/09/14/tensorflow-gcc6-1/?utm_source=atom_feed" rel="related" type="text/html" title="Compile TensorFlow from source with gcc6.1" />
                <link href="https://mentat.za.net/blog/2016/02/26/matplotlib-on-osx/?utm_source=atom_feed" rel="related" type="text/html" title="Python &amp; Matplotlib on OSX" />
            
                <id>https://mentat.za.net/blog/2018/10/31/using-org-mode-with-neomutt/</id>
            
            
            <published>2018-10-31T00:00:00+00:00</published>
            <updated>2018-10-31T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p><em><strong>Update 2018-11-2:</strong> Change the URL scheme to <code>message://</code>.
See <a href="#other-systems">&ldquo;Other Systems&rdquo;</a> below.</em></p>
<p><a href="https://orgmode.org">org-mode</a> is, to me, is one of the most valuable
parts of the emacs ecosystem.  I use it to take notes, plan projects,
manage tasks, and write &amp; publish documents.</p>
<p>Nowadays, a lot of work arrives via email, and so it is helpful to be
able to refer to messages directly from my notes or lists of
tasks.</p>
<p>The <em>simplest</em> option might be to store URLs pointing to an online
inbox such as <a href="https://fastmail.com">Fastmail</a> or GMail, but I wanted
a solution that was both future proof (i.e., what if I moved my emails
to a different provider?) and worked with my terminal-based mail
client of choice, <a href="https://neomutt.org/">neomutt</a>.</p>
<p>I started with
a
<a href="https://upsilon.cc/~zack/blog/posts/2010/02/integrating_Mutt_with_Org-mode/">solution provided by Stefano Zacchiroli</a>,
and simplified it for my specific use-case.</p>
<h2 id="overview">
  Overview
<a class="anchor" href="#overview">#</a>
</h2>
<p>The solution has two parts: sending email links from neomutt to Emacs,
and later opening those links from Emacs by invoking neomutt.  The
first achieved via <code>org-protocol</code>, the latter via launching neomutt
and then simulating keypresses.</p>
<p>When launching neomutt, we have to tell it in which directory the
message lives.  We therefore use <code>notmuch</code> to find the message file
first, based on its Message-ID.  <code>maildir-utils</code> would be another way
of doing so.  <strong>Please note that you have to have notmuch or
maildir-utils set up already for this scheme to work.</strong></p>
<p>I initially avoided the <code>org-protocol</code> package, because installation
looked complicated.  That, it turns out, is only the case if you care
about web browser integration, which we don&rsquo;t.</p>
<h2 id="neomutt-configuration">
  Neomutt configuration
<a class="anchor" href="#neomutt-configuration">#</a>
</h2>
<p>First, we have a Python script that can parse an e-mail and share the
Message-ID and Subject with emacs.  I call it <code>mutt-save-org-link.py</code>,
and make it executable using <code>chmod +x mutt-save-org-link.py</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">email</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">subprocess</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">urllib.parse</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Parse the email from standard input</span>
</span></span><span class="line"><span class="cl"><span class="n">message_bytes</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="n">buffer</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">message</span> <span class="o">=</span> <span class="n">email</span><span class="o">.</span><span class="n">message_from_bytes</span><span class="p">(</span><span class="n">message_bytes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Grab the relevant message headers</span>
</span></span><span class="line"><span class="cl"><span class="n">message_id</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">quote</span><span class="p">(</span><span class="n">message</span><span class="p">[</span><span class="s1">&#39;message-id&#39;</span><span class="p">][</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="n">subject</span> <span class="o">=</span> <span class="n">message</span><span class="p">[</span><span class="s1">&#39;subject&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ask emacsclient to save a link to the message</span>
</span></span><span class="line"><span class="cl"><span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;emacsclient&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="sa">f</span><span class="s1">&#39;org-protocol://store-link?url=message://</span><span class="si">{</span><span class="n">message_id</span><span class="si">}</span><span class="s1">&amp;title=</span><span class="si">{</span><span class="n">subject</span><span class="si">}</span><span class="s1">&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">])</span>
</span></span></code></pre></div><p>We then configure neomutt (typically in <code>~/.muttrc</code>) to call the
script with a shortcut.  I chose Esc-L (the same as Alt-L).</p>
<pre tabindex="0"><code>macro index,pager \el &#34;|~/scripts/mutt-save-org-link.py\n&#34;
</code></pre><h2 id="emacs-configuration">
  Emacs configuration
<a class="anchor" href="#emacs-configuration">#</a>
</h2>
<p>Using <code>org-protocol</code>, we instruct emacsclient to intercept URLs with
the <code>org-protocol://</code> scheme, as used by our <code>mutt-save-org-link.py</code>
script.  We also tell org-mode how to handle special URLs of the form
<code>message://message-id+goes_here@mail.gmail.com</code>.  Neomutt needs to know
which Maildir folder to open, so we ask <code>notmuch</code> to tell us where the
message is located.</p>
<p>In my <code>~/.emacs</code> file I have:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="c1">; Make sure org-protocol is loaded</span>
</span></span><span class="line"><span class="cl"><span class="c1">; Now, org-protocol:// schemas are intercepted.</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">require</span> <span class="nv">org-protocol</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Call this function, which spawns neomutt, whenever org-mode</span>
</span></span><span class="line"><span class="cl"><span class="c1">; tries to open a link of the form message://message-id+goes_here@mail.gmail.com</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefanv/mutt-open-message</span> <span class="p">(</span><span class="nv">message-id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="s">&#34;In neomutt, open the email with the the given Message-ID&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">let*</span>
</span></span><span class="line"><span class="cl">      <span class="p">((</span><span class="nv">message-id</span> <span class="p">(</span><span class="nv">replace-regexp-in-string</span> <span class="s">&#34;^/*&#34;</span> <span class="s">&#34;&#34;</span> <span class="nv">message-id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">mail-file</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nv">replace-regexp-in-string</span>
</span></span><span class="line"><span class="cl">         <span class="s">&#34;\n$&#34;</span> <span class="s">&#34;&#34;</span> <span class="p">(</span><span class="nv">shell-command-to-string</span>
</span></span><span class="line"><span class="cl">                   <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;notmuch search --output=files id:%s&#34;</span> <span class="nv">message-id</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">mail-dir</span> <span class="p">(</span><span class="nv">replace-regexp-in-string</span> <span class="s">&#34;/\\(cur\\|new\\|tmp\\)/$&#34;</span> <span class="s">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">                                           <span class="p">(</span><span class="nf">file-name-directory</span> <span class="nv">mail-file</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nf">process-id</span> <span class="p">(</span><span class="nf">concat</span> <span class="s">&#34;neomutt-&#34;</span> <span class="nv">message-id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">message-id-escaped</span> <span class="p">(</span><span class="nf">regexp-quote</span> <span class="nv">message-id</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">mutt-keystrokes</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;l~i %s\n\n&#34;</span> <span class="p">(</span><span class="nv">shell-quote-argument</span> <span class="nv">message-id-escaped</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nv">mutt-command</span> <span class="p">(</span><span class="nf">list</span> <span class="s">&#34;neomutt&#34;</span> <span class="s">&#34;-R&#34;</span> <span class="s">&#34;-f&#34;</span> <span class="nv">mail-dir</span>
</span></span><span class="line"><span class="cl">                           <span class="s">&#34;-e&#34;</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;push &#39;%s&#39;&#34;</span> <span class="nv">mutt-keystrokes</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">message</span> <span class="s">&#34;Launching neomutt for message %s&#34;</span> <span class="nv">message-id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="nf">call-process</span> <span class="s">&#34;setsid&#34;</span> <span class="no">nil</span> <span class="no">nil</span>
</span></span><span class="line"><span class="cl">                   <span class="s">&#34;-f&#34;</span> <span class="s">&#34;gnome-terminal&#34;</span> <span class="s">&#34;--window&#34;</span> <span class="s">&#34;--&#34;</span>
</span></span><span class="line"><span class="cl">                   <span class="s">&#34;neomutt&#34;</span> <span class="s">&#34;-R&#34;</span> <span class="s">&#34;-f&#34;</span> <span class="nv">mail-dir</span>
</span></span><span class="line"><span class="cl">                   <span class="s">&#34;-e&#34;</span> <span class="p">(</span><span class="nf">format</span> <span class="s">&#34;push &#39;%s&#39;&#34;</span> <span class="nv">mutt-keystrokes</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Whenever org-mode sees a link starting with `message://`, it</span>
</span></span><span class="line"><span class="cl"><span class="c1">; calls our `mutt-open-message` function</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">org-add-link-type</span> <span class="s">&#34;message&#34;</span> <span class="ss">&#39;stefanv/mutt-open-message</span><span class="p">)</span>
</span></span></code></pre></div><p>There are a few caveats: if you use <code>maildir-utils</code>, the search
command is <code>mu find -f l i:%s</code> instead of notmuch; and if you are not
on Linux, then <code>setsid</code> (which we use to launch a detached background
process) is not going to work, and you will want to use a different
terminal emulator.</p>
<h2 id="a-nameother-systemsaother-systems">
  <a name="#other-systems"></a>Other Systems
<a class="anchor" href="#a-nameother-systemsaother-systems">#</a>
</h2>
<p><a href="https://vxlabs.com/">Charl Botha</a> mentioned in the comments that, on
MacOS,
<a href="https://orgmode.org/worg/org-contrib/org-mac-link.html">org-mac-link</a>
lets you grab hyperlinks from a wide variety of apps.  Email messages,
specifically, are stored as <code>message://message-id</code> URLs, which MacOS
knows how to open.  This post has been updated to use the same link schema.</p>
<h2 id="wrap-up">
  Wrap-up
<a class="anchor" href="#wrap-up">#</a>
</h2>
<p>That&rsquo;s it!  I&rsquo;ve added the code
to
<a href="https://github.com/stefanv/org-neomutt">https://github.com/stefanv/org-neomutt</a>.
Please file issues and PRs there, or tell me about your use cases
in the comments below.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="org-mode" label="org-mode" />
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="python" label="python" />
                             
                                <category scheme="taxonomy:Tags" term="mutt" label="mutt" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Search headers in org-mode]]></title>
            <link href="https://mentat.za.net/blog/2016/12/15/org-mode-header-search/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/?utm_source=atom_feed" rel="related" type="text/html" title="Adobe&#39;s new free font: Source Code Pro" />
                <link href="https://mentat.za.net/blog/2012/09/25/emacs-package-management/?utm_source=atom_feed" rel="related" type="text/html" title="Emacs package management" />
            
                <id>https://mentat.za.net/blog/2016/12/15/org-mode-header-search/</id>
            
            
            <published>2016-12-15T00:00:00+00:00</published>
            <updated>2016-12-15T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p>In org-mode, I often have the need to jump to a top-level heading
matching some word.</p>
<p>Since an org-mode buffer can be searched just like any other, I can
simply invoke forward search with <code>C-s</code>, but this will match <em>all</em>
occurrences of the text, instead of limiting the search to headings only.</p>
<p>This makes it hard to search for a phrase like &ldquo;Travel&rdquo;, for which I
have a top-level heading, but also often occurs elsewhere in my notes.</p>
<p>I have a solution of the following form:</p>
<ol>
<li>Launch a regular expression search</li>
<li>Pre-fill the text input with <code>^* </code> so that only headings are
matched.</li>
</ol>
<p>First, define a custom search function.  It puts the keys <code>^* </code> in the
&ldquo;unread command events&rdquo; list (i.e, a list of events waiting to be seen
by emacs), and then launches interactive forward regular expression search.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">stefan/isearch-heading</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">setq</span> <span class="nv">unread-command-events</span> <span class="p">(</span><span class="nv">listify-key-sequence</span> <span class="s">&#34;^* &#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">isearch-mode</span> <span class="no">t</span> <span class="no">t</span> <span class="no">nil</span> <span class="no">t</span><span class="p">))</span>
</span></span></code></pre></div><p>Next, we add a keybinding for org-mode:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-elisp" data-lang="elisp"><span class="line"><span class="cl"><span class="p">(</span><span class="nb">defun</span> <span class="nv">org-mode-keys</span> <span class="p">()</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nb">interactive</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">local-set-key</span> <span class="p">(</span><span class="nv">kbd</span> <span class="s">&#34;C-c g&#34;</span><span class="p">)</span> <span class="ss">&#39;stefan/isearch-heading</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;org-mode-hook</span> <span class="ss">&#39;org-mode-keys</span><span class="p">)</span>
</span></span></code></pre></div><p>And that&rsquo;s it!  Pressing <code>C-c g</code> (for &ldquo;go&rdquo;) in org-mode will
now present you with a search prompt.  Typing a heading name will take you
there directly, at which point you can choose to expand it with the
TAB key.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="org-mode" label="org-mode" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Adobe's new free font: Source Code Pro]]></title>
            <link href="https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
                <link href="https://mentat.za.net/blog/2012/09/25/emacs-package-management/?utm_source=atom_feed" rel="related" type="text/html" title="Emacs package management" />
            
                <id>https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/</id>
            
            
            <published>2012-09-26T00:00:00+00:00</published>
            <updated>2012-09-26T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p>Adobe yesterday
<a href="http://blogs.adobe.com/typblography/2012/09/source-code-pro.html">released its free and open source Type family, Source Code Pro</a>,
which includes an eye-pleasing monospace font  ideally suited for coding.
In the past, and at the recommendation of <a href="http://blog.fperez.org/">Fernando Perez</a>, I&rsquo;ve
used the beautiful (but non-free) <a href="http://www.microsoft.com/en-us/download/details.aspx?id=17879">Consolas by Microsoft</a>; now,
which is best?</p>
<p>To install on Linux:</p>
<ol>
<li><a href="https://github.com/adobe-fonts/source-sans-pro/releases/tag/variable-fonts">Grab the font</a>.</li>
<li>Copy the files to <code>~/.fonts</code>.</li>
<li>Run <code>fc-cache -f -v</code>.</li>
</ol>
<p>The font should now be available for selection in apps such as Firefox, Gnome
Terminal, etc.  To make it the default font in Emacs::</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span class="line"><span class="cl">    <span class="p">(</span><span class="nv">set-default-font</span> <span class="s">&#34;Source Code Pro&#34;</span><span class="p">)</span>
</span></span></code></pre></div><p>Here&rsquo;s a comparison of Consolas (left) and Source Code Pro (right):</p>








<figure>
    <img
        
            sizes="(min-width: 35em) 1200px, 100vw"
              
            srcset='
            
                   https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/consolas_vs_source_code_pro_hu5491080204787102733.png 480w,
            
                   https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/consolas_vs_source_code_pro_hu17953295771476538767.png 800w,
            
                   https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/consolas_vs_source_code_pro_hu7176974525714387819.png 1200w,
            
                   
            '

            
            
            src="https://mentat.za.net/blog/2012/09/26/consolas-vs-source-code-pro/consolas_vs_source_code_pro_hu17953295771476538767.png"
            

        /> <figcaption>
            <h4>Comparison: Consolas vs Source Code Pro</h4>
        </figcaption>
</figure>

<p>Comments also on <a href="https://plus.google.com/104831275312843762750/posts/Ju6Ns8Dtuik">Google+</a>.</p>
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="coding" label="coding" />
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="linux" label="linux" />
                            
                        
                    
                
            
        </entry>
    
        
        <entry>
            <title type="html"><![CDATA[Emacs package management]]></title>
            <link href="https://mentat.za.net/blog/2012/09/25/emacs-package-management/?utm_source=atom_feed" rel="alternate" type="text/html" />
            
            
                <id>https://mentat.za.net/blog/2012/09/25/emacs-package-management/</id>
            
            
            <published>2012-09-25T00:00:00+00:00</published>
            <updated>2012-09-25T00:00:00+00:00</updated>
            
            
            <content type="html"><![CDATA[<p><strong>EDIT 2023-01-06:</strong> Nowadays, there is <a href="https://github.com/jwiegley/use-package"><code>use-package</code></a>.</p>
<p>I recently tried to install MuMaMo as one of the dependencies for Takafumi
Arakaki&rsquo;s <a href="https://github.com/tkf/emacs-ipython-notebook">Emacs-based IPython notebook</a>.  The instructions on the MuMaMo
webpage were as clear as mud and aimed primarily at Windows users.  Enters
<a href="https://github.com/dimitri/el-get">apt-get for Emacs</a>!</p>
<p>My Emacs setup is shared across multiple machines: a synchronized <code>elisp</code>
folder, containing <code>*.el</code> files, along with my <code>.emacs</code> configuration.
<code>el-get</code> allows you to share your package installation folder in a similar
fashion.  Here are some relevant configuration snippets:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-common-lisp" data-lang="common-lisp"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Everything gets installed into ~/elisp, a folder</span>
</span></span><span class="line"><span class="cl"><span class="c1">; I sync across all my machines</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">setq</span> <span class="nv">el-get-dir</span> <span class="s">&#34;~/elisp/el-get&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">setq</span> <span class="nv">el-get-install-dir</span> <span class="s">&#34;~/elisp/el-get/el-get&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">add-to-list</span> <span class="ss">&#39;load-path</span> <span class="nv">el-get-install-dir</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; If el-get is missing, install it automatically</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nb">unless</span> <span class="p">(</span><span class="nf">require</span> <span class="ss">&#39;el-get</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="p">(</span><span class="nv">url-retrieve</span>
</span></span><span class="line"><span class="cl">   <span class="s">&#34;https://raw.github.com/dimitri/el-get/master/el-get-install.el&#34;</span>
</span></span><span class="line"><span class="cl">   <span class="p">(</span><span class="nb">lambda</span> <span class="p">(</span><span class="nv">s</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">     <span class="p">(</span><span class="nv">goto-char</span> <span class="p">(</span><span class="nv">point-max</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">     <span class="p">(</span><span class="nv">eval-print-last-sexp</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Install these packages, and call the specified configuration snippets</span>
</span></span><span class="line"><span class="cl"><span class="c1">; after each load</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">setq</span> <span class="nv">el-get-sources</span>
</span></span><span class="line"><span class="cl">      <span class="o">&#39;</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="ss">:name</span> <span class="nv">ethan-wspace</span>
</span></span><span class="line"><span class="cl">         <span class="ss">:after</span> <span class="p">(</span><span class="k">progn</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">global-ethan-wspace-mode</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                  <span class="p">(</span><span class="nv">set-face-background</span> <span class="ss">&#39;ethan-wspace-face</span> <span class="s">&#34;gray95&#34;</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="ss">:name</span> <span class="nv">column-marker</span>
</span></span><span class="line"><span class="cl">         <span class="ss">:after</span> <span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;font-lock-mode-hook</span>
</span></span><span class="line"><span class="cl">                          <span class="p">(</span><span class="nb">lambda</span> <span class="p">()</span> <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span> <span class="p">(</span><span class="nv">column-marker-1</span> <span class="mi">80</span><span class="p">))))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Also install these packages, no configuration required</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="k">setq</span> <span class="nv">my-packages</span>
</span></span><span class="line"><span class="cl">      <span class="p">(</span><span class="nf">append</span>
</span></span><span class="line"><span class="cl">       <span class="o">&#39;</span><span class="p">(</span><span class="nv">el-get</span> <span class="nv">maxframe</span> <span class="nv">markdown-mode</span> <span class="nv">ein</span> <span class="nv">python</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">       <span class="p">(</span><span class="nf">mapcar</span> <span class="ss">&#39;el-get-source-name</span> <span class="nv">el-get-sources</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">       <span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">; Check packages and install any that are missing</span>
</span></span><span class="line"><span class="cl"><span class="p">(</span><span class="nv">el-get</span> <span class="ss">&#39;sync</span> <span class="nv">my-packages</span><span class="p">)</span>
</span></span></code></pre></div><p>There are two ways to specify packages to be installed: either include them in
the <code>my-packages</code> list, or add them to <code>el-get-sources</code>, which in addition
allows further customization upon successful loading of the package.</p>
<p><a href="http://software-carpentry.org/2012/09/whats-in-your-stack/">What&rsquo;s in your stack?</a> Here&rsquo;s my list of Emacs packages:</p>
<pre><code>Org Mode, Ethan's wspace, Tab Bar, Column Marker, Max Frame, EIN, Python,
JS2
</code></pre>
<p>Do you know of any other useful packages?  Let me know!</p>
<!-- References -->
]]></content>
            
                 
                    
                 
                    
                         
                        
                            
                             
                                <category scheme="taxonomy:Tags" term="emacs" label="emacs" />
                             
                                <category scheme="taxonomy:Tags" term="python" label="python" />
                             
                                <category scheme="taxonomy:Tags" term="scipy" label="scipy" />
                            
                        
                    
                
            
        </entry>
    
</feed>
