Drafts and iCloud Drive

I didn’t renew my Dropbox Plus account when it expired a month or two ago. For several months I’d had both it and a 2 TB iCloud account active at the same time and had been moving my files and my way of working from one to the other. This was mainly due to my shift over the past four years from being Mac-only to Mac-mainly to iPad-mainly. While the Finder is equally adept at managing files in either cloud, Files is much better with files on iCloud Drive.

My concern was with Drafts. There are programmatic ways to save a draft to a specified file in Dropbox—I use a “filelines” system similar to Vim’s modelines in which the file path is embedded in the text of the draft—but sandboxing prevents that working with file paths in iCloud Drive. Here’s a Drafts forum thread in which Greg Pierce (agiletortoise) explains the problem.

As it turned out, my concern was overblown. Shortly after writing this post in which I talk about writing almost everything in Drafts, I started write almost everything that needs to be saved as a file in Textastic. Textastic is file-based and can read and write anywhere in iCloud Drive (or anyplace Files can access) without continual user approval.

Still, I did occasionally miss being able to use filelines to save drafts directly to iCloud Drive. It wasn’t until this past week that I realized there was a way around it by using Scriptable.

Scriptable has a feature called “bookmarks,” which are ways to access files (and folders) outside of the Scriptable sandbox. You create them by choosing File Bookmarks in Settings.

Scriptable settings

Then tap the + button in the upper right corner and choose Pick Folder from the popup menu.

Add Scriptable bookmark

You’re now presented with the usual Files-style list of file providers. Choose iCloud Drive.

Choose folder from Files picker

Finally, you’re asked to choose a name for this bookmark. I chose “iCloud.”

Bookmark naming

You can now use this bookmark and Scriptable’s FileManager library to access any folder or file in iCloud Drive. The great thing about this is that you’re not limited to just the top level of iCloud Drive—any file or folder at any level in the hierarchy below iCloud Drive is accessible.

With this bookmark defined, I can create a system that looks for an iCloud fileline, a line in a draft that contains

icloud:/path/to/subfolder/filename.txt

and saves the contents of the draft to a file in the given location. Typically, this line will be in a comment, so it will be

# icloud:/path/to/subfolder/filename.py

for a Python file or

% icloud:/path/to/subfolder/filename.tex

for a LaTeX file.

The system consists of two parts:

  1. A Drafts action that gets the fileline, extracts the path, and sends the path and the full draft contents to a shorcut.
  2. A shortcut that takes the information from the previous step and writes the contents of the draft to the given file.

The Drafts action (which you can download), starts with this JavaScript step,

javascript:
 1:  // Get the folder and filename from the dbox line.
 2:  var d = draft.content;
 3:  
 4:  // Regex for fileline.
 5:  var fileRE = /icloud:\s*(.+)\s*$/m;
 6:  if (fileRE.test(d)) {
 7:    // Get the path. Add a slash to the front if I forgot.
 8:    var path = d.match(fileRE)[1];
 9:    if (path[0] != '/') {
10:      path = '/' + path;
11:    }
12:  
13:    // Create a JSON template to pass to Scriptable via Shortcuts
14:     var fileinfo = {"path":path, "text":d};
15:    
16:    // Create a template tag from the dictionary.
17:    draft.setTemplateTag("fileinfo", JSON.stringify(fileinfo))
18:   
19:  } else {
20:    alert("No icloud: line");
21:    context.fail("No icloud: line");
22:  }

which extracts the path from the iCloud fileline. If there is no fileline, it stops the action with an alert. If there is a fileline, it creates a JSON dictionary with two entries: the path from the fileline and the full text of the draft. The dictionary is saved to a template tag in Line 17 so it can be passed to the next step of the action.

The second and final step in the Drafts action is this Run Shortcut step,

Run Shortcut step

which passes the dictionary created in the first step to a shortcut entitled “Save to iCloud.”

Here’s the “Save to iCloud” shortcut:

StepActionComment
0 Save to iCloud Step 00 Even though we won’t be using it from the Share Sheet, we define it this way so it can accept the text passed to it from Drafts.
1 Save to iCloud Step 01 The inline JavaScript, shown in full below, extracts the path and the file contents from the JSON dictionary and writes the draft contents to the given file. The “Run in App” setting has to be on for the bookmark to work.

Here’s the inline JavaScript:

javascript:
1:  // The argument passed in from Shortcuts should be a
2:  // JSON dictionary with "path" and "text" entries.
3:  var d = args.shortcutParameter;
4:  
5:  // Set up connection to the root level of iCloud Drive
6:  // through a Scriptable bookmark and save the text.
7:  var myFM = FileManager.iCloud();
8:  var iCloud = myFM.bookmarkedPath('iCloud');
9:  myFM.writeString(iCloud + d['path'], d['text']);

Line 3 gets the argument passed in and saves it to the JavaScript dictionary, d. The rest of the script gets the iCloud bookmark, appends the filepath to it, and writes the text of the draft to that file.

If you don’t feel like writing it yourself, you can download the shortcut.

My understanding (based on a post from its developer) is that Toolbox Pro is beta testing a similiar bookmarking system. If that gets released, it may simplify the shortcut.

There is a hitch in this system that’s unlikely to affect me but might affect you. Saving a draft from my iPad to iCloud drive works perfectly, and every time I edit the draft and resave it, the file is overwritten with the latest version of the draft, just as you would expect. But if I edit that draft on my iPhone and save it, a new file gets created in iCloud Drive. If the original file saved from the iPad was

/path/to/subfolder/filename.txt

the file saved from the iPhone will be

/path/to/subfolder/filename 2.txt

even though the fileline is still

icloud:/path/to/subfolder/filename.txt

I assume this has something to do with Scriptable bookmark on the iPhone being somehow different from the bookmark on the iPad, despite them both pointing to the same iCloud Drive location.

As I say, I don’t think this will affect me, as the writing I do on my phone tends to be ephemeral stuff. But it is one of those things that shows how iCloud Drive isn’t quite on the level as Dropbox (or Box or Google Drive or…) when it comes to working with Drafts.