{ config, lib, ... }: let inherit (lib) mkIf mkOption types; cfg = config.programs.readline; mkSetVariableStr = n: v: let mkValueStr = v: if v == true then "on" else if v == false then "off" else if lib.isInt v then toString v else if lib.isString v then v else abort "values ${lib.toPretty v} is of unsupported type"; in "set ${n} ${mkValueStr v}"; mkBindingStr = k: v: let isKeynameNotKeyseq = k: builtins.elem (builtins.head (lib.splitString "-" (lib.toLower k))) [ "control" "meta" ]; in if isKeynameNotKeyseq k then "${k}: ${v}" else ''"${k}": ${v}''; in { options.programs.readline = { enable = lib.mkEnableOption "readline"; bindings = mkOption { default = { }; type = types.attrsOf types.str; example = lib.literalExpression '' { "\\C-h" = "backward-kill-word"; } ''; description = "Readline bindings."; }; variables = mkOption { type = with types; attrsOf (either str (either int bool)); default = { }; example = { expand-tilde = true; }; description = '' Readline customization variable assignments. ''; }; includeSystemConfig = mkOption { type = types.bool; default = true; description = "Whether to include the system-wide configuration."; }; extraConfig = mkOption { type = types.lines; default = ""; description = '' Configuration lines appended unchanged to the end of the {file}`~/.inputrc` file. ''; }; }; config = mkIf cfg.enable ( let finalConfig = let configStr = lib.concatStringsSep "\n" ( lib.optional cfg.includeSystemConfig "$include /etc/inputrc" ++ lib.mapAttrsToList mkSetVariableStr cfg.variables ++ lib.mapAttrsToList mkBindingStr cfg.bindings ); in '' # Generated by Home Manager. ${configStr} ${cfg.extraConfig} ''; in lib.mkMerge [ (mkIf (!config.home.preferXdgDirectories) { home.file.".inputrc".text = finalConfig; }) (mkIf config.home.preferXdgDirectories { xdg.configFile.inputrc.text = finalConfig; home.sessionVariables.INPUTRC = "${config.xdg.configHome}/inputrc"; }) ] ); }