diff --git a/modules/lib/nushell.nix b/modules/lib/nushell.nix index e831380cd..5ef5ad36d 100644 --- a/modules/lib/nushell.nix +++ b/modules/lib/nushell.nix @@ -1,7 +1,9 @@ { lib }: rec { mkNushellInline = expr: lib.setType "nushell-inline" { inherit expr; }; - toNushell = { indent ? "", multiline ? true, asBindings ? false }@args: + isNushellInline = lib.isType "nushell-inline"; + + toNushell = { indent ? "", multiline ? true, asBindings ? false, }@args: v: let innerIndent = "${indent} "; @@ -18,7 +20,6 @@ asBindings = false; }; concatItems = lib.concatStringsSep introSpace; - isNushellInline = lib.isType "nushell-inline"; generatedBindings = assert lib.assertMsg (badVarNames == [ ]) "Bad Nushell variable names: ${ diff --git a/modules/programs/nushell.nix b/modules/programs/nushell.nix index ec00210af..a4e767c8a 100644 --- a/modules/programs/nushell.nix +++ b/modules/programs/nushell.nix @@ -1,9 +1,7 @@ { config, lib, pkgs, ... }: - -with lib; - let - + inherit (lib) types; + inherit (lib.hm.nushell) isNushellInline toNushell; cfg = config.programs.nushell; configDir = if pkgs.stdenv.isDarwin && !config.xdg.enable then @@ -14,13 +12,13 @@ let linesOrSource = name: types.submodule ({ config, ... }: { options = { - text = mkOption { + text = lib.mkOption { type = types.lines; default = if config.source != null then builtins.readFile config.source else ""; - defaultText = literalExpression + defaultText = lib.literalExpression "if source is defined, the content of source, otherwise empty"; description = '' Text of the nushell {file}`${name}` file. @@ -28,7 +26,7 @@ let ''; }; - source = mkOption { + source = lib.mkOption { type = types.nullOr types.path; default = null; description = '' @@ -39,39 +37,29 @@ let }; }); in { - meta.maintainers = - [ maintainers.Philipp-M maintainers.joaquintrinanes maintainers.aidalgol ]; - - imports = [ - (mkRemovedOptionModule [ "programs" "nushell" "settings" ] '' - Please use - - 'programs.nushell.configFile' and 'programs.nushell.envFile' - - instead. - '') + meta.maintainers = with lib.maintainers; [ + Philipp-M + joaquintrinanes + aidalgol ]; options.programs.nushell = { - enable = mkEnableOption "nushell"; + enable = lib.mkEnableOption "nushell"; - package = mkOption { - type = types.package; - default = pkgs.nushell; - defaultText = literalExpression "pkgs.nushell"; - description = "The package to use for nushell."; - }; + package = lib.mkPackageOption pkgs "nushell" { }; - configFile = mkOption { + configFile = lib.mkOption { type = types.nullOr (linesOrSource "config.nu"); default = null; - example = literalExpression '' - { text = ''' - let $config = { - filesize_metric: false - table_mode: rounded - use_ls_colors: true + example = lib.literalExpression '' + { + text = ''' + const NU_LIB_DIRS = $NU_LIB_DIRS ++ ''${ + lib.hm.nushell.toNushell (lib.concatStringsSep ":" [ ./scripts ]) } + $env.config.filesize_metric = false + $env.config.table_mode = 'rounded' + $env.config.use_ls_colors = true '''; } ''; @@ -82,7 +70,7 @@ in { ''; }; - envFile = mkOption { + envFile = lib.mkOption { type = types.nullOr (linesOrSource "env.nu"); default = null; example = '' @@ -95,7 +83,7 @@ in { ''; }; - loginFile = mkOption { + loginFile = lib.mkOption { type = types.nullOr (linesOrSource "login.nu"); default = null; example = '' @@ -111,7 +99,7 @@ in { ''; }; - extraConfig = mkOption { + extraConfig = lib.mkOption { type = types.lines; default = ""; description = '' @@ -119,7 +107,7 @@ in { ''; }; - extraEnv = mkOption { + extraEnv = lib.mkOption { type = types.lines; default = ""; description = '' @@ -127,7 +115,7 @@ in { ''; }; - extraLogin = mkOption { + extraLogin = lib.mkOption { type = types.lines; default = ""; description = '' @@ -135,7 +123,7 @@ in { ''; }; - plugins = mkOption { + plugins = lib.mkOption { type = types.listOf types.package; default = [ ]; example = lib.literalExpression "[ pkgs.nushellPlugins.formats ]"; @@ -144,24 +132,55 @@ in { ''; }; - shellAliases = mkOption { + settings = lib.mkOption { + type = types.attrsOf lib.hm.types.nushellValue; + default = { }; + example = { + show_banner = false; + history.format = "sqlite"; + }; + description = '' + Nushell settings. These will be flattened and assigned one by one to `$env.config` to avoid overwriting the default or existing options. + + For example: + ```nix + { + show_banner = false; + completions.external = { + enable = true; + max_results = 200; + }; + } + ``` + becomes: + ```nushell + $env.config.completions.external.enable = true + $env.config.completions.external.max_results = 200 + $env.config.show_banner = false + ``` + ''; + }; + + shellAliases = lib.mkOption { type = types.attrsOf types.str; default = { }; - example = { ll = "ls -l"; }; + example = { + ll = "ls -l"; + g = "git"; + }; description = '' An attribute set that maps aliases (the top level attribute names in this option) to command strings or directly to build outputs. ''; }; - environmentVariables = mkOption { - type = types.attrsOf hm.types.nushellValue; + environmentVariables = lib.mkOption { + type = types.attrsOf lib.hm.types.nushellValue; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { FOO = "BAR"; LIST_VALUE = [ "foo" "bar" ]; - NU_LIB_DIRS = lib.concatStringsSep ":" [ ./scripts ]; PROMPT_COMMAND = lib.hm.nushell.mkNushellInline '''{|| "> "}'''; ENV_CONVERSIONS.PATH = { from_string = lib.hm.nushell.mkNushellInline "{|s| $s | split row (char esep) }"; @@ -177,39 +196,57 @@ in { }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { home.packages = [ cfg.package ]; - home.file = mkMerge [ + home.file = lib.mkMerge [ (let writeConfig = cfg.configFile != null || cfg.extraConfig != "" - || aliasesStr != ""; + || aliasesStr != "" || cfg.settings != { }; - aliasesStr = concatStringsSep "\n" - (mapAttrsToList (k: v: "alias ${k} = ${v}") cfg.shellAliases); - in mkIf writeConfig { - "${configDir}/config.nu".text = mkMerge [ - (mkIf (cfg.configFile != null) cfg.configFile.text) + aliasesStr = lib.concatLines + (lib.mapAttrsToList (k: v: "alias ${toNushell { } k} = ${v}") + cfg.shellAliases); + in lib.mkIf writeConfig { + "${configDir}/config.nu".text = lib.mkMerge [ + (let + hasEnvVars = cfg.environmentVariables != { }; + envVarsStr = '' + load-env ${toNushell { } cfg.environmentVariables} + ''; + in lib.mkIf hasEnvVars envVarsStr) + (let + flattenSettings = let + joinDot = a: b: "${if a == "" then "" else "${a}."}${b}"; + unravel = prefix: value: + if lib.isAttrs value && !isNushellInline value then + lib.concatMap (key: unravel (joinDot prefix key) value.${key}) + (builtins.attrNames value) + else + [ (lib.nameValuePair prefix value) ]; + in unravel ""; + mkLine = { name, value }: '' + $env.config.${name} = ${toNushell { } value} + ''; + settingsLines = + lib.concatMapStrings mkLine (flattenSettings cfg.settings); + + in lib.mkIf (cfg.settings != { }) settingsLines) + (lib.mkIf (cfg.configFile != null) cfg.configFile.text) cfg.extraConfig aliasesStr ]; }) - (let - hasEnvVars = cfg.environmentVariables != { }; - envVarsStr = '' - load-env ${hm.nushell.toNushell { } cfg.environmentVariables} - ''; - in mkIf (cfg.envFile != null || cfg.extraEnv != "" || hasEnvVars) { - "${configDir}/env.nu".text = mkMerge [ - (mkIf (cfg.envFile != null) cfg.envFile.text) + (lib.mkIf (cfg.envFile != null || cfg.extraEnv != "") { + "${configDir}/env.nu".text = lib.mkMerge [ + (lib.mkIf (cfg.envFile != null) cfg.envFile.text) cfg.extraEnv - envVarsStr ]; }) - (mkIf (cfg.loginFile != null || cfg.extraLogin != "") { - "${configDir}/login.nu".text = mkMerge [ - (mkIf (cfg.loginFile != null) cfg.loginFile.text) + (lib.mkIf (cfg.loginFile != null || cfg.extraLogin != "") { + "${configDir}/login.nu".text = lib.mkMerge [ + (lib.mkIf (cfg.loginFile != null) cfg.loginFile.text) cfg.extraLogin ]; }) @@ -220,11 +257,11 @@ in { ${lib.getExe cfg.package} \ --plugin-config "$out/plugin.msgpackz" \ --commands '${ - concatStringsSep "; " + lib.concatStringsSep "; " (map (plugin: "plugin add ${lib.getExe plugin}") cfg.plugins) }' ''; - in mkIf (cfg.plugins != [ ]) { + in lib.mkIf (cfg.plugins != [ ]) { "${configDir}/plugin.msgpackz".source = "${msgPackz}/plugin.msgpackz"; }) ]; diff --git a/tests/modules/programs/nushell/config-expected.nu b/tests/modules/programs/nushell/config-expected.nu index a306fabd8..57bc16ee8 100644 --- a/tests/modules/programs/nushell/config-expected.nu +++ b/tests/modules/programs/nushell/config-expected.nu @@ -1,9 +1,31 @@ -let $config = { +load-env { + "ENV_CONVERSIONS": { + "PATH": { + "from_string": ({|s| $s | split row (char esep) }) + "to_string": ({|v| $v | str join (char esep) }) + } + } + "FOO": "BAR" + "LIST_VALUE": [ + "foo" + "bar" + ] + "PROMPT_COMMAND": ({|| "> "}) +} + +$env.config.display_errors.exit_code = false +$env.config.hooks.pre_execution = [ + ({|| "pre_execution hook"}) +] +$env.config.show_banner = false + +let config = { filesize_metric: false table_mode: rounded use_ls_colors: true } -alias ll = ls -a -alias lsname = (ls | get name) \ No newline at end of file +alias "ll" = ls -a +alias "multi word alias" = cd - +alias "z" = __zoxide_z diff --git a/tests/modules/programs/nushell/env-expected.nu b/tests/modules/programs/nushell/env-expected.nu index 50f6f767b..aacc37925 100644 --- a/tests/modules/programs/nushell/env-expected.nu +++ b/tests/modules/programs/nushell/env-expected.nu @@ -1,17 +1,2 @@ $env.FOO = 'BAR' - -load-env { - "ENV_CONVERSIONS": { - "PATH": { - "from_string": ({|s| $s | split row (char esep) }) - "to_string": ({|v| $v | str join (char esep) }) - } - } - "FOO": "BAR" - "LIST_VALUE": [ - "foo" - "bar" - ] - "PROMPT_COMMAND": ({|| "> "}) -} diff --git a/tests/modules/programs/nushell/example-settings.nix b/tests/modules/programs/nushell/example-settings.nix index e758000bf..9f0108a30 100644 --- a/tests/modules/programs/nushell/example-settings.nix +++ b/tests/modules/programs/nushell/example-settings.nix @@ -5,7 +5,7 @@ enable = true; configFile.text = '' - let $config = { + let config = { filesize_metric: false table_mode: rounded use_ls_colors: true @@ -26,8 +26,16 @@ plugins = [ pkgs.nushellPlugins.formats ]; shellAliases = { - "lsname" = "(ls | get name)"; "ll" = "ls -a"; + "multi word alias" = "cd -"; + "z" = "__zoxide_z"; + }; + + settings = { + show_banner = false; + display_errors.exit_code = false; + hooks.pre_execution = + [ (lib.hm.nushell.mkNushellInline ''{|| "pre_execution hook"}'') ]; }; environmentVariables = {