In Leopard, Spotlight has become really powerful, but one of the problems with the Spotlight menu for finding things is that it is indiscriminant – it finds everything with the search term in it even though you normally have at least some idea of where it is; in your Scripts folder, for example. The ability to search in a Finder window is very useful since these searches can be either by file name or by content and can be directed to occur only in the chosen folder. Combined with QuickLook, the combination of a Finder search window followed by a QuickLook scan of the contents of the found files is very fast. It is particularly useful that QuickLook understands the up and down arrows, because having clicked the first file in the found set, and then pressed the space bar for a quick look, you can thereafter use the down arrow (leaving the QuickLook window open) to examine the candidates one at a time (the only difficulty you run into doing this with your scripts, is that the script will sometimes open an application).
Not satisfied with that convenience, however, I wanted a script to do it for me because I could assign a hot key for the script in Quicksilver (and there are lots of other ways to accomplish that too). Unfortunately, that requires GUI scripting because the Finder’s scripting dictionary does not include direct access to those features of a search window. My first attempt is given below; a script for searching in my Scripts folder by content or file name:
tell application "Finder"
activate
set {Btn, toFind} to {button returned, text returned} of (display dialog "Enter the word(s) to find in Scripts." default answer "" buttons {"Cancel", "In Content", "In File Name"} default button "In Content" with icon 1)
open (path to scripts folder from user domain)
end tell
-- Now GUI script that window for a search.
delay 0.5 -- wait for the Finder to get on with it.
tell application "System Events" to tell process "Finder"
set value of text field 1 of group 1 of tool bar 1 of window "Scripts" to toFind
delay 0.5 -- wait for Sys Events to get to the right place before clicking.
click radio button 2 of radio group 1 of group 1 of group 1 of splitter group 1 of window 1
if Btn contains "File" then click radio button 2 of radio group 2 of group 1 of group 1 of splitter group 1 of window 1
end tell
As you can see, most of this script is preoccupied with scripting the search window once opened, and the terms used deserve some explanation. I got the appropriate terms for the objects in that window by using Prefab Software’s “UI Browser” application, which, at $55, is not cheap but is indespensible if you do much GUI scripting. The only alternative is Apple’s own UI Scripting utility but its results are not nearly so easily understood as Bill Cheeseman’s UI Browser is.
Consider a typical Finder search window:
Figure 1: A typical Finder search window.
Scripting the user interface of any application is done by telling System Events to tell the application’s process to do something. In this case, we want to enter a search term or terms in the search text box. The folder’s window is open. Its search box is the only text field in the toolbar of the open window, and the toolbar only has one group to which the search box belongs. The box itself contains a value, so the following line sets that to our search term
“set value of text field 1 of group 1 of tool bar 1 of window “Scripts” to toFind”
Search windows blindly (and annoyingly, in my view) default to “This Mac” for searches instead of to the folder that is already open in the window, so we need to select the folder button (labeled with the folder’s name). The search bar just below the title bar of the window is a “splitter group” because it has more than one section with a “|” between them: “This Mac” and the “Folder Name” are buttons in group 1, and the “Contents” and “File Name” buttons are in group 2 of the splitter bar.
“click radio button 2 of radio group 1 of group 1 of group 1 of splitter group 1 of window 1” does it.
Next (and last), Finder window searches default to “Contents”, so if the user has chosen “File Name”, we must click on that radio button, and this does it:
“if Btn contains “File” then click radio button 2 of radio group 2 of group 1 of group 1 of splitter group 1 of window 1”, Done.
Expanding the Context of Finder Searches
Never one to leave well enough alone, I realized that I could make that script searching script much broader by using AppleScript constants for a bunch of useful folders. The next script shows how many places a script can address without knowing specifically where they are:
-- The AppleScript path constants.
set tPaths to {path to application support from user domain, path to application support from local domain, path to applications folder, path to desktop pictures folder, path to documents folder, path to downloads folder, path to favorites folder, path to Folder Action scripts, path to fonts, path to help, path to home folder, path to internet plugins folder from user domain, path to keychain folder, path to library folder from local domain, path to library folder from user domain, path to modem scripts folder, path to movies folder, path to music folder, path to pictures folder, path to preferences folder, path to scripts folder from local domain, path to scripts folder from user domain, path to scripting additions from user domain, path to scripting additions from local domain, path to scripting additions from system domain, path to shared documents, path to shared libraries, path to speakable items from user domain, path to startup disk, path to startup items, path to stationery from user domain, path to system folder, path to system preferences, path to temporary items, path to trash, path to users folder, path to utilities folder, path to voices folder from user domain, path to voices folder from local domain, path to voices from system domain, path to workflows folder}
-- An easy way to number them for making choices (the paths themselves don't do well in a choose from list statement).
set C to count tPaths
set N to {} -- placeholder for the numbered names of the folders at the end of the paths.
tell application "Finder" to repeat with k from 1 to C
if k < 10 then
set I to "0" & k
else
set I to "" & k
end if
set N's end to I & ". " & name of item k of tPaths
end repeat
-- An easy way to choose one path from the paths list by using its name and the numbering scheme above
set ch to (choose from list N with prompt "Choose one folder. In the case of multiple names the folders are in the user, machine, and/or system domains respectively.") as Unicode text
-- Note in the next line that "ch" is unicode text, so if the user cancels, the false returned will become "false".
if ch is not "false" then set myPath to item ((text 1 thru ((offset of "." in ch) - 1) of ch) as integer) of tPaths
myPath
The first list in this script are all of the paths that AppleScript recognizes (in Leopard, anyway). Note that some of them specify a domain. There are three Library folders, for example, one in the System, one “local” which means in the boot disk (/, in Posix terms), and one in the User’s area (~/ in Posix terms). I have ordered the list above so they appear in User/Local/System order because their names are the same. The rest of the script is gravy. I find it useful when I want to offer a user a choice, but have the choice apply to another list than was used in “choose from list”, numbering the entries and then using the number as an index into the other list is a useful way to do it. Look at it carefully, and you’ll see how that works.
Final Example
In a more practical vein, I don’t actually search all of the folders in the previous script very often. I find that most of my searches are in the Documents, Scripts, Pictures, Movies, and Applications folders. Using the technique in the previous script, I’ve set up a Finder search for those folders, and only those, as follows:
tell application "Finder"
activate
-- Common folders, easy to add more from the earlier script.
set Places to {documents folder, scripts folder, pictures folder, movies folder, applications folder}
-- Need their names for the choose from list statement.
set PN to {"1. Documents", "2. Scripts", "3. Pictures", "4. Movies", "5. Applications"}
-- Grab the first character of the folder chosen to use as an index into Places.
set choice to ((character 1 of item 1 of (choose from list PN)) as integer)
if choice < 5 then -- Applications is not in User Domain.
set tFolder to path to (item choice of Places) from user domain
set DefButton to "In Content" -- the normal search parameter
else -- the Applications folder was chosen.
set tFolder to path to (item choice of Places) from local domain
set DefButton to "In File Name" -- more meaningful for Applications, although finding by content will still find names. Not strictly necessary, in other words.
end if
set Fname to word -1 of item choice of PN -- just the name, not the number.
set {Btn, toFind} to {button returned, text returned} of (display dialog "Enter the word(s) to find in Fname" default answer "" buttons {"Cancel", "In Content", "In File Name"} default button DefButton with icon 1)
open tFolder -- the chosen folder.
delay 0.5 -- wait for the Finder to get on with it.
-- A bit of GUI Scripting (tested in Leopard) as in the first script above.
tell application "System Events" to tell process "Finder"
(* We have the chosen folder window open. Its search box is the only text field in the toolbar of the open window, and the toolbar only has one group to which the search box belongs. The box itself contains a value, so the following line sets that to our search term *)
set value of text field 1 of group 1 of tool bar 1 of window Fname to toFind
delay 0.5 -- wait for Sys Events to get to the right place before clicking.
(* Search windows blindly (and annoyingly) default to "This Mac" for searches instead of to the folder that is open in the window so we need to select the folder button (labeled with its name). The search bar just below the title bar of the window is a "splitter group" because it has more than one section: "This Mac" and the "Folder Name" buttons in group 1, and "Contents" and "File Name" buttons in group 2 of the splitter bar. *)
-- click on the folder name button (radio button 2) in the first group of the splitter bar.
click radio button 2 of radio group 1 of group 1 of group 1 of splitter group 1 of window 1
-- now click the content or file name radio button as chosen. These form the second radio group of group 1 of group 1 of the splitter group just above the listing with the first being Content and the second labeled File Name.
if Btn contains "File" then click radio button 2 of radio group 2 of group 1 of group 1 of splitter group 1 of window 1 -- it defaults to "Content" so do nothing for that, and nothing bad happens if we click it again for Applications.
end tell
end tell
Searching for files on a Mac is an amazingly simple process. Hope you enjoy this alternative way to do it.