Files
home-manager/modules/programs/t3code.nix
Austin Horstman 355734d876 treewide: remove literalExpression where unneeded
`literalExpression` is intended just to signify code that needs to stay
a string that gets represented exactly as-is for docs. It has been
misused heavily and people get confused repeatedly on when or not to use
it because of the rampant misuse.
2026-05-17 21:43:25 -05:00

190 lines
5.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
literalExpression
mkIf
mkMerge
mkOption
types
;
cfg = config.programs.t3code;
jsonFormat = pkgs.formats.json { };
json5 = pkgs.python3Packages.toPythonApplication pkgs.python3Packages.json5;
impureConfigMerger = empty: jqOperation: path: staticSettings: ''
mkdir -p "$(dirname -- ${lib.escapeShellArg path})"
if [ ! -e ${lib.escapeShellArg path} ]; then
echo ${lib.escapeShellArg empty} > ${lib.escapeShellArg path}
fi
dynamic="$(${lib.getExe json5} --as-json ${lib.escapeShellArg path})"
static="$(cat ${lib.escapeShellArg staticSettings})"
config="$(${lib.getExe pkgs.jq} -n ${lib.escapeShellArg jqOperation} --argjson dynamic "$dynamic" --argjson static "$static")"
printf '%s\n' "$config" > ${lib.escapeShellArg path}
unset config
'';
userDataDir = "${config.home.homeDirectory}/.t3/userdata";
in
{
meta.maintainers = [
lib.maintainers.iamanaws
];
options.programs.t3code = {
enable = lib.mkEnableOption "T3 Code, a minimal web GUI for coding agents";
package = mkOption {
type = types.nullOr types.package;
default = pkgs.t3code or null;
defaultText = literalExpression "pkgs.t3code";
description = ''
The t3code package to install.
'';
};
mutableUserSettings = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether user settings ({file}`settings.json`) can be updated by t3code.
'';
};
mutableKeybindings = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether user keybindings ({file}`keybindings.json`) can be updated by t3code.
'';
};
mutableClientSettings = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether client settings ({file}`client-settings.json`) can be updated by t3code.
'';
};
userSettings = mkOption {
inherit (jsonFormat) type;
default = { };
example = {
enableAssistantStreaming = true;
providerInstances = {
codex = {
driver = "codex";
enabled = true;
config = {
enabled = true;
binaryPath = "codex";
homePath = "";
shadowHomePath = "";
customModels = [ ];
};
};
};
};
description = ''
Configuration written to t3code's {file}`settings.json`.
'';
};
keybindings = mkOption {
inherit (jsonFormat) type;
default = [ ];
example = [
{
key = "mod+j";
command = "terminal.toggle";
}
{
key = "mod+d";
command = "terminal.split";
when = "terminalFocus";
}
{
key = "mod+d";
command = "diff.toggle";
when = "!terminalFocus";
}
];
description = ''
Configuration written to t3code's {file}`keybindings.json`.
'';
};
clientSettings = mkOption {
inherit (jsonFormat) type;
default = { };
example = {
settings = {
favorites = [
{
provider = "codex";
model = "gpt-5.5";
}
];
sidebarProjectGroupingMode = "repository";
timestampFormat = "locale";
};
};
description = ''
Configuration written to t3code's {file}`client-settings.json`.
'';
};
};
config = mkIf cfg.enable {
home.packages = mkIf (cfg.package != null) [ cfg.package ];
home.activation = mkMerge [
(mkIf (cfg.mutableUserSettings && cfg.userSettings != { }) {
t3codeSettingsActivation = lib.hm.dag.entryAfter [ "linkGeneration" ] (
impureConfigMerger "{}" "$dynamic * $static" "${userDataDir}/settings.json" (
jsonFormat.generate "t3code-user-settings" cfg.userSettings
)
);
})
(mkIf (cfg.mutableKeybindings && cfg.keybindings != [ ]) {
t3codeKeybindingsActivation = lib.hm.dag.entryAfter [ "linkGeneration" ] (
impureConfigMerger "[]"
"$dynamic + $static | group_by([.key, .when]) | map(reduce .[] as $item ({}; . * $item))"
"${userDataDir}/keybindings.json"
(jsonFormat.generate "t3code-user-keybindings" cfg.keybindings)
);
})
(mkIf (cfg.mutableClientSettings && cfg.clientSettings != { }) {
t3codeClientSettingsActivation = lib.hm.dag.entryAfter [ "linkGeneration" ] (
impureConfigMerger "{}" "$dynamic * $static" "${userDataDir}/client-settings.json" (
jsonFormat.generate "t3code-client-settings" cfg.clientSettings
)
);
})
];
home.file = mkMerge [
(mkIf (!cfg.mutableUserSettings && cfg.userSettings != { }) {
".t3/userdata/settings.json".source = jsonFormat.generate "t3code-user-settings" cfg.userSettings;
})
(mkIf (!cfg.mutableKeybindings && cfg.keybindings != [ ]) {
".t3/userdata/keybindings.json".source =
jsonFormat.generate "t3code-user-keybindings" cfg.keybindings;
})
(mkIf (!cfg.mutableClientSettings && cfg.clientSettings != { }) {
".t3/userdata/client-settings.json".source =
jsonFormat.generate "t3code-client-settings" cfg.clientSettings;
})
];
};
}