diff --git a/modules/common/shell/0_nushell.nu b/modules/common/shell/0_nushell.nu index 755e37f..6c333fb 100644 --- a/modules/common/shell/0_nushell.nu +++ b/modules/common/shell/0_nushell.nu @@ -18,8 +18,6 @@ $env.config.cursor_shape.emacs = "line" $env.config.cursor_shape.vi_insert = "line" $env.config.cursor_shape.vi_normal = "block" -$env.CARAPACE_BRIDGES = "inshellisense,carapace,zsh,fish,bash" - $env.config.completions.algorithm = "substring" $env.config.completions.sort = "smart" $env.config.completions.case_sensitive = false diff --git a/modules/common/shell/carapace.nix b/modules/common/shell/carapace.nix index 6167138..b12a714 100644 --- a/modules/common/shell/carapace.nix +++ b/modules/common/shell/carapace.nix @@ -1,12 +1,31 @@ -{ pkgs, ... }: { +{ lib, pkgs, ... }: +let + inherit (lib) getExe; +in +{ environment.systemPackages = [ pkgs.carapace pkgs.fish pkgs.zsh + pkgs.bash pkgs.inshellisense ]; + environment.variables.CARAPACE_BRIDGES = "inshellisense,carapace,zsh,fish,bash"; + home-manager.sharedModules = [{ - programs.carapace.enable = true; + programs.carapace = { + enable = true; + enableNushellIntegration = false; + enableZshIntegration = false; + }; + + programs.nushell.extraConfig = /* nu */ '' + source ${ + pkgs.runCommand "carapace.nu" { } '' + ${getExe pkgs.carapace} _carapace nushell > $out + '' + } + ''; }]; } diff --git a/modules/common/shell/default.nix b/modules/common/shell/default.nix index 86f5cf2..80bd437 100644 --- a/modules/common/shell/default.nix +++ b/modules/common/shell/default.nix @@ -10,7 +10,9 @@ let const flatten getAttr + getExe mapAttrsToList + mkBefore mkOption sortOn toInt @@ -67,6 +69,113 @@ in homeArgs: let config' = homeArgs.config; + nuExe = getExe (lib.head config'.shellsByPriority); + fishPromptBody = '' + set -l last_status $status + + set -l pwd_display (prompt_pwd) + set -l workspace_root + set -l workspace_subpath + + if command -sq jj + set workspace_root (jj workspace root ^/dev/null) + if test $status -eq 0 -a -n "$workspace_root" + set workspace_subpath (path relative -- $PWD $workspace_root) + end + end + + set -l path_segment + if test -n "$workspace_root" + set -l workspace_name (basename "$workspace_root") + if test -n "$workspace_subpath" -a "$workspace_subpath" != "." + set path_segment (set_color bryellow)$workspace_name(set_color magenta)' → '(set_color blue)$workspace_subpath + else + set path_segment (set_color bryellow)$workspace_name + end + else + set path_segment (set_color cyan)$pwd_display + end + + set -l prefix + if test $last_status -ne 0 + set prefix (set_color brred)$last_status(set_color yellow)'┣' + end + + set -l duration_segment + if set -q CMD_DURATION; and test "$CMD_DURATION" -gt 2000 + set duration_segment (set_color brmagenta)(math --scale 2 "$CMD_DURATION / 1000")s + end + + set -l left_prefix (set_color bryellow)'┏' + if test -n "$prefix" + set left_prefix "$left_prefix$prefix" + end + if test -n "$duration_segment" + set left_prefix "$left_prefix"(set_color bryellow)'┣'"$duration_segment" + end + set left_prefix "$left_prefix"(set_color bryellow)'━'(set_color normal) + + set -l suffix_parts + if set -q IN_NIX_SHELL; and test -n "$IN_NIX_SHELL" + set suffix_parts $suffix_parts (set_color brblue)'nix'(set_color normal) + end + if set -q VIRTUAL_ENV_PROMPT; and test -n "$VIRTUAL_ENV_PROMPT" + set suffix_parts $suffix_parts (set_color brgreen)$VIRTUAL_ENV_PROMPT(set_color normal) + end + + set -l suffix "" + if test (count $suffix_parts) -gt 0 + set suffix ' ' + for item in $suffix_parts + set suffix "$suffix"(set_color bryellow)'• '(set_color normal)"$item " + end + set suffix (string trim --right -- $suffix) + end + + echo + echo -n "$left_prefix$path_segment$suffix" + echo + echo -n (set_color bryellow)'┃'(set_color normal)' ' + ''; + fishRightPromptBody = '' + set -l parts + + if command -sq jj + set -l jj_status (jj --quiet --color always --ignore-working-copy log --no-graph --revisions @ --template ' + separate( + " ", + if(empty, label("empty", "(empty)")), + coalesce( + surround( + "\"", + "\"", + if( + description.first_line().substr(0, 24).starts_with(description.first_line()), + description.first_line().substr(0, 24), + description.first_line().substr(0, 23) ++ "…" + ) + ), + label(if(empty, "empty"), description_placeholder) + ), + bookmarks.join(", "), + change_id.shortest(), + commit_id.shortest(), + if(conflict, label("conflict", "(conflict)")), + ) + ' ^/dev/null) + if test $status -eq 0 -a -n "$jj_status" + set parts $parts $jj_status + end + end + + if set -q SSH_CONNECTION; and test -n "$SSH_CONNECTION" + set parts $parts (set_color brgreen)'@'(prompt_hostname)(set_color normal) + end + + if test (count $parts) -gt 0 + echo -n (string join ' ' $parts) + end + ''; nuExecCondition = if config.isDarwin then '' @@ -76,19 +185,45 @@ in ''[ -z "$INTELLIJ_ENVIRONMENT_READER" ] && [ -z "$skip" ] && [ -z "$SSH_TTY" ]''; in { - home.file.".zshrc".text = # zsh + programs.fish = { + enable = true; + + interactiveShellInit = '' + set -g fish_greeting + set -g fish_key_bindings fish_vi_key_bindings + set -g fish_cursor_default block + set -g fish_cursor_insert line + set -g fish_cursor_replace_one underscore + set -g fish_cursor_visual block + set -g fish_cursor_external line + ''; + + shellInitLast = '' + if set -q GHOSTTY_RESOURCES_DIR + source "$GHOSTTY_RESOURCES_DIR/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish" 2>/dev/null + end + ''; + + functions = { + fish_prompt.body = fishPromptBody; + fish_right_prompt.body = fishRightPromptBody; + }; + }; + + programs.zsh.initContent = mkBefore # zsh '' export PATH="$HOME/.local/bin:/run/wrappers/bin:/run/current-system/sw/bin:/nix/var/nix/profiles/default/bin:/etc/profiles/per-user/$USER/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin''${PATH:+:}''${PATH}" source ${config'.home.sessionVariablesPackage}/etc/profile.d/hm-session-vars.sh - if ${nuExecCondition}; then - parent_cmd="$(ps -o command= -p "$PPID" 2>/dev/null || true)" - case "$parent_cmd" in - *"/Applications/Zed.app/Contents/MacOS/zed --printenv"*) return ;; - esac - SHELL='${lib.getExe <| lib.head config'.shellsByPriority}' exec "$SHELL" - fi - ''; + if ${nuExecCondition}; then + parent_cmd="$(ps -o command= -p "$PPID" 2>/dev/null || true)" + case "$parent_cmd" in + *"/Applications/Zed.app/Contents/MacOS/zed --printenv"*) return ;; + esac + export SHELL='${nuExe}' + exec "$SHELL" + fi + ''; } ) ]; diff --git a/modules/common/shell/direnv.nix b/modules/common/shell/direnv.nix index 7df82ca..329a641 100644 --- a/modules/common/shell/direnv.nix +++ b/modules/common/shell/direnv.nix @@ -1,44 +1,14 @@ -{ lib, ... }: { +{ ... }: { home-manager.sharedModules = [ - (homeArgs: let - direnv = lib.getExe homeArgs.config.programs.direnv.package; - in { + { programs.direnv = { enable = true; nix-direnv.enable = true; - enableNushellIntegration = false; + enableZshIntegration = false; }; - - programs.nushell.extraConfig = lib.mkAfter /* nu */ '' - $env.config = ($env.config? | default {}) - $env.config.hooks = ($env.config.hooks? | default {}) - $env.config.hooks.pre_prompt = ( - $env.config.hooks.pre_prompt? - | default [] - | append {|| - ${direnv} export json - | from json --strict - | default {} - | items {|key, value| - let value = do ( - { - "PATH": { - from_string: {|s| $s | split row (char esep) | path expand --no-symlink } - to_string: {|v| $v | path expand --no-symlink | str join (char esep) } - } - } - | merge ($env.ENV_CONVERSIONS? | default {}) - | get -o $key - | get -o from_string - | if ($in | is-empty) { {|x| $x} } else { $in } - ) $value - return [ $key $value ] - } - | into record - | load-env - } - ) - ''; - }) + programs.nushell = { + enable = true; + }; + } ]; } diff --git a/modules/common/shell/zoxide.nix b/modules/common/shell/zoxide.nix index 3e193af..9d543f1 100644 --- a/modules/common/shell/zoxide.nix +++ b/modules/common/shell/zoxide.nix @@ -1,54 +1,13 @@ { lib, pkgs, ... }: -let - inherit (lib) getExe; - zoxide = getExe pkgs.zoxide; -in { home-manager.sharedModules = [ { programs.zoxide = { enable = true; options = [ "--cmd cd" ]; - enableNushellIntegration = false; + enableNushellIntegration = true; + enableZshIntegration = false; }; - - programs.nushell.extraConfig = # nu - '' - # Zoxide integration with full path - $env.config = ($env.config? | default {}) - $env.config.hooks = ($env.config.hooks? | default {}) - $env.config.hooks.env_change = ($env.config.hooks.env_change? | default {}) - $env.config.hooks.env_change.PWD = ($env.config.hooks.env_change.PWD? | default []) - - let __zoxide_hooked = ($env.config.hooks.env_change.PWD | any { try { get __zoxide_hook } catch { false } }) - if not $__zoxide_hooked { - $env.config.hooks.env_change.PWD = ($env.config.hooks.env_change.PWD | append { - __zoxide_hook: true, - code: {|_, dir| ${zoxide} add -- $dir} - }) - } - - def --env __zoxide_z [...rest: string] { - let path = if ($rest | length) == 0 { - $env.HOME - } else if ($rest | length) == 1 and ($rest.0 == "-") { - $env.OLDPWD - } else if ($rest | length) == 1 and (($rest.0 | path expand) | path exists) { - $rest.0 - } else { - ${zoxide} query --exclude (pwd) -- ...$rest | str trim -r -c (char newline) - } - cd $path - } - - def --env __zoxide_zi [...rest: string] { - let path = ${zoxide} query --interactive -- ...$rest | str trim -r -c (char newline) - cd $path - } - - alias cd = __zoxide_z - alias cdi = __zoxide_zi - ''; } ]; }