diff --git a/modules/modules.nix b/modules/modules.nix index 5d40a82fc8f5..75de9730ea02 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -262,6 +262,7 @@ let ./programs/wpaperd.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 b57cc142a56c..1e70316f5ef4 100644 --- a/modules/programs/atuin.nix +++ b/modules/programs/atuin.nix @@ -53,6 +53,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; @@ -139,6 +149,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 c31e2feed539..ae929dae2765 100644 --- a/modules/programs/carapace.nix +++ b/modules/programs/carapace.nix @@ -24,6 +24,10 @@ in { default = true; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; + enableFishIntegration = mkEnableOption "Fish integration" // { default = true; }; @@ -45,6 +49,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 f1a79023525d..a0f78a4f53cd 100644 --- a/modules/programs/command-not-found/command-not-found.nix +++ b/modules/programs/command-not-found/command-not-found.nix @@ -48,6 +48,16 @@ in { config = mkIf cfg.enable { programs.bash.initExtra = shInit "command_not_found_handle"; 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 37899c4a2355..3f892b592ee7 100644 --- a/modules/programs/direnv.nix +++ b/modules/programs/direnv.nix @@ -64,6 +64,14 @@ in { ''; }; + enableXonshIntegration = mkOption { + default = true; + type = types.bool; + description = '' + Whether to enable Xonsh integration. + ''; + }; + enableFishIntegration = mkOption { default = true; type = types.bool; @@ -172,6 +180,27 @@ in { ) ''); + programs.xonsh = mkIf cfg.enableXonshIntegration { + xonshrc = "xontrib load direnv"; + extraPackages = ps: + [ + (ps.buildPythonPackage { + name = "xonsh-direnv"; + src = pkgs.fetchFromGitHub { + owner = "74th"; + repo = "xonsh-direnv"; + rev = "fd086e737a2d54495619a40d2a0f9e96475626e7"; + hash = "sha256-6/V7ZYMOB3E7TO7y8emC5lfdgeYxmfc/yLnEhjrWQ54="; + }; + postPatch = '' + substituteInPlace xontrib/direnv.xsh --replace '$(direnv' '$(${ + getExe cfg.package + }' + ''; + }) + ]; + }; + home.sessionVariables = lib.mkIf cfg.silent { DIRENV_LOG_FORMAT = ""; }; }; } diff --git a/modules/programs/eza.nix b/modules/programs/eza.nix index f35912b8c822..790287404c17 100644 --- a/modules/programs/eza.nix +++ b/modules/programs/eza.nix @@ -37,6 +37,10 @@ with lib; default = true; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; + enableNushellIntegration = mkEnableOption "Nushell integration"; extraOptions = mkOption { @@ -131,6 +135,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 654c43fca61d..4e69a4ab0fbf 100644 --- a/modules/programs/starship.nix +++ b/modules/programs/starship.nix @@ -69,6 +69,10 @@ in { default = true; }; + enableXonshIntegration = mkEnableOption "Xonsh integration" // { + default = true; + }; + enableNushellIntegration = mkEnableOption "Nushell integration" // { default = true; }; @@ -130,6 +134,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 ab56ea0167c3..a5d6f15ba223 100644 --- a/modules/programs/thefuck.nix +++ b/modules/programs/thefuck.nix @@ -80,5 +80,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 000000000000..58e4eb27b09f --- /dev/null +++ b/modules/programs/xonsh.nix @@ -0,0 +1,64 @@ +{ 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 = mkOption { + type = with types; functionTo (listOf package); + default = _: [ ]; + defaultText = "_: []"; + description = '' + List of python packages and xontrib to make avaiable + ''; + }; + }; + 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 9c47345f5000..439b385dfe80 100644 --- a/modules/programs/yazi.nix +++ b/modules/programs/yazi.nix @@ -39,6 +39,21 @@ let rm -fp $tmp } ''; + + xonshIntegration = '' + def __yazi_init(): + def yy(args): + tmp = $(mktemp -t "yazi-cwd.XXXXX").strip() + $[yazi @(args) @(f"--cwd-file={tmp}")] + cwd = fp"{tmp}".read_text() + if cwd != "" and cwd != $PWD: + xonsh.dirstack.cd((cwd,)) + $[rm -f -- @(tmp)] + + aliases['yy'] = yy + __yazi_init() + del __yazi_init + ''; in { meta.maintainers = with maintainers; [ xyenon eljamm ]; @@ -72,6 +87,8 @@ in { default = true; }; + enableXonshIntegration = mkEnableOption "Xonsh integration"; + keymap = mkOption { type = tomlFormat.type; default = { }; @@ -208,6 +225,8 @@ in { programs.nushell.extraConfig = mkIf cfg.enableNushellIntegration nushellIntegration; + programs.xonsh.xonshrc = mkIf cfg.enableXonshIntegration xonshIntegration; + xdg.configFile = { "yazi/keymap.toml" = mkIf (cfg.keymap != { }) { source = tomlFormat.generate "yazi-keymap" cfg.keymap; diff --git a/modules/programs/zoxide.nix b/modules/programs/zoxide.nix index f5e258af9aa3..75027e508632 100644 --- a/modules/programs/zoxide.nix +++ b/modules/programs/zoxide.nix @@ -63,6 +63,14 @@ in { Whether to enable Nushell integration. ''; }; + + enableXonshIntegration = mkOption { + default = true; + type = types.bool; + description = '' + Whether to enable Xonsh integration. + ''; + }; }; config = mkIf cfg.enable { @@ -93,5 +101,9 @@ in { source ${config.xdg.cacheHome}/zoxide/init.nu ''; }; + + programs.xonsh.xonshrc = 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 ec543c84d7b6..1e01e7f80ba3 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 000000000000..313198140fe3 --- /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}' + ''; +}