Skip to content

Instantly share code, notes, and snippets.

@blackfog
Last active December 13, 2015 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blackfog/4961201 to your computer and use it in GitHub Desktop.
Save blackfog/4961201 to your computer and use it in GitHub Desktop.
As described here (http://craigipedia.blogspot.com/2013/02/linking-drafts-day-one-and-textexpander.html) this script provides the glue between Drafts, TextExpander, Pythonista, and Day One on iOS to bring TextExpander fill-in support to a workflow.
#!/usr/bin/env python
#############################################################################
#
# Fill-in Expander
# (c) 2013 Craig A. Pearlman
# code@craig.blackfog.net
#
# This code is licensed under a Creative Commons Attribution 3.0 Unported
# license (http://creativecommons.org/licenses/by/3.0/). Attribution is not
# required, but it would be a nice gesture.
#
# This is my first (real) python script. Please make corrections. I know it's
# a tad clumsy.
#
#############################################################################
#
# Call from Drafts with a custom URL action as follows:
#
# pythonista://fillin_expander?action=run&argv=[urlencoded snippet]
#
# Essentially, fill in the form in Drafts with the proper values. You will
# need to expand the snippet in Drafts, as well. If you want the action to
# fire off Day One at the end, you will need to enable firing actions from
# URL support in Drafts' settings.
#
# When done, this will return the filled-in snippet back to Drafts and then
# automatically shove it off to Day One (you can modify this behavior to suit
# your needs).
#
#############################################################################
# NOTE: this does not currently support "optional sections" (don't use 'em)
# TODO: See if there's a way to do this more graphically
### REQUIREMENTS ###
import console
import re
import sys
import urllib
import webbrowser
### FUNCTIONS ###
def parse_fillin(parts):
properties = dict()
last_key = 'type'
for part in parts:
components = re.split('=', part)
if 'type' in properties and \
properties['type'] == 'fillpopup' and \
'options' not in properties:
properties['options'] = []
if (len(components) == 1):
if last_key == 'options':
properties['options'].append(components[0])
else:
properties[last_key] = components[0]
last_key = 'options'
else:
if components[0] == 'default':
properties['default'] = components[1]
if 'options' in properties and 'default' in properties:
properties['options'].append(properties['default'])
else:
properties[ components[0] ] = components[1]
return properties
def prompt_text(properties):
prompt = 'TEXT (' + properties['name'] + ')'
if 'default' in properties:
prompt += ' [' + properties['default'] + ']: '
else:
prompt += ': '
sys.stdout.write(prompt)
data = sys.stdin.readline().rstrip()
if data == '' and 'default' in properties:
data = properties['default']
return data
# separate from TEXT in case we decide to handle it differently
def prompt_area(properties):
prompt = 'AREA (' + properties['name'] + ')'
if 'default' in properties:
prompt += ' [' + properties['default'] + ']: '
else:
prompt += ': '
sys.stdout.write(prompt)
data = sys.stdin.readline().rstrip()
if data == '' and 'default' in properties:
data = properties['default']
return data
def prompt_popup(properties):
sys.stdout.write('MENU (' + properties['name'] + ')')
if 'default' in properties:
sys.stdout.write(' [' + properties['default'] + ']: ')
else:
sys.stdout.write(': ')
sys.stdout.write("\n")
# there's something wonky in the indices here; prolly don't understand
# something about one of the functions (but it works)
for i in range(1, len(properties['options']) + 1):
print(' [' + str(i) + '] ' + properties['options'][i - 1])
sys.stdout.write('=> ')
data = sys.stdin.readline().rstrip()
if (data == '' or not data.isdigit()) and 'default' in properties:
data = properties['options'].index(properties['default'])
else:
data = int(data) - 1
return properties['options'][int(data)]
def do_replacements(fillin):
trimmed = re.sub('^%|%$', '', fillin)
parts = re.split(':', trimmed)
properties = parse_fillin(parts)
if properties['type'] == 'filltext':
return prompt_text(properties)
elif properties['type'] == 'fillpopup':
return prompt_popup(properties)
elif properties['type'] == 'fillarea':
return prompt_area(properties)
else:
raise Exception('Unsupported fillin type: ' + properties['type'])
### MAIN ###
console.clear()
# need to change to urllib.parse.x in 3.x (Apple, wherefore 2.x?)
snippet = urllib.unquote_plus(sys.argv[1])
fillins = re.findall('%[^%]+%', snippet)
for fillin in fillins:
replacement = do_replacements(fillin)
#print(fillin.rstrip() + ': ' + replacement)
snippet = re.sub(fillin, replacement, snippet)
# need to change to urllib.parse.x in 3.x (Apple, wherefore 2.x?)
encoded_snippet = urllib.quote(snippet)
webbrowser.open('drafts://x-callback-url/create?text=' + encoded_snippet + \
'&action=' + urllib.quote('Send to Day One'))
# END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment