{ config, pkgs, lib, ... }: with lib; let cfg = config.programs.atuin; daemonCfg = cfg.daemon; tomlFormat = pkgs.formats.toml { }; inherit (pkgs.stdenv) isLinux isDarwin; in { meta.maintainers = [ maintainers.hawkw maintainers.water-sucks ]; options.programs.atuin = { enable = mkEnableOption "atuin"; package = mkOption { type = types.package; default = pkgs.atuin; defaultText = literalExpression "pkgs.atuin"; description = "The package to use for atuin."; }; enableBashIntegration = mkOption { type = types.bool; default = true; description = '' Whether to enable Atuin's Bash integration. This will bind `ctrl-r` to open the Atuin history. ''; }; enableZshIntegration = mkOption { type = types.bool; default = true; description = '' Whether to enable Atuin's Zsh integration. If enabled, this will bind `ctrl-r` and the up-arrow key to open the Atuin history. ''; }; enableFishIntegration = mkOption { default = true; type = types.bool; description = '' Whether to enable Atuin's Fish integration. If enabled, this will bind 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 = 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 for the full list of options. ''; }; enableNushellIntegration = mkOption { default = true; type = types.bool; description = '' Whether to enable Nushell integration. ''; }; daemon = { enable = 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 = escapeShellArgs cfg.flags; in mkIf cfg.enable (mkMerge [ { # Always add the configured `atuin` package. home.packages = [ cfg.package ]; # If there are user-provided settings, generate the config file. xdg.configFile."atuin/config.toml" = mkIf (cfg.settings != { }) { source = tomlFormat.generate "atuin-config" cfg.settings; }; 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.initExtra = mkIf cfg.enableZshIntegration '' if [[ $options[zle] = on ]]; then eval "$(${lib.getExe cfg.package} init zsh ${flagsStr})" fi ''; programs.fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' ${lib.getExe cfg.package} init fish ${flagsStr} | source ''; programs.nushell = mkIf cfg.enableNushellIntegration { extraEnv = '' let atuin_cache = "${config.xdg.cacheHome}/atuin" if not ($atuin_cache | path exists) { mkdir $atuin_cache } ${ lib.getExe cfg.package } init nu ${flagsStr} | save --force ${config.xdg.cacheHome}/atuin/init.nu ''; extraConfig = '' source ${config.xdg.cacheHome}/atuin/init.nu ''; }; } (mkIf daemonCfg.enable (mkMerge [ { assertions = [ { assertion = versionAtLeast cfg.package.version "18.2.0"; message = '' The Atuin daemon requires at least version 18.2.0 or later. ''; } { assertion = isLinux || isDarwin; message = "The Atuin daemon can only be configured on either Linux or macOS."; } ]; programs.atuin.settings = { daemon = { enabled = true; }; }; } (mkIf isLinux { programs.atuin.settings = { daemon = { systemd_socket = true; }; }; 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} daemon"; 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 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; }; }; }) (mkIf isDarwin { launchd.agents.atuin-daemon = { enable = true; config = { ProgramArguments = [ "${lib.getExe cfg.package}" "daemon" ]; EnvironmentVariables = lib.optionalAttrs (daemonCfg.logLevel != null) { ATUIN_LOG = daemonCfg.logLevel; }; KeepAlive = { Crashed = true; SuccessfulExit = false; }; ProcessType = "Background"; }; }; }) ])) ]); }