For me, the Mac OS X keyboard shortcuts for the text editing commands “Use Selection for Find” and “Find Next” / “Find Previous” are a reflex by now. These shortcuts and the way the commands work are pretty consistent across all Mac OS X apps that allow text editing.
The exception, of course, is Microsoft Word.
It drove me nuts that it doesn’t work the same way there, and obviously Word is exactly where I edit a lot of text. To bring it in line with the other applications I created three AppleScripts that implement these commands and bound them to the standard shortcuts ⌘E, ⌘G and ⇧⌘G with FastScripts (which is out in a great new version 2.4 with more features available for free).
Use Selection for Find:
tell application "Microsoft Word"
set mySelection to content of selection
set myFind to find object of selection
set content of myFind to mySelection
end tell
Find Next:
tell application "Microsoft Word"
set myFind to find object of selection
execute find myFind wrap find find continue with match forward
end tell
Find Previous:
tell application "Microsoft Word"
set myFind to find object of selection
execute find myFind wrap find find continue without match forward
end tell
I wanted to export all tracks of an iTunes playlist into a folder, but iTunes’ export feature only exports the track list (as XML or plain text file), not the actual music files.
Drag-and-drop from the iTunes window to the Finder folder window works but doesn’t preserve the playlist order, and the filenames are messy because of the leading track numbers.
I wrote this AppleScript that reads the XML export track list file and copies the tracks to a folder on the desktop. It strips leading numbers from the filenames and adds new ones corresponding to the playlist order.
on open (theFiles)
set theFile to item 1 of theFiles
set myUrls to {}
tell application "System Events"
set myContents to contents of property list file (theFile as string)
tell myContents
tell property list item "Playlists"
tell property list item 1
tell property list item "Playlist Items"
repeat with aPlaylistEntry in property list items
set aTrackId to |Track ID| of (value of aPlaylistEntry as record)
tell property list item "Tracks" of myContents
tell property list item (aTrackId as string)
set myUrl to |Location| of (value as record)
set end of myUrls to myUrl
end tell
end tell
end repeat
end tell
end tell
end tell
end tell
end tell
set myIndex to 1
do shell script "mkdir -p ~/Desktop/itunes-playlist-export"
repeat with myUrl in myUrls
if myIndex < 10 then
set myIndex to "0" & myIndex
end if
set myUrl to myUrl as URL
set myPath to POSIX path of POSIX file myUrl
set myBasename to do shell script "basename " & quoted form of myPath & " | sed -e 's/^[ 0-9-]*//'"
set myDestination to (myIndex as string) & " " & myBasename
set cmd to "cp " & quoted form of myPath & " ~/Desktop/itunes-playlist-export/" & quoted form of myDestination
do shell script cmd
set myIndex to myIndex + 1
end repeat
end open
I haven’t touched my small calculator application in years because it pretty much does what it needs to do.
Today I added one feature and bumped the version to 1.3. You can now select one of the results in the history list and use the Copy menu command or its shortcut to copy the result of that history entry to the clipboard.
Download it on the software page and if you like it feel free to rate it on MacUpdate or iusethis.
ctags is an old-school UNIX program that indexes language objects such as functions, methods, classes etc. in source code files. Text editors read the index (called a “tags” file) to locate these language objects quickly.
When BBEdit finds a tags file, it enables these features:
- opening the contextual menu for a selected language object shows a submenu with all definitions of that object
- the completion list is populated with language objects that match what you typed so far
- your custom language objects are colorized in the source code
- the “Find Definition” menu command jumps directly to the definition of the selected word, if there’s only one match, or shows a list with possible matches if there are several
Let’s look at these four features with and without a tags file.
First the contextual menu for a selection. Here I selected the rootdir method call and opened the contextual menu, without a tags file present:
Here’s the same menu with a tags file:
The rootdir method is defined in four files and selecting an entry from the menu brings you directly to that definition.
On to the completion list. I type the word “root” and hit the completion shortcut without a tags file present:
BBEdit offers no completions because what I’m looking for, the rootdir method, does not occur in the current file.
With a tags file, it looks like this:
Here’s how your own symbols look without a tags file:
There’s no difference between the language objects and any other text, they’re all black. With a tags file, the language objects are highlighted with a separate color:
Finally, the “Find Definition” command in the Search menu. You select a word and invoke this command to show the definition of the selected language object. Without a tags file, nothing happens. With a tags file present, BBEdit either opens the definition directly if there’s only one candidate or it presents a list with all matches if there are several:
Creating the Tags File
To create the tags file, open the Terminal and cd to the toplevel directory of your project, the one that contains all related source code. Issue this command:/Applications/BBEdit.app/Contents/MacOS/ctags --excmd=number --tag-relative=no --fields=+a+m+n+S -f tags -R "$PWD"
I made myself an alias called “bbtags” with some Perl-specific excludes and added it to my $HOME/.bashrc file:
alias bbtags='/Applications/BBEdit.app/Contents/MacOS/ctags --excmd=number --tag-relative=no --fields=+a+m+n+S -f tags --exclude=blib --exclude=pod -R "$PWD"
Now I can just type bbtags and I’m all set.
As you edit and save your files, the index gets out of sync. You need to rebuild the tags file from time to time so it matches the changed files. If you work in a programming language that uses a build/compilation phase such as C or Java, you can run the ctags update command during the build process, as Seth notes in the comments below.
If you work in a dynamic programming language like Perl or PHP, you can try the following BBEdit menu AppleScript:
on MenuSelect(mycommand, myname)
return false
end MenuSelect
on PostMenuSelect()
tell application "BBEdit"
if not my isKnownLanguage(source language of text document 1) then return
set docFile to file of text document 1
end tell
set docPath to POSIX path of docFile
repeat while docPath is not equal to "/"
set docPath to (do shell script "dirname " & (quoted form of docPath))
if checkAndRebuildTagsFile(docPath) then return
end repeat
end PostMenuSelect
on isKnownLanguage(sourceLanguage)
return {"PHP", "Perl"} contains sourceLanguage
end isKnownLanguage
on checkAndRebuildTagsFile(tagsParentPath)
set tagsPath to tagsParentPath & "/tags"
set tagsFile to POSIX file tagsPath
tell application "Finder"
if not (exists tagsFile) then return false
end tell
if folder of (info for tagsFile) then return false
set updateCommand to "/Applications/BBEdit.app/Contents/MacOS/ctags 2>&1 --excmd=number --tag-relative=no --fields=+a+m+n+S+l+K+i -f tags --exclude=blib -R " & quoted form of tagsParentPath
set ctagsResult to do shell script updateCommand
do shell script "syslog -l notice -s rebuilt tags file with command " & updateCommand & ", result: " & quoted form of ctagsResult
return true
end checkAndRebuildTagsFile
Save it in your $HOME/Library/Application Support/BBEdit/Menu Scripts folder with the name “File•Save” to run it whenever you save the document. It looks for a tags file in all parent directories of the file you just saved, and if it finds one it runs the ctags update command. It seems to be a bit slow on the big source code trees I work on, but just give it a try, it might work better for you.
If you want to exclude certain directories permanently in all projects, I suggest you create a $HOME/.ctags file with exclude lines in it:
--exclude=blib --exclude=unittest
See the ctags documentation for the details.
In conclusion, if you use BBEdit in multifile projects, you should try the ctags feature. I suspect that it is seriously under-used and unknown even among experienced BBEdit users.
Stuff like this is why I love Mac OS X and wouldn’t dream of using anything else:
This shows the “Recent” menu present in most Mac OS X applications. It offers quick access to documents the user has previously worked on.
In this particular case, the menu shows that in the past I worked on two documents with identical filenames but stored in different locations. The “Recent” menu entries would normally be of no use in figuring out which one is the one I want. But Mac OS X notices the duplicates and provides a helpful hint by appending a folder name to the document name.
Until now I thought that it simply appends the document’s parent folder name, but I just realized that it is smarter than that, it ascends the hierarchy until it finds the first non-matching folder. The two documents you see in the screenshot are stored in these locations:
/Users/liyanage/svn/entropy/xmlviewplugin/XMLWebKitPlugin.xcodeproj /Users/liyanage/git/entropy/xmlviewplugin/XMLWebKitPlugin.xcodeproj
The git or svn folders are three levels up from the document name and they are the first ones to differ on the path of the documents.
If I change one of the xmlviewplugin or entropy folder names, then those show up. It’s brilliant!
It’s a small, simple detail but immensely useful for everyday work. Whoever thought of this implementation is a genius :-). Stuff like this, and there’s a lot of it, is what’s so great about Mac OS X.
Here’s an AppleScript implementation of a great idea by Ebi.
It provides numeric keyboard shortcuts to jump to a specific Safari Tab directly. You can press ⌘-⌥-1 to switch to the first tab, ⌘-⌥-2 for the second etc.
Here’s the script code:set myPath to (path to me) as text set tabNumber to (word -2 of myPath) as number tell application "Safari" tell window 1 try set current tab to tab tabNumber on error beep end try end tell end tell
I saved this exact same script nine times with the following file names:
Switch to Tab 1.scpt Switch to Tab 2.scpt Switch to Tab 3.scpt ...
I put them in my Home > Library > Scripts > Applications > Safari folder and used FastScripts to assign numeric keyboard shortcuts:
Pick whatever you like, you can also use Ctrl-1, ⌘-1 etc.
Here’s the 2009 update to my “Exclude From Backup” AppleScript, which I published in a previous article.
The script excludes selected items from the Time Machine backup. I use it to exclude large downloads such as pirated TV shows Linux ISO images from the backup, so they don’t clutter up the backup disk.
The new features are:
- Notifications via Growl both for successful and failed exclusions. Growl is required, I don’t check for it
- Three different ways to launch the script and pass the files (see below)
- As a side effect of the previous one, the script now handles multiple files
The Growl notifications look like this:

There are three ways to use it:
1.) Via the Finder contextual menu item through Ranchero’s BigCat. This is what it could do before, and this method is still limited to one file at a time. Unfortunately the BigCat web page at Ranchero’s site is missing at the time of this writing, maybe it’s just temporary and it will come back. If not, use one of the other methods.
You must store the AppleScript in the Library/Application Support/Big Cat Scripts/Files folder in your home folder.

2.) The second way is via LaunchBar’s “Send to” feature: Select one or more items to be
excluded, press and hold your activation shortcut, press the Tab
key, type an abbreviation of the script’s name, e.g. “excl”, and hit return.
This requires you to store the script in the Library/Scripts/Applications/Finder in your home folder.
Other launchers such as QuickSilver or Butler might work similarly, if they pass the affected files to the script’s open handler. In fact, since the open handler is a generic feature, there are probably many other ways to use this.
One of them is to save the script as a droplet, a stand-alone application onto which you can drop the icons of the files you want excluded. If you stick it in the Dock, it’s pretty convenient to use. The download below contains the droplet version in addition to the regular script.
3.) The third way is via FastScripts or Apple’s Script Menu: select the items to be excluded in the Finder and invoke the script from the menu or, in the case of FastScripts, via a keybord shortcut.
Download a zip file with the script file here: exclude-from-backup.zip
It always bothered me that Safari doesn’t show raw XML data in a useful way, like Firefox and other browsers do. I had to use “View Source” every time to see the XML data, because Safari seems to interpret the XML elements as HTML, leaving only text element content visible:

