MacOS – Programatically modify tag visibility, order

automationfinderfinder-tagmacospreferences

I need to programatically alter both the visibility and default sort order for tags, explicitly in Catalina: I have different categories of tags that, depending on what project I'm working on, I'd like to show and hide in the Finder sidebar en bloc (i.e. 'food: xxx' or 'font: xxx').

I'm familiar with the command-line tag utility and Leap's apps; neither seem to offer the option to modify visibility or sort order.

the dictionary in com.apple.finder.plist appears to list them in display order, and the <

> attribute seems to indicate visibility, but the file warns:

//
// The pretty-printed property list below has been created
// from a binary version on disk and should not be saved as
// the ASCII format is a subset of the binary representation!
//

The target data is represented in binary form in values[:FinderTagDict][:remotevalue] – but it's unclear if that is the ultimate repository for the properties, or if that's just part of the pretty-printed attributes.

Will updating values[:FinderTagDict][:remotevalue] in com.apple.finder.plist be sufficient to update finder preferences? Or is there another layer of abstraction that needs to be addressed?

Alternately, is there some other class tucked away that manages kMDItemUserTags attributes?

For the time being, modifying visibility and order is the primary use case. The non-resizable, no-filter preferences pane just is not cutting it.

(fifth time I've tried to find an answer to this, if there are any resources out there I'm just not finding them.)

Best Answer

Here's a partial solution that might serve until I can see something more effective. Instead of trying to track down the correct place to modify the Finder settings under the hood — which is surprisingly difficult — this GUI-scripts the Finder to turn on only those tags you want to use at a given moment. The script presents you with a token field, where you enter the names of the tags you want activated (commas and returns are the separation characters), then it opens the Finder preferences window, loops through all the items in the table view, and clicks them on or off as needed so you'll only see the ones you want. It's slow and occasionally throws an error (typical of GUI scripting) but it gets the job done.


  • Script updated 11/29/20 with trap some GUI synchronization issues..

global click_error_depth, seek_error_depth

set {click_error_depth, seek_error_depth} to {0, 0}

set tag_string to text returned of (display dialog "Enter a list of tags" default answer "")
set tid to my text item delimiters
set my text item delimiters to {",  ", ", ", ","}
set tag_list to text items of tag_string
set my text item delimiters to tid

tell application "Finder"
    open window of Finder preferences
    tell Finder preferences
        tell its window
            set (current panel) to Label Preferences panel
        end tell
    end tell
end tell
tell application "System Events"
    tell process "Finder"
        tell window "Finder Preferences"
            tell first scroll area's first table
                with timeout of 3600 seconds
                    set curretly_tagged to first checkbox of first UI element of (every row whose first UI element's first checkbox's value is 1)
                end timeout
                repeat with this_checkbox in curretly_tagged
                    my clickErrorTrap(this_checkbox)
                end repeat
                repeat with a_tag in tag_list
                    set target_checkbox to my seekErrorTrap(a_tag)
                    if class of target_checkbox is checkbox then
                        my clickErrorTrap(target_checkbox)
                    end if
                end repeat
            end tell
        end tell
    end tell
end tell
tell application "Finder"
    tell Finder preferences
        tell its window
            close
        end tell
    end tell
end tell

on clickErrorTrap(a_checkbox)
    try
        tell application "System Events"
            tell a_checkbox
                click
            end tell
        end tell
        return true
    on error
        if click_error_depth < 10 then
            set click_error_depth to click_error_depth + 1
            delay 0.1
            set flag to clickErrorTrap(a_checkbox)
        else
            return false
        end if
        set click_error_depth to click_error_depth - 1
        return flag
    end try
end clickErrorTrap

on seekErrorTrap(a_tag)
    try
        tell application "System Events"
            tell process "Finder"
                tell window "Finder Preferences"
                    tell first scroll area's first table
                        set target_checkbox to first checkbox of first UI element of (first row whose first UI element's name is a_tag)
                        return target_checkbox
                    end tell
                end tell
            end tell
        end tell
    on error
        if seek_error_depth < 5 then
            set seek_error_depth to seek_error_depth + 1
            delay 0.1
            set target_checkbox to seekErrorTrap(a_tag)
            set seek_error_depth to seek_error_depth - 1
            return target_checkbox
        else
            return false
        end if
    end try
end seekErrorTrap