fish-shell/share/functions/fish_add_path.fish
Fabian Boehm f59cdfaa8d fish_add_path: Be more informative in verbose mode
One issue with fish_add_path at the moment is that it is sometimes a bit too intransparent.

You'll try to add a path, but it won't appear - was that because it wasn't a directory,
or because it doesn't exist, or because it was already included?

If it isn't usable after, did fish_add_path not add it because of something or did something *else* remove it?

So we give more explanations - "skipping this because it's a file", "not setting anything because no paths are left to add", ...
2024-06-06 16:47:39 +02:00

111 lines
4.3 KiB
Fish

function fish_add_path --description "Add paths to the PATH"
# This is meant to be the easy one-stop shop to adding stuff to $PATH.
# By default it'll prepend the given paths to a universal $fish_user_paths, excluding the already-included ones.
#
# That means it can be executed once in an interactive session, or stuffed in config.fish,
# and it will do The Right Thing.
#
# The options:
# --prepend or --append to select whether to put the new paths first or last
# --global or --universal to decide whether to use a universal or global fish_user_paths
# --path to set $PATH instead
# --move to move existing entries instead of ignoring them
# --verbose to print the set-command used
# --dry-run to print the set-command without running it
# We do not allow setting $PATH universally.
#
# It defaults to keeping $fish_user_paths or creating a universal, prepending and ignoring existing entries.
argparse -x g,U -x P,U -x a,p g/global U/universal P/path p/prepend a/append h/help m/move v/verbose n/dry-run -- $argv
or return
if set -q _flag_help
__fish_print_help fish_add_path
return 0
end
set -l scope $_flag_global $_flag_universal
if not set -q scope[1]; and not set -q fish_user_paths
set scope -U
end
set -l var fish_user_paths
set -q _flag_path
and set var PATH
# $PATH should be global
and set scope -g
set -l mode $_flag_prepend $_flag_append
set -q mode[1]; or set mode -p
# Enable verbose mode if we're interactively used
status current-command | string match -rq '^fish_add_path$'
and isatty stdout
and set -l _flag_verbose yes
# To keep the order of our arguments, go through and save the ones we want to keep.
set -l newpaths
set -l indexes
for path in $argv
# Realpath allows us to canonicalize the path, which is needed for deduplication.
# We could add a non-canonical version of the given path if no duplicate exists, but tbh that's a recipe for disaster.
# realpath complains if a parent directory does not exist, so we silence stderr.
set -l p (builtin realpath -s -- $path 2>/dev/null)
# Ignore non-existing paths
if not test -d "$p"
# path does not exist
if set -q _flag_verbose
# print a message in verbose mode
if test -f "$p"
printf (_ "Skipping path because it is a file instead of a directory: %s\n") "$p"
else
printf (_ "Skipping non-existent path: %s\n") "$p"
end
end
continue
end
if set -l ind (contains -i -- $p $$var)
# In move-mode, we remove it from its current position and add it back.
if set -q _flag_move; and not contains -- $p $newpaths
set -a indexes $ind
set -a newpaths $p
else if set -q _flag_verbose
printf (_ "Skipping already included path: %s\n") "$p"
end
else if not contains -- $p $newpaths
# Without move, we only add it if it's not in.
set -a newpaths $p
end
end
# Ensure the variable is only set once, by constructing a new variable before.
# This is to stop any handlers or anything from firing more than once.
set -l newvar $$var
if set -q _flag_move; and set -q indexes[1]
# We remove in one step, so the indexes don't move.
set -e newvar["$indexes"]
end
set $mode newvar $newpaths
# Finally, only set if there is anything *to* set.
# This saves us from setting, especially in the common case of someone putting this in config.fish
# to ensure a path is in $PATH.
if set -q newpaths[1]; or set -q indexes[1]
if set -q _flag_verbose; or set -q _flag_n
# The escape helps make it unambiguous - so you see whether an argument includes a space or something.
echo (string escape -- set $scope $var $newvar)
end
not set -q _flag_n
and set $scope $var $newvar
return 0
else
if set -q _flag_verbose
# print a message in verbose mode
printf (_ "No paths to add, not setting anything.\n") "$p"
end
return 1
end
end