Here’s the same data in Firefox:

In my current project at work I had to use “View Source” all the time, so I decided to do something about it. Joachim Fornallaz pitched in and the result is “XML View Plugin”, a Safari WebKit plugin that registers as a handler for some XML MIME types and displays the raw XML code:

It can optionally pretty-print it with Tidy:

I’d like to add syntax coloring if I can find a C-based library with a BSD-ish license that does that.
The inspiration for this project came from the fantastic ClickToFlash plugin that was in the Mac news recently. Like XML View Plugin, ClickToFlash is implemented as a WebKit plugin. Before reading about it, I did not realize that there’s a convenient, Objective-C based alternative to the old-school Netscape browser plugin API.Download and more information are on the plugin’s info page. Please try it out and let me know what you think, and especially let me know if you find any problems that impact Safari’s stability.
Update 2009-03-04: Version 1.5 added user-customizable syntax coloring, see the info page for details. This is how it looks by default:

This was originally a comment on a previous posting but I decided to give this topic its own entry.
I love Apple’s Pages application and I use it for my private stuff, letters, invoices or birthday cards. It just “feels” great, exactly like a Mac application should.
Unfortunately, it’s not there yet for my professional work.
A big part of my job is writing long, structured technical documents. Over the years I refined a set of templates and style sheets that let me format the text efficiently while I write, resulting in documents that have the very specific look I want.
This is where Pages doesn’t work for me. Even in iWork 09, its paragraph styles are still not powerful enough to create the visual effects I use in my templates.
The missing features are mostly related to paragraph borders and background colors combined with paragraph indents. In Word, a left or right indent also indents the left or right box edge. In Pages, a paragraph indent only shifts the text but the box still uses the full column width. Without borders or background that box is invisible and it doesn’t matter, but with borders or background, the full-width box is visible and looks ridiculous:
Another thing: It seems that Pages paragraph styles cannot be based on other styles, which I think is critical. In Word, I build hierarchies of styles so I can change visual effects in one central place and have them propagate through the styles automatically.
I’ve been looking for a solution to this for years. Maybe somebody can give me a tip. I posted a detailed description of what I’m looking for in an Apple support discussion forum thread.
Basically, I want a real Meta key in the Mac OS X Terminal application. The “Use option as meta key” checkbox in the preferences doesn’t count because on my Swiss German keyboard layout I need the option key to type all sorts of characters that are important on the UNIX command line. The ESC key doesn’t count either, as explained in the discussion post.
Microsoft delighted me several times today.
First I realized that Word 2008 finally lets me place PDF images in Word files, and when I print the document using the OS X “Print to PDF” feature, the placed PDF images are properly embedded as vector images in the final PDF and not as bitmaps. Yessss!!! :-).
I’m not sure but I think this is new in Word 2008 and it’s major news for me. I think EPS also didn’t work in previous versions, they were output as bitmaps. I can now finally place logos and diagrams into my technical documents and have them preserved as high quality vector images in the final output.
This is a page of a Word document with a placed PDF diagram at 2000% magnification in Preview:

Unfortunately it’s still not possible to transform the document’s heading structure into PDF bookmarks, which is essential for long documents.
The second pleasant surprise was the keyboard short cut list for Word 2008 on the Microsoft website. I wanted a hardcopy, but looking at the page’s two-column layout I thought that it would be hard to get a nice printout from that page:

But it turns out that Microsoft thought about that and added a print media CSS stylesheet. It suppresses all of the interactive stuff that’s useless in print, producing in a very printer-friendly page:

Not rocket science, I know, but nice when somebody thinks about it and makes online help so much more useful by using this feature.
Lastly, it appears that Word now notices when I move an open document in the Finder and updates the window title and saves to the new location from that point on. Unless I am mistaken, this is also new in Word 2008.
I released version 2.1 of Album Artwork Assistant, my Mac OS X application for finding iTunes album cover artwork on the web.
This version lets you surf the web and pick images directly off web pages in an embedded web browser. This is useful if the image search doesn’t turn up suitable results and you have to hunt down the artwork. Watch this screencast to see how it works:
There are also some bug fixes and stability improvements, as listed in the release notes.
For Developers
Here are some observations for Cocoa developers.
WebKit
First off, WebKit is a fantastic library, I have used it in many projects and it’s always a joy to use it.
In this case I was impressed how easy it is to get information about and interact with the DOM elements loaded in a web view when the mouse cursor hovers over them. You get a delegate callback with a dictionary of useful information about the element. The dictionary content depends a bit on the type of the element. In the case of IMG elements, you even get the full URL of the image source, which is exactly what I needed in my application.
This delegate method allows the application code to do very interesting interactive things with the web content rendered in the web view; think about all the cool stuff an application can do if it has full access to the structure of the web content and doesn’t just have to deal with it as a dumb bitmap.
Another thing that’s very easy is to adapt the contextual menu contents when the user opens the menu over some DOM element.
Both features are provided by the WebUIDelegate protocol.
ImageKit
ImageKit flat out doesn’t work under garbage collection. See my bug report for the details. In short, old image objects stick around forever and don’t free the resources they use. More and more memory is consumed, but even worse, if you use the IKImageBrowserNSURLRepresentationType image type and supply http URLs, the dead objects will keep the HTTP socket open, quickly exhausting the available file descriptors.
In my application I could work around the open sockets problem by loading the images myself and then passing raw image data instead of the image URL to ImageKit. But the memory consumption is still a problem, the memory usage of the application grows steadily with every image search. I hope this gets fixed by Apple.
NSError
Related the the previous issue, NSError’s localizedDescription method crashes if the file descriptor table is full. This is bad because you start getting NSErrors from many APIs precisely when the file descriptor table is full. I filed a bug about this too.
Garbage Collection Debugging in GDB
The GDB commands info gc-references and info gc-roots are very useful to debug garbage collection-related problems (and it’s also interesting and educational to poke around with them).
Here I hit a breakpoint and inspected the images array:
(gdb) po images <NSCFArray 0x107eb30>( <TestImageBrowserItem: 0x107df10>, <TestImageBrowserItem: 0x102dbf0>, ...
Let’s check out its first item:
(gdb) info gc-references 0x107df10 0 Kind: stack rc: 0 Address: 0xbfffee9c Frame level: 0 Symbol: foo warning: can't find class named `IKImageBrowserCell' given by ObjC class object 1 Kind: object rc: 0 Address: 0x0106def0 Offset: 0x00000008 Class: IKImageBrowserCell 2 Kind: object rc: 0 Address: 0x0107b2a0 Offset: 0x00000020 warning: can't find class named `IKImageCellDatasourceProxy' given by ObjC class object 3 Kind: object rc: 0 Address: 0x0108ca60 Offset: 0x00000004 Class: IKImageCellDatasourceProxy
This shows that four locations in memory reference my image object. One is in a local variable foo on the stack (the high address, with Kind: stack), the remaining references are in other objects on the heap (the low addresses, with Kind: object).
In some situations it didn’t work for me, both commands would just hang forever without producing any output. One of them did produce output when I added a type cast in front of the object’s memory address:
(gdb) info gc-references (TestImageBrowserItem *)0x107df10
I wrote the AppleScript below to eject one or more selected volumes in the Finder. If a volume represents a disk image, the script trashes the image at the same time. I use this a lot with downloaded application distribution images.
I run the script with FastScripts with the keyboard short cut Cmd-Option-E. Unfortunately, there seems to be a Finder bug that makes the script take a very long time do finish.
set myVolumes to getSelectedVolumes()
if (count myVolumes) < 1 then return
set myImages to getImageList()
repeat with myVolume in myVolumes
set myImagePath to ""
set myImageFile to null
repeat with myImage in myImages
repeat with myEntity in |system-entities| of myImage
try
set mountPoint to |mount-point| of myEntity
displayed name of myVolume
if mountPoint = ("/Volumes/" & displayed name of myVolume) then
set myImagePath to |image-path| of myImage
set myImageFile to POSIX file myImagePath
end if
end try
end repeat
end repeat
tell application "Finder"
eject myVolume
if myImageFile is not null then
try
delete file myImageFile
end try
end if
end tell
end repeat
on getSelectedVolumes()
set volumeList to {}
tell application "Finder"
set mySelection to selection
repeat with myItem in mySelection
set myItem to contents of myItem
-- log class of myItem
if kind of myItem is "Volume" then
set end of volumeList to myItem
end if
end repeat
end tell
return volumeList
end getSelectedVolumes
on getImageList()
set diskinfo to do shell script "hdiutil info -plist"
tell application "System Events"
set diskinfo to value of (make new property list item with properties {text:diskinfo})
set imageList to |images| of diskinfo
end tell
return imageList
end getImageList
Here’s another trick to speed up file system navigation in the shell. A previous tip showed how to use bookmarks to reach deeply nested directories effectively.
I use that a lot, but I frequently use it to enter directories with a large number of subdirectories whose names are long and share a prefix:
... Arteria-Media-ImageEditor Arteria-Media-ImageEditor-Base Arteria-Media-ImageRep-Magick Arteria-Media-JSONClient Arteria-Media-JSONSegmenter Arteria-Media-Webapp-MediaServer ...
I wanted a way to enter one of these directories by typing only a minimal, unique substring of its name (like typing *substring* but only considering directories and ignoring case), so I wrote this shell function:
function c {
shopt -q nocasematch || resetcase=1
shopt -s nocasematch
for i in *; do [ -d "$i" ] && [[ "$i" == *"$1"* ]] && cd "$i" && break; done
[ $resetcase ] && shopt -u nocasematch
}
Now I can type
c ncl
and, in the example directory above, it takes me directly into the Arteria-Media-JSONClient subdirectory.
A while ago I published a Finder toolbar AppleScript called “Open Terminal Here” to open a terminal window in the directory displayed by the frontmost Finder window or the Finder selection or the files/folders dropped onto the icon.
However, these days I find myself using a similar script triggered by a keyboard shortcut much more often. I assigned it to Cmd-T which is very convenient and quick. As always, I use FastScripts to do the keyboard launching.
Here’s the script:
tell application "Finder" set sel to selection if (count sel) > 0 then set myTarget to item 1 of sel else if (count window) > 0 then set myTarget to target of window 1 else set myTarget to path to desktop folder end if my openTerminal(myTarget) end tell on openTerminal(location) set location to location as alias set the_path to POSIX path of location repeat until the_path ends with "/" set the_path to text 1 thru -2 of the_path end repeat set cmd to "cd " & quoted form of the_path & " && echo $'\\ec'" tell application "System Events" to set terminalIsRunning to exists application process "Terminal" tell application "Terminal" activate if terminalIsRunning is true then do script with command cmd else do script with command cmd in window 1 end if end tell end openTerminalOpen this script in Script Editor
|



