2.home-manager/modules/programs/atuin.nix
Austin Horstman 165228b0ef
Some checks are pending
/ triage (push) Waiting to run
GitHub Pages / publish (ubuntu-latest) (push) Waiting to run
launchd: restore gui domain defaults
User-domain agents are not rediscovered from the user LaunchAgents directory after reboot. Let built-in agents inherit the GUI default while keeping explicit user-domain configuration available.
2026-07-15 10:29:26 -05:00

321 lines
9.1 KiB
Nix

{
config,
pkgs,
lib,
...
}:
let
cfg = config.programs.atuin;
daemonCfg = cfg.daemon;
tomlFormat = pkgs.formats.toml { };
# atuin 18.13.0 deprecated `atuin daemon` in favour of `atuin daemon start`
daemonArgs =
if lib.versionAtLeast cfg.package.version "18.13.0" then
[
"daemon"
"start"
]
else
[ "daemon" ];
inherit (lib)
mkIf
mkOption
types
;
in
{
meta.maintainers = with lib.maintainers; [
hawkw
water-sucks
];
options.programs.atuin = {
enable = lib.mkEnableOption "atuin";
package = lib.mkPackageOption pkgs "atuin" { };
enableBashIntegration = lib.hm.shell.mkBashIntegrationOption {
inherit config;
extraDescription = "If enabled, this will bind `ctrl-r` to open the Atuin history.";
};
enableFishIntegration = lib.hm.shell.mkFishIntegrationOption {
inherit config;
extraDescription = "If enabled, this will bind the up-arrow key to open the Atuin history.";
};
enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; };
enableZshIntegration = lib.hm.shell.mkZshIntegrationOption {
inherit config;
extraDescription = ''
If enabled, this will bind `ctrl-r` and the up-arrow key to open the
Atuin history.
'';
};
flags = mkOption {
default = [ ];
type = types.listOf types.str;
example = [
"--disable-up-arrow"
"--disable-ctrl-r"
];
description = ''
Flags to append to the shell hook.
'';
};
settings = mkOption {
type =
with types;
let
prim = oneOf [
bool
int
str
];
primOrPrimAttrs = either prim (attrsOf prim);
entry = either prim (listOf primOrPrimAttrs);
entryOrAttrsOf = t: either entry (attrsOf t);
entries = entryOrAttrsOf (entryOrAttrsOf entry);
in
attrsOf entries // { description = "Atuin configuration"; };
default = { };
example = lib.literalExpression ''
{
auto_sync = true;
sync_frequency = "5m";
sync_address = "https://api.atuin.sh";
search_mode = "prefix";
}
'';
description = ''
Configuration written to
{file}`$XDG_CONFIG_HOME/atuin/config.toml`.
See <https://docs.atuin.sh/configuration/config/> for the full list
of options.
'';
};
forceOverwriteSettings = mkOption {
type = types.bool;
default = false;
description = ''
When enabled, force overwriting of the Atuin configuration file
({file}`$XDG_CONFIG_HOME/atuin/config.toml`).
Any existing Atuin configuration will be lost.
Enabling this is useful when adding settings for the first time
because Atuin writes its default config file after every single
shell command, which can make it difficult to manually remove.
'';
};
themes = mkOption {
type = types.attrsOf (
types.oneOf [
tomlFormat.type
types.path
types.lines
]
);
description = ''
Each theme is written to
{file}`$XDG_CONFIG_HOME/atuin/themes/theme-name.toml`
where the name of each attribute is the theme-name
See <https://docs.atuin.sh/guide/theming/> for the full list
of options.
'';
default = { };
example = lib.literalExpression ''
{
"my-theme" = {
theme.name = "My Theme";
colors = {
Base = "#000000";
Title = "#FFFFFF";
};
};
}
'';
};
daemon = {
enable = lib.mkEnableOption "Atuin daemon";
logLevel = mkOption {
default = null;
type = types.nullOr (
types.enum [
"trace"
"debug"
"info"
"warn"
"error"
]
);
description = ''
Verbosity of Atuin daemon logging.
'';
};
};
};
config =
let
flagsStr = lib.escapeShellArgs cfg.flags;
atuinFishConfig =
pkgs.runCommand "atuin-fish-config.fish"
{
nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ];
}
''
${lib.getExe cfg.package} init fish ${flagsStr} > "$out"
'';
in
mkIf cfg.enable (
lib.mkMerge [
{
# Always add the configured `atuin` package.
home.packages = [ cfg.package ];
# If there are user-provided settings, generate the config file.
xdg.configFile = lib.mkMerge [
(mkIf (cfg.settings != { }) {
"atuin/config.toml" = {
source = tomlFormat.generate "atuin-config" cfg.settings;
force = cfg.forceOverwriteSettings;
};
})
(mkIf (cfg.themes != { }) (
lib.mapAttrs' (
name: theme:
lib.nameValuePair "atuin/themes/${name}.toml" {
source =
if lib.isString theme then
pkgs.writeText "atuin-theme-${name}" theme
else if builtins.isPath theme || lib.isStorePath theme then
theme
else
tomlFormat.generate "atuin-theme-${name}" theme;
}
) cfg.themes
))
];
programs.bash.initExtra = mkIf cfg.enableBashIntegration ''
if [[ :$SHELLOPTS: =~ :(vi|emacs): ]]; then
source "${pkgs.bash-preexec}/share/bash/bash-preexec.sh"
eval "$(${lib.getExe cfg.package} init bash ${flagsStr})"
fi
'';
programs.zsh.initContent = mkIf cfg.enableZshIntegration ''
if [[ $options[zle] = on ]]; then
eval "$(${lib.getExe cfg.package} init zsh ${flagsStr})"
fi
'';
programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration ''
source ${atuinFishConfig}
'';
programs.nushell = mkIf cfg.enableNushellIntegration {
# Load after fzf so Atuin keeps Ctrl-R in Nushell.
extraConfig = lib.mkOrder 2000 ''
source ${
pkgs.runCommand "atuin-nushell-config.nu"
{
nativeBuildInputs = [ pkgs.writableTmpDirAsHomeHook ];
}
''
${lib.getExe cfg.package} init nu ${flagsStr} >> "$out"
''
}
'';
};
}
(mkIf config.home.preferXdgDirectories {
programs.atuin.settings.logs = {
dir = lib.mkDefault "${config.xdg.stateHome}/atuin/logs";
};
})
(mkIf daemonCfg.enable {
assertions = [
{
assertion = config.systemd.user.enable || config.launchd.enable;
message = "The Atuin daemon can only be configured on systems with systemd or launchd.";
}
];
programs.atuin.settings.daemon = {
enabled = true;
systemd_socket = config.systemd.user.enable;
socket_path = lib.mkIf (!config.systemd.user.enable) (
lib.mkDefault "${config.xdg.dataHome}/atuin/daemon.sock"
);
};
systemd.user.services.atuin-daemon = {
Unit = {
Description = "Atuin daemon";
Requires = [ "atuin-daemon.socket" ];
};
Install = {
Also = [ "atuin-daemon.socket" ];
WantedBy = [ "default.target" ];
};
Service = {
ExecStart = "${lib.getExe cfg.package} ${lib.concatStringsSep " " daemonArgs}";
Environment = lib.optionals (daemonCfg.logLevel != null) [ "ATUIN_LOG=${daemonCfg.logLevel}" ];
Restart = "on-failure";
RestartSteps = 3;
RestartMaxDelaySec = 6;
};
};
systemd.user.sockets.atuin-daemon =
let
socket_dir = if lib.versionAtLeast cfg.package.version "18.4.0" then "%t" else "%D/atuin";
in
{
Unit = {
Description = "Atuin daemon socket";
};
Install = {
WantedBy = [ "sockets.target" ];
};
Socket = {
ListenStream = "${socket_dir}/atuin.sock";
SocketMode = "0600";
RemoveOnStop = true;
};
};
launchd.agents.atuin-daemon = {
enable = true;
config = {
ProgramArguments = [ (lib.getExe cfg.package) ] ++ daemonArgs;
EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) {
ATUIN_LOG = daemonCfg.logLevel;
};
KeepAlive = {
Crashed = true;
SuccessfulExit = false;
};
ProcessType = "Background";
};
};
})
]
);
}