<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/assets/rss.xsl" type="text/xsl"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"

>
<channel>
	<title>Sacha Chua - tag - helm</title>
	<atom:link href="https://sachachua.com/blog/tag/helm/feed/index.xml" rel="self" type="application/rss+xml" />
	<atom:link href="https://sachachua.com/blog/tag/helm" rel="alternate" type="text/html" />
	<link>https://sachachua.com/blog/tag/helm/feed/index.xml</link>
	<description>Emacs, sketches, and life</description>
  
	<lastBuildDate>Wed, 10 Jun 2026 15:05:24 GMT</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>daily</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>11ty</generator>
  <item>
		<title>Getting Helm and org-refile to clock in or create tasks</title>
		<link>https://sachachua.com/blog/2015/03/getting-helm-org-refile-clock-create-tasks/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Wed, 04 Mar 2015 13:00:00 GMT</pubDate>
    <category>emacs</category>
<category>org</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27940</guid>
		<description><![CDATA[<p>I&apos;ve been thinking about how to improve the way that I navigate to, clock in, and create tasks in Org Mode. If the task is one of the ones I&apos;ve planned for today, I use my Org agenda. If I know that the task exists, I use <code>C-u C-c C-w</code> (<code>org-refile</code>) to jump to it, and then <code>!</code> (one of my <code>org-speed-commands-user</code> options) to clock in and track it on Quantified Awesome. If I want to resume an interrupted task, I use <code>C-u C-c j</code> (my shortcut for <code>org-clock-goto</code>). For new tasks, I go to the appropriate project entry and create it, although I really should be using <code>org-capture</code> instead.</p>
<p></p><div class="sketch-full"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2015-01-30%20How%20can%20I%20get%20better%20at%20being%20clever%20on%20demand%20&#45;&#45;%20index%20card%20%23emacs.png" data-src="https://sketches.sachachua.com/static/2015-01-30%20How%20can%20I%20get%20better%20at%20being%20clever%20on%20demand%20&#45;&#45;%20index%20card%20%23emacs.png" data-title="2015-01-30 How can I get better at being clever on demand &#45;&#45; index card #emacs" data-w="1497" data-h="896"><picture>
      <img src="https://sketches.sachachua.com/static/2015-01-30%20How%20can%20I%20get%20better%20at%20being%20clever%20on%20demand%20&#45;&#45;%20index%20card%20%23emacs.png" width="1497" height="896" alt="2015-01-30 How can I get better at being clever on demand &#45;&#45; index card #emacs" loading="lazy" style="max-height: 90vw; height: auto; width: auto" decoding="async">
      <figcaption>2015-01-30 How can I get better at being clever on demand &#45;&#45; index card #emacs</figcaption>
    </picture></a></div><p></p>
<p>I thought about how I can reduce some of these distinctions. For example, what if it didn&apos;t matter whether or not a task already exists? I can modify the org-refile interface to make it easier for me to create tasks if my description doesn&apos;t match anything. To make things simpler, I&apos;ll just reuse one of my <code>org-capture-templates</code>, and I&apos;ll pre-fill it with the candidate from Helm.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">ert-deftest</span> <span class="org-function-name">sacha/org-capture-prefill-template</span> ()
  (should
   <span class="org-comment-delimiter">;; </span><span class="org-comment">It should fill things in one field at a time</span>
   (string=
    (sacha/org-capture-prefill-template
     <span class="org-string">&quot;* TODO %^{Task}\nSCHEDULED: %^t\n:PROPERTIES:\n:Effort: %^{effort|1:00|0:05|0:15|0:30|2:00|4:00}\n:END:\n%?\n&quot;</span>
     <span class="org-string">&quot;Hello World&quot;</span>)
    <span class="org-string">&quot;* TODO Hello World\nSCHEDULED: %^t\n:PROPERTIES:\n:Effort: %^{effort|1:00|0:05|0:15|0:30|2:00|4:00}\n:END:\n%?\n&quot;</span>
    ))
  (should
   (string=
    (sacha/org-capture-prefill-template
     <span class="org-string">&quot;* TODO %^{Task}\nSCHEDULED: %^t\n:PROPERTIES:\n:Effort: %^{effort|1:00|0:05|0:15|0:30|2:00|4:00}\n:END:\n%?\n&quot;</span>
     <span class="org-string">&quot;Hello World&quot;</span> <span class="org-string">&quot;&lt;2015-01-01&gt;&quot;</span>)
    <span class="org-string">&quot;* TODO Hello World\nSCHEDULED: &lt;2015-01-01&gt;\n:PROPERTIES:\n:Effort: %^{effort|1:00|0:05|0:15|0:30|2:00|4:00}\n:END:\n%?\n&quot;</span>))
  (should
   (string=
    (sacha/org-capture-prefill-template
     <span class="org-string">&quot;* TODO %^{Task}\nSCHEDULED: %^t\n:PROPERTIES:\n:Effort: %^{effort|1:00|0:05|0:15|0:30|2:00|4:00}\n:END:\n%?\n&quot;</span>
     <span class="org-string">&quot;Hello World&quot;</span> <span class="org-string">&quot;&lt;2015-01-01&gt;&quot;</span> <span class="org-string">&quot;0:05&quot;</span>)
    <span class="org-string">&quot;* TODO Hello World\nSCHEDULED: &lt;2015-01-01&gt;\n:PROPERTIES:\n:Effort: 0:05\n:END:\n%?\n&quot;</span>)))

(<span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-capture-prefill-template</span> (template <span class="org-type">&amp;rest</span> values)
  <span class="org-doc">&quot;Pre-fill TEMPLATE with VALUES.&quot;</span>
  (setq template (or template (org-capture-get <span class="org-builtin">:template</span>)))
  (<span class="org-keyword">with-temp-buffer</span>
    (insert template)
    (goto-char (point-min))
    (<span class="org-keyword">while</span> (re-search-forward
            (concat <span class="org-string">&quot;%</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;\\[</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">.+</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">\\]</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;&lt;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[</span><span class="org-string"><span class="org-negation-char">^</span></span><span class="org-string">&gt;\n]+</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">&gt;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[tTuUaliAcxkKInfF]</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">:[-a-zA-Z]+</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;\\^</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">{</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[</span><span class="org-string"><span class="org-negation-char">^</span></span><span class="org-string">}]*</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">}</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;?</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[gGtTuUCLp]</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">?</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">|</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;%\\\\</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[1-9][0-9]*</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">&quot;</span>
                    <span class="org-string">&quot;</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">&quot;</span>) nil t)
      (<span class="org-keyword">if</span> (car values)
          (replace-match (car values) nil t))
      (setq values (cdr values)))
    (buffer-string)))

(<span class="org-keyword">defun</span> <span class="org-function-name">sacha/helm-org-create-task</span> (candidate)
  (<span class="org-keyword">let</span> ((entry (org-capture-select-template <span class="org-string">&quot;T&quot;</span>)))
    (org-capture-set-plist entry)
    (org-capture-get-template)
    (org-capture-set-target-location)
    (<span class="org-keyword">condition-case</span> error
        (<span class="org-keyword">progn</span>
          (org-capture-put
           <span class="org-builtin">:template</span>
           (org-capture-fill-template
            (sacha/org-capture-prefill-template (org-capture-get <span class="org-builtin">:template</span>)
                                                candidate)))
          (org-capture-place-template
           (equal (car (org-capture-get <span class="org-builtin">:target</span>)) &apos;function)))
      ((<span class="org-warning">error</span> quit)
       (<span class="org-keyword">if</span> (get-buffer <span class="org-string">&quot;*Capture*&quot;</span>) (kill-buffer <span class="org-string">&quot;*Capture*&quot;</span>))
       (<span class="org-warning">error</span> <span class="org-string">&quot;Capture abort: %s&quot;</span> error)))) t)
</pre>
</div>
<p>Next, I want to add this to the way that Helm prompts me to refile. That means that my creation task should return something ready for <code>org-refile</code>. Actually, maybe I don&apos;t have to do that if I know I&apos;m always going to call it when I want to jump to something. I might as well add that bit of code that sets up clocking in, too.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">defvar</span> <span class="org-variable-name">sacha/helm-org-refile-locations</span> nil)

(<span class="org-keyword">defun</span> <span class="org-function-name">sacha/helm-org-clock-in-and-track-from-refile</span> (candidate)
  (<span class="org-keyword">let</span> ((location (org-refile&#45;&#45;get-location candidate sacha/helm-org-refile-locations)))
    (<span class="org-keyword">save-window-excursion</span>
      (org-refile 4 nil location)
      (sacha/org-clock-in-and-track)
      t)))

(<span class="org-keyword">defun</span> <span class="org-function-name">sacha/helm-org-refile-read-location</span> (tbl)
  (setq sacha/helm-org-refile-locations tbl)
  (helm
   (list
    (helm-build-sync-source <span class="org-string">&quot;Refile targets&quot;</span>
      <span class="org-builtin">:candidates</span> (mapcar &apos;car tbl)
      <span class="org-builtin">:action</span> &apos;((<span class="org-string">&quot;Select&quot;</span> . identity)
                (<span class="org-string">&quot;Clock in and track&quot;</span> . sacha/helm-org-clock-in-and-track-from-refile))
      <span class="org-builtin">:history</span> &apos;org-refile-history)
    (helm-build-dummy-source <span class="org-string">&quot;Create task&quot;</span>
      <span class="org-builtin">:action</span> (helm-make-actions
               <span class="org-string">&quot;Create task&quot;</span>
               &apos;sacha/helm-org-create-task)))))

(<span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-refile-get-location</span> (<span class="org-type">&amp;optional</span> prompt default-buffer new-nodes no-exclude)
  <span class="org-doc">&quot;Prompt the user for a refile location, using PROMPT.</span>
<span class="org-doc">PROMPT should not be suffixed with a colon and a space, because</span>
<span class="org-doc">this function appends the default value from</span>
<span class="org-doc">`</span><span class="org-doc"><span class="org-constant">org-refile-history</span></span><span class="org-doc">&apos; automatically, if that is not empty.</span>
<span class="org-doc">When NO-EXCLUDE is set, do not exclude headlines in the current subtree,</span>
<span class="org-doc">this is used for the GOTO interface.&quot;</span>
  (<span class="org-keyword">let</span> ((org-refile-targets org-refile-targets)
        (org-refile-use-outline-path org-refile-use-outline-path)
        excluded-entries)
    (<span class="org-keyword">when</span> (and (derived-mode-p &apos;org-mode)
               (not org-refile-use-cache)
               (not no-exclude))
      (org-map-tree
       (<span class="org-keyword">lambda</span>()
         (setq excluded-entries
               (append excluded-entries (list (org-get-heading t t)))))))
    (setq org-refile-target-table
          (org-refile-get-targets default-buffer excluded-entries)))
  (<span class="org-keyword">unless</span> org-refile-target-table
    (<span class="org-warning">user-error</span> <span class="org-string">&quot;No refile targets&quot;</span>))
  (<span class="org-keyword">let*</span> ((cbuf (current-buffer))
         (partial-completion-mode nil)
         (cfn (buffer-file-name (buffer-base-buffer cbuf)))
         (cfunc (<span class="org-keyword">if</span> (and org-refile-use-outline-path
                         org-outline-path-complete-in-steps)
                    &apos;org-olpath-completing-read
                  &apos;org-icompleting-read))
         (extra (<span class="org-keyword">if</span> org-refile-use-outline-path <span class="org-string">&quot;/&quot;</span> <span class="org-string">&quot;&quot;</span>))
         (cbnex (concat (buffer-name) extra))
         (filename (and cfn (expand-file-name cfn)))
         (tbl (mapcar
               (<span class="org-keyword">lambda</span> (x)
                 (<span class="org-keyword">if</span> (and (not (member org-refile-use-outline-path
                                       &apos;(file full-file-path)))
                          (not (equal filename (nth 1 x))))
                     (cons (concat (car x) extra <span class="org-string">&quot; (&quot;</span>
                                   (file-name-nondirectory (nth 1 x)) <span class="org-string">&quot;)&quot;</span>)
                           (cdr x))
                   (cons (concat (car x) extra) (cdr x))))
               org-refile-target-table))
         (completion-ignore-case t)
         cdef
         (prompt (concat prompt
                         (or (and (car org-refile-history)
                                  (concat <span class="org-string">&quot; (default &quot;</span> (car org-refile-history) <span class="org-string">&quot;)&quot;</span>))
                             (and (assoc cbnex tbl) (setq cdef cbnex)
                                  (concat <span class="org-string">&quot; (default &quot;</span> cbnex <span class="org-string">&quot;)&quot;</span>))) <span class="org-string">&quot;: &quot;</span>))
         pa answ parent-target child parent old-hist)
    (setq old-hist org-refile-history)
    <span class="org-comment-delimiter">;; </span><span class="org-comment">Use Helm&apos;s sources instead</span>
    (setq answ (sacha/helm-org-refile-read-location tbl))
    (<span class="org-keyword">if</span> (and (stringp answ)
             (setq pa (org-refile&#45;&#45;get-location answ tbl)))
        (<span class="org-keyword">progn</span>
          (org-refile-check-position pa)
          (<span class="org-keyword">when</span> (or (not org-refile-history)
                    (not (eq old-hist org-refile-history))
                    (not (equal (car pa) (car org-refile-history))))
            (setq org-refile-history
                  (cons (car pa) (<span class="org-keyword">if</span> (assoc (car org-refile-history) tbl)
                                     org-refile-history
                                   (cdr org-refile-history))))
            (<span class="org-keyword">if</span> (equal (car org-refile-history) (nth 1 org-refile-history))
                (pop org-refile-history)))
          pa)
      (<span class="org-keyword">if</span> (and (stringp answ) (string-match <span class="org-string">&quot;\\`</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">.*</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">/</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">(</span></span><span class="org-string">[</span><span class="org-string"><span class="org-negation-char">^</span></span><span class="org-string">/]+</span><span class="org-string"><span class="org-regexp-grouping-backslash">\\</span></span><span class="org-string"><span class="org-regexp-grouping-construct">)</span></span><span class="org-string">\\&apos;&quot;</span> answ))
          (<span class="org-keyword">progn</span>
            (setq parent (match-string 1 answ)
                  child (match-string 2 answ))
            (setq parent-target (org-refile&#45;&#45;get-location parent tbl))
            (<span class="org-keyword">when</span> (and parent-target
                       (or (eq new-nodes t)
                           (and (eq new-nodes &apos;confirm)
                                (y-or-n-p (format <span class="org-string">&quot;Create new node \&quot;%s\&quot;? &quot;</span>
                                                  child)))))
              (org-refile-new-child parent-target child)))
        (<span class="org-keyword">if</span> (not (equal answ t)) (<span class="org-warning">user-error</span> <span class="org-string">&quot;Invalid target location&quot;</span>))))))

(fset &apos;org-refile-get-location &apos;sacha/org-refile-get-location)
</pre>
</div>
<p>Hooray! Now <code>C-u C-c C-w</code> (<code>org-refile</code>) also lets me use <code>TAB</code> or <code>F2</code> to select the alternative action of quickly clocking in on a task. Mwahaha.</p>
<p>You can check out&#xA0;this code in my <a href="https://sachachua.com/dotemacs">config</a> to see if anything has been updated. Want to learn more about modifying Helm? Check out these posts by <a href="http://kitchingroup.cheme.cmu.edu/blog/2015/01/24/Anatomy-of-a-helm-source/">John Kitchin</a> and <a href="http://rubikitch.com/2015/02/02/helm-add-actions/">Rubikitch</a>.</p>
<p>I think I&apos;m getting the hang of tweaking Helm.&#xA0; Yay!</p>

<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2015%2F03%2Fgetting-helm-org-refile-clock-create-tasks%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Digital index piles with Emacs: Rapid categorization of Org Mode items</title>
		<link>https://sachachua.com/blog/2015/02/digital-index-piles-emacs-rapid-categorization-org-mode-items/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Fri, 06 Feb 2015 21:00:00 GMT</pubDate>
    <category>emacs</category>
<category>org</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27923</guid>
		<description><![CDATA[<p>Somewhat daunted by the prospect of categorizing more than a hundred sketches and blog posts for my monthly review, I spent some time figuring out how to create the digital equivalent of sorting index cards into various piles.</p>
<p><a href="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Digital-piles-of-index-card-index-card-indexing-organization-pkm.png"><img loading="lazy" class="alignnone size-medium wp-image-27924" src="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Digital-piles-of-index-card-index-card-indexing-organization-pkm-640x383.png" alt="2015-02-01 Digital piles of index card &#45;&#45; index card #indexing #organization #pkm" width="640" height="383" srcset="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Digital-piles-of-index-card-index-card-indexing-organization-pkm-640x383.png 640w, https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Digital-piles-of-index-card-index-card-indexing-organization-pkm-280x168.png 280w, https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Digital-piles-of-index-card-index-card-indexing-organization-pkm.png 1497w" sizes="(max-width: 640px) 100vw, 640px"></a></p>
<p></p><div class="sketch-thumbnail"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" data-src="https://sketches.sachachua.com/static/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" data-title="2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating" data-w="1497" data-h="896"><picture>
      <img src="https://sketches.sachachua.com/thumbnails/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" width="" height="" alt="2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating" loading="lazy" decoding="async">
      <figcaption>2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating</figcaption>
    </picture></a></div><p></p>
<p>In fact, wouldn&apos;t it be super-cool if the items could automatically guess which category they should probably go in, prompting me only if it wasn&apos;t clear?</p>
<p>I wanted to write a function that could take a list structured like this:</p>
<ul class="org-ul">
<li>Keyword A
<ul class="org-ul">
<li>Previous links</li>
</ul>
</li>
<li>Keyword B
<ul class="org-ul">
<li>Previous links</li>
</ul>
</li>
<li>Link 1 with Keyword A</li>
<li>Link 2 with Keyword B</li>
<li>Link 3 with Keyword A</li>
<li>Link 4</li>
</ul>
<p>It should file Link 1 and 3 under Keyword A, Link 2 under Keyword B, and prompt me for the category for Link 4. At that prompt, I should be able to select Keyword A or Keyword B, or specify a new category.</p>
<p>Inspired by John Kitchin&apos;s recent post on <a href="http://kitchingroup.cheme.cmu.edu/blog/2015/01/24/Anatomy-of-a-helm-source/">defining a Helm source</a>, I wanted to get it to work with Helm.</p>
<p>First step: I needed to figure out the structure of the list, maybe including a sample from the category to make it clearer what&apos;s included. <code>org-list.el</code> seemed to have useful functions for this. <code>org-list-struct</code> gave me the structure of the current list. Let&apos;s say that a category is anything whose text does not match <code>org-bracket-link-regexp</code>.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-get-list-categories</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-doc">&quot;Return a list of (category indent matching-regexp sample).</span>
<span class="org-doc">List categories are items that don&apos;t contain links.&quot;</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>list <span class="org-rainbow-delimiters-depth-5">(</span>org-list-struct<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span> last-category results<span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">save-excursion</span>
      <span class="org-rainbow-delimiters-depth-4">(</span>mapc
       <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-6">(</span>x<span class="org-rainbow-delimiters-depth-6">)</span>
         <span class="org-rainbow-delimiters-depth-6">(</span>goto-char <span class="org-rainbow-delimiters-depth-7">(</span>car x<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
         <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">let</span> <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-rainbow-delimiters-depth-8">(</span>current-item
                <span class="org-rainbow-delimiters-depth-9">(</span>buffer-substring-no-properties
                 <span class="org-rainbow-delimiters-depth-1">(</span>+ <span class="org-rainbow-delimiters-depth-2">(</span>point<span class="org-rainbow-delimiters-depth-2">)</span>
                    <span class="org-rainbow-delimiters-depth-2">(</span>elt x 1<span class="org-rainbow-delimiters-depth-2">)</span>
                    <span class="org-rainbow-delimiters-depth-2">(</span>length <span class="org-rainbow-delimiters-depth-3">(</span>elt x 2<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
                 <span class="org-rainbow-delimiters-depth-1">(</span>line-end-position<span class="org-rainbow-delimiters-depth-1">)</span><span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span>
           <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-keyword">if</span> <span class="org-rainbow-delimiters-depth-8">(</span>string-match
                org-bracket-link-regexp
                <span class="org-rainbow-delimiters-depth-9">(</span>buffer-substring-no-properties
                 <span class="org-rainbow-delimiters-depth-1">(</span>point<span class="org-rainbow-delimiters-depth-1">)</span>
                 <span class="org-rainbow-delimiters-depth-1">(</span>line-end-position<span class="org-rainbow-delimiters-depth-1">)</span><span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span>
               <span class="org-comment-delimiter">;; </span><span class="org-comment">Link - update the last category</span>
               <span class="org-rainbow-delimiters-depth-8">(</span><span class="org-keyword">when</span> last-category
                 <span class="org-rainbow-delimiters-depth-9">(</span><span class="org-keyword">if</span> <span class="org-rainbow-delimiters-depth-1">(</span>&lt; <span class="org-rainbow-delimiters-depth-2">(</span>elt x 1<span class="org-rainbow-delimiters-depth-2">)</span> <span class="org-rainbow-delimiters-depth-2">(</span>elt last-category 1<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
                     <span class="org-rainbow-delimiters-depth-1">(</span>setq results
                           <span class="org-rainbow-delimiters-depth-2">(</span>cons <span class="org-rainbow-delimiters-depth-3">(</span>append last-category
                                         <span class="org-rainbow-delimiters-depth-4">(</span>list
                                          <span class="org-rainbow-delimiters-depth-5">(</span>match-string-no-properties
                                           3
                                           <span class="org-rainbow-delimiters-depth-6">(</span>buffer-substring-no-properties
                                            <span class="org-rainbow-delimiters-depth-7">(</span>point<span class="org-rainbow-delimiters-depth-7">)</span>
                                            <span class="org-rainbow-delimiters-depth-7">(</span>line-end-position<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
                                 <span class="org-rainbow-delimiters-depth-3">(</span>cdr results<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span><span class="org-rainbow-delimiters-depth-9">)</span>
                 <span class="org-rainbow-delimiters-depth-9">(</span>setq last-category nil<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span>
             <span class="org-comment-delimiter">;; </span><span class="org-comment">Category</span>
             <span class="org-rainbow-delimiters-depth-8">(</span>setq results
                     <span class="org-rainbow-delimiters-depth-9">(</span>cons
                      <span class="org-rainbow-delimiters-depth-1">(</span>setq last-category
                            <span class="org-rainbow-delimiters-depth-2">(</span>list
                             current-item
                             <span class="org-rainbow-delimiters-depth-3">(</span>elt x 1<span class="org-rainbow-delimiters-depth-3">)</span>
                             <span class="org-rainbow-delimiters-depth-3">(</span>concat <span class="org-string">&quot;^&quot;</span>
                                     <span class="org-rainbow-delimiters-depth-4">(</span>make-string <span class="org-rainbow-delimiters-depth-5">(</span>elt x 1<span class="org-rainbow-delimiters-depth-5">)</span> ?\ <span class="org-rainbow-delimiters-depth-4">)</span>
                                     <span class="org-rainbow-delimiters-depth-4">(</span>regexp-quote
                                      <span class="org-rainbow-delimiters-depth-5">(</span>concat <span class="org-rainbow-delimiters-depth-6">(</span>elt x 2<span class="org-rainbow-delimiters-depth-6">)</span>
                                              current-item<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
                                     <span class="org-string">&quot;$&quot;</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
                      results<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
       list<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    results<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>The next step was to write a function that guessed the list category based on the item text, and moved the item there.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defvar</span> <span class="org-variable-name">sacha/helm-org-list-candidates</span> nil<span class="org-rainbow-delimiters-depth-1">)</span>
<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">sacha/helm-org-list-categories-init-candidates</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-doc">&quot;Return a list of categories from this list in a form ready for Helm.&quot;</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>setq sacha/helm-org-list-candidates
        <span class="org-rainbow-delimiters-depth-3">(</span>mapcar <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-5">(</span>x<span class="org-rainbow-delimiters-depth-5">)</span>
                  <span class="org-rainbow-delimiters-depth-5">(</span>cons <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">if</span> <span class="org-rainbow-delimiters-depth-7">(</span>elt x 3<span class="org-rainbow-delimiters-depth-7">)</span>
                            <span class="org-rainbow-delimiters-depth-7">(</span>format <span class="org-string">&quot;%s - %s&quot;</span> <span class="org-rainbow-delimiters-depth-8">(</span>car x<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>elt x 3<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span>
                          <span class="org-rainbow-delimiters-depth-7">(</span>car x<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
                        x<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
                <span class="org-rainbow-delimiters-depth-4">(</span>sacha/org-get-list-categories<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-move-current-item-to-category</span> <span class="org-rainbow-delimiters-depth-2">(</span>category<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">when</span> category
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">let*</span> <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span>beg <span class="org-rainbow-delimiters-depth-6">(</span>line-beginning-position<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
           <span class="org-rainbow-delimiters-depth-5">(</span>end <span class="org-rainbow-delimiters-depth-6">(</span>line-end-position<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
           <span class="org-rainbow-delimiters-depth-5">(</span>string <span class="org-rainbow-delimiters-depth-6">(</span>buffer-substring-no-properties beg end<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
      <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">save-excursion</span>
        <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">when</span> <span class="org-rainbow-delimiters-depth-6">(</span>re-search-backward <span class="org-rainbow-delimiters-depth-7">(</span>elt category 2<span class="org-rainbow-delimiters-depth-7">)</span> nil t<span class="org-rainbow-delimiters-depth-6">)</span>
          <span class="org-rainbow-delimiters-depth-6">(</span>delete-region beg <span class="org-rainbow-delimiters-depth-7">(</span>min <span class="org-rainbow-delimiters-depth-8">(</span>1+ end<span class="org-rainbow-delimiters-depth-8">)</span> <span class="org-rainbow-delimiters-depth-8">(</span>point-max<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
          <span class="org-rainbow-delimiters-depth-6">(</span>forward-line 1<span class="org-rainbow-delimiters-depth-6">)</span>
          <span class="org-rainbow-delimiters-depth-6">(</span>insert <span class="org-rainbow-delimiters-depth-7">(</span>make-string <span class="org-rainbow-delimiters-depth-8">(</span>+ 2 <span class="org-rainbow-delimiters-depth-9">(</span>elt category 1<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span> ?\ <span class="org-rainbow-delimiters-depth-7">)</span>
                  string <span class="org-string">&quot;\n&quot;</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span> t<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-guess-list-category</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-type">&amp;optional</span> categories<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>interactive<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">require</span> &apos;<span class="org-constant">cl-lib</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">unless</span> categories
    <span class="org-rainbow-delimiters-depth-3">(</span>setq categories
          <span class="org-rainbow-delimiters-depth-4">(</span>sacha/helm-org-list-categories-init-candidates<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let*</span> <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>beg <span class="org-rainbow-delimiters-depth-5">(</span>line-beginning-position<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
         <span class="org-rainbow-delimiters-depth-4">(</span>end <span class="org-rainbow-delimiters-depth-5">(</span>line-end-position<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
         <span class="org-rainbow-delimiters-depth-4">(</span>string <span class="org-rainbow-delimiters-depth-5">(</span>buffer-substring-no-properties beg end<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
         <span class="org-rainbow-delimiters-depth-4">(</span>found
          <span class="org-rainbow-delimiters-depth-5">(</span>cl-member string
                     categories
                     <span class="org-builtin">:test</span>
                     <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-7">(</span>string cat-entry<span class="org-rainbow-delimiters-depth-7">)</span>
                       <span class="org-rainbow-delimiters-depth-7">(</span>string-match <span class="org-rainbow-delimiters-depth-8">(</span>regexp-quote <span class="org-rainbow-delimiters-depth-9">(</span>downcase <span class="org-rainbow-delimiters-depth-1">(</span>car cat-entry<span class="org-rainbow-delimiters-depth-1">)</span><span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span>
                                     string<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">when</span> <span class="org-rainbow-delimiters-depth-4">(</span>car found<span class="org-rainbow-delimiters-depth-4">)</span>
      <span class="org-rainbow-delimiters-depth-4">(</span>sacha/org-move-current-item-to-category
       <span class="org-rainbow-delimiters-depth-5">(</span>cdr <span class="org-rainbow-delimiters-depth-6">(</span>car found<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
      t<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>After that, I wrote a function that used Helm to prompt me for a category in case it couldn&apos;t guess the category. It took me a while to figure out that I needed to use <code>:init</code> instead of <code>:candidates</code> because I wanted to read information from the buffer before Helm kicked in.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>setq sacha/helm-org-list-category-source
      <span class="org-rainbow-delimiters-depth-2">(</span>helm-build-sync-source
          <span class="org-string">&quot;Non-link categories in the current list&quot;</span>
        <span class="org-builtin">:init</span> &apos;sacha/helm-org-list-categories-init-candidates
        <span class="org-builtin">:candidates</span> &apos;sacha/helm-org-list-candidates
        <span class="org-builtin">:action</span> &apos;sacha/org-move-current-item-to-category
        <span class="org-builtin">:fuzzy-match</span> t<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>

<span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span> <span class="org-function-name">sacha/org-guess-uncategorized</span> <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>interactive<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span>sacha/helm-org-list-categories-init-candidates<span class="org-rainbow-delimiters-depth-2">)</span>
  <span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let</span> <span class="org-rainbow-delimiters-depth-3">(</span>done<span class="org-rainbow-delimiters-depth-3">)</span>
    <span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">while</span> <span class="org-rainbow-delimiters-depth-4">(</span>not done<span class="org-rainbow-delimiters-depth-4">)</span>
      <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">save-excursion</span>
        <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">unless</span> <span class="org-rainbow-delimiters-depth-6">(</span>sacha/org-guess-list-category sacha/helm-org-list-candidates<span class="org-rainbow-delimiters-depth-6">)</span>
          <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">unless</span>
              <span class="org-rainbow-delimiters-depth-7">(</span>helm <span class="org-builtin">:sources</span>
                    &apos;<span class="org-rainbow-delimiters-depth-8">(</span>sacha/helm-org-list-category-source
                      sacha/helm-org-list-category-create-source<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span>
            <span class="org-rainbow-delimiters-depth-7">(</span>setq done t<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
      <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">unless</span> done
        <span class="org-rainbow-delimiters-depth-5">(</span>setq done <span class="org-rainbow-delimiters-depth-6">(</span>not <span class="org-rainbow-delimiters-depth-7">(</span>looking-at <span class="org-string">&quot;^[-+] \\[&quot;</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>The <code>:action</code> above refers to this function, which creates a category if it doesn&apos;t exist yet.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>setq sacha/helm-org-list-category-create-source
      <span class="org-rainbow-delimiters-depth-2">(</span>helm-build-dummy-source
          <span class="org-string">&quot;Create category&quot;</span>
        <span class="org-builtin">:action</span> <span class="org-rainbow-delimiters-depth-3">(</span>helm-make-actions
                 <span class="org-string">&quot;Create category&quot;</span>
                 <span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">lambda</span> <span class="org-rainbow-delimiters-depth-5">(</span>candidate<span class="org-rainbow-delimiters-depth-5">)</span>
                   <span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">save-excursion</span>
                     <span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">let*</span> <span class="org-rainbow-delimiters-depth-7">(</span><span class="org-rainbow-delimiters-depth-8">(</span>beg <span class="org-rainbow-delimiters-depth-9">(</span>line-beginning-position<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span>
                            <span class="org-rainbow-delimiters-depth-8">(</span>end <span class="org-rainbow-delimiters-depth-9">(</span>line-end-position<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span>
                            <span class="org-rainbow-delimiters-depth-8">(</span>string <span class="org-rainbow-delimiters-depth-9">(</span>buffer-substring beg end<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span>
                       <span class="org-rainbow-delimiters-depth-7">(</span>delete-region beg <span class="org-rainbow-delimiters-depth-8">(</span>min <span class="org-rainbow-delimiters-depth-9">(</span>1+ end<span class="org-rainbow-delimiters-depth-9">)</span> <span class="org-rainbow-delimiters-depth-9">(</span>point-max<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span>
                       <span class="org-rainbow-delimiters-depth-7">(</span>org-beginning-of-item-list<span class="org-rainbow-delimiters-depth-7">)</span>
                       <span class="org-rainbow-delimiters-depth-7">(</span>insert <span class="org-string">&quot;- &quot;</span> candidate <span class="org-string">&quot;\n  &quot;</span> string <span class="org-string">&quot;\n&quot;</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
                   <span class="org-rainbow-delimiters-depth-5">(</span>sacha/helm-org-list-categories-init-candidates<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>I&apos;m new to fiddling with Helm, so this implementation is not the best it could be. But it&apos;s nifty and it works the way I want it to, hooray! Now I can generate a list of blog posts and unblogged sketches, categorize them quickly, and then tweak the categorizations afterwards.</p>
<p><a href="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Index-card-sketches-and-monthly-reviews-index-card-organization-pkm-indexing.png"><img loading="lazy" class="alignnone size-medium wp-image-27925" src="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Index-card-sketches-and-monthly-reviews-index-card-organization-pkm-indexing-640x383.png" alt="2015-02-01 Index card sketches and monthly reviews &#45;&#45; index card #organization #pkm #indexing" width="640" height="383" srcset="https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Index-card-sketches-and-monthly-reviews-index-card-organization-pkm-indexing-640x383.png 640w, https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Index-card-sketches-and-monthly-reviews-index-card-organization-pkm-indexing-280x168.png 280w, https://sachachua.com/blog/wp-content/uploads/2015/02/2015-02-01-Index-card-sketches-and-monthly-reviews-index-card-organization-pkm-indexing.png 1497w" sizes="(max-width: 640px) 100vw, 640px"></a></p>
<p></p><div class="sketch-thumbnail"><a class="photoswipe" href="https://sketches.sachachua.com/filename/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" data-src="https://sketches.sachachua.com/static/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" data-title="2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating" data-w="1497" data-h="896"><picture>
      <img src="https://sketches.sachachua.com/thumbnails/2015-02-01%20Accelerating%20my%20learning%20&#45;&#45;%20index%20card%20%23learning%20%23accelerating.png" width="" height="" alt="2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating" loading="lazy" decoding="async">
      <figcaption>2015-02-01 Accelerating my learning &#45;&#45; index card #learning #accelerating</figcaption>
    </picture></a></div><p></p>
<p>You can see the results in my <a href="https://sachachua.com/blog/2015/02/monthly-review-january-2015/">January 2015</a> review, or check my <a href="https://sachachua.com/dotemacs">config</a> to see if the code has changed.</p>
<p>My next step for learning more about Helm sources is probably to write a Helm command that creates a montage of selected images. John Kitchin has a post about <a href="http://kitchingroup.cheme.cmu.edu/blog/">handling multiple selection in Helm</a>, so I just need to combine that with my code for using Imagemagick to create a montage of images. Whee!</p>

<p>You can <a href="https://sachachua.com/blog/2015/02/digital-index-piles-emacs-rapid-categorization-org-mode-items/#comment">view 1 comment</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2015%2F02%2Fdigital-index-piles-emacs-rapid-categorization-org-mode-items%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Emacs kaizen: helm-swoop and editing</title>
		<link>https://sachachua.com/blog/2015/01/emacs-kaizen-helm-swoop-editing/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Mon, 26 Jan 2015 21:00:00 GMT</pubDate>
    <category>emacs</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27659</guid>
		<description><![CDATA[<p> Continuing on this quest to focus on one tiny little workflow change at a time, so that I can get even better at using Emacs&#x2026; </p>
<p> One of those packages I installed but never got around to trying out was <code>all</code>, which lets you interactively edit all lines matching a given regular expression. It&#8217;s like an editable occur, sorta. </p>
<p> It turns out that <code>helm-swoop</code> lets you use <code>C-c C-e</code> to edit matching lines interactively (so you can use keyboard macros or replace-regexp or whatever). You can type <code>C-x C-s</code> to save it back to the buffer. </p>
<p> On a related note, I&#8217;m still tickled pink every time I use <code>dired-toggle-read-only</code> (<code>C-x C-q</code>) to make a Dired buffer editable so that I can batch-rename filenames. </p>

<p>You can <a href="https://sachachua.com/blog/2015/01/emacs-kaizen-helm-swoop-editing/#comment">view 11 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2015%2F01%2Femacs-kaizen-helm-swoop-editing%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Emacs kaizen: ace-isearch combines ace-jump-mode and helm-swoop</title>
		<link>https://sachachua.com/blog/2015/01/emacs-kaizen-ace-isearch-combines-ace-jump-mode-helm-swoop/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Wed, 07 Jan 2015 13:00:00 GMT</pubDate>
    <category>emacs</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27658</guid>
		<description><![CDATA[<p> I&#8217;m a fan of clever little things that change their behaviour depending on what you&#8217;re doing while letting you mentally think of it as just one function. </p>
<p> <code>ace-isearch</code> looks like it&#8217;ll be useful for collapsing three different functions into one mental thing in my head: </p>
<ul class="org-ul">
<li>jumping to a specific character that I can see (ace-jump-mode)
</li>
<li>searching through a buffer for a few characters (isearch)
</li>
<li>doing <code>helm-swoop</code> to quickly preview and navigate through matching lines in a buffer
</li>
</ul>
<p> If you install the <code>ace-isearch</code> package and turn on <code>global-ace-isearch-mode</code>, then searching for a single character triggers <code>ace-jump-mode</code>, searching for less than 5 characters triggers <code>isearch</code>, and anything longer triggers <code>helm-swoop-from-isearch</code>. You can customize those thresholds, of course. </p>
<p> Neat! </p>

<p>You can <a href="https://sachachua.com/blog/2015/01/emacs-kaizen-ace-isearch-combines-ace-jump-mode-helm-swoop/#comment">view 5 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2015%2F01%2Femacs-kaizen-ace-isearch-combines-ace-jump-mode-helm-swoop%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Emacs: M-y as helm-show-kill-ring</title>
		<link>https://sachachua.com/blog/2014/12/emacs-m-y-helm-show-kill-ring/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Wed, 10 Dec 2014 13:00:00 GMT</pubDate>
    <category>emacs</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27640</guid>
		<description><![CDATA[<p>After realizing that I barely scratched the surface of Helm's awesomeness (really, I basically use it as an <code>ido-vertical-mode</code>), I made a concerted effort to explore more of the interesting things in the Helm toolkit. <code>helm-show-kill-ring</code> is one such thing. I've bound it to <code>M-y</code>, which I had previously configured to be <code>browse-kill-ring</code>, but <code>helm-show-kill-ring</code> is much cooler because it makes it easy to dynamically filter your kill ring. Also, Kcode>M-y works better for me than <code>C-y</code> does because I know when I want the last thing I killed, but going beyond that is a little annoying.</p>
<p>That said, <code>browse-kill-ring</code> does make it easy to edit a kill ring entry. Maybe I should learn how to modify Helm's behaviour so that I can add an edit action. There's already a delete action. Besides, I haven't used that feature in <code>browse-kill-ring</code> yet, so I can probably get by even without it.</p>
<p><code>ido</code> fans: you can use <code>helm-show-kill-ring</code> without activating <code>helm-mode</code>, if you want.</p>
<p>On a related note, I like how rebinding <code>M-x</code> (<code>execute-extended-comand</code>) to <code>helm-M-x</code> shows me keybindings as I search for commands. You do have to get used to the quirk of typing <code>C-u</code> and other prefixes <b>after</b> <code>M-x</code> instead of before, but I haven't had a problem with this yet. This is mostly because I haven't dug into just how many commands do awesome things when given a prefix argument. I know about using <code>C-u C-c C-w</code> (<code>org-refile</code>) to jump to places instead of refiling notes, but that's about it. I haven't gone anywhere close to <code>C-u C-u</code>. Does anyone have a favourite command they use that does really smart things when given that prefix? =)</p>
<p>This <a href="http://tuhdo.github.io/helm-intro.html">Helm intro</a> has animated GIFs and a few other useful commands. Check it out!</p>

<p>You can <a href="https://sachachua.com/blog/2014/12/emacs-m-y-helm-show-kill-ring/#comment">view 18 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2014%2F12%2Femacs-m-y-helm-show-kill-ring%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item><item>
		<title>Emacs Basics: Call commands by name with M-x (with tips for better completion using ido or helm)</title>
		<link>https://sachachua.com/blog/2014/03/emacs-basics-call-commands-name-m-x-tips-better-completion-using-ido-helm/</link>
		<dc:creator><![CDATA[Sacha Chua]]></dc:creator>
		<pubDate>Mon, 31 Mar 2014 12:00:51 GMT</pubDate>
    <category>emacs</category>
<category>emacs-basics</category>
<category>podcast</category>
		<guid isPermaLink="false">https://sachachua.com/blog/?p=27062</guid>
		<description><![CDATA[<p>Emacs has way too many keyboard shortcuts to memorize. Fortunately, you can call commands by name by typing <kbd>M-x</kbd> and the name of the command. <kbd>M-</kbd> stands for the Meta key. If your keyboard does not have a Meta key (and most don't, these days), use Alt or Option. For example, on a PC keyboard, you can type <kbd>Alt-x</kbd>. Alternatively, you can replace <kbd>Meta</kbd> with <kbd>ESC</kbd>. <kbd>M-x</kbd> then becomes <kbd>ESC x</kbd>.</p>
<p><iframe loading="lazy" src="https://www.youtube.com/embed/m7GlzatkvyY" width="640" height="480" frameborder="0" allowfullscreen="allowfullscreen"></iframe></p>
<p>If you know the name of the command to execute, you can type it after <kbd>M-x</kbd>, and then press <kbd>RET</kbd> (the <kbd>Return</kbd> key, which is the same as the <kbd>Enter</kbd> key). For example, <kbd>M-x find-file</kbd> opens a file. <kbd>M-x save-buffer</kbd> saves the current file. You can use <kbd>TAB</kbd> to complete words. Use <kbd>&lt;up&gt;</kbd> and <kbd>&lt;down&gt;</kbd> to go through your command history.</p>
<p>What if you don't know the name of the command to execute? You can use <kbd>M-x apropos-command</kbd> to search for the command using keywords. If you know the keyboard shortcut or you can find the command on a menu, you can also use <kbd>M-x describe-key</kbd> and then do the keyboard shortcut or select it from the menu.</p>
<p>If a command you execute has a keyboard shortcut, it will flash briefly at the bottom of your screen. For example:</p>
<pre class="example">You can run the command `find-file' with C-x C-f</pre>
<p>Using <kbd>TAB</kbd> for completion can be a little slow. Here are two ways to make that and a whole lot of other things faster: <b>ido</b> and <b>helm</b>. To explore these approaches, you will need to add the MELPA package repository to your configuration. To set that up, add the following to the beginning of your <code>~/.emacs.d/init.el</code> file.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(package-initialize)
(add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/") t)</pre>
</div>
<p>Then use <kbd>M-x eval-buffer</kbd> to load the changes into your current Emacs, and use <kbd>M-x package-refresh-contents</kbd> to reload the list of packages.</p>
<div id="outline-container-sec-2" class="outline-2">
<h3 id="sec-2">Helm mode</h3>
<div id="text-2" class="outline-text-2">
<p>This is what completion with Helm looks like:</p>
<div class="figure">
<p><img src="https://sachachua.com/blog/wp-content/uploads/2014/03/wpid-2014-03-17-13_06_54-c__sacha_personal_organizer.org_.png" alt="2014-03-17 13_06_54-c__sacha_personal_organizer.org.png" width="640"></p>
<p><span class="figure-number">Figure 2:</span> Helm</p>
</div>
<p>Use <kbd>M-x package-install</kbd> to install the <code>helm</code> package. Then you can try it out with <kbd>M-x helm-mode</kbd> . After you start Helm mode, try <kbd>M-x</kbd> again. You can type in multiple words to search for a command, and you can use <kbd>&lt;up&gt;</kbd> and <kbd>&lt;down&gt;</kbd> to go through completions. Use <kbd>M-p</kbd> and <kbd>M-n</kbd> to go through your command history.</p>
<p>If you like it, here's some code that you can add to your <code>~/.emacs.d/init.el</code> file to load it automatically next time, and to tweak it for more convenience.</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(require 'helm-config) 
(helm-mode 1)</pre>
</div>
<p>Use <kbd>M-x eval-buffer</kbd> to load your changes.</p>
<p>If you change your mind and want to disable <code>helm-mode</code>, you can toggle it off with <kbd>M-x helm-mode</kbd> .</p>
<p>If you like how that works, you may want to <code>(global-set-key (kbd "M-x") 'helm-M-x)</code>. If you do, you'll be able to see keybindings when you call commands with <code>M-x</code>. Note that if you want to use a prefix argument (ex: <code>C-u</code>), you will need to do that <em>after</em> calling <code>M-x</code> instead of before.
</p></div>
</div>
<div id="outline-container-sec-1" class="outline-2">
<h3 id="sec-1">Ido, ido-hacks, smex, ido-vertical-mode, and flx-ido</h3>
<div id="text-1" class="outline-text-2">
<p>Ido is like Helm, but it takes a different approach. Here's what this combination will get you:</p>
<div class="figure">
<p><img src="https://sachachua.com/blog/wp-content/uploads/2014/03/wpid-2014-03-17-12_40_40-MELPA.png" alt="2014-03-17 12_40_40-MELPA.png" width="640"></p>
<p><span class="figure-number">Figure 1:</span> ido, smex, ido-vertical-mode, and flx-ido</p>
</div>
<p>If you want to give this a try, remove or comment out <code>(helm-mode 1)</code> from your <code>~/.emacs.d/init.el</code> (if you added it), and disable helm-mode if you still have it active from the previous section.</p>
<p>To set Ido up, use <kbd>M-x package-install</kbd> to install <code>ido</code>, <code>smex</code>, <code>ido-vertical-mode</code>, <code>ido-hacks</code>, and <code>flx-ido</code>.</p>
<p>After the packages are installed, add the following code to your <code>~/.emacs.d/init.el</code> .</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(ido-mode 1)
(require 'ido-hacks nil t)
(if (commandp 'ido-vertical-mode) 
    (progn
      (ido-vertical-mode 1)
      (setq ido-vertical-define-keys 'C-n-C-p-up-down-left-right)))
(if (commandp 'smex)
    (global-set-key (kbd "M-x") 'smex))
(if (commandp 'flx-ido-mode)
    (flx-ido-mode 1))</pre>
</div>
<p>Use <kbd>M-x eval-buffer</kbd> to load your changes, then try <kbd>M-x</kbd> again. You should now have much better completion. You'll be able to call commands by typing in part of their names. Use <kbd>&lt;up&gt;</kbd> and <kbd>&lt;down&gt;</kbd> to go through the completion options, and use <kbd>&lt;left&gt;</kbd> and <kbd>&lt;right&gt;</kbd> to go through your history.</p>
<p>Try it for a week. If you like it, keep it. If you don't like it, try the Helm approach.</p>
</div>
</div>
<div id="outline-container-sec-3" class="outline-2">
<h3 id="sec-3">Other tips</h3>
<div id="text-3" class="outline-text-2">
<p>When you learn keyboard shortcuts, try to remember the names of the commands as well. You can do that with <kbd>C-h k</kbd> (<code>describe-key</code>). For example, <kbd>M-x</kbd> calls the command <code>execute-extended-command</code>. That way, even if you forget the keyboard shortcut, you can call the command by name.</p>
<p>If you forget the name of the command and you don't know the keyboard shortcut for it, you can look for it in the menus or in the help file. You can open the help file with <kbd>C-h i</kbd> (<code>info</code>). You can also use <kbd>M-x apropos-command</kbd> to search through the commands that you can call with <kbd>M-x</kbd>.</p>
<p>Make your own cheat sheet with frequently-used keyboard shortcuts and commands to help you learn more about Emacs. Good luck!</p>
<div id="attachment_27064" style="width: 650px" class="wp-caption alignnone"><a href="https://sachachua.com/blog/wp-content/uploads/2014/03/emacs-basics-meta-x.png"><img aria-describedby="caption-attachment-27064" loading="lazy" class="size-medium wp-image-27064" src="https://sachachua.com/blog/wp-content/uploads/2014/03/emacs-basics-meta-x-640x448.png" alt="Emacs Basics: M-x" width="640" height="448" srcset="https://sachachua.com/blog/wp-content/uploads/2014/03/emacs-basics-meta-x-640x448.png 640w, https://sachachua.com/blog/wp-content/uploads/2014/03/emacs-basics-meta-x-280x196.png 280w, https://sachachua.com/blog/wp-content/uploads/2014/03/emacs-basics-meta-x.png 1500w" sizes="(max-width: 640px) 100vw, 640px"></a><p id="caption-attachment-27064" class="wp-caption-text">Emacs Basics: M-x</p></div>
<p><a href="http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3">You can download the MP3 from archive.org.</a></p>
</div>
</div>
<div class="powerpress_player" id="powerpress_player_5465"><audio class="wp-audio-shortcode" id="audio-27062-9" preload="none" style="width: 100%;" controls="controls"><source type="audio/mpeg" src="http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3?_=9"><a href="http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3">http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3</a></audio></div><p class="powerpress_links powerpress_links_mp3">Podcast: <a href="http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3" class="powerpress_link_pinw" target="_blank" title="Play in new window" onclick="return powerpress_pinw('https://sachachua.com/blog/?powerpress_pinw=27062-podcast');" rel="nofollow">Play in new window</a> | <a href="http://archive.org/download/EmacsBasicsCallingCommandsByNameWithMX/Emacs-Basics-Calling-commands-by-name-with-M-x.mp3" class="powerpress_link_d" title="Download" rel="nofollow" download="Emacs-Basics-Calling-commands-by-name-with-M-x.mp3">Download</a></p><p class="powerpress_links powerpress_subscribe_links">Subscribe: <a href="https://sachachua.com/blog/feed/podcast/" class="powerpress_link_subscribe powerpress_link_subscribe_rss" title="Subscribe via RSS" rel="nofollow">RSS</a></p>
<p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2014%2F03%2Femacs-basics-call-commands-name-m-x-tips-better-completion-using-ido-helm%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></description>
		</item>
	</channel>
</rss>