Zephyrizing

Thoughts on cast-iron seasoning, programming and everything…

Playing With Org-mode

| Comments

So, as a way to procrastinate on actually starting to write/practice my lightning talk for Thursday, I decided that I absolutely wanted to make a slide show using the org-html-slideshow, a pretty neat piece of Clojurescript written by those smart guys at Relevance Cognitect.

Basically, it lets you take an outline/document written in Org-mode (another really cool piece of software!) and put some small annotations in it to delimit your “slides” and then you have a document that can be viewed as either a slideshow, or a web page. It’s harder to explain in words than it is to observe, so here’s the example page from their github repo, and the org-mode document that produced that page.

Now that is pretty neat. However, the workflow needed to create one of these is sort of a pain. From the documentation on the project page, you’re expected to create a one-off web site that has the contents of this production folder available and then manually generate the html document from the org-mode source. Ick.

My blog is made with Jekyll, which is a static site generator. None of my posts are actually written in html, instead I write them in Markdown, and then Jekyll handling converts the markdown into html. When it does this I can also cause it to be inserted into a page template (i.e. layout). The upshot is, I can create a static site but not have to duplicate all of the code to have a common set of header info, navigation toolbar, nifty sidebar etc. Because only the unique things are specified in each document, and the general boilerplate is automatically included for me by Jekyll.

So if I’m generating html from markdown automatically with Jekyll it feels sort of wrong to be generating html manually with an interactive emacs command and then committing this generated html into my git repo. It would be so much nicer if I could just get Jekyll to invoke emacs as the translator for turning .org files into .html files.

Well, pursuing that line of thought today I worked with Waldemar Quevedo. He showed me his incredible org-based workflow for everything (he also gave an awesome lightning talk on it the first week of Hacker School!). While it looks really cool, it’s sort heavy-weight for what I want to do. Frankly, I’m really comfortable writing markdown, so I’ll probably continue to write most of my posts in it. But org-html-slideshow is exciting enough that I’d be willing to write my presentations in Org-mode so I can utilize it.

I won’t attempt to explain Wally’s setup, but he’s got some pretty cool stuff going on. In essence though, he uses a ruby gem to parse the org syntax and transform it into markdown. As of this writing though, it doesn’t support the tags feature that org-html-slideshow depends on for it’s functionality.

While showing Wally the slideshow thing got him excited to try and integrate it into his workflow, I started poking around and looking at how to integrate it into my site. The solution I decided on was to make .org files a generic member of the Jekyll source files. This means that they’ll still use a YAML frontmatter to mark that they need to be transformed. This means that I need some way to transform a body of org text into just the html content that it represents. Normally when you generate an html page from org-mode, you get a complete html page, html, body tags and all. What I needed was a way to invoke the org->html transformation using the Elisp code in org-mode from Jekyll.

With Wally’s help, I was able to get this far towards that goal. This is the elisp that will continuously read from the minibuffer until an error occurs, and then transform that text using the org->html backend, and finally print out the generated html.

1
2
3
4
5
6
7
8
9
10
11
12
(progn
  (require 'org)
  (progn
    (condition-case nil
        (while t
          (insert (read-string "") "\n"))
      (error nil))
    (set-buffer
     (org-export-to-buffer 'html "*Org HTML Export*"
       nil nil nil t nil
       (lambda () t)))
       (message "%s" (buffer-string))))

And this is how you invoke the transformation of a file from org to html. The $emacs is because I use Emacs for Mac OSX which means that my emacs executable is buried inside of a mac .app file/folder thing. Pipe a file into this script and if it’s valid org syntax, you’ll get the corresponding html.

1
tail -n+4 hello.org | $emacs --batch --eval "(progn (require 'org) (progn (condition-case nil (while t (insert (read-string \"\") \"\\n\")) (error nil)) (set-buffer (org-export-to-buffer 'html \"*Org HTML Export*\" nil nil nil t nil (lambda () t))) (message \"%s\" (buffer-string))))"

Now the only thing that’s left is to write a Jekyll plugin to do this invocation to produce the final output. This is what I came up with as a first attempt. Of course, it doesn’t actually work for me, because of the dumb location of my emacs executable… Oh well, that’s for tomorrow.

Edit 10/28: So I spent the first half of today fixing this up. Turned out to be more involved than I suspected. I had to evolve the emacs lisp command enough that I actually made a separate git repo for it. I fixed the problem of locating a proper emacs binary by deferring to an appropriately named environment variable. I originally implemented this shortcut by letting the user specify the location of emacs in their _config.yml. But then I realized, this is not a configuration that happens per-site, it’s per machine so the site config file is totally inappropriate. It’s kind of annoying though since if I forget to specify this environment variable then my site generation won’t work…

Anyhow, it works and as proof I made a version of the example presentation that is generated by my plugin, not by hand. You don’t have to take my word for it, but you will have to look at the git repository for this site.

And here is the final code for my org-mode plugin generator:

“Org Converter” (org_converter.rb) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# A generator that uses a emacs invoked in batch mode to process
# org-mode files into html

require 'open3'

module Jekyll

  class OrgModeConverter < Converter
    safe false
    priority :low

    @@emacs_org_html_cmd = "(progn (require (quote org)) (setq font-lock-mode t) (setq org-html-head-include-default-style nil) (setq org-html-head-include-scripts nil) (condition-case nil (while t (insert (read-string \"\") \"\n\")) (error nil)) (set-buffer (org-export-to-buffer (quote html) \"*Org HTML Export*\" nil nil nil t nil (lambda nil t))) (send-string-to-terminal (buffer-string) nil))"

    def matches(ext)
      ext =~ /^\.org$/i
    end

    def output_ext(ext)
      ".html"
    end

    def convert(content)
      emacs_path = if ENV.has_key?("EMACS")
                     ENV["EMACS"]
                   else
                     `which emacs`
                   end

      if emacs_path.empty?
        puts "Could not find an emacs executable."
      else
        out, status = Open3.capture2("#{emacs_path} --batch --eval " +
                                     "#{@@emacs_org_html_cmd.inspect}",
                                     :stdin_data=>content)
        out unless status != 0
      end

    end
  end
end

Comments