diff --git a/fish/.gitignore b/fish/.gitignore index 562cb70..23efee9 100644 --- a/fish/.gitignore +++ b/fish/.gitignore @@ -1,2 +1 @@ fish_variables -fisher/ diff --git a/fish/completions/fisher.fish b/fish/completions/fisher.fish new file mode 100644 index 0000000..6d23ce4 --- /dev/null +++ b/fish/completions/fisher.fish @@ -0,0 +1,7 @@ +complete --command fisher --exclusive --long help --description "Print help" +complete --command fisher --exclusive --long version --description "Print version" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments install --description "Install plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments update --description "Update installed plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments remove --description "Remove installed plugins" +complete --command fisher --exclusive --condition __fish_use_subcommand --arguments list --description "List installed plugins matching regex" +complete --command fisher --exclusive --condition "__fish_seen_subcommand_from update remove" --arguments "(fisher list)" diff --git a/fish/completions/replay.fish b/fish/completions/replay.fish new file mode 100644 index 0000000..d4589a9 --- /dev/null +++ b/fish/completions/replay.fish @@ -0,0 +1,3 @@ +complete --command replay --no-files +complete --command replay --exclusive --long version --description "Print version" +complete --command replay --exclusive --long help --description "Print help" diff --git a/fish/completions/sdk.fish b/fish/completions/sdk.fish new file mode 100644 index 0000000..17fcb7e --- /dev/null +++ b/fish/completions/sdk.fish @@ -0,0 +1,226 @@ +# Defines autocompletion for SDKMAN! + +# Copyright (c) 2018 Raphael Reitzig +# MIT License (MIT) +# https://github.com/reitzig/sdkman-for-fish + +# Guard: SDKMAN! needs to be installed +if not test -f "$HOME/.sdkman/bin/sdkman-init.sh" + exit 0 +end + +# # # # # # +# Completion trigger predicates +# # # # # # + +# Test if there is no command +function __fish_sdkman_no_command + set cmd (commandline -opc) + + if [ (count $cmd) -eq 1 ] + return 0 + end + return 1 +end + +# Test if the main command matches one of the parameters +function __fish_sdkman_using_command + set cmd (commandline -opc) + + if [ (count $cmd) -eq 2 ] + if contains $cmd[2] $argv + return 0 + end + end + return 1 +end + +function __fish_sdkman_specifying_candidate + set cmd (commandline -opc) + + if [ (count $cmd) -eq 3 ] # currently, sdk does not support multiple versions + if contains $cmd[2] $argv + return 0 + end + end + return 1 +end + +function __fish_sdkman_command_has_enough_parameters + set cmd (commandline -opc) + + if [ (count $cmd) -ge (math $argv[1] + 2) ]; and contains $cmd[2] $argv[2..-1] + return 0 + end + return 1 +end + +# # # # # # +# Data collectors +# # # # # # + +function __fish_sdkman_candidates + cat "$HOME"/.sdkman/var/candidates | tr ',' '\n' +end + +function __fish_sdkman_candidates_with_versions + set regexpHome (string replace -a '/' '\\/' "$HOME/") + + find "$HOME"/.sdkman/candidates/ -mindepth 2 -maxdepth 2 -name '*current' \ + | awk -F '/' '{ print $(NF-1) }' \ + | sort -u +end + +function __fish_sdkman_installed_versions + set cmd (commandline -opc) + if [ -d "$HOME"/.sdkman/candidates/$cmd[3]/current ] + ls -v1 "$HOME"/.sdkman/candidates/$cmd[3] | grep -v current + end +end + +# # # # # # +# Completion specification +# # # # # # + +# install +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'i install' \ + -d 'Install new version' +complete -c sdk -f -n '__fish_sdkman_using_command i install' \ + -a "(__fish_sdkman_candidates)" +complete -c sdk -f -n '__fish_sdkman_specifying_candidate i install' \ + # TODO complete available versions --> #4 + -a 'a.b.c' \ + -d "version list unavailable" +complete -c sdk -f -n '__fish_sdkman_specifying_candidate i install' \ + -a 'x.y.z' \ + -d "Add your own; specify path!" + # Implicit: complete files as fourth parameter +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 3 i install' + # block + +# uninstall +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'rm uninstall' -d 'Uninstall version' +complete -c sdk -f -n '__fish_sdkman_using_command rm uninstall' \ + -a "(__fish_sdkman_candidates_with_versions)" +complete -c sdk -f -n '__fish_sdkman_specifying_candidate rm uninstall' \ + -a "(__fish_sdkman_installed_versions)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 2 rm uninstall' + # block + +# list +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'ls list' \ + -d 'List versions' +complete -c sdk -f -n '__fish_sdkman_using_command ls list' \ + -a "(__fish_sdkman_candidates)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 ls list' + # block + +# use +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'u use' \ + -d 'Use specific version' +complete -c sdk -f -n '__fish_sdkman_using_command u use' \ + -a "(__fish_sdkman_candidates_with_versions)" +complete -c sdk -f -n '__fish_sdkman_specifying_candidate u use' \ + -a "(__fish_sdkman_installed_versions)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 2 u use' + # block + +# default +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'd default' \ + -d 'Set default version' +complete -c sdk -f -n '__fish_sdkman_using_command d default' \ + -a "(__fish_sdkman_candidates_with_versions)" +complete -c sdk -f -n '__fish_sdkman_specifying_candidate d default' \ + -a "(__fish_sdkman_installed_versions)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 2 d default' + # block + +# current +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'c current' \ + -d 'Display current version' +complete -c sdk -f -n '__fish_sdkman_using_command c current' \ + -a "(__fish_sdkman_candidates)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 c current' + # block + +# upgrade +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'ug upgrade' \ + -d 'Display what is outdated' +complete -c sdk -f -n '__fish_sdkman_using_command ug upgrade' \ + -a "(__fish_sdkman_candidates_with_versions)" +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 ug upgrade' + # block + +# version +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'v version' \ + -d 'Display version' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 0 v version' + # block + +# broadcast +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'b broadcast' \ + -d 'Display broadcast message' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 0 b broadcast' + # block + +# help +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'h help' \ + -d 'Display help message' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 0 h help' + # block + +# offline +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'offline' \ + -d 'Set offline status' +complete -c sdk -f -n '__fish_sdkman_using_command offline' \ + -a 'enable' \ + -d 'Make sdk work while offline' +complete -c sdk -f -n '__fish_sdkman_using_command offline' \ + -a 'disable' \ + -d 'Turn on all features' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 offline' + # block + +# selfupdate +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'selfupdate' \ + -d 'Update sdk' +complete -c sdk -f -n '__fish_sdkman_using_command selfupdate' \ + -a 'force' \ + -d 'Force re-install of current version' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 selfupdate' + # block + +# update +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'update' \ + -d 'Reload the candidate list' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 0 update' + # block + +# flush +complete -c sdk -f -n '__fish_sdkman_no_command' \ + -a 'flush' \ + -d 'Clear out caches' +complete -c sdk -f -n '__fish_sdkman_using_command flush' \ + -a 'broadcast' \ + -d 'Re-download news' +complete -c sdk -f -n '__fish_sdkman_using_command flush' \ + -a 'archives' \ + -d 'Remove downloads' +complete -c sdk -f -n '__fish_sdkman_using_command flush' \ + -a 'temp' \ + -d 'Clear installation prep folder' +complete -c sdk -f -n '__fish_sdkman_command_has_enough_parameters 1 flush' + # block diff --git a/fish/conf.d/fisher.fish b/fish/conf.d/fisher.fish deleted file mode 100644 index 9074668..0000000 --- a/fish/conf.d/fisher.fish +++ /dev/null @@ -1,7 +0,0 @@ -# https://github.com/jorgebucaran/fisher -set -g fisher_path $__fish_config_dir/fisher -set fish_function_path $fish_function_path[1] $fisher_path/functions $fish_function_path[2..-1] -set fish_complete_path $fish_complete_path[1] $fisher_path/completions $fish_complete_path[2..-1] -for file in $fisher_path/conf.d/*.fish - builtin source $file 2>/dev/null -end diff --git a/fish/conf.d/nix-env.fish b/fish/conf.d/nix-env.fish new file mode 100644 index 0000000..22d7b31 --- /dev/null +++ b/fish/conf.d/nix-env.fish @@ -0,0 +1,138 @@ +# Setup Nix + +# We need to distinguish between single-user and multi-user installs. +# This is difficult because there's no official way to do this. +# We could look for the presence of /nix/var/nix/daemon-socket/socket but this will fail if the +# daemon hasn't started yet. /nix/var/nix/daemon-socket will exist if the daemon has ever run, but +# I don't think there's any protection against accidentally running `nix-daemon` as a user. +# We also can't just look for /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh because +# older single-user installs used the default profile instead of a per-user profile. +# We can still check for it first, because all multi-user installs should have it, and so if it's +# not present that's a pretty big indicator that this is a single-user install. If it does exist, +# we still need to verify the install type. To that end we'll look for a root owner and sticky bit +# on /nix/store. Multi-user installs set both, single-user installs don't. It's certainly possible +# someone could do a single-user install as root and then manually set the sticky bit but that +# would be extremely unusual. + +set -l nix_profile_path /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh +set -l single_user_profile_path ~/.nix-profile/etc/profile.d/nix.sh +if test -e $nix_profile_path + # The path exists. Double-check that this is a multi-user install. + # We can't just check for ~/.nix-profile/… because this may be a single-user install running as + # the wrong user. + + # stat is not portable. Splitting the output of ls -nd is reliable on most platforms. + set -l owner (string split -n ' ' (command ls -nd /nix/store 2>/dev/null))[3] + if not test -k /nix/store -a $owner -eq 0 + # /nix/store is either not owned by root or not sticky. Assume single-user. + set nix_profile_path $single_user_profile_path + end +else + # The path doesn't exist. Assume single-user + set nix_profile_path $single_user_profile_path +end + +if test -e $nix_profile_path + # Source the nix setup script + # We're going to run the regular Nix profile under bash and then print out a few variables + for line in (command env -u BASH_ENV bash -c '. "$0"; for name in PATH "${!NIX_@}"; do printf "%s=%s\0" "$name" "${!name}"; done' $nix_profile_path | string split0) + set -xg (string split -m 1 = $line) + end + + # Insert Nix's fish share directories into fish's special variables. + # nixpkgs-installed fish tries to set these up already if NIX_PROFILES is defined, which won't + # be the case when sourcing $__fish_data_dir/share/config.fish normally, but might be for a + # recursive invocation. To guard against that, we'll only insert paths that don't already exit. + # Furthermore, for the vendor_conf.d sourcing, we'll use the pre-existing presence of a path in + # $fish_function_path to determine whether we want to source the relevant vendor_conf.d folder. + + # To start, let's locally define NIX_PROFILES if it doesn't already exist. + set -al NIX_PROFILES + if test (count $NIX_PROFILES) -eq 0 + set -a NIX_PROFILES $HOME/.nix-profile + end + # Replicate the logic from nixpkgs version of $__fish_data_dir/__fish_build_paths.fish. + set -l __nix_profile_paths (string split ' ' -- $NIX_PROFILES)[-1..1] + set -l __extra_completionsdir \ + $__nix_profile_paths/etc/fish/completions \ + $__nix_profile_paths/share/fish/vendor_completions.d + set -l __extra_functionsdir \ + $__nix_profile_paths/etc/fish/functions \ + $__nix_profile_paths/share/fish/vendor_functions.d + set -l __extra_confdir \ + $__nix_profile_paths/etc/fish/conf.d \ + $__nix_profile_paths/share/fish/vendor_conf.d \ + + ### Configure fish_function_path ### + # Remove any of our extra paths that may already exist. + # Record the equivalent __extra_confdir path for any function path that exists. + set -l existing_conf_paths + for path in $__extra_functionsdir + if set -l idx (contains --index -- $path $fish_function_path) + set -e fish_function_path[$idx] + set -a existing_conf_paths $__extra_confdir[(contains --index -- $path $__extra_functionsdir)] + end + end + # Insert the paths before $__fish_data_dir. + if set -l idx (contains --index -- $__fish_data_dir/functions $fish_function_path) + # Fish has no way to simply insert into the middle of an array. + set -l new_path $fish_function_path[1..$idx] + set -e new_path[$idx] + set -a new_path $__extra_functionsdir + set fish_function_path $new_path $fish_function_path[$idx..-1] + else + set -a fish_function_path $__extra_functionsdir + end + + ### Configure fish_complete_path ### + # Remove any of our extra paths that may already exist. + for path in $__extra_completionsdir + if set -l idx (contains --index -- $path $fish_complete_path) + set -e fish_complete_path[$idx] + end + end + # Insert the paths before $__fish_data_dir. + if set -l idx (contains --index -- $__fish_data_dir/completions $fish_complete_path) + set -l new_path $fish_complete_path[1..$idx] + set -e new_path[$idx] + set -a new_path $__extra_completionsdir + set fish_complete_path $new_path $fish_complete_path[$idx..-1] + else + set -a fish_complete_path $__extra_completionsdir + end + + ### Source conf directories ### + # The built-in directories were already sourced during shell initialization. + # Any __extra_confdir that came from $__fish_data_dir/__fish_build_paths.fish was also sourced. + # As explained above, we're using the presence of pre-existing paths in $fish_function_path as a + # signal that the corresponding conf dir has also already been sourced. + # In order to simulate this, we'll run through the same algorithm as found in + # $__fish_data_dir/config.fish except we'll avoid sourcing the file if it comes from an + # already-sourced location. + # Caveats: + # * Files will be sourced in a different order than we'd ideally do (because we're coming in + # after the fact to source them). + # * If there are existing extra conf paths, files in them may have been sourced that should have + # been suppressed by paths we're inserting in front. + # * Similarly any files in $__fish_data_dir/vendor_conf.d that should have been suppressed won't + # have been. + set -l sourcelist + for file in $__fish_config_dir/conf.d/*.fish $__fish_sysconf_dir/conf.d/*.fish + # We know these paths were sourced already. Just record them. + set -l basename (string replace -r '^.*/' '' -- $file) + contains -- $basename $sourcelist + or set -a sourcelist $basename + end + for root in $__extra_confdir + for file in $root/*.fish + set -l basename (string replace -r '^.*/' '' -- $file) + contains -- $basename $sourcelist + and continue + set -a sourcelist $basename + contains -- $root $existing_conf_paths + and continue # this is a pre-existing path, it will have been sourced already + [ -f $file -a -r $file ] + and source $file + end + end +end diff --git a/fish/conf.d/sdk.fish b/fish/conf.d/sdk.fish new file mode 100644 index 0000000..507b212 --- /dev/null +++ b/fish/conf.d/sdk.fish @@ -0,0 +1,84 @@ +#!/usr/bin/fish + +# Makes command and binaries from SDKMAN! available in fish. +# Delegates to bash for the `sdk` command. + +# Copyright (c) 2018 Raphael Reitzig +# MIT License (MIT) +# https://github.com/reitzig/sdkman-for-fish + +set __fish_sdkman_init "$HOME/.sdkman/bin/sdkman-init.sh" +set __fish_sdkman_noexport_init "$HOME/.config/fisher/github.com/reitzig/sdkman-for-fish/sdkman-noexport-init.sh" + +# Guard: SDKMAN! needs to be installed +if not test -f "$__fish_sdkman_init" + exit 0 +end + +# Hack for issue #19: +# Create version of sdkman-init that doesn't export any environment variables. +# Refresh if sdkman-init changed. +if begin not test -f "$__fish_sdkman_noexport_init"; + or env test "$__fish_sdkman_init" -nt "$__fish_sdkman_noexport_init" + end + mkdir -p (dirname $__fish_sdkman_noexport_init) + sed -E -e 's/^(\s*).*(export|to_path).*$/\1:/g' "$__fish_sdkman_init" \ + > "$__fish_sdkman_noexport_init" +end + +# Runs the given command in bash, capturing some side effects +# and repeating them on the current fish shell. +# Returns the same status code as the given command. +function __fish_sdkman_run_in_bash + # We need to leave stdin and stdout of sdk free for user interaction. + # So, pipe relevant environment variables (which might have changed) + # through a file. + # But since now getting the exit code of sdk itself is a hassle, + # pipe it as well. + # + # TODO: Can somebody get this to work without the overhead of a file? + set pipe (mktemp) + bash -c "$argv[1]; + echo -e \"\$?\" > $pipe; + env | grep -e '^SDKMAN_\|^PATH' >> $pipe; + env | grep -i -E \"^(`echo \${SDKMAN_CANDIDATES_CSV} | sed 's/,/|/g'`)_HOME\" >> $pipe; + echo \"SDKMAN_OFFLINE_MODE=\${SDKMAN_OFFLINE_MODE}\" >> $pipe" # it's not an environment variable! + set bashDump (cat $pipe; rm $pipe) + + set sdkStatus $bashDump[1] + set bashEnv $bashDump[2..-1] + + # If SDKMAN! succeeded, copy relevant environment variables + # to the current shell (they might have changed) + if [ $sdkStatus = 0 ] + for line in $bashEnv + set parts (string split "=" $line) + set var $parts[1] + set value (string join "=" $parts[2..-1]) + + switch "$var" + case "PATH" + # Special treatment: need fish list instead + # of colon-separated list. + set value (string split : "$value") + end + + if test -n value + set -gx $var $value + # Note: This makes SDKMAN_OFFLINE_MODE an environment variable. + # That gives it the behaviour we _want_! + end + end + end + + return $sdkStatus +end + +# If this is a subshell of a(n initialized) fish owned by the same user, +# no initialization necessary. +# Otherwise: +if not set -q SDKMAN_DIR; or test (ls -ld "$SDKMAN_DIR" | awk '{print $3}') != (whoami) + set -e SDKMAN_DIR + __fish_sdkman_run_in_bash "source $__fish_sdkman_init" +end + diff --git a/fish/functions/fisher.fish b/fish/functions/fisher.fish new file mode 100644 index 0000000..6407479 --- /dev/null +++ b/fish/functions/fisher.fish @@ -0,0 +1,212 @@ +function fisher --argument-names cmd --description "A plugin manager for Fish" + set --query fisher_path || set --local fisher_path $__fish_config_dir + set --local fisher_version 4.3.1 + set --local fish_plugins $__fish_config_dir/fish_plugins + + switch "$cmd" + case -v --version + echo "fisher, version $fisher_version" + case "" -h --help + echo "Usage: fisher install Install plugins" + echo " fisher remove Remove installed plugins" + echo " fisher update Update installed plugins" + echo " fisher update Update all installed plugins" + echo " fisher list [] List installed plugins matching regex" + echo "Options:" + echo " -v or --version Print version" + echo " -h or --help Print this help message" + echo "Variables:" + echo " \$fisher_path Plugin installation path. Default: ~/.config/fish" + case ls list + string match --entire --regex -- "$argv[2]" $_fisher_plugins + case install update remove + isatty || read --local --null --array stdin && set --append argv $stdin + + set --local install_plugins + set --local update_plugins + set --local remove_plugins + set --local arg_plugins $argv[2..-1] + set --local old_plugins $_fisher_plugins + set --local new_plugins + + if ! set --query argv[2] + if test "$cmd" != update + echo "fisher: Not enough arguments for command: \"$cmd\"" >&2 && return 1 + else if test ! -e $fish_plugins + echo "fisher: \"$fish_plugins\" file not found: \"$cmd\"" >&2 && return 1 + end + set arg_plugins (string match --regex -- '^[^\s]+$' <$fish_plugins) + end + + for plugin in $arg_plugins + test -e "$plugin" && set plugin (realpath $plugin) + contains -- "$plugin" $new_plugins || set --append new_plugins $plugin + end + + if set --query argv[2] + for plugin in $new_plugins + if contains -- "$plugin" $old_plugins + test "$cmd" = remove && + set --append remove_plugins $plugin || + set --append update_plugins $plugin + else if test "$cmd" = install + set --append install_plugins $plugin + else + echo "fisher: Plugin not installed: \"$plugin\"" >&2 && return 1 + end + end + else + for plugin in $new_plugins + contains -- "$plugin" $old_plugins && + set --append update_plugins $plugin || + set --append install_plugins $plugin + end + + for plugin in $old_plugins + contains -- "$plugin" $new_plugins || set --append remove_plugins $plugin + end + end + + set --local pid_list + set --local source_plugins + set --local fetch_plugins $update_plugins $install_plugins + echo (set_color --bold)fisher $cmd version $fisher_version(set_color normal) + + for plugin in $fetch_plugins + set --local source (command mktemp -d) + set --append source_plugins $source + + command mkdir -p $source/{completions,conf.d,functions} + + fish --command " + if test -e $plugin + command cp -Rf $plugin/* $source + else + set temp (command mktemp -d) + set name (string split \@ $plugin) || set name[2] HEAD + set url https://api.github.com/repos/\$name[1]/tarball/\$name[2] + set header 'Accept: application/vnd.github.v3+json' + + echo Fetching (set_color --underline)\$url(set_color normal) + + if curl --silent -L -H \$header \$url | tar -xzC \$temp -f - 2>/dev/null + command cp -Rf \$temp/*/* $source + else + echo fisher: Invalid plugin name or host unavailable: \\\"$plugin\\\" >&2 + command rm -rf $source + end + command rm -rf \$temp + end + + set files $source/* && string match --quiet --regex -- .+\.fish\\\$ \$files + " & + + set --append pid_list (jobs --last --pid) + end + + wait $pid_list 2>/dev/null + + for plugin in $fetch_plugins + if set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] && test ! -e $source + if set --local index (contains --index -- "$plugin" $install_plugins) + set --erase install_plugins[$index] + else + set --erase update_plugins[(contains --index -- "$plugin" $update_plugins)] + end + end + end + + for plugin in $update_plugins $remove_plugins + if set --local index (contains --index -- "$plugin" $_fisher_plugins) + set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files + + if contains -- "$plugin" $remove_plugins + for name in (string replace --filter --regex -- '.+/conf\.d/([^/]+)\.fish$' '$1' $$plugin_files_var) + emit {$name}_uninstall + end + printf "%s\n" Removing\ (set_color red --bold)$plugin(set_color normal) " "$$plugin_files_var + end + + command rm -rf $$plugin_files_var + functions --erase (string replace --filter --regex -- '.+/functions/([^/]+)\.fish$' '$1' $$plugin_files_var) + + for name in (string replace --filter --regex -- '.+/completions/([^/]+)\.fish$' '$1' $$plugin_files_var) + complete --erase --command $name + end + + set --erase _fisher_plugins[$index] + set --erase $plugin_files_var + end + end + + if set --query update_plugins[1] || set --query install_plugins[1] + command mkdir -p $fisher_path/{functions,conf.d,completions} + end + + for plugin in $update_plugins $install_plugins + set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] + set --local files $source/{functions,conf.d,completions}/* + + if set --local index (contains --index -- $plugin $install_plugins) + set --local user_files $fisher_path/{functions,conf.d,completions}/* + set --local conflict_files + + for file in (string replace -- $source/ $fisher_path/ $files) + contains -- $file $user_files && set --append conflict_files $file + end + + if set --query conflict_files[1] && set --erase install_plugins[$index] + echo -s "fisher: Cannot install \"$plugin\": please remove or move conflicting files first:" \n" "$conflict_files >&2 + continue + end + end + + for file in (string replace -- $source/ "" $files) + command cp -Rf $source/$file $fisher_path/$file + end + + set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files + set --query files[1] && set --universal $plugin_files_var (string replace -- $source $fisher_path $files) + + contains -- $plugin $_fisher_plugins || set --universal --append _fisher_plugins $plugin + contains -- $plugin $install_plugins && set --local event install || set --local event update + + printf "%s\n" Installing\ (set_color --bold)$plugin(set_color normal) " "$$plugin_files_var + + for file in (string match --regex -- '.+/[^/]+\.fish$' $$plugin_files_var) + source $file + if set --local name (string replace --regex -- '.+conf\.d/([^/]+)\.fish$' '$1' $file) + emit {$name}_$event + end + end + end + + command rm -rf $source_plugins + + set --query _fisher_plugins[1] || set --erase _fisher_plugins + set --query _fisher_plugins && + printf "%s\n" $_fisher_plugins >$fish_plugins || + command rm -f $fish_plugins + + set --local total (count $install_plugins) (count $update_plugins) (count $remove_plugins) + test "$total" != "0 0 0" && echo (string join ", " ( + test $total[1] = 0 || echo "Installed $total[1]") ( + test $total[2] = 0 || echo "Updated $total[2]") ( + test $total[3] = 0 || echo "Removed $total[3]") + ) plugin/s + case \* + echo "fisher: Unknown command: \"$cmd\"" >&2 && return 1 + end +end + +## Migrations ## +function _fisher_fish_postexec --on-event fish_postexec + if functions --query _fisher_list + fisher update >/dev/null 2>/dev/null + set --query XDG_DATA_HOME || set --local XDG_DATA_HOME ~/.local/share + test -e $XDG_DATA_HOME/fisher && command rm -rf $XDG_DATA_HOME/fisher + functions --erase _fisher_list _fisher_plugin_parse + set --erase fisher_data + end + functions --erase _fisher_fish_postexec +end diff --git a/fish/functions/replay.fish b/fish/functions/replay.fish new file mode 100644 index 0000000..b8f170f --- /dev/null +++ b/fish/functions/replay.fish @@ -0,0 +1,48 @@ +function replay --description "Run Bash commands replaying changes in Fish" + switch "$argv" + case -v --version + echo "replay, version 1.2.0" + case "" -h --help + echo "Usage: replay Run Bash commands replaying changes in Fish" + echo "Options:" + echo " -v or --version Print version" + echo " -h or --help Print this help message" + case \* + set --local env + set --local sep @$fish_pid(random)(command date +%s) + set --local argv $argv[1] \"$argv[2..-1]\" + set --local out (command bash -c " + $argv + status=\$? + [ \$status -gt 0 ] && exit \$status + + command compgen -e | command awk -v sep=$sep '{ + gsub(/\n/, \"\\\n\", ENVIRON[\$0]) + print \$0 sep ENVIRON[\$0] + }' && alias + ") || return + + string replace --all -- \\n \n ( + for line in $out + if string split $sep $line | read --local --line name value + set --append env $name + + contains -- $name SHLVL PS1 BASH_FUNC || test "$$name" = "$value" && continue + + if test "$name" = PATH + string replace --all : " " "set $name $value" + else if test "$name" = PWD + echo builtin cd \"$value\" + else + echo "set --global --export $name "(string escape -- $value) + end + else + set --query env[1] && string match --entire --regex -- "^alias" $line || echo "echo \"$line\"" + end + end | string replace --all -- \$ \\\$ + for name in (set --export --names) + contains -- $name $env || echo "set --erase $name" + end + ) | source + end +end diff --git a/fish/functions/sdk.fish b/fish/functions/sdk.fish new file mode 100644 index 0000000..1bc2a16 --- /dev/null +++ b/fish/functions/sdk.fish @@ -0,0 +1,36 @@ +function sdk -d "Manage SDKs" + # Guard: SDKMAN! needs to be installed + if not test -f "$__fish_sdkman_init" + # Propose to install SDKMAN! + + function read_confirm + while true + read -l -P "$argv[1] [y/N] " confirm + + switch $confirm + case Y y + return 0 + case '' N n + return 1 + end + end + end + + if read_confirm "You don't seem to have SDKMAN! installed. Install now?" + if not which curl > /dev/null + echo "curl required" + return 1 + end + if not which bash > /dev/null + echo "bash required" + return 1 + end + + curl -s "https://get.sdkman.io" | bash | sed '/All done!/q' + echo "Please open a new terminal/shell to load SDKMAN!" + end + else + # Declare the _actual_ sdk command for fish + __fish_sdkman_run_in_bash "source \"$__fish_sdkman_noexport_init\" && sdk $argv" + end +end diff --git a/install.sh b/install.sh index 6ff786a..8f1c55c 100755 --- a/install.sh +++ b/install.sh @@ -29,4 +29,3 @@ fi confirm "Set login shell?" && "$ROOTDIR/install/install-shell.sh" confirm "Create symlinks?" && "$ROOTDIR/install/install-symlinks.sh" confirm "Install vim plugins?" && "$ROOTDIR/install/install-vim-plugins.sh" -confirm "Install fish plugins?" && "$ROOTDIR/install/install-fish-plugins.sh" diff --git a/install/install-fish-plugins.sh b/install/install-fish-plugins.sh deleted file mode 100755 index ccf8cb6..0000000 --- a/install/install-fish-plugins.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -echo "To install fish plugins, run this command interactively in fish:" -echo -echo " curl -fsSL https://git.io/fisher | source && fisher update" -echo