Swift: Searching playgrounds

Spotlight doesn’t index playground contents. This is a source of endless frustration to me and today I finally had enough. I wrote this. It performs a spotlight search for playground bundles and then manually greps their contents for search phrases. Let me know if anyone finds it useful. And please file a radar. I don’t want mine to be lonely.

I also set up a bunch of smart folders to help me find things.

Screen Shot 2015-06-17 at 7.30.12 PM

The first two list all playgrounds and all swift files on my Mac. The second two show any playgrounds and swift files I’ve opened today. There isn’t overlap because swift files within playgrounds aren’t indexed.

Create smart folders by opening a Finder window. Type Command-F.  Enter search criteria and then click Save.

Screen Shot 2015-06-17 at 7.32.47 PM

Today’s two main.swift files are from this morning’s “eval” example and this evening’s “pggrep”. None of my work on playgrounds today shows up in the search.

Compare with the “Today’s Playgrounds” results:

Screen Shot 2015-06-17 at 7.35.44 PM

3 Comments

  • I am also surprised you can’t quicklook a playground file. I am so used to navigating through the finder and hitting space on source files, it was quite jarring to just see only a large playground icon.

  • No idea how to use it… plus it’s not been updated for Swift 2.0

  • #!/usr/bin/env swift
    //
    // main.swift
    // pggrep
    //
    // Created by Erica Sadun on 6/17/15.
    // Copyright © 2015 Erica Sadun. All rights reserved.
    //

    import Foundation

    // mdfind ‘kMDItemDisplayName == *.playground’
    func PlaygroundList() -> [String] {
    let task = NSTask()
    task.launchPath = “/usr/bin/mdfind”
    task.arguments = [“kMDItemDisplayName == *.playground”]

    let pipe = NSPipe()
    task.standardOutput = pipe
    task.launch()
    task.waitUntilExit()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()

    guard var s = NSString(data: data, encoding: NSUTF8StringEncoding) else {return []}
    s = s.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    return s.componentsSeparatedByString(“\n”)
    }

    func SwiftList() -> [String] {
    let task = NSTask()
    task.launchPath = “/usr/bin/mdfind”
    task.arguments = [“kMDItemDisplayName == *.swift”]

    let pipe = NSPipe()
    task.standardOutput = pipe
    task.launch()
    task.waitUntilExit()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()

    guard var s = NSString(data: data, encoding: NSUTF8StringEncoding) else {return []}
    s = s.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    return s.componentsSeparatedByString(“\n”)
    }

    func PerformQuery(query : String, path: String) -> NSString {
    let task = NSTask()
    task.launchPath = “/usr/bin/grep”
    task.arguments = [“-R”, query, path]

    let pipe = NSPipe()
    task.standardOutput = pipe
    task.launch()
    task.waitUntilExit()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    guard var s = NSString(data: data, encoding: NSUTF8StringEncoding) else {return “”}
    s = s.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    return s
    }

    func grep(query: String) {

    print(“Searching for \(query)”)

    // Iterate through each playground
    let pgPaths = PlaygroundList()
    for path in pgPaths {
    // Fetch results
    let s = PerformQuery(query, path: path)
    if s.length == 0 {continue}

    // Defer printing playground info until a match is found
    var isFirst = true

    // Decompose the grep results into lines
    let array = s.componentsSeparatedByString(“\n”)
    for line in array {
    // Ignore any “Binary” files
    if line.hasPrefix(“Binary”) {continue}

    // Split the rest into fileName:match
    let splits = line.characters.split {$0 == Character(“:”)}.map{String($0)}
    let range = path.startIndex..<path.endIndex
    var fname: String = splits[0] // NSString(string: splits[0]).lastPathComponent
    fname.removeRange(range)
    if !fname.hasSuffix("swift") {continue}
    if splits.count < 2 {continue}
    // If this is a first match, show the playground info
    if isFirst {
    let playgroundName = NSString(string: NSString(string: path).lastPathComponent).stringByDeletingPathExtension
    print(String(count:playgroundName.characters.count, repeatedValue:Character("-")))
    print(playgroundName)
    print(String(count:playgroundName.characters.count, repeatedValue:Character("-")))
    let pathIncludingPlaygroundName = NSString(string:path).stringByDeletingPathExtension
    print(pathIncludingPlaygroundName)
    isFirst = false
    }

    // Print the file name and the match
    let rest = splits[1]
    let pathIncludingPageName = NSString(string:fname).stringByDeletingPathExtension
    print(" \(pathIncludingPageName): \(rest)")
    }

    // Leave spaces between playground results
    if !isFirst {print("")}
    }
    }

    var args = Process.arguments.dropFirst()
    if args.count == 0 {
    print("Must suply query")
    exit(-1)
    }