diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index f24e64d9..09b89345 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 a96f90a9..221fcd77 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 00000000..961c8667
--- /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 00000000..4481f33b
--- /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 00000000..f722fbfa
--- /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 00000000..2afbae4a
--- /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;
+ };
+ };
+}