Soon to be a major emacs mode.

Org capture tricks

I recently started to use quite big org capture templates at work. They describe my usual workflow for a complete ticket (triage, implementation, code review, deploy). To make the capturing more efficient, I came up with three helpful functions:

EDIT: This post got updated with some code improvements on 03/05/2016.

Use user input in several locations

Org capture templates can prompt for user input, but then only inserts it at one location. This is quite limiting. The template I created asked for a JIRA ticket number and I wanted to use it throughout my template without prompting for the same thing again.

But org capture supports custom lisp expressions. That's like allowing cheat codes. Super powerful. So I wrote a function that will prompt the user for a string, save it to a buffer local variable and return it (so it is inserted at the first location).

(defvar oc-capture-prmt-history nil
  "History of prompt answers for org capture.")
(defun oc/prmt (prompt variable)
  "PROMPT for string, save it to VARIABLE and insert it."
  (make-local-variable variable)
  (set variable (read-string (concat prompt ": ") nil oc-capture-prmt-history)))

For inserting progn is all you need. So let's say I have a capture template like this:

* JIRA Ticket %(oc/prmt "JIRA Project" 'jr-prj)-%(oc/prmt "JIRA Ticket No." 'jr-no)
For project %(prgn jr-prj) I have to do the following stuff:
** Triage %(progn jr-prj)-%(progn jr-no)
Do the triage.
** Implement %(progn jr-prj)-%(progn jr-no)
Implement stuff
- [ ] Tests pass?

It has two calls to oc/prmt in the first heading and several calls to oc/ins afterwards.

Orc capture will first prompt for the JIRA project: /assets/blog/2016/05/02/org-capture-tricks/org-capture-jira-prj-prmt.png

Then for the ticket number: /assets/blog/2016/05/02/org-capture-tricks/org-capture-jira-no.png

Afterwards everywhere I use oc/ins, the stored text is inserted: /assets/blog/2016/05/02/org-capture-tricks/org-capture-prmt-finish.png

Conditionally insert text

Sometimes I don't need a triage or an implementation for a ticket. So it would be nice to have org-capture ask whether I want to include a section.

The function is very minimal:

(defun oc/inc (what text &rest fmtvars)
  "Ask user to include WHAT.  If user agrees return TEXT."
  (when (y-or-n-p (concat "Include " what "?"))
    (apply 'format text fmtvars))

The capture template starts to look a little bit ugly:

* JIRA Ticket %(oc/prmt "JIRA Project" 'jr-prj)-%(oc/prmt "JIRA Ticket No." 'jr-no)
For project %(progn jr-prj) I have to do the following stuff:
%(oc/inc "triage"
 "** Triage %s-%s
Do the triage."
 jr-prj jr-no)
%(oc/inc "implementation"
 "** Implement %s-%s
Implement stuff
- [ ] Tests pass?"
 jr-prj jr-no)

So after getting prompted for the project and ticket number, org-capture will ask whether to include the triage: /assets/blog/2016/05/02/org-capture-tricks/org-capture-include-triage.png

Then for the implementation. You can see that the triage text already got inserted: /assets/blog/2016/05/02/org-capture-tricks/org-capture-include-implementation.png

The fully expanded template looks like this: /assets/blog/2016/05/02/org-capture-tricks/org-capture-include-all.png

If you decide not to include a section, a blank line remains: /assets/blog/2016/05/02/org-capture-tricks/org-capture-include-one.png You could fix that by putting all the include statements in one line and add a newline at the end of the text but that would look very ugly. Unfortunately it's not easy to work around that.

Let me know if you find this useful or have other ideas for org capture templates.


comments powered by Disqus