Search code examples
swiftmacoscocoafinder

How do I retrieve all available Finder tags?


I'm trying to retrieve a list of all the available Finder tags.

I found NSWorkspace().fileLabels, which does return an array, but only an array of the tag colours, not the tags themselves:

print(NSWorkspace.shared().fileLabels) // prints ["None", "Gray", "Green", "Purple", "Blue", "Yellow", "Red", "Orange"]

Which as you can see is not even all the default tags, it's missing Home, Work and Important, and obviously doesn't have any of the custom ones that I created. It looks like it's just the nice names that go with fileLabelColors.

I found NSMetadataQuery for actually searching for things, but how do I get a list of all the tags I have created in the Finder?


Solution

  • NSWorkspace.shared().fileLabels only returns the system tags that were available when the user account was created (the default system tags).

    There's unfortunately no API in macOS to retrieve the tags that you have created yourself in the Finder.

    The solution is to parse the ~/Library/SyncedPreferences/com.apple.finder.plist:

    func allTagLabels() -> [String] {
        // this doesn't work if the app is Sandboxed:
        // the users would have to point to the file themselves with NSOpenPanel
        let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
        let keyPath = "values.FinderTagDict.value.FinderTags"
        if let d = try? Data(contentsOf: url) {
            if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
                let pdict = plist as? NSDictionary,
                let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
            {
                return ftags.flatMap { $0["n"] as? String }
            }
        }
        return []
    }
    
    let all = allTagLabels()
    print(all)
    

    This gets all Finder tags labels.

    You can also select only the custom tags (ignore the system ones):

    func customTagLabels() -> [String] {
        let url = URL(fileURLWithPath: "\(NSHomeDirectory())/Library/SyncedPreferences/com.apple.finder.plist")
        let keyPath = "values.FinderTagDict.value.FinderTags"
        if let d = try? Data(contentsOf: url) {
            if let plist = try? PropertyListSerialization.propertyList(from: d, options: [], format: nil),
                let pdict = plist as? NSDictionary,
                let ftags = pdict.value(forKeyPath: keyPath) as? [[AnyHashable: Any]]
            {
                return ftags.flatMap { tag in
                    if let n = tag["n"] as? String,
                        tag.values.count != 2
                    {
                        return n
                    }
                    return nil
                }
            }
        }
        return []
    }