I have finally decided to transition my snippets from TE to Alfred’s snippet expansion.
It’s not so much that I am disenchanted with TE; I have been a subscriber since they went to the subscription model. It’s more that I am no longer really using the advanced capabilities of TE to any extent and so it’s just an unnecessary subscription for me, and moving to Alfred is just one less piece of software to take care of.
The majority of my TE snippets are simple text substitutions, which work well with Alfred’s snippet expansion. I don’t know how Alfred performs with large numbers of snippets, but I haven’t seen issues yet, having imported maybe 50 or so thus far.
I do have some TE snippets which utilize pop-ups for selection among several options, and I’ll be playing with Alfred’s snippet triggers in coming days to see how well I can reproduce this functionality. Hopefully this will work out well.
I also have a couple of very complex TE snippets that are based on executing python code for some very complex operations. I suspect I could port those to Alfred snippet triggers as well, but since I actually haven’t needed any of these in a while due to workflow changes, I’ll leave that on the back burner.
For anyone who is also thinking of making this transition, I will include below a python script I am using to transfer my snippets to Alfred. BEWARE that I threw this together quickly last night to automate my own transition. It has minimal if any error checking and recovery; I didn’t invest the time since I only need to use it once.
You run it from the command line in Terminal, using the command:
te2alfred Textexpanderfile prefix suffix
Textexpander file is a file exported from TE by using the function to save the contents of a group; control click on a group name to get the context menu to find this. Export each group to a separate file which you run the script on. (It works this way because of the way exporting works when you use the subscription version of TE, which is what I have).
prefix and suffix specify the prefix/suffix that Alfred should apply to each snippet in the group. If you look at Alfred’s snippets setup this should be clear. Note that TE also allows you to apply a prefix (but not suffix) to a group as well. For unclesr reasons, when you do the export from TE this information does not appear in the output file, so you need to supply this info on the command line, You can leave it blank (specify “” for each parameter to indicate an empty string) and add it in Alfred later if you want, but you DO have to put something on the command line even if blank strings. Again, quick and dirty as a run-once script for me.
The program’s output is a file with the same name as the TE group file, but the extension changes to .alfredsnippets. This is a zip file as required for import to Alfred. Double click it and Alfred will import your snippets.
Again, this is a quick script for my purposes, so I would suggest checking the group just created in Alfred to ensure your snippets are properly imported. Use at your own risk. The code is brief and you can see what it is doing easily enough.
This code also ONLY handles TE plaintext snippets (type 0). All other types are exported into individual files named with the group, snippet name, and UUID of that snippet, and the contents of the file is both an Alfred-format JSON snippet description and the XML from TE. I did this so things like my more complex TE snippets that run code could be saved and I could decide what to do with them later if I need them.
Note that TE snippets that contain substitutions, like inserting the clipboard, are handled by this program because they are just plaintext snippets. However, not everything that TE can include works in Alfred, like pop-ups and choose lists and the like, so those snippets will get imported into Alfred but won’t actually work. If you use that functionality a lot you probably want to stay with TE in the first place.
There is a variable called snippet_replacement_strings near the top of the code. This provides a listing of strings for string substitution in the snippet. There is one entry, which replaces %clipboard (the TE code for inserting the clipboard into the snippet expansion) with {clipboard}, the Alfred equivalent. You can add any other substitutions as parenthesized pairs that you might want. I don’t use a lot of stuff like dates and the like in my snippets, so I didn’t include that here; I’ll fix those snippets by hand since I only have a few of them.
Anyway, this is not intended as criticism of TE, which I have used for years and was OK with paying for on the subscription plan when it was useful for me. I just don’t need the functionality anymore and so I have decided to employ Alfred for the limited text replacement I need.
Sorry for the length of this posting. I hope someone finds it helpful!
Code:
#!/usr/bin/python
import plistlib
import sys
import os.path
import zipfile
output_location = os.path.expanduser('~/Desktop/Test')
snippet_replacement_strings = (
('%clipboard', '{clipboard}'),
)
plist_template = u'''<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>snippetkeywordprefix</key>
<string>{}</string>
<key>snippetkeywordsuffix</key>
<string>{}</string>
</dict>
</plist>
'''
snippet_template = u'''{{
"alfredsnippet" : {{
"snippet" : "{}",
"uid" : "{}",
"name" : "{}",
"keyword" : "{}"
}}
}}
'''
def fail(s):
sys.stdout.write(s)
sys.exit(1)
def replace_strings(t):
for f, r in snippet_replacement_strings:
t = t.replace(f, r)
return t
def transform_snippet(s):
name = s['abbreviation'] if s.label == '' else s.label
filename = '{} [{}].json'.format(name, s['uuidString'])
ts = snippet_template.format(
replace_strings(s['plainText']),
s['uuidString'],
name,
s['abbreviation']
)
return filename, ts
def main():
args = sys.argv
# Parse the arguments; any errors, just fail.
try:
te_file = args[1]
prefix = args[2]
suffix = args[3]
output_filename = os.path.splitext(os.path.basename(te_file))[0]
except:
fail('usage: TE2Alfred <TEFile>.textexpander <prefix> <suffix>\n')
# Get the plist file
try:
p = plistlib.readPlist(te_file)
except:
fail('Failed to read textexpander plist file.\n')
# Get the snippets
snippets = p['snippetsTE2']
# Create the zip archive for the group
zfile = zipfile.ZipFile(
os.path.join(output_location, output_filename) + '.alfredsnippets',
'w')
# Write the info.plist file to the zip archive
zfile.writestr('info.plist', plist_template.format(prefix, suffix))
# Write the snippets to the file
for s in snippets:
filename, alfred_snippet = transform_snippet(s)
if s['snippetType'] == 0: # Only handle text substitutions now
zfile.writestr(filename, alfred_snippet.encode("utf-8"))
else: # Just write this one to a file
with open(os.path.join(
output_location, '[' + output_filename + '] ' + filename), 'w') as f:
f.write(alfred_snippet)
f.write('\n')
f.write(repr(s))
# Close the archive to ensure proper cleanup
zfile.close()
if __name__ == '__main__':
main()