diff --git a/modules/common/shell/0_nushell.nix b/modules/common/shell/0_nushell.nix index 0226b61..f96211a 100644 --- a/modules/common/shell/0_nushell.nix +++ b/modules/common/shell/0_nushell.nix @@ -1,60 +1,17 @@ { config, lib, pkgs, ... }: let - inherit (lib) attrNames attrValues concatStringsSep const enabled filter filterAttrs flatten foldl' head last listToAttrs mapAttrs mapAttrsToList match nameValuePair readFile replaceStrings splitString; + inherit (lib) attrNames attrValues const enabled filterAttrs mapAttrs readFile replaceStrings; package = pkgs.nushell; in { - shells."0" = package; - home-manager.sharedModules = [(homeArgs: let config' = homeArgs.config; - environmentVariables = let - variablesMap = { - HOME = config'.home.homeDirectory; - USER = config'.home.username; - - XDG_CACHE_HOME = config'.xdg.cacheHome; - XDG_CONFIG_HOME = config'.xdg.configHome; - XDG_DATA_HOME = config'.xdg.dataHome; - XDG_STATE_HOME = config'.xdg.stateHome; - } - |> mapAttrsToList (name: value: [ - { name = "\$${name}"; inherit value; } - { name = "\${${name}}"; inherit value; } - ]) - |> flatten - |> listToAttrs; - - environmentVariables = config.environment.variables; - - homeVariables = config'.home.sessionVariables; - - homeVariablesExtra = pkgs.runCommand "home-variables-extra.env" {} '' - bash -ic ' - ${variablesMap - |> mapAttrsToList (name: value: "export ${name}='${value}'") - |> concatStringsSep "\n"} - - alias export=echo - source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh - ' > $out - '' - |> readFile - |> splitString "\n" - |> filter (s: s != "") - |> map (match "([^=]+)=(.*)") - |> map (keyAndValue: nameValuePair (head keyAndValue) (last keyAndValue)) - |> foldl' (x: y: x // y) {}; - - homeSearchVariables = config'.home.sessionSearchVariables - |> mapAttrs (const <| concatStringsSep ":"); - in environmentVariables - // homeVariables - // homeVariablesExtra - // homeSearchVariables - |> mapAttrs (const <| replaceStrings (attrNames variablesMap) (attrValues variablesMap)) + environmentVariables = config.environment.variables + |> mapAttrs (const <| replaceStrings (attrNames config'.variablesMap) (attrValues config'.variablesMap)) |> filterAttrs (name: const <| name != "TERM"); in { + shells."0" = package; + programs.nushell = enabled { inherit package; diff --git a/modules/common/shell/default.nix b/modules/common/shell/default.nix index a22401e..9f68be9 100644 --- a/modules/common/shell/default.nix +++ b/modules/common/shell/default.nix @@ -1,16 +1,78 @@ -{ config, lib, ... }: let - inherit (lib) attrsToList catAttrs mkConst mkIf mkValue sortOn toInt; +{ config, lib, pkgs, ... }: let + inherit (lib) attrsToList catAttrs concatStringsSep const filter flatten foldl' getAttr getExe head last listToAttrs mapAttrs mapAttrsToList match mkConst mkIf mkValue nameValuePair readFile sortOn splitString toInt unique; in { - options.shells = mkValue {}; + environment.shells = config.home-manager.users + |> mapAttrsToList (const <| getAttr "shellsByPriority") + |> flatten + |> unique; - options.shellsByPriority = mkConst (config.shells - |> attrsToList - |> sortOn ({ name, ... }: toInt name) - |> catAttrs "value"); + home-manager.sharedModules = [ - config = mkIf config.isDarwin { - environment.shells = config.shellsByPriority; - }; + (homeArgs: let + config' = homeArgs.config; + in { + options.shells = mkValue {}; + + options.shellsByPriority = mkConst (config'.shells + |> attrsToList + |> sortOn ({ name, ... }: toInt name) + |> catAttrs "value"); + + options.variablesMap = mkConst ({ + HOME = config'.home.homeDirectory; + USER = config'.home.username; + + XDG_CACHE_HOME = config'.xdg.cacheHome; + XDG_CONFIG_HOME = config'.xdg.configHome; + XDG_DATA_HOME = config'.xdg.dataHome; + XDG_STATE_HOME = config'.xdg.stateHome; + } + |> mapAttrsToList (name: value: [ + { name = "\$${name}"; inherit value; } + { name = "\${${name}}"; inherit value; } + ]) + |> flatten + |> listToAttrs); + }) + + (mkIf config.isDarwin (homeArgs: let + config' = homeArgs.config; + + homeSessionVariables = let + homeSessionVariables = config'.home.sessionVariables; + + homeSessionVariablesExtra = pkgs.runCommand "home-variables-extra.env" {} '' + bash -ic ' + ${config'.variablesMap + |> mapAttrsToList (name: value: "export ${name}='${value}'") + |> concatStringsSep "\n"} + + alias export=echo + source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh + ' > $out + '' + |> readFile + |> splitString "\n" + |> filter (s: s != "") + |> map (match "([^=]+)=(.*)") + |> map (keyAndValue: nameValuePair (head keyAndValue) (last keyAndValue)) + |> foldl' (x: y: x // y) {}; + + homeSessionSearchVariables = config'.home.sessionSearchVariables + |> mapAttrs (const <| concatStringsSep ":"); + in homeSessionVariables + // homeSessionVariablesExtra + // homeSessionSearchVariables; + in { + home.file.".zshrc".text = mkIf config.isDarwin /* zsh */ '' + ${homeSessionVariables + |> mapAttrsToList (name: value: "export ${name}='${value}'") + |> concatStringsSep "\n"} + SHELL='${getExe <| head config'.shellsByPriority}' exec "$SHELL" + ''; + })) + + ]; # More at modules/linux/shell/default.nix. # diff --git a/modules/common/shell/shadow-xcode.nix b/modules/common/shell/shadow-xcode.nix new file mode 100644 index 0000000..e66f932 --- /dev/null +++ b/modules/common/shell/shadow-xcode.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, ... }: let + inherit (lib) getExe mkAfter mkIf; +in { + home-manager.sharedModules = mkIf config.isDarwin [(homeArgs: let + config' = homeArgs.config; + lib' = homeArgs.lib; + + inherit (lib'.hm.dag) entryAfter; + + # Replace with the command that has been triggering + # the "install developer tools" popup. + # + # Set by default to "SplitForks" because who even uses that? + originalTrigger = "/usr/bin/SplitForks"; + originalTriggerLiteral = ''"${originalTrigger}"''; + + # Where the symbolic links to `/usr/bin/false` will + # be created in to shadow all popup-triggering binaries. + # + # Place this in your $env.PATH right before /usr/bin + # to never get the "install developer tools" popup ever again: + # + # ```nu + # let usr_bin_index = $env.PATH + # | enumerate + # | where item == /usr/bin + # | get 0.index + # + # $env.PATH = $env.PATH | insert $usr_bin_index $shadow_path + # ``` + # + # Do NOT set this to a path that you use for other things, + # it will get deleted if it exists to only have the shadowers. + shadowPath = "${config'.home.homeDirectory}/.local/shadow"; # Did you read the comment? + shadowPathLiteral = ''"${shadowPath}"''; + in { + home.activation.shadow = entryAfter [ "installPackages" "linkGeneration" ] /* bash */ '' + ${getExe pkgs.nushell} ${pkgs.writeScript "shadow-xcode.nu" '' + use std null_device + + let original_size = ls ${originalTriggerLiteral} | get 0.size + + let shadoweds = ls /usr/bin + | flatten + | where { + # All xcode-select binaries are the same size, so we can narrow down and not run weird stuff. + $in.size == $original_size and (try { + open $null_device | ^$in.name out+err>| str contains "xcode-select: note: No developer tools were found, requesting install." + } catch { + # If it exited with a nonzero code, it's probably already set up. + false + }) + } + | get name + | each { path basename } + + rm -rf ${shadowPathLiteral} + mkdir ${shadowPathLiteral} + + for shadowed in $shadoweds { + ln --symbolic /usr/bin/false (${shadowPathLiteral} | path join $shadowed) + } + ''} + ''; + + programs.nushell.configFile.text = mkAfter /* nu */ '' + do --env { + let usr_bin_index = $env.PATH + | enumerate + | where item == /usr/bin + | get 0.index; + + $env.PATH = $env.PATH + | insert $usr_bin_index ${shadowPathLiteral}; + } + ''; + })]; +} diff --git a/modules/linux/shell/default.nix b/modules/linux/shell/default.nix index dff21fa..56eed90 100644 --- a/modules/linux/shell/default.nix +++ b/modules/linux/shell/default.nix @@ -1,9 +1,15 @@ { config, lib, pkgs, ... }: let - inherit (lib) concatStringsSep; + inherit (lib) concatStringsSep const flatten getAttr mapAttrsToList unique; in { users.defaultUserShell = pkgs.crash; - environment.sessionVariables.SHELLS = config.shellsByPriority - |> map (drv: "${drv}${drv.shellPath}") - |> concatStringsSep ":"; + # TODO: This should be a per-user session variable. But we can't set + # a home-manager session variable because that's initialized by the + # shell itself! Lol. + environment.sessionVariables.SHELLS = config.home-manager.users + |> mapAttrsToList (const <| getAttr "shellsByPriority") + |> flatten + |> map (drv: "${drv}${drv.shellPath}") + |> unique + |> concatStringsSep ":"; } diff --git a/rebuild.nu b/rebuild.nu index 1578e88..deda31e 100755 --- a/rebuild.nu +++ b/rebuild.nu @@ -57,77 +57,7 @@ def main --wrapped [ if (uname | get kernel-name) == "Darwin" { NH_BYPASS_ROOT_CHECK=true NH_NO_CHECKS=true nh darwin switch . ...$nh_flags -- ...$nix_flags - - if not (xcode-select --install e>| str contains "Command line tools are already installed") { - darwin-shadow-xcode-popup - } - - darwin-set-zshrc } else { NH_BYPASS_ROOT_CHECK=true NH_NO_CHECKS=true nh os switch . ...$nh_flags -- ...$nix_flags } } - -# Replace with the command that has been triggering -# the "install developer tools" popup. -# -# Set by default to "SplitForks" because who even uses that? -const original_trigger = "/usr/bin/SplitForks" - -# Where the symbolic links to `/usr/bin/false` will -# be created in to shadow all popup-triggering binaries. -# -# Place this in your $env.PATH right before /usr/bin -# to never get the "install developer tools" popup ever again: -# -# ```nu -# let usr_bin_index = $env.PATH -# | enumerate -# | where item == /usr/bin -# | get 0.index -# -# $env.PATH = $env.PATH | insert $usr_bin_index $shadow_path -# ``` -# -# Do NOT set this to a path that you use for other things, -# it will get deleted if it exists to only have the shadowers. -const shadow_path = "~/.local/shadow" | path expand # Did you read the comment? - -def darwin-shadow-xcode-popup [] { - print "shadowing xcode popup binaries..." - - let original_size = ls $original_trigger | get 0.size - - let shadoweds = ls /usr/bin - | flatten - | where { - # All xcode-select binaries are the same size, so we can narrow down and not run weird stuff. - $in.size == $original_size - } - | where { - ^$in.name e>| str contains "xcode-select: note: No developer tools were found, requesting install." - } - | get name - | each { path basename } - - rm -rf $shadow_path - mkdir $shadow_path - - for shadowed in $shadoweds { - let shadow_path = $shadow_path | path join $shadowed - - ln --symbolic /usr/bin/false $shadow_path - } -} - -def darwin-set-zshrc [] { - print "setting zshrc..." - - let nu_command = $"let usr_bin_index = $env.PATH | enumerate | where item == /usr/bin | get 0.index; -$env.PATH = $env.PATH | insert $usr_bin_index ($shadow_path | path expand); -$env.SHELL = which nu | get 0.path" | str replace --all "\n" "" - - let zshrc = $"exec nu --execute '($nu_command)'" - - $zshrc | save --force ~/.zshrc -}