Working with TextBundles

While evaluating Ulysses for writing future blog posts I stumbled upon the TextBundle file format which can be created by Ulysses and other editors like Bear.

To quote the specification:

The purpose of the TextBundle file format is to simplify the exchange of various plain text files together with additional images between sandboxed applications.

Let’s take this post as an example and export it as TextBundle. The result is a single file by the name of Working with TextBundles.textpack which is a compressed TextBundle:

unzip ./Working\ with\ TextBundles.textpack
Archive:  ./Working with TextBundles.textpack
   creating: Content.textbundle/
   creating: Content.textbundle/assets/
  inflating: Content.textbundle/assets/textbundle-logo.png
  inflating: Content.textbundle/
  inflating: Content.textbundle/info.json

Now, a TextBundle contains three main components:

  1. The text itself stored in text.*.

  2. Metadata about the bundle stored in info.json.

  3. Assets used within the text stored as separate files inside the assets/ folder. Metadata is mostly optional except for one thing: It has to specify the format-version of the bundle. At this point, version 2 is the latest and also used by Ulysses:

    { “creatorURL” : “file:///Applications/”, “transient” : false, “type” : “net.daringfireball.markdown”, “creatorIdentifier” : “com.ulyssesapp.mac”, “version” : 2 }

type is optional but defaults to net.daringfireball.markdown for backwards-compatibility. Theoretically, a bundle could contain multiple text files with different extensions but handling of such a case seems not to be specified by spec.

Since I might want to integrate Ulysses into my blogging workflow and TextBundle sounds like a decent exchange format, I started playing around with implementing a little Go library for reading TextPack files:

> r, _ := textbundle.OpenReader("Working with TextBundles.textpack")
> fmt.Println(string(r.Text))

# Working with TextBundles

> for _, a := range r.Assets {
>   fmt.Println(a.Name)
> }

As a little experiment I’ve also created a little import-textbundle command for my blog that uses this library 🙂

This post inspired...