Today I was bored and my playful mind presented me with an idea

I’m starting to use org-capture for lots of things, what if I create a capture entry for new capture entries?

and that’s what I did. It took me some time and didn’t end up quite perfect, but good and useful enough.


We’ll be using a plain type and use a non-org file as the target, so we are going to have to navigate and edit the file using elisp, and this assumes a specific structure.

In particular, it assumes that the file we’re using has this structure (and every space, line and character counts)

;; A lot of functions I showed before

(setq org-capture-templates
        ;; All the templates

(defun fdx/open-capture.el-buffer ()
  ;; An important function I'll explain in a moment

Why it’s not perfect

  • It doesn’t leave the file well indented (bummer, but easily solvable)
  • It doesn’t leave a space between templates. This is not needed, but I’d like to have it

How does it work?

We first add our new template

(setq org-capture-templates
        ;; All the other templates

        ("c" "Org-capture"          plain     (function fdx/open-capture.el-buffer)
         "        (\"%(fdx/prompt \"Key\" 'key)\" \"%(fdx/prompt \"Description\" 'description)\" %(fdx/prompt \"Type\" 'capture-type) %(fdx/prompt \"Target\" 'target)
         \"%(fdx/prompt \"Body\" 'body)%?\")")

And then we define the fdx/open-capture.el-buffer function

(defun fdx/open-capture.el-buffer ()
  (with-current-buffer (find-file "/path/to/org-capture/config/file.el")
    (search-forward "(setq org-capture-templates")
    (next-line) (end-of-line) (backward-char)
    (previous-line) (end-of-line)
    (newline) (newline)

It’s VERY IMPORTANT for this function to go AFTER the templates, because if not it won’t work properly.

What this function does is very nasty IMHO, but it works for this.

It first opens the file, then, using the newly opened buffer, it goes to the beginning and searches for the org-capture-templates definition (this is the step that messes everything up if the file structure is not maintained).

Then it advances a line, goes to the end and back a char. This places us in the opening parenthesis of the templates list.

Then it goes to the closing parenthesis and moves to the end of the previous line.

Finally it opens a couple of lines and tries to re-indent the buffer. Those two actions don’t actually work here, but I left them in.

And now we are placed in the last element of the list, ready to start filling out the template.

The template

The template is pretty simple, it just uses several prompts to fill in the different parts of the capture.

"        (\"%(fdx/prompt \"Key\" 'key)\" \"%(fdx/prompt \"Description\" 'description)\" %(fdx/prompt \"Type\" 'capture-type) %(fdx/prompt \"Target\" 'target)
        \"%(fdx/prompt \"Body\" 'body)%?\")"

I won’t go into too much detail here because it’ll be long and it’s self explanatory.


I did this as an experiment, to challenge myself and ended up with a result that I liked for the most part.

I hope you liked it too.