diff --git a/modules/modules.nix b/modules/modules.nix index bf2795b8a..8049f2cdc 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -284,6 +284,7 @@ let ./programs/wofi.nix ./programs/xmobar.nix ./programs/xplr.nix + ./programs/xonsh.nix ./programs/yambar.nix ./programs/yazi.nix ./programs/yt-dlp.nix diff --git a/modules/programs/atuin.nix b/modules/programs/atuin.nix index ccb4347fa..0e2be233f 100644 --- a/modules/programs/atuin.nix +++ b/modules/programs/atuin.nix @@ -46,6 +46,16 @@ in { ''; }; + enableXonshIntegration = mkOption { + default = true; + type = types.bool; + description = '' + Whether to enable Atuin's Xonsh integration. + + If enabled, this will bind the up-arrow key to open the Atuin history. + ''; + }; + flags = mkOption { default = [ ]; type = types.listOf types.str; @@ -124,6 +134,10 @@ in { ${lib.getExe cfg.package} init fish ${flagsStr} | source ''; + programs.xonsh.xonshrc = mkIf cfg.enableXonshIntegration '' + execx($(${cfg.package}/bin/atuin init xonsh)) + ''; + programs.nushell = mkIf cfg.enableNushellIntegration { extraEnv = '' let atuin_cache = "${config.xdg.cacheHome}/atuin" diff --git a/modules/programs/carapace.nix b/modules/programs/carapace.nix index d07cb6bd0..f70d40bc5 100644 --- a/modules/programs/carapace.nix +++ b/modules/programs/carapace.nix @@ -25,6 +25,10 @@ in { enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; + enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; }; @@ -41,6 +45,10 @@ in { source <(${bin} _carapace zsh) ''; + xonsh.xonshrc = mkIf cfg.enableXonshIntegration '' + exec($(${bin} _carapace)) + ''; + fish.interactiveShellInit = mkIf cfg.enableFishIntegration '' ${bin} _carapace fish | source ''; diff --git a/modules/programs/command-not-found/command-not-found.nix b/modules/programs/command-not-found/command-not-found.nix index c539e6e2e..a0f78a4f5 100644 --- a/modules/programs/command-not-found/command-not-found.nix +++ b/modules/programs/command-not-found/command-not-found.nix @@ -47,7 +47,17 @@ in { config = mkIf cfg.enable { programs.bash.initExtra = shInit "command_not_found_handle"; - programs.zsh.initContent = shInit "command_not_found_handler"; + programs.zsh.initExtra = shInit "command_not_found_handler"; + programs.xonsh.xonshrc = '' + @events.on_command_not_found + def _command_not_found_nix(cmd): + import os.path + if os.path.isfile(${builtins.toJSON cfg.dbPath}): + ${commandNotFound}/bin/command-not-found @(cmd) + else: + echo "$1: command not found" >&2 + return 127 + ''; home.packages = [ commandNotFound ]; }; diff --git a/modules/programs/direnv.nix b/modules/programs/direnv.nix index c588c6b14..e75ced800 100644 --- a/modules/programs/direnv.nix +++ b/modules/programs/direnv.nix @@ -57,7 +57,6 @@ in { Note, enabling the direnv module will always activate its functionality for Fish since the direnv package automatically gets loaded in Fish. If this is not the case try adding - ```nix environment.pathsToLink = [ "/share/fish" ]; ``` @@ -69,6 +68,14 @@ in { readOnly = true; }; + enableXonshIntegration = mkOption { + default = true; + type = types.bool; + description = '' + Whether to enable Xonsh integration. + ''; + }; + enableNushellIntegration = lib.hm.shell.mkNushellIntegrationOption { inherit config; }; @@ -160,6 +167,11 @@ in { ) ''); + programs.xonsh = mkIf cfg.enableXonshIntegration { + xonshrc = "xontrib load direnv"; + extraPackages = ps: [ pkgs.xonsh.xontribs.xonsh-direnv ]; + }; + home.sessionVariables = lib.mkIf cfg.silent { DIRENV_LOG_FORMAT = ""; }; }; } diff --git a/modules/programs/eza.nix b/modules/programs/eza.nix index 14547d730..d51f1de96 100644 --- a/modules/programs/eza.nix +++ b/modules/programs/eza.nix @@ -35,6 +35,9 @@ with lib; enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; extraOptions = mkOption { type = types.listOf types.str; @@ -128,6 +131,18 @@ with lib; programs.ion.shellAliases = optionsAlias // optionalAttrs cfg.enableIonIntegration aliases; + programs.xonsh.shellAliases = { + eza = [ "eza" ] ++ optional cfg.icons "--icons" + ++ optional cfg.git "--git" ++ cfg.extraOptions; + } // optionalAttrs cfg.enableXonshIntegration + (builtins.mapAttrs (_name: value: lib.mkDefault value) { + ls = [ "eza" ]; + ll = [ "eza" "-l" ]; + la = [ "eza" "-a" ]; + lt = [ "eza" "--tree" ]; + lla = [ "eza" "-la" ]; + }); + programs.nushell.shellAliases = optionsAlias // optionalAttrs cfg.enableNushellIntegration aliases; }; diff --git a/modules/programs/starship.nix b/modules/programs/starship.nix index c3b2a61ae..1874b0ef7 100644 --- a/modules/programs/starship.nix +++ b/modules/programs/starship.nix @@ -68,6 +68,10 @@ in { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; + enableInteractive = mkOption { type = types.bool; default = true; @@ -125,6 +129,11 @@ in { end ''; + programs.xonsh.xonshrc = mkIf cfg.enableXonshIntegration '' + if $TERM != "dumb": + execx($(${starshipCmd} init xonsh)) + ''; + programs.nushell = mkIf cfg.enableNushellIntegration { # Unfortunately nushell doesn't allow conditionally sourcing nor # conditionally setting (global) environment variables, which is why the diff --git a/modules/programs/thefuck.nix b/modules/programs/thefuck.nix index 2561bf5f5..ac1eb6348 100644 --- a/modules/programs/thefuck.nix +++ b/modules/programs/thefuck.nix @@ -64,5 +64,9 @@ with lib; alias fuck = ${cfg.package}/bin/thefuck $"(history | last 1 | get command | get 0)" ''; }; + + programs.xonsh.xonshrc = '' + aliases["fuck"] = lambda args, stdin=None: execx($(${cfg.package}/bin/thefuck @(__xonsh__.history[-1].cmd))) + ''; }; } diff --git a/modules/programs/xonsh.nix b/modules/programs/xonsh.nix new file mode 100644 index 000000000..e7fe9a6a2 --- /dev/null +++ b/modules/programs/xonsh.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.programs.xonsh; + inherit (lib) types mkOption; +in { + options.programs.xonsh = { + enable = lib.mkEnableOption "xonsh"; + + package = lib.mkPackageOption pkgs "xonsh" { }; + finalPackage = lib.mkOption { + type = types.package; + internal = true; + description = "Package that will actually get installed"; + }; + xonshrc = mkOption { + type = types.lines; + default = ""; + description = '' + The contents of .xonshrc + ''; + }; + pythonPackages = mkOption { + type = types.raw; + default = pkgs.pythonPackages; + defaultText = "pkgs.pythonPackages"; + description = '' + The pythonPackages set extraPackages are taken from + ''; + }; + shellAliases = mkOption { + type = with types; attrsOf (listOf str); + default = { }; + example = { ll = [ "ls" "-l" ]; }; + description = '' + An attribute set that maps aliases (the top level attribute names in + this option) to commands + ''; + }; + extraPackages = lib.mkOption { + default = (ps: [ ]); + type = with lib.types; + coercedTo (listOf lib.types.package) (v: (_: v)) + (functionTo (listOf lib.types.package)); + description = '' + Add the specified extra packages to the xonsh package. + Preferred over using `programs.xonsh.package` as it composes with `pkgs.xonsh.xontribs`. + Take care in using this option along with manually defining the package + option above, as the two can result in conflicting sets of build dependencies. + This option assumes that the package option has an overridable argument + called `extraPackages`, so if you override the package option but also + intend to use this option as in the case of many enableXonshIntegration options, + be sure that your resulting package still honors the necessary option. + ''; + }; + }; + config = lib.mkIf cfg.enable { + home.packages = [ cfg.finalPackage ]; + programs.xonsh = { + xonshrc = lib.mkMerge + (lib.mapAttrsToList (n: v: "aliases['${n}']=${builtins.toJSON v}") + cfg.shellAliases); + shellAliases = lib.mapAttrs (n: v: lib.mkDefault (lib.splitString " " v)) + config.home.shellAliases; + finalPackage = + (cfg.package.override (old: { inherit (cfg) extraPackages; })); + }; + xdg.configFile."xonsh/rc.xsh" = { + enable = cfg.xonshrc != ""; + text = cfg.xonshrc; + }; + }; +} diff --git a/modules/programs/yazi.nix b/modules/programs/yazi.nix index 59d734d34..b8259597f 100644 --- a/modules/programs/yazi.nix +++ b/modules/programs/yazi.nix @@ -6,6 +6,7 @@ let cfg = config.programs.yazi; tomlFormat = pkgs.formats.toml { }; + in { meta.maintainers = with lib.maintainers; [ eljamm khaneliman xyenon ]; @@ -35,6 +36,8 @@ in { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + enableXonshIntegration = mkEnableOption "Xonsh integration"; + keymap = mkOption { type = tomlFormat.type; default = { }; @@ -193,6 +196,20 @@ in { rm -fp $tmp } ''; + + xonshIntegration = '' + def _y(args): + tmp = $(mktemp -t "yazi-cwd.XXXXXX") + args.append(f"--cwd-file={tmp}") + $[yazi @(args)] + with open(tmp) as f: + cwd = f.read().strip() + if cwd != $PWD: + cd @(cwd) + rm -f -- @(tmp) + + aliases["${cfg.shellWrapperName}"] = _y + ''; in { bash.initExtra = mkIf cfg.enableBashIntegration bashIntegration; @@ -203,6 +220,8 @@ in { nushell.extraConfig = mkIf cfg.enableNushellIntegration nushellIntegration; + + xonsh.xonshrc = lib.mkIf cfg.enableXonshIntegration xonshIntegration; }; xdg.configFile = { diff --git a/modules/programs/zoxide.nix b/modules/programs/zoxide.nix index 66c911b0b..996d632d8 100644 --- a/modules/programs/zoxide.nix +++ b/modules/programs/zoxide.nix @@ -31,6 +31,14 @@ in { enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; }; + + enableXonshIntegration = lib.mkOption { + default = true; + type = lib.types.bool; + description = '' + Whether to enable Xonsh integration. + ''; + }; }; config = lib.mkIf cfg.enable { @@ -63,5 +71,9 @@ in { source ${config.xdg.cacheHome}/zoxide/init.nu ''; }; + + programs.xonsh.xonshrc = lib.mkIf cfg.enableXonshIntegration '' + execx($(${cfg.package}/bin/zoxide init xonsh), 'exec', __xonsh__.ctx, filename='zoxide') + ''; }; } diff --git a/tests/modules/programs/yazi/default.nix b/tests/modules/programs/yazi/default.nix index ec543c84d..1e01e7f80 100644 --- a/tests/modules/programs/yazi/default.nix +++ b/tests/modules/programs/yazi/default.nix @@ -5,4 +5,5 @@ yazi-zsh-integration-enabled = ./zsh-integration-enabled.nix; yazi-fish-integration-enabled = ./fish-integration-enabled.nix; yazi-nushell-integration-enabled = ./nushell-integration-enabled.nix; + yazi-xonsh-integration-enabled = ./xonsh-integration-enabled.nix; } diff --git a/tests/modules/programs/yazi/xonsh-integration-enabled.nix b/tests/modules/programs/yazi/xonsh-integration-enabled.nix new file mode 100644 index 000000000..313198140 --- /dev/null +++ b/tests/modules/programs/yazi/xonsh-integration-enabled.nix @@ -0,0 +1,31 @@ +{ ... }: + +let + shellIntegration = '' + def __yazi_init(): + def ya(args): + tmp = $(mktemp -t "yazi-cwd.XXXXX") + $[yazi @(args) @(f"--cwd-file={tmp}")] + cwd = fp"{tmp}".read_text() + if cwd != "" and cwd != $PWD: + xonsh.dirstack.cd(cwd) + $[rm -f -- @(tmp)] + + aliases['ya'] = ya + __yazi_init() + del __yazi_init + ''; +in { + programs.xonsh.enable = true; + + programs.yazi = { + enable = true; + enableXonshIntegration = true; + }; + + test.stubs.yazi = { }; + + nmt.script = '' + assertFileContains home-files/.config/xonsh/rc.xsh '${shellIntegration}' + ''; +}