diff --git a/darwin/profiles/desktop/home/default.nix b/darwin/profiles/desktop/home/default.nix index b19be61..8c05127 100644 --- a/darwin/profiles/desktop/home/default.nix +++ b/darwin/profiles/desktop/home/default.nix @@ -1,7 +1,7 @@ { - config, pkgs, lib, + config, ... }: { imports = map (n: ../../../../home/applications/${n}) [ @@ -29,40 +29,36 @@ "telegram-desktop" ]; - home = { - activation = { - # Workaround for spotlight indexing - # https://github.com/nix-community/home-manager/issues/1341#issuecomment-1705731962_ - trampolineApps = let - apps = pkgs.buildEnv { - name = "home-manager-applications"; - paths = config.home.packages; - pathsToLink = "/Applications"; - }; - in - lib.hm.dag.entryAfter ["writeBoundary"] '' - toDir="$HOME/Applications/Home Manager Trampolines" - fromDir="${apps}/Applications/" - rm -rf "$toDir" - mkdir "$toDir" - ( - cd "$fromDir" - for app in *.app; do - /usr/bin/osacompile -o "$toDir/$app" -e 'do shell script "open '$fromDir/$app'"' - done - ) - ''; + # Install MacOS applications to the user Applications folder. Also update Docked applications + # Modified version of: https://github.com/nix-community/home-manager/issues/1341#issuecomment-1870352014 + home.file."Applications/Home Manager Apps".enable = false; + home.activation.trampolineApps = let + apps = pkgs.buildEnv { + name = "home-manager-applications"; + paths = config.home.packages; + pathsToLink = "/Applications"; }; + in + lib.hm.dag.entryAfter ["writeBoundary"] '' + ${builtins.readFile ./trampoline-apps.sh} + fromDir="${apps}/Applications" + toDir="$HOME/Applications/Home Manager Trampolines" + sync_trampolines "$fromDir" "$toDir" + ''; + home.extraActivationPath = with pkgs; [ + rsync + dockutil + gawk + ]; - packages = with pkgs; [ - ## GUI - ### Tools - keka # un-archive-r - iterm2 - ### Misc - element-desktop - ]; - }; + home.packages = with pkgs; [ + ## GUI + ### Tools + keka # un-archive-r + iterm2 + ### Misc + element-desktop + ]; # macOS don't have fontconfig programs = let diff --git a/darwin/profiles/desktop/home/trampoline-apps.sh b/darwin/profiles/desktop/home/trampoline-apps.sh new file mode 100644 index 0000000..43455cd --- /dev/null +++ b/darwin/profiles/desktop/home/trampoline-apps.sh @@ -0,0 +1,131 @@ +# Utilities not in nixpkgs. +plutil="/usr/bin/plutil" +killall="/usr/bin/killall" +osacompile="/usr/bin/osacompile" + +copyable_app_props=( + "CFBundleDevelopmentRegion" + "CFBundleDocumentTypes" + "CFBundleGetInfoString" + "CFBundleIconFile" + "CFBundleIdentifier" + "CFBundleInfoDictionaryVersion" + "CFBundleName" + "CFBundleShortVersionString" + "CFBundleURLTypes" + "NSAppleEventsUsageDescription" + "NSAppleScriptEnabled" + "NSDesktopFolderUsageDescription" + "NSDocumentsFolderUsageDescription" + "NSDownloadsFolderUsageDescription" + "NSPrincipalClass" + "NSRemovableVolumesUsageDescription" + "NSServices" + "UTExportedTypeDeclarations" +) + +function sync_icons() { + local from="$1" + local to="$2" + from_resources="$from/Contents/Resources/" + to_resources="$to/Contents/Resources/" + + find "$to_resources" -name "*.icns" -delete + rsync --include "*.icns" --exclude "*" --recursive "$from_resources" "$to_resources" +} + +function copy_paths() { + local from="$1" + local to="$2" + local paths=("${@:3}") + + keys=$(jq -n '$ARGS.positional' --args "${paths[@]}") + jqfilter='to_entries |[.[]| select(.key as $item| $keys | index($item) >= 0) ] | from_entries' + + temp_dir=$(mktemp -d) + trap 'rm -rf "$temp_dir"' EXIT + + pushd "$temp_dir" > /dev/null || exit + + cp "$from" "orig" + chmod u+w "orig" + + cp "$to" "bare-wrapper" + chmod u+w "bare-wrapper" + + $plutil -convert json -- "orig" + $plutil -convert json -- "bare-wrapper" + jq --argjson keys "$keys" "$jqfilter" < "orig" > "filtered" + cat "bare-wrapper" "filtered" | jq -s add > "final" + $plutil -convert xml1 -- "final" + + cp "final" "$to" + popd > /dev/null || exit +} + +function sync_dock() { + # Make sure all environment variables are cleared that might affect dockutil + unset SUDO_USER + + # Array of applications to sync + declare -a apps=("$@") + + # Iterate through each provided app + for app_path in "${apps[@]}"; do + if [ -d "$app_path" ]; then + # Extract the name of the app from the path + app_name=$(basename "$app_path") + app_name=${app_name%.*} # Remove the '.app' extension + resolved_path=$(realpath "$app_path") + + # Find the current Dock item for the app, if it exists + current_dock_item=$(dockutil --list --no-restart | grep "$app_name.app" | awk -F "\t" '{print $1}' || echo "") + + if [ -n "$current_dock_item" ]; then + # The app is currently in the Dock, attempt to replace it + echo "Updating $app_name in Dock..." + dockutil --add "$resolved_path" --replacing "$current_dock_item" --no-restart + else + # The app is not in the Dock; you might choose to add it or do nothing + echo "$app_name is not currently in the Dock." + fi + else + echo "Warning: Provided path $app_path is not valid." + fi + done + + # Restart the Dock to apply changes + $killall Dock +} + +function mktrampoline() { + local app="$1" + local trampoline="$2" + + if [[ ! -d $app ]]; then + echo "app path is not directory." + return 1 + fi + + cmd="do shell script \"open '$app'\"" + $osacompile -o "$trampoline" -e "$cmd" + sync_icons "$app" "$trampoline" + copy_paths "$(realpath "$app/Contents/Info.plist")" "$(realpath "$trampoline/Contents/Info.plist")" "${copyable_app_props[@]}" +} + +function sync_trampolines() { + [[ ! -d $1 ]] && echo "Source directory does not exist" && return 1 + + if [[ -d $2 ]]; then + rm -rf "$2" + fi + mkdir -p "$2" + + apps=("$1"/*.app) + + for app in "${apps[@]}"; do + trampoline="$2/$(basename "$app")" + mktrampoline "$app" "$trampoline" + done + sync_dock "${apps[@]}" +} diff --git a/treefmt.nix b/treefmt.nix index 5b824e4..5dbd171 100644 --- a/treefmt.nix +++ b/treefmt.nix @@ -7,8 +7,15 @@ programs.alejandra.enable = true; ### shell - programs.shellcheck.enable = true; programs.shfmt.enable = true; + settings.formatter.shfmt.options = ["-i" "2" "-sr"]; + programs.shellcheck.enable = true; + settings.formatter.shellcheck.options = [ + "-s" + "bash" + "-e" + "SC2016" # shfmt kept doing it, didn't find a toggle to turn it off + ]; ### toml programs.taplo.enable = true;