aboutsummaryrefslogtreecommitdiffstats
path: root/ves.fish
diff options
context:
space:
mode:
Diffstat (limited to 'ves.fish')
-rw-r--r--ves.fish104
1 files changed, 104 insertions, 0 deletions
diff --git a/ves.fish b/ves.fish
new file mode 100644
index 0000000..3315f61
--- /dev/null
+++ b/ves.fish
@@ -0,0 +1,104 @@
+# ves.fish
+#
+# fish shell shim for sh-ves. Runs each ves command in a POSIX sh subshell
+# against the real implementation, then diffs the subshell's resulting
+# environment against fish's and replays the changes with set -gx / set -e.
+# The activation save-state is carried in exported SHVES_SAVED_* variables,
+# so it survives between subshell invocations.
+#
+# Install this file to ~/.config/fish/functions/ves.fish (make install does
+# this automatically when fish is present).
+
+function ves --description 'sh-ves: Bourne Shell Virtual Environment System'
+ if not set -q SHVES_SCRIPTS_DIR
+ set -gx SHVES_SCRIPTS_DIR $HOME/.local/bin/ves_scripts
+ end
+
+ if not test -f "$SHVES_SCRIPTS_DIR/ves-init.sh"
+ printf "ERROR: sh-ves scripts not found in [%s]. Is sh-ves installed?\n" "$SHVES_SCRIPTS_DIR" >&2
+ return 1
+ end
+
+ set -l dump (mktemp)
+
+ # Resolve env(1) to an absolute path up front: the command may rewrite
+ # PATH inside the subshell, which would otherwise make the dump fail.
+ set -l envbin (command -v env)
+ if test -z "$envbin"
+ set envbin /usr/bin/env
+ end
+
+ # Run the real command, then dump the subshell's final environment
+ # NUL-delimited (values may contain newlines) for replay into fish.
+ VES_ENV_DUMP=$dump VES_ENV_BIN=$envbin sh -c '
+ . "$SHVES_SCRIPTS_DIR"/ves-init.sh
+ ves "$@"
+ _shves_status=$?
+ "$VES_ENV_BIN" -0 > "$VES_ENV_DUMP"
+ exit $_shves_status
+ ' ves $argv
+ set -l ret $status
+
+ # An empty dump means the subshell could not write its environment at
+ # all; replaying it would wrongly erase every exported variable.
+ if not test -s $dump
+ printf "ERROR: failed to capture subshell environment, shell state unchanged.\n" >&2
+ rm -f $dump
+ return 1
+ end
+
+ # Variables managed by the wrapper machinery itself, plus per-process
+ # bookkeeping that should never be replayed into the parent shell.
+ set -l skip VES_ENV_DUMP VES_ENV_BIN PWD OLDPWD SHLVL _
+
+ # fish list-style path variables: replay these split on ':' so fish
+ # keeps treating them as lists.
+ set -l pathvars PATH CDPATH MANPATH
+
+ set -l seen
+ for entry in (string split0 < $dump)
+ set -l kv (string split -m1 = -- $entry)
+ set -l name $kv[1]
+ set -l value $kv[2]
+
+ # entries that are not well-formed variable names (e.g. exported
+ # multiline values' continuation, or odd env entries) are skipped
+ if not string match -qr '^[a-zA-Z_][a-zA-Z0-9_]*$' -- $name
+ continue
+ end
+ if contains -- $name $skip
+ continue
+ end
+
+ set -a seen $name
+
+ if contains -- $name $pathvars
+ set -l new (string split : -- $value)
+ if not set -q $name
+ set -gx $name $new
+ else if test "$new" != "$$name"
+ set -gx $name $new
+ end
+ else
+ if not set -q $name
+ set -gx $name $value
+ else if test "$value" != "$$name"
+ set -gx $name $value
+ end
+ end
+ end
+
+ # Anything fish exports that vanished from the subshell environment
+ # was unset by the command (e.g. by ves deactivate).
+ for name in (set -nx)
+ if contains -- $name $skip
+ continue
+ end
+ if not contains -- $name $seen
+ set -e $name
+ end
+ end
+
+ rm -f $dump
+ return $ret
+end