Supercharged Search Scopes

Xcode’s search facility is pretty robust, offering the ability to add custom scopes that can restrict with some precision the focus of your search:

Xcode custom search scope editor

However, if you browse the list of options in the popup menu for some of these items, there are frustrating omissions. For example, in the screenshot above you can see that I’m searching files that are within a folder “RSCommon” but whose path is not “YuckySources”. Unfortunately this search is not very useful, because none of my files has a path exactly equal to “YuckySources”. What I really want is an option to specify that the path does not contain “YuckySources”, but the option is not made available to me. Similarly, Xcode offers no choice for “is not within folder.” Generally, there are glaring omissions for negating conditions. (Radar #24510002).

Frustrated by this limitation, I went poking around in Xcode’s configuration files, and was pleased to discover that search scopes are saved in plain text in a file called SearchScopes.xcsclist, for example in Xcode’s configuration folder:

[Home] -> Library -> Xcode -> UserData -> SearchScopes.xcsclist

Update: As of Xcode 9 the search scopes are stored in a file called IDEFindNavigatorScopes.plist.

If you open this up in a text editor, you’ll see that in fact each search scope definition is substantially defined by a standard NSPredicate style expression:

<Scope
  name = "Yummy Sources"
  predicate = "path != &quot;YuckySources&quot; AND location_filesystem == &quot;/Users/daniel/Sources/RSCommon&quot;"
  uuid = "F5110DAA-5DE7-4DD8-A4B1-6D7CB4A2DF1E">
</Scope>

Do I dare to dream that fine-tuning this predicate in a text editor will lead to the desired search results in Xcode? I do! I quit Xcode and edited the predicate in the file so it reads:

(NOT path CONTAINS "YuckySources") AND location_filesystem == "/Volumes/Data/daniel/Sources-Modern/RSCommon"

This expresses the predicate for what I really wanted my search scope to be, but which Xcode wouldn’t allow me to configure. Opening Xcode and selecting the “Yummy Sources” search now allows me to search for results in RSCommon, but NOT in YuckySources. We’re golden!

So I think the limitation here is in Xcode’s predicate editor, which is apparently not robust enough to specify the variety of options afforded by predicate syntax. In fact a caveat here is if I now attempt to edit the hand-tuned predicate above, Xcode crashes with an exception:

comparisonPredicate should be an instance inheriting from NSComparisonPredicate, but it is <NSCompoundPredicate: 0x7fedcff19ff0>

Lucky for us, the code that applies the predicate seems perfectly happy with the hand-tuned, robust predicate. So I’ll be contented to continue using my fancy, supercharged search scopes, but I’ll remember to edit them in BBEdit when necessary.

By the way, the search scopes you create in Xcode are saved by default to the home folder relative path described above, but Xcode will also search for and load any search scopes configured within a workspace’s xcuserdata folder. For example, if you want to configure search scopes that are only meaningful to your “Delicious” project, you could store the configurations in this file:

/Delicious.xcworkspace/xcuserdata/[yourname].xcuserdatad/SearchScopes.xcsclist

I hope this understanding of Xcode’s search scopes helps you transform its already powerful search capability into an even better, finer-tuned resource for navigating your source files.