From a938343f87c82475980ae2c9dcf9a128442c2c9c Mon Sep 17 00:00:00 2001 From: voidarc Date: Tue, 28 Jul 2026 19:21:28 +0100 Subject: [PATCH] devenv support (zsh feature) --- modules/features/zsh/default.nix | 26 ++++++---- modules/features/zsh/devenv.zsh | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 modules/features/zsh/devenv.zsh diff --git a/modules/features/zsh/default.nix b/modules/features/zsh/default.nix index 83799c6..3360706 100644 --- a/modules/features/zsh/default.nix +++ b/modules/features/zsh/default.nix @@ -36,26 +36,27 @@ assert flakeLocation != ""; inputs.wrappers.wrappers.zsh.wrap { inherit pkgs; - runtimePkgs = [pkgs.carapace pkgs.fzf]; + runtimePkgs = [pkgs.carapace pkgs.devenv pkgs.fzf]; zshAliases = { ls = "${lib.getExe pkgs.lsd} -l"; v = lib.getExe self'.packages.nvim; cat = lib.getExe pkgs.bat; lg = lib.getExe pkgs.lazygit; - devenv = lib.getExe pkgs.devenv; - carapace = lib.getExe pkgs.carapace; man = "man -P \"${lib.getExe pkgs.bat} -p\""; nsh = "nix-shell -p"; nrs = "( cd ${flakeLocation} && sudo nixos-rebuild switch --impure --flake . )"; - vinix = "nvim --cmd 'cd ${flakeLocation}'"; + vinix = "nvim --cmd 'cd ${flakeLocation}'"; }; zshrc.content = '' - if (( ''${+terminfo[smkx]} )) && (( ''${+terminfo[rmkx]} )); then - function zle-line-init() { echoti smkx } + source ${./devenv.zsh} + + if (( ''${+terminfo[smkx]} )) && (( ''${+terminfo[rmkx]} )); then + function zle-line-init() { echoti smkx } function zle-line-finish() { echoti rmkx } zle -N zle-line-init zle -N zle-line-finish fi + autoload -U compinit && compinit export CARAPACE_BRIDGES='zsh,fish,bash,inshellisense' # optional zstyle ':completion:*' format $'\e[2;37mCompleting %d\e[m' @@ -80,12 +81,21 @@ setopt NO_CASE_GLOB + ${lib.getExe pkgs.any-nix-shell} zsh --info-right | source /dev/stdin + export EDITOR=nvim - eval "$(${lib.getExe pkgs.devenv} hook zsh)" eval "$(${lib.getExe self'.packages.ohMyPosh} init zsh)" - ${lib.getExe pkgs.any-nix-shell} zsh --info-right | source /dev/stdin + eval "$(${lib.getExe pkgs.devenv} hook zsh)" + + typeset -ag precmd_functions + if (( ! ''${precmd_functions[(I)__devenv_reload_apply]} )); then + precmd_functions+=(__devenv_reload_apply) + fi + if (( ! ''${precmd_functions[(I)__devenv_restore_path]} )); then + precmd_functions+=(__devenv_restore_path) + fi ''; }; ohMyPosh = inputs.wrappers.wrappers.oh-my-posh.wrap { diff --git a/modules/features/zsh/devenv.zsh b/modules/features/zsh/devenv.zsh new file mode 100644 index 0000000..a2e6484 --- /dev/null +++ b/modules/features/zsh/devenv.zsh @@ -0,0 +1,82 @@ +__devenv_reload_apply() { + if [ -n "$DEVENV_RELOAD_FILE" ] && [ -f "$DEVENV_RELOAD_FILE" ]; then + local output + output=$(DEVENV_RELOAD_FILE="$DEVENV_RELOAD_FILE" bash <<'RELOAD_BASH' 2>/dev/null +__devenv_ignored_var() { + case "$1" in + _*|PWD|OLDPWD|SHLVL|SHELL|SHELLOPTS|BASHOPTS|BASH_*|HISTCMD|HISTFILE) + return 0 ;; + PS1|PS2|PS3|PS4|PROMPT|PROMPT_COMMAND|PROMPT_DIRTRIM) + return 0 ;; + COMP_*|READLINE_*|MAILCHECK|COLUMNS|LINES|RANDOM|SECONDS|LINENO|EPOCHSECONDS|EPOCHREALTIME|SRANDOM) + return 0 ;; + STARSHIP_*|__fish*|DIRENV_*|nix_saved_*) + return 0 ;; + *) return 1 ;; + esac +} +__devenv_capture_env() { declare -p -x 2>/dev/null | LC_ALL=C sort; } +__devenv_serialize_diff() { gzip -c | base64 -w0; } +__devenv_deserialize_diff() { echo "$1" | base64 -d | gzip -d 2>/dev/null; } +__devenv_compute_diff() { + local before_file="$1" after_file diff_content + after_file=$(mktemp); diff_content=$(mktemp) + __devenv_capture_env > "$after_file" + local -A before_vars after_vars + while IFS= read -r line; do + [[ "$line" != declare\ -x\ * ]] && continue + local vardef="${line#declare -x }" var="${vardef%%=*}" + [[ -z "$var" ]] && continue + __devenv_ignored_var "$var" && continue + before_vars["$var"]="$line" + done < "$before_file" + while IFS= read -r line; do + [[ "$line" != declare\ -x\ * ]] && continue + local vardef="${line#declare -x }" var="${vardef%%=*}" + [[ -z "$var" ]] && continue + __devenv_ignored_var "$var" && continue + after_vars["$var"]="$line" + done < "$after_file" + for var in "${!before_vars[@]}"; do + [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]] && echo "P:${before_vars[$var]}" >> "$diff_content" + done + for var in "${!after_vars[@]}"; do + if [[ -z "${before_vars[$var]+x}" ]]; then echo "N:$var" >> "$diff_content" + elif [[ "${after_vars[$var]}" != "${before_vars[$var]}" ]]; then echo "N:$var" >> "$diff_content"; fi + done + _DEVENV_DIFF=$(__devenv_serialize_diff < "$diff_content"); export _DEVENV_DIFF + rm -f "$after_file" "$diff_content" +} +__devenv_apply_reverse_diff() { + [[ -z "$_DEVENV_DIFF" ]] && return + local -A prev_vars + local diff_content; diff_content=$(__devenv_deserialize_diff "$_DEVENV_DIFF") + while IFS= read -r line; do + if [[ "$line" == P:declare\ * ]]; then + local decl="${line#P:}" var="${decl#declare -x }"; var="${var%%=*}" + prev_vars["$var"]=1; eval "export ${decl#declare -x }" 2>/dev/null + fi + done <<< "$diff_content" + while IFS= read -r line; do + if [[ "$line" == N:* ]]; then + local var="${line#N:}" + [[ -z "${prev_vars[$var]+x}" ]] && unset "$var" + fi + done <<< "$diff_content" +} +__devenv_apply_reverse_diff +_before=$(mktemp); __devenv_capture_env > "$_before" +if { : >/dev/tty; } 2>/dev/null; then _devenv_reload_out=/dev/tty; else _devenv_reload_out=/dev/null; fi +source "$DEVENV_RELOAD_FILE" >"$_devenv_reload_out" 2>"$_devenv_reload_out" +rm -f "$DEVENV_RELOAD_FILE"; unset _devenv_reload_out +__devenv_compute_diff "$_before"; rm -f "$_before" +export -p +RELOAD_BASH +) + if [ -n "$output" ]; then eval "$output"; fi + _DEVENV_PATH="$PATH" + fi +} +__devenv_restore_path() { + [ -n "$_DEVENV_PATH" ] && export PATH="$_DEVENV_PATH" +}