
TextExpander experiments
I’ve seen a few people around the ‘net sharing their TextExpander snippets, so I thought I’d join in. Not familiar with TextExpander? It’s a Mac utility that expands short snippets into full text you’ve defined. There are quite a few programs that do text expansion (see Typinator), but TextExpander currently holds my heart because of its extra features such as shell scripting, completion suggestion and a new Fill dialog for variable input.
Most of my snippets are specific only to me, such as email signoffs and abbreviations for companies I work for. I have a few more general snippets, though, so that’s what I’m sharing. For reference, I’m currently experimenting with triggering only after a Tab press, à la TextMate tab-triggers. That shouldn’t make a difference on many of these, they should work with whatever you have set up.
All of the snippets I’m sharing are available for download. For more detail, read on…
Lorem Ipsum
First, there are the Lipsums. This is a collection of my most-used Lorem Ipsum snippets, great for filling in fields when testing forms, making quick HTML markup for CSS styling, or anywhere you just need to fill up some space. I have snippets for 1, 2, and 3 paragraphs of standard Lorem Ipsum text, as well as a few for HTML-specific lipsum. The king of these is a snippet I pulled from http://html-ipsum.com/ that inserts all of the major elements of HTML markup. It’s great for giving your CSS stylesheet a quick test to make sure you’ve covered the basics.
The Tools collection is a sampling of scripts and snippets, some more useful than others, that I’ve been experimenting with (and, in some cases, making good use of). Some examples:
Hyphenate clipboard
I tend to write out very long, multi-word modifiers that need hyphenation. While it’s more effective to use a System Service, I’ve found that the Automator services are too slow for such simple operations. So I cut the needs-to-be-hyphenated text to the clipboard and type „-. When I hit tab, the hyphenated version is pasted, with proper attention to punctuation and leading/trailing spaces. It looks like this:
#!/usr/bin/env ruby -wKU
# get the clipboard using pbpaste
clip = %x{__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste}
# print it out, hyphenated
print clip.gsub(/\b\s\b/,'-')
Encode email address
This one takes an email address from the clipboard and returns a “mailto:” link with the email address itself encrypted, at least to the point where it’s not human readable anymore.
#!/usr/bin/env ruby -wKU
clipboard = %x{__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste}.strip
print "mailto:#{$2.gsub(/./) {sprintf("&#x%02X;", $&.unpack("U")[0])}}" if clipboard =~ /\A(mailto:)?(.*?@.*\..*)\z/
Paste Markdown references
This one parses the clipboard for any and all urls, pasting the resulting matches as a Markdown reference list. It automatically names the references based on the url’s domain, strips duplicate urls and sorts the list alphanumerically by reference name. If the clipboard is already a reference list, it will sort it and remove duplicates before pasting it. You can then use the references in your Markdown to link to the associated URL, or just make the list look nice in an email or other non-rendered document.
#!/usr/bin/env ruby -rjcode -Ku
clipboard = %x{__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste}.strip
links = clipboard.scan /(?:\[([^\]]+)\]\: )?(https?:\/\/[^ \n\r"]+)/m
norepeat = []
output = []
exit if links.nil?
links.each {|url|
fresh = true
output.each {|a|
fresh = false if a['link'] == url[1]
}
next unless fresh
if url[0].nil?
domain = url[1].match(/https?:\/\/([^\/]+)/)
parts = domain[1].split('.')
name = case parts.length
when 1,2: parts[0]
else parts[1]
end
else
name = url[0]
end
name = "itunes" if url[1] =~ /(itunes|phobos).apple.com/
while norepeat.include? name
name = name =~ / ?[0-9]$/ ? name.next! : name = name + " 2"
end
output << {'title' => name, 'link' => url[1] }
norepeat.push name
}
output.sort {|a,b| a['title'] <=> b['title']}.each { |x| puts "[#{x['title']}]: #{x['link']}" }
Shortening URLs
There are 4 commands in the group for shortening URLs, using bit.ly, go., is.gd and tinyurl, respectively. There are some AppleScript-based commands already available which do this, but I like the string-handling flexibility of Ruby a little better (and it processes a tiny bit quicker, as well).
The basic command looks like this, with slight differences for each service:
#!/usr/bin/env ruby -wKU
require 'open-uri'
require 'cgi'
def entity_escape(text)
text.gsub(/&(?!([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+);)/, '&')
end
def make_link(text)
case text
when %r{\Ahttps?://.*?\.\w{2,4}.*?\z}:
entity_escape(text)
when %r{\A(www\..*|.*\.\w{2,4})\z}:
"http://#{entity_escape text}"
when %r{\A.*?\.\w{2,4}\/?.*\z}:
"http://#{entity_escape text}"
else
nil
end
end
url = make_link %x{__CF_USER_TEXT_ENCODING=$UID:0x8000100:0x8000100 pbpaste}.strip
print open("http://bit.ly/api?url=#{CGI.escape(url)}").read unless url.nil?
I’ll stop there for now. The Tools set also contains:
Clipboard HTML link
Makes an html hyperlink (code, not rich text) from a url in the clipboard. Uses the Fill feature to request the link text.
Markdown Link
Makes a Markdown format link from a url in the clipboard. Uses the Fill feature to request the link text.
Rounded Corners
Uses the Fill feature to request a pixel radius, and creates cross-browser CSS for rounded corners. There are 5 variations, one for each corner and one for all corners.
CSS Reset
Your typical CSS reset code, in Meyers and YUI flavors.
Make URL
Take whatever text is in the clipboard and provide a best-guess URL for it. Handy if you have a qualified domain and just need the protocol added, or if you have an email address and want it to be a mailto: link.
Hashbang
Instant hashbangs for ruby, osascript and bash.
Feel free to download, explore and improve!
TextExpander Snippets — A collection of TextExpander snippets including lots of Lipsum, improved URL shortening and other useful scripts. More Info

Congrats: this is exactly what I’ve been wanting, you’re spot on as usual Brett.
Thanks, Donald! If you’ve got any suggestions for new snippets, I’m always up for a challenge :).
I’m new to textexpander. Your tips really show what is possible. I decided to start off with a simple signature. I wanted to add small social media icons that would click through to my various pages (flickr, twitter, etc.). Is it possible to add a hyperlink to an image embedded in a snippet?
If I’m not mistaken, you should be able to link the images a rich text editor (like TextEdit in Rich Text mode) and copy them into a rich text snippet in TextExpander. Just insert the image into TextEdit, select it, and type ⌘K to bring up the link dialog. Set the link, select all and copy it into TextExpander. I just tested it and then used the snippet in an email to myself and the link works like a charm.
THANK YOU! I’ll give that a try, sounds like a simple solution :)
Brett, It just occurs to me that it would be nice if the bit.ly snippet could be modified to create the short URL in one’s own account. What do you think?
Here, I made you something :).
Brett, Here is one for you! Make a text expander that pulls the contacts name from address book to start an email.
Example: I want to send an email to David. 1. I open mail 2. In To: I type David and it finds me in my address book. 3. I Type (expander short-cut) i don’t know “hfn”
The result would be: Hello David,
Intereting idea, I’ll give it a shot when I get a chance!
The hyphenation script is really useful for replacing spaces with dashes in file names on the fly. Thanks!
Sure thing! That’s actually exactly why I originally wrote it :). I have one that removes punctuation at the same time, if you ever need shell-friendly filenames.
Would love that.
Today, I found another use case for the hyphenation script: fast editing permalink slugs. I have an insatiable need to fiddle with my blog post titles — often right up until the time they go live. Sometimes I leave the slugs alone, but sometimes I have to edit them so it all makes sense (to me anyway).
Thanks for the snippets! Very creative. These TextExpander posts are great.
I ran into an issue using some of them with Ruby 1.9, but I got them working by changing the call to the Ruby interpreter to just
#!/usr/bin/env rubyand switching the syntax of the case statements so they use “then” instead of a colon and a newline. For example, from the Markdown reference list snippet:Becomes:
Sorry for the delayed reply, but thanks for the tip. Sounds like a lot of my stuff is going to break when I finally get around to running 1.9 in anything other than RVM.
[…] Yes, this is another TextExpander post. Sorry. It’s actually Brett Terpstra’s fault. His shell script tricks are like a song I just can’t get out of my head. But hey, if it keeps Lady Gaga out. . […]
Hi Brett,
I’ve been using TextExpander for some years, but only recently began to use it for more than vanilla snippets. Since I’ve recently began to use Markdown seriously, your scripts are highly welcome. Thanks!
Still, I’ve got a question on the “Markdown Link” script. Perhaps, it even useful to someone else.
I’ve spent some time trying to combine it with a family of simple AppleScripts to get Safari’s URL, title, selected text with some formating into the clipboard. (what fun I had two weeks ago to find out how to get selected text from Safari…) Before I mangle up the chars, I play safe and present it stripped-down without quotes: set w to front window set theTitle to name of w set theURL to URL of document of w set the clipboard to theURL & Quote & theTitle & Quote end tell
The best I got to is to run the AppleScript with Apptivate (or some other minimalistic Launcher), then type the abbreviation for your script. Well, I’m down to 4 key strokes, but have to invoke the script separately. Any hint how to get an Apple Script (using osascript, I guess) running inside the Ruby Script inside TextExpander would be highly appreciated. I’ve had no luck with osascript, but this may be due to my (lack of) proper escaping talent. Just running the scripts in TextExpander as snippets didn’t work either, but I can’t tell what goes wrong inside TextExpander. Since the AppleScript just fills the clipboard, there’s no interaction with the outer script or TextExpander. I haven’t been able to find any detailed info on Smile’s site.
Thomas
Ok, just answered it myself to a good degree. Should I mention that I just installed your Weblogzinc bundle two hours ago and haven’t checked all components. Wow, TextMate (and you) are getting more and more impressive ;-)
Cool. In case you need it, you just need to use a “heredoc” to call osascript: