diff --git a/modules/misc/news.nix b/modules/misc/news.nix index f24e64d9f..09b89345d 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1822,6 +1822,29 @@ in A new module is available: 'services.playerctld'. ''; } + + { + time = "2021-01-28T15:07:34+00:00"; + condition = hostPlatform.isDarwin; + message = '' + New options are available for 'targets.darwin': + + - targets.darwin.defaults + + This adds options for configuring macOS through the defaults(1) + system. + + - targets.darwin.keybindings + + This adds options for configuring the default keybindings for macOS + text fields. + + - targets.darwin.search + + This adds options for configuring the default search engine for + macOS. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index a96f90a95..221fcd778 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -204,7 +204,7 @@ let (loadModule ./services/xscreensaver.nix { }) (loadModule ./services/xsuspender.nix { condition = hostPlatform.isLinux; }) (loadModule ./systemd.nix { }) - (loadModule ./targets/darwin.nix { condition = hostPlatform.isDarwin; }) + (loadModule ./targets/darwin { condition = hostPlatform.isDarwin; }) (loadModule ./targets/generic-linux.nix { condition = hostPlatform.isLinux; }) (loadModule ./xcursor.nix { }) (loadModule ./xresources.nix { }) diff --git a/modules/targets/darwin/default.nix b/modules/targets/darwin/default.nix new file mode 100644 index 000000000..961c8667e --- /dev/null +++ b/modules/targets/darwin/default.nix @@ -0,0 +1,51 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.targets.darwin; + + toDefaultsFile = domain: attrs: + pkgs.writeText "${domain}.plist" (lib.generators.toPlist { } attrs); + + toActivationCmd = domain: attrs: + "$DRY_RUN_CMD defaults import ${escapeShellArg domain} ${ + toDefaultsFile domain attrs + }"; + + nonNullDefaults = + mapAttrs (domain: attrs: (filterAttrs (n: v: v != null) attrs)) + cfg.defaults; + writableDefaults = filterAttrs (domain: attrs: attrs != { }) nonNullDefaults; + activationCmds = mapAttrsToList toActivationCmd writableDefaults; +in { + imports = [ ./keybindings.nix ./linkapps.nix ./search.nix ]; + + options.targets.darwin.defaults = mkOption { + type = types.submodule ./options.nix; + default = { }; + example = { + "com.apple.desktopservices" = { + DSDontWriteNetworkStores = true; + DSDontWriteUSBStores = true; + }; + }; + description = '' + Set macOS user defaults. Values set to null are + ignored. + + + + Some settings might require a re-login to take effect. + + + ''; + }; + + config = mkIf (activationCmds != [ ]) { + home.activation.setDarwinDefaults = hm.dag.entryAfter [ "writeBoundary" ] '' + $VERBOSE_ECHO "Configuring macOS user defaults" + ${concatStringsSep "\n" activationCmds} + ''; + }; +} diff --git a/modules/targets/darwin/keybindings.nix b/modules/targets/darwin/keybindings.nix new file mode 100644 index 000000000..4481f33bd --- /dev/null +++ b/modules/targets/darwin/keybindings.nix @@ -0,0 +1,42 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.targets.darwin; + homeDir = config.home.homeDirectory; + confFile = pkgs.writeText "DefaultKeybinding.dict" + (lib.generators.toPlist { } cfg.keybindings); +in { + options.targets.darwin.keybindings = mkOption { + type = with types; attrsOf anything; + default = { }; + example = { + "^u" = "deleteToBeginningOfLine:"; + "^w" = "deleteWordBackward:"; + }; + description = '' + This will configure the default keybindings for text fields in macOS + applications. See + Apple's documentation + for more details. + + + + Existing keybinding configuration will be wiped when using this + option. + + + ''; + }; + + config = mkIf (cfg.keybindings != { }) { + # NOTE: just copy the files because symlinks won't be recognized by macOS + home.activation.setCocoaKeybindings = + hm.dag.entryAfter [ "writeBoundary" ] '' + $VERBOSE_ECHO "Configuring keybindings for the Cocoa Text System" + $DRY_RUN_CMD install -Dm644 $VERBOSE_ARG \ + "${confFile}" "${homeDir}/Library/KeyBindings/DefaultKeyBinding.dict" + ''; + }; +} diff --git a/modules/targets/darwin.nix b/modules/targets/darwin/linkapps.nix similarity index 100% rename from modules/targets/darwin.nix rename to modules/targets/darwin/linkapps.nix diff --git a/modules/targets/darwin/options.nix b/modules/targets/darwin/options.nix new file mode 100644 index 000000000..f722fbfae --- /dev/null +++ b/modules/targets/darwin/options.nix @@ -0,0 +1,189 @@ +{ config, lib, ... }: + +with lib; + +let + mkNullableOption = args: + lib.mkOption (args // { + type = types.nullOr args.type; + default = null; + }); + + mkNullableEnableOption = name: + lib.mkOption { + type = with types; nullOr bool; + default = null; + example = true; + description = "Whether to enable ${name}."; + }; + + safari = config."com.apple.Safari"; +in { + freeformType = with types; attrsOf (attrsOf anything); + + options = { + NSGlobalDomain = { + AppleLanguages = mkNullableOption { + type = with types; listOf str; + example = [ "en" ]; + description = "Sets the language to use in the preferred order."; + }; + + AppleLocale = mkNullableOption { + type = types.str; + example = "en_US"; + description = "Configures the user locale."; + }; + + AppleMeasurementUnits = mkNullableOption { + type = types.enum [ "Centimeters" "Inches" ]; + example = "Centimeters"; + description = "Sets the measurement unit."; + }; + + AppleTemperatureUnit = mkNullableOption { + type = types.enum [ "Celsius" "Fahrenheit" ]; + example = "Celsius"; + description = "Sets the temperature unit."; + }; + + AppleMetricUnits = mkNullableEnableOption "the metric system"; + + NSAutomaticCapitalizationEnabled = + mkNullableEnableOption "automatic captilization"; + + NSAutomaticDashSubstitutionEnabled = + mkNullableEnableOption "smart dashes"; + + NSAutomaticPeriodSubstitutionEnabled = + mkNullableEnableOption "period with double space"; + + NSAutomaticQuoteSubstitutionEnabled = + mkNullableEnableOption "smart quotes"; + + NSAutomaticSpellingCorrectionEnabled = + mkNullableEnableOption "spelling correction"; + }; + + "com.apple.desktopservices" = { + DSDontWriteNetworkStores = mkNullableOption { + type = types.bool; + example = false; + description = '' + Disable use of .DS_Store files on network shares. + See the + official article for more info. + ''; + }; + DSDontWriteUSBStores = mkNullableOption { + type = types.bool; + example = false; + description = '' + Disable use of .DS_Store files on thumb drives. + ''; + }; + }; + + "com.apple.dock" = { + tilesize = mkNullableOption { + type = types.int; + example = 64; + description = "Sets the size of the dock."; + }; + size-immutable = mkNullableEnableOption "locking of the dock size"; + expose-group-apps = mkNullableEnableOption + "grouping of windows by application in Mission Control"; + }; + + "com.apple.menuextra.battery".ShowPercent = mkNullableOption { + type = types.enum [ "YES" "NO" ]; + example = "NO"; + description = "Whether to show battery percentage in the menu bar."; + }; + + "com.apple.Safari" = { + AutoOpenSafeDownloads = + mkNullableEnableOption "opening of downloaded files"; + AutoFillPasswords = + mkNullableEnableOption "autofill of usernames and passwords"; + AutoFillCreditCardData = + mkNullableEnableOption "autofill of credit card numbers"; + IncludeDevelopMenu = + mkNullableEnableOption ''"Develop" menu in the menu bar''; + ShowOverlayStatusBar = mkNullableEnableOption "status bar"; + + WebKitDeveloperExtrasEnabledPreferenceKey = mkNullableOption { + type = types.bool; + description = '' + Configures the web inspector. + + + + Instead of setting this option directly, set + instead. + + + ''; + }; + "com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled" = + mkNullableOption { + type = types.bool; + description = '' + Configures the web inspector. + + + + Instead of setting this option directly, set + instead. + + + ''; + }; + }; + + "com.googlecode.iterm2" = { + AddNewTabAtEndOfTabs = mkNullableEnableOption + "placement of new tabs at the end of the tab bar"; + + AlternateMouseScroll = mkNullableEnableOption + "arrow keys when scrolling in alternate screen mode"; + + CopySelection = + mkNullableEnableOption "copy to clipboard upon selecting text"; + + OpenTmuxWindowsIn = mkNullableOption { + type = types.int; + example = 2; + description = '' + Configures how to restore tmux windows when attaching to a session. + + Possible Values + + 0 + Native windows + + + 1 + Native tabs in a new window + + + 2 + Tabs in the attaching window + + + ''; + }; + + ExperimentalKeyHandling = mkNullableEnableOption + "experimental key handling for AquaSKK compatibility"; + }; + }; + + config = { + "com.apple.Safari" = mkIf (safari.IncludeDevelopMenu != null) { + WebKitDeveloperExtrasEnabledPreferenceKey = safari.IncludeDevelopMenu; + "com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled" = + safari.IncludeDevelopMenu; + }; + }; +} diff --git a/modules/targets/darwin/search.nix b/modules/targets/darwin/search.nix new file mode 100644 index 000000000..2afbae4af --- /dev/null +++ b/modules/targets/darwin/search.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.targets.darwin; + searchEngines = { + Bing = "com.bing.www"; + DuckDuckGo = "com.duckduckgo"; + Ecosia = "org.ecosia.www"; + Google = "com.google.www"; + Yahoo = "com.yahoo.www"; + }; + searchId = getAttr cfg.search searchEngines; +in { + options.targets.darwin.search = mkOption { + type = with types; nullOr (enum (attrNames searchEngines)); + default = null; + description = "Default search engine."; + }; + + config = mkIf (cfg.search != null) { + targets.darwin.defaults = { + NSGlobalDomain.NSPreferredWebServices = { + NSWebServicesProviderWebSearch = { + NSDefaultDisplayName = cfg.search; + NSProviderIdentifier = searchId; + }; + }; + "com.apple.Safari".SearchProviderIdentifier = searchId; + }; + }; +}