💾 Archived View for republic.circumlunar.space › users › johngodlee › posts › 2022-12-29-terminal_co… captured on 2024-08-31 at 13:00:34. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

Shell script to extract colours from macOS Terminal.app themes

DATE: 2022-12-29

AUTHOR: John L. Godlee

On macOS, configuration profiles for Terminal.app are stored as plist files with the extension .terminal. These files contain XML or binary data. The profiles contain, among other settings, the colour scheme for the terminal.

I wrote a shell script to extract the colour scheme information as RGB255 values for each colour scheme value. The function uses a combination of xmlstarlet[1], awk[2], and some programs which come with macOS, like tr, base64, and plutil.

1: https://xmlstar.sourceforge.net/

2: https://www.gnu.org/software/gawk/manual/gawk.html

First, I define a function to extract colour values:

function dict_search() {
    # If colour code found in file
    if grep -q "${1}" "${2}"; then
    	xml sel --net -t -v "//key[.=\"$1\"]/following-sibling::data[1]" "${2}" |
    		tr -d '[:space:]' |
    		base64 --decode |
    		plutil -convert xml1 - -o - |
    		xml sel --net -t -v "//dict/array/dict/key[.='NSRGB']/following-sibling::data[1]" |
    		tr -d '[:space:]' |
    		base64 --decode |
    		awk -v var="${1}" 'BEGIN{ ORS=" "; print var } 
    				{ for(i=1;i<=3;i++) { printf "%.0f ", $i*255 }; printf "\n" }' 
    fi
}

Going line by line:

Then I create an array containing all the colour IDs of interest:

colArray=("ANSIBlackColor" "ANSIBlueColor" "ANSICyanColor" "ANSIGreenColor" "ANSIMagentaColor" "ANSIRedColor" "ANSIWhiteColor" "ANSIYellowColor" "ANSIBrightBlackColor" "ANSIBrightBlueColor" "ANSIBrightCyanColor" "ANSIBrightGreenColor" "ANSIBrightMagentaColor" "ANSIBrightRedColor" "ANSIBrightWhiteColor" "ANSIBrightYellowColor" "BackgroundColor" "CursorColor" "SelectionColor" "TextBoldColor" "TextColor")

Finally, to construct the output of the script, firstly printing the filename, then running the function for each colour ID, and only printing the result to stdout if the function output is not empty:

# Print filepath of theme
printf "%s\n" "${1}"

# For each in array, run function
for i in ${colArray[@]}; do
    # Run function
    out=$(dict_search "${i}" "${1}")

    # If output not empty, print 
    if [ -n "${out}" ]; then
    	printf "%s\n" "${out}"
    fi
done

This produces, for example for my tweaked version of the Smyck[3] colour scheme, which I use every day:

3: https://color.smyck.org/

smyck.terminal
ANSIBlackColor 0 0 0
ANSIBlueColor 64 125 153
ANSICyanColor 32 115 131
ANSIGreenColor 125 169 0
ANSIMagentaColor 186 138 204
ANSIRedColor 184 65 49
ANSIWhiteColor 161 161 161
ANSIYellowColor 196 165 7
ANSIBrightBlackColor 75 75 75
ANSIBrightBlueColor 141 207 240
ANSIBrightCyanColor 106 217 207
ANSIBrightGreenColor 196 241 55
ANSIBrightMagentaColor 247 154 255
ANSIBrightRedColor 214 131 124
ANSIBrightWhiteColor 247 247 247
ANSIBrightYellowColor 254 225 77
BackgroundColor 18 21 28
CursorColor 32 115 130
SelectionColor 32 115 131
TextBoldColor 247 247 247
TextColor 247 247 247

Smyck colour scheme.

Smyck colour scheme in the terminal.