From f384af1bec6423a0d4ba1855917ab948f64e5808 Mon Sep 17 00:00:00 2001 From: Kays <115312476+kayskayskays@users.noreply.github.com> Date: Wed, 15 Apr 2026 23:50:59 +1000 Subject: [PATCH] macos-terminal: add module --- .../misc/news/2026/04/2026-04-15_21-57-57.nix | 14 ++ modules/programs/macos-terminal.nix | 179 ++++++++++++++++++ .../macos-terminal/basic-configuration.nix | 30 +++ .../programs/macos-terminal/default.nix | 8 + .../expected-basic-configuration.plist | 28 +++ 5 files changed, 259 insertions(+) create mode 100644 modules/misc/news/2026/04/2026-04-15_21-57-57.nix create mode 100644 modules/programs/macos-terminal.nix create mode 100644 tests/modules/programs/macos-terminal/basic-configuration.nix create mode 100644 tests/modules/programs/macos-terminal/default.nix create mode 100644 tests/modules/programs/macos-terminal/expected-basic-configuration.plist diff --git a/modules/misc/news/2026/04/2026-04-15_21-57-57.nix b/modules/misc/news/2026/04/2026-04-15_21-57-57.nix new file mode 100644 index 000000000..a2a6abd64 --- /dev/null +++ b/modules/misc/news/2026/04/2026-04-15_21-57-57.nix @@ -0,0 +1,14 @@ +{ + pkgs, + ... +}: +{ + time = "2026-04-15T11:57:57+00:00"; + condition = pkgs.stdenv.hostPlatform.isDarwin; + message = '' + A new module is available: `programs.macos-terminal`. + + This module allows for configuration of preferences for the macOS + Terminal.app application. + ''; +} diff --git a/modules/programs/macos-terminal.nix b/modules/programs/macos-terminal.nix new file mode 100644 index 000000000..334daac39 --- /dev/null +++ b/modules/programs/macos-terminal.nix @@ -0,0 +1,179 @@ +{ + lib, + pkgs, + config, + ... +}: +let + inherit (lib) + maintainers + mapAttrs + mkEnableOption + mkIf + mkOption + mkOptionDefault + types + ; + + inherit (lib.hm) + assertions + dag + ; + + inherit (lib.platforms) darwin; + inherit (pkgs.formats) plist; + + cfg = config.programs.macos-terminal; + plistFormat = plist { escape = true; }; +in +{ + meta.maintainers = with maintainers; [ + kayskayskays + ]; + + options.programs.macos-terminal = { + enable = mkEnableOption "macOS Terminal"; + + profiles = mkOption { + type = types.attrsOf ( + types.submodule { + # These settings will be passed directly to the plist generator. + options.settings = mkOption { + type = types.attrsOf plistFormat.type; + + default = { }; + + example = '' + { + FontAntialias = true; + ShowActiveProcessInTitle = true; + ShowCommandKeyInTitle = true; + }; + ''; + + description = '' + Raw plist-compatible settings for profiles within the Terminal.app + application. + + This attribute set is intended for simple settings that have a + well defined mapping to plist properties. + + Properties that are more obscure and require serialization as + archived Cocoa objects, for example, are unsupported here - they + may require dedicated module options in future. + + Attribute names should reflect the name of plist properties + understood by the Terminal.app application. Unknown attributes + will still be serialized, but may remain unrecognised - and thus + unhonored - by the Terminal.app application. + ''; + }; + + config.settings = { + # For profiles, the "type" plist property should always be "Window + # Settings". + type = mkOptionDefault "Window Settings"; + + # Other common profile defaults. + rowCount = mkOptionDefault 24; + columnCount = mkOptionDefault 80; + ProfileCurrentVersion = mkOptionDefault 2.07; + }; + } + ); + + default = { }; + + example = '' + { + Basic.settings = { + FontAntialias = true; + ShowActiveProcessInTitle = true; + }; + + "Red Sands".settings = { + BackgroundAlphaInactive = 0.5; + CommandString = "ssh compute"; + }; + } + ''; + + description = '' + Configuration settings for profiles within the Terminal.app application. + + Each attribute name is used as the name of the profile, and the value + defines the plist-compatible settings for that profile. + ''; + }; + + preferences = mkOption { + type = types.submodule { + options = { + importSettings = mkOption { + type = types.bool; + + default = true; + + description = '' + Whether to import the generated plist into the + `com.apple.Terminal` preferences domain during activation. + ''; + }; + + writeFile = mkOption { + type = types.bool; + + default = false; + + description = '' + Whether to write the generated plist into the + `~/Library/Preferences/com.apple.Terminal.plist` file during + activation. + + This is primarily useful for inspection and testing purposes. + ''; + }; + }; + }; + + default = { }; + + example = '' + { + importSettings = true; + writeFile = false; + } + ''; + + description = '' + Options controlling how Terminal.app preferences are applied and + managed. + ''; + }; + }; + + config = mkIf cfg.enable ( + let + finalSettings = mapAttrs (name: profile: profile.settings // { inherit name; }) cfg.profiles; + + plistFile = plistFormat.generate "com.apple.Terminal.plist" { + "Window Settings" = finalSettings; + }; + in + { + assertions = [ + (assertions.assertPlatform "programs.macos-terminal" pkgs darwin) + ]; + + home.file."Library/Preferences/com.apple.Terminal.plist" = mkIf cfg.preferences.writeFile { + source = plistFile; + }; + + home.activation.appleTerminal = mkIf cfg.preferences.importSettings ( + dag.entryAfter [ "writeBoundary" ] '' + run /usr/bin/defaults import com.apple.Terminal "${plistFile}" + '' + ); + } + ); +} diff --git a/tests/modules/programs/macos-terminal/basic-configuration.nix b/tests/modules/programs/macos-terminal/basic-configuration.nix new file mode 100644 index 000000000..dd1750f70 --- /dev/null +++ b/tests/modules/programs/macos-terminal/basic-configuration.nix @@ -0,0 +1,30 @@ +{ + programs.macos-terminal = { + enable = true; + + profiles = { + Basic.settings = { + CommandString = "echo test"; + + ShowActiveProcessArgumentsInTitle = false; + ShowTTYNameInTitle = true; + + columnCount = 50; + }; + }; + + preferences = { + importSettings = false; + writeFile = true; + }; + }; + + nmt.script = + let + plistFile = "home-files/Library/Preferences/com.apple.Terminal.plist"; + in + '' + assertFileExists "${plistFile}" + assertFileContent "${plistFile}" ${./expected-basic-configuration.plist} + ''; +} diff --git a/tests/modules/programs/macos-terminal/default.nix b/tests/modules/programs/macos-terminal/default.nix new file mode 100644 index 000000000..f33f528ed --- /dev/null +++ b/tests/modules/programs/macos-terminal/default.nix @@ -0,0 +1,8 @@ +{ + lib, + pkgs, + ... +}: +lib.optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { + macos-terminal-basic-configuration = ./basic-configuration.nix; +} diff --git a/tests/modules/programs/macos-terminal/expected-basic-configuration.plist b/tests/modules/programs/macos-terminal/expected-basic-configuration.plist new file mode 100644 index 000000000..2f6cc8b28 --- /dev/null +++ b/tests/modules/programs/macos-terminal/expected-basic-configuration.plist @@ -0,0 +1,28 @@ + + + + + Window Settings + + Basic + + CommandString + echo test + ProfileCurrentVersion + 2.070000 + ShowActiveProcessArgumentsInTitle + + ShowTTYNameInTitle + + columnCount + 50 + name + Basic + rowCount + 24 + type + Window Settings + + + + \ No newline at end of file