Drafts and Dropbox redux

About a year ago, I wrote a post about using something I called filelines (akin to Vim’s modelines) and Drafts actions to save drafts to Dropbox. The little two-step action I wrote back then served me well for a long time, but I’ve recently updated it and created a reverse action for pulling files from Dropbox and putting their text into drafts.

The motivation for this is simple: although I do a lot of writing entirely in Drafts, text often needs to be saved in files before it can be used. And with longer pieces, like the reports I do for work, I often switch between working on my iPad and my Macs.1

The key to going back and forth between drafts and files is the fileline, a comment line that tells Drafts where that draft is saved as a file in Dropbox. In LaTeX, a fileline takes this form:

% dbox:/projects/ritchie.condo/report/report.tex

Similarly in Python:

# dbox:/projects/thompson.bridge/analysis/stringer.py

Basically, a fileline is dbox: followed by the POSIX-style path to the file, starting at the root of the Dropbox folder.

The action that saves a draft to the file specified in the fileline has just one step, this script:

javascript:
 1:  // Get Dropbox path from dbox: file line in draft
 2:  // and save the draft to that file.
 3:  
 4:  var d = draft.content;
 5:  
 6:  // Regex for fileline.
 7:  var fileRE = /dbox:(.+)$/m;
 8:  
 9:  if (fileRE.test(d)) {
10:    // Set the path. Add a slash to the front if I forgot.
11:    var fileline = d.match(fileRE);
12:    var flStart = d.search(fileRE);
13:    var path = fileline[1];
14:    if (path[0] != '/') {
15:      path = '/' + path;
16:      editor.setTextInRange(flStart + 5, 0, '/');
17:    }
18:    // Save the draft to the specified file.
19:    var db = Dropbox.create();
20:    var check = db.write(path, draft.content, "overwrite");
21:    if (!check) {
22:      alert("Couldn't save to " + path);
23:    }
24:  } else {
25:    alert("No dbox line");
26:  }

The basics of the script are simple; most of the code is there to handle mistakes I might make in creating the fileline.

Line 4 puts the content of the current draft into the variable d. Line 7 defines the regular expression used to find the fileline and extract the path from it.

The if/else block that starts on Line 9 tests whether there is a fileline in the draft. If there is, it does what we’ll talk about in the next few paragraphs; if not, it puts up an alert box (Line 25) warning me.

Assuming a fileline is present, Lines 11 and 12 get the matching text and its starting location in the draft. The starting location is the character position of the “d” in “dbox.” Line 13 then pulls out the part of the matching text corresponding to the parentheses in the regex and saves it to the path variable.

Lines 14–17 handle the case where I forget that the Dropbox path has to start with a slash. I have trouble remembering this because the path is relative to the Dropbox folder, and relative paths in Unix don’t start with a slash. But the Drafts scripting commands for communicating with Dropbox (which we’ll get to soon) require the leading slash. So if I forget, these lines add the leading slash to the path (Line 15) and add the slash to the fileline (Line 16).

Now we’re in the endgame. Line 19 creates the connection to Dropbox, and Line 20 saves the content of the draft (which may have been edited in Line 16) to the file defined by path. If something bad happens during the save, Line 22 tells me.

This action is called Save to Dropbox Fileline and I’ve given it the keyboard shortcut ⇧⌘S. I suppose I could have gone with just ⌘S, but that seemed presumptuous when I first wrote this action (too important a shortcut for my little script), and I haven’t changed it.

I use the reverse action when I started writing something on my iPad, wrote some more on the Mac, and then want to continue writing on the iPad. When I open the draft on my iPad, it won’t have the additions made on the Mac. But the fileline is there, so I can read in the text of the updated file from Dropbox and replace the draft with it. The action that does it, Reload from Dropbox Fileline (⇧⌘R), has a single step consisting of this script:

javascript:
 1:  // Get Dropbox path from dbox: file line in draft
 2:  // and replace draft with that file.
 3:  
 4:  var d = draft.content;
 5:  
 6:  // Regex for fileline.
 7:  var fileRE = /dbox:(.+)$/m;
 8:  
 9:  if (fileRE.test(d)) {
10:    // Set the path. Add a slash to the front if I forgot.
11:    var fileline = d.match(fileRE);
12:    var path = fileline[1];
13:    if (path[0] != '/') {
14:      path = '/' + path;
15:    }
16:    // Download file and replace the current draft.
17:    var db = Dropbox.create();
18:    var txt = db.read(path);
19:    editor.setText(txt);
20:  } else {
21:    alert("No dbox line");
22:  }

Most of the reloading script is the same as the saving script. The part that handles the possibility of my forgetting to include the leading slash in the path is simpler, because editing the draft to add it is of no value—the draft is going to be overwritten by the contents of the Dropbox file.2

Lines 18 and 19 are new. Line 18 reads the content of the file defined by path into the variable txt. Line 19 then replaces the content of the current draft with txt.

There are, of course, text editors for iOS that handle the syncing of files to Dropbox (or iCloud) automatically. If I could get as much functionality out of them as I can from Drafts, I would switch. But where can I go? I’ve had trouble with persistent scripting bugs in Editorial and it seems like abandonware now. 1Writer sounds like it has good scripting support, but when I tried it a year or two ago it just kept crashing (I probably should give it another look).

At the moment, Drafts is the only text editor I can bend to meet my needs, including reading and writing to files.


  1. The recent release of Drafts for the Mac has certainly been helpful in switching between platforms, but until the Mac Drafts feature set is on par with that of iOS Drafts, I’ll continue to do most of my writing on the Mac in BBEdit. 

  2. Given that I’ve already saved the draft to Dropbox—and my saving script adds the leading slash—the condition tested in Line 13 should never occur. But I’ve kept the test in anyway, because things that should never occur sometimes do.