diff --git a/files/fish/completions/autorestic.fish b/files/fish/completions/autorestic.fish new file mode 100644 index 0000000..a06fe15 --- /dev/null +++ b/files/fish/completions/autorestic.fish @@ -0,0 +1,164 @@ +# fish completion for autorestic -*- shell-script -*- + +function __autorestic_debug + set file "$BASH_COMP_DEBUG_FILE" + if test -n "$file" + echo "$argv" >> $file + end +end + +function __autorestic_perform_completion + __autorestic_debug "Starting __autorestic_perform_completion with: $argv" + + set args (string split -- " " "$argv") + set lastArg "$args[-1]" + + __autorestic_debug "args: $args" + __autorestic_debug "last arg: $lastArg" + + set emptyArg "" + if test -z "$lastArg" + __autorestic_debug "Setting emptyArg" + set emptyArg \"\" + end + __autorestic_debug "emptyArg: $emptyArg" + + if not type -q "$args[1]" + # This can happen when "complete --do-complete autorestic" is called when running this script. + __autorestic_debug "Cannot find $args[1]. No completions." + return + end + + set requestComp "$args[1] __complete $args[2..-1] $emptyArg" + __autorestic_debug "Calling $requestComp" + + set results (eval $requestComp 2> /dev/null) + set comps $results[1..-2] + set directiveLine $results[-1] + + # For Fish, when completing a flag with an = (e.g., -n=) + # completions must be prefixed with the flag + set flagPrefix (string match -r -- '-.*=' "$lastArg") + + __autorestic_debug "Comps: $comps" + __autorestic_debug "DirectiveLine: $directiveLine" + __autorestic_debug "flagPrefix: $flagPrefix" + + for comp in $comps + printf "%s%s\n" "$flagPrefix" "$comp" + end + + printf "%s\n" "$directiveLine" +end + +# This function does three things: +# 1- Obtain the completions and store them in the global __autorestic_comp_results +# 2- Set the __autorestic_comp_do_file_comp flag if file completion should be performed +# and unset it otherwise +# 3- Return true if the completion results are not empty +function __autorestic_prepare_completions + # Start fresh + set --erase __autorestic_comp_do_file_comp + set --erase __autorestic_comp_results + + # Check if the command-line is already provided. This is useful for testing. + if not set --query __autorestic_comp_commandLine + # Use the -c flag to allow for completion in the middle of the line + set __autorestic_comp_commandLine (commandline -c) + end + __autorestic_debug "commandLine is: $__autorestic_comp_commandLine" + + set results (__autorestic_perform_completion "$__autorestic_comp_commandLine") + set --erase __autorestic_comp_commandLine + __autorestic_debug "Completion results: $results" + + if test -z "$results" + __autorestic_debug "No completion, probably due to a failure" + # Might as well do file completion, in case it helps + set --global __autorestic_comp_do_file_comp 1 + return 1 + end + + set directive (string sub --start 2 $results[-1]) + set --global __autorestic_comp_results $results[1..-2] + + __autorestic_debug "Completions are: $__autorestic_comp_results" + __autorestic_debug "Directive is: $directive" + + set shellCompDirectiveError 1 + set shellCompDirectiveNoSpace 2 + set shellCompDirectiveNoFileComp 4 + set shellCompDirectiveFilterFileExt 8 + set shellCompDirectiveFilterDirs 16 + + if test -z "$directive" + set directive 0 + end + + set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2) + if test $compErr -eq 1 + __autorestic_debug "Received error directive: aborting." + # Might as well do file completion, in case it helps + set --global __autorestic_comp_do_file_comp 1 + return 1 + end + + set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2) + set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2) + if test $filefilter -eq 1; or test $dirfilter -eq 1 + __autorestic_debug "File extension filtering or directory filtering not supported" + # Do full file completion instead + set --global __autorestic_comp_do_file_comp 1 + return 1 + end + + set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2) + set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2) + + __autorestic_debug "nospace: $nospace, nofiles: $nofiles" + + # Important not to quote the variable for count to work + set numComps (count $__autorestic_comp_results) + __autorestic_debug "numComps: $numComps" + + if test $numComps -eq 1; and test $nospace -ne 0 + # To support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + __autorestic_debug "Adding second completion to perform nospace directive" + set --append __autorestic_comp_results $__autorestic_comp_results[1]. + end + + if test $numComps -eq 0; and test $nofiles -eq 0 + __autorestic_debug "Requesting file completion" + set --global __autorestic_comp_do_file_comp 1 + end + + # If we don't want file completion, we must return true even if there + # are no completions found. This is because fish will perform the last + # completion command, even if its condition is false, if no other + # completion command was triggered + return (not set --query __autorestic_comp_do_file_comp) +end + +# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves +# so we can properly delete any completions provided by another script. +# The space after the the program name is essential to trigger completion for the program +# and not completion of the program name itself. +complete --do-complete "autorestic " > /dev/null 2>&1 +# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + +# Remove any pre-existing completions for the program since we will be handling all of them. +complete -c autorestic -e + +# The order in which the below two lines are defined is very important so that __autorestic_prepare_completions +# is called first. It is __autorestic_prepare_completions that sets up the __autorestic_comp_do_file_comp variable. +# +# This completion will be run second as complete commands are added FILO. +# It triggers file completion choices when __autorestic_comp_do_file_comp is set. +complete -c autorestic -n 'set --query __autorestic_comp_do_file_comp' + +# This completion will be run first as complete commands are added FILO. +# The call to __autorestic_prepare_completions will setup both __autorestic_comp_results and __autorestic_comp_do_file_comp. +# It provides the program's completion choices. +complete -c autorestic -n '__autorestic_prepare_completions' -f -a '$__autorestic_comp_results' + diff --git a/files/fish/completions/fisher.fish b/files/fish/completions/fisher.fish new file mode 100644 index 0000000..271e314 --- /dev/null +++ b/files/fish/completions/fisher.fish @@ -0,0 +1 @@ +fisher complete diff --git a/files/fish/conf.d/omf.fish b/files/fish/conf.d/omf.fish new file mode 100644 index 0000000..3e0f6d6 --- /dev/null +++ b/files/fish/conf.d/omf.fish @@ -0,0 +1,7 @@ +# Path to Oh My Fish install. +set -q XDG_DATA_HOME + and set -gx OMF_PATH "$XDG_DATA_HOME/omf" + or set -gx OMF_PATH "$HOME/.local/share/omf" + +# Load Oh My Fish configuration. +source $OMF_PATH/init.fish diff --git a/files/fish/config.fish b/files/fish/config.fish new file mode 100644 index 0000000..9b23a79 --- /dev/null +++ b/files/fish/config.fish @@ -0,0 +1,10 @@ +set -g fish_user_paths "/usr/local/sbin" $fish_user_paths + +set -x PIPENV_VENV_IN_PROJECT true + +export GOPATH="$HOME/.go" +export GOROOT=(brew --prefix go)"/libexec" +export PATH="$PATH:$GOPATH/bin:$GOROOT/bin:$HOME/.cargo/bin" + +# The next line updates PATH for the Google Cloud SDK. +if [ -f '$HOME/Desktop/google-cloud-sdk/path.fish.inc' ]; . '$HOME/Desktop/google-cloud-sdk/path.fish.inc'; end diff --git a/files/fish/fish_variables b/files/fish/fish_variables new file mode 100644 index 0000000..48ec6b2 --- /dev/null +++ b/files/fish/fish_variables @@ -0,0 +1,33 @@ +# This file contains fish universal variable definitions. +# VERSION: 3.0 + +SETUVAR __fish_initialized:3100 +SETUVAR fish_color_autosuggestion:555\x1ebrblack +SETUVAR fish_color_cancel:\x2dr +SETUVAR fish_color_command:005fd7 +SETUVAR fish_color_comment:990000 +SETUVAR fish_color_cwd:green +SETUVAR fish_color_cwd_root:red +SETUVAR fish_color_end:009900 +SETUVAR fish_color_error:ff0000 +SETUVAR fish_color_escape:00a6b2 +SETUVAR fish_color_history_current:\x2d\x2dbold +SETUVAR fish_color_host:normal +SETUVAR fish_color_host_remote:yellow +SETUVAR fish_color_match:\x2d\x2dbackground\x3dbrblue +SETUVAR fish_color_normal:normal +SETUVAR fish_color_operator:00a6b2 +SETUVAR fish_color_param:00afff +SETUVAR fish_color_quote:999900 +SETUVAR fish_color_redirection:00afff +SETUVAR fish_color_search_match:bryellow\x1e\x2d\x2dbackground\x3dbrblack +SETUVAR fish_color_selection:white\x1e\x2d\x2dbold\x1e\x2d\x2dbackground\x3dbrblack +SETUVAR fish_color_status:red +SETUVAR fish_color_user:brgreen +SETUVAR fish_color_valid_path:\x2d\x2dunderline +SETUVAR fish_greeting:Welcome\x20to\x20fish\x2c\x20the\x20friendly\x20interactive\x20shell\x0aType\x20\x60help\x60\x20for\x20instructions\x20on\x20how\x20to\x20use\x20fish +SETUVAR fish_key_bindings:fish_default_key_bindings +SETUVAR fish_pager_color_completion:\x1d +SETUVAR fish_pager_color_description:B3A06D\x1eyellow +SETUVAR fish_pager_color_prefix:white\x1e\x2d\x2dbold\x1e\x2d\x2dunderline +SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan diff --git a/files/fish/fishfile b/files/fish/fishfile new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/files/fish/fishfile @@ -0,0 +1 @@ + diff --git a/files/fish/functions/dc.fish b/files/fish/functions/dc.fish new file mode 100644 index 0000000..05ca294 --- /dev/null +++ b/files/fish/functions/dc.fish @@ -0,0 +1,4 @@ +# Defined in - @ line 1 +function dc --wraps=docker-compose --description 'alias dc=docker-compose' + docker compose $argv; +end diff --git a/files/fish/functions/dpa.fish b/files/fish/functions/dpa.fish new file mode 100644 index 0000000..4ad9b06 --- /dev/null +++ b/files/fish/functions/dpa.fish @@ -0,0 +1,4 @@ +# Defined in - @ line 1 +function dpa --wraps='docker system prune -af --volumes' --description 'alias dpa docker system prune -af --volumes' + docker system prune -af --volumes $argv; +end diff --git a/files/fish/functions/fish_prompt.fish b/files/fish/functions/fish_prompt.fish new file mode 100644 index 0000000..4c47f7f --- /dev/null +++ b/files/fish/functions/fish_prompt.fish @@ -0,0 +1,1104 @@ +# name: bobthefish +# +# bobthefish is a Powerline-style, Git-aware fish theme optimized for awesome. +# +# You will need a Powerline-patched font for this to work: +# +# https://powerline.readthedocs.org/en/master/installation.html#patched-fonts +# +# I recommend picking one of these: +# +# https://github.com/Lokaltog/powerline-fonts +# +# For more advanced awesome, install a nerd fonts patched font (and be sure to +# enable nerd fonts support with `set -g theme_nerd_fonts yes`): +# +# https://github.com/ryanoasis/nerd-fonts +# +# You can override some default prompt options in your config.fish: +# +# set -g theme_display_git no +# set -g theme_display_git_dirty no +# set -g theme_display_git_untracked no +# set -g theme_display_git_ahead_verbose yes +# set -g theme_display_git_dirty_verbose yes +# set -g theme_display_git_stashed_verbose yes +# set -g theme_display_git_master_branch yes +# set -g theme_git_worktree_support yes +# set -g theme_display_vagrant yes +# set -g theme_display_docker_machine no +# set -g theme_display_k8s_context yes +# set -g theme_display_k8s_namespace no +# set -g theme_display_hg yes +# set -g theme_display_virtualenv no +# set -g theme_display_nix no +# set -g theme_display_ruby no +# set -g theme_display_user ssh +# set -g theme_display_hostname ssh +# set -g theme_display_sudo_user yes +# set -g theme_display_vi no +# set -g theme_display_nvm yes +# set -g theme_avoid_ambiguous_glyphs yes +# set -g theme_powerline_fonts no +# set -g theme_nerd_fonts yes +# set -g theme_show_exit_status yes +# set -g theme_display_jobs_verbose yes +# set -g default_user your_normal_user +# set -g theme_color_scheme dark +# set -g fish_prompt_pwd_dir_length 0 +# set -g theme_project_dir_length 1 +# set -g theme_newline_cursor yes + + +# ============================== +# Helper methods +# ============================== + +function __bobthefish_basename -d 'basically basename, but faster' + string replace -r '^.*/' '' -- $argv +end + +function __bobthefish_dirname -d 'basically dirname, but faster' + string replace -r '/[^/]+/?$' '' -- $argv +end + +function __bobthefish_pwd -d 'Get a normalized $PWD' + # The pwd builtin accepts `-P` on at least Fish 3.x, but fall back to $PWD if that doesn't work + builtin pwd -P 2>/dev/null + or echo $PWD +end + +# Note that for fish < 3.0 this falls back to unescaped, rather than trying to do something clever /shrug +# After we drop support for older fishies, we can inline this without the fallback. +function __bobthefish_escape_regex -a str -d 'A backwards-compatible `string escape --style=regex` implementation' + string escape --style=regex "$str" 2>/dev/null + or echo "$str" +end + +function __bobthefish_git_branch -S -d 'Get the current git branch (or commitish)' + set -l ref (command git symbolic-ref HEAD 2>/dev/null) + and begin + [ "$theme_display_git_master_branch" != 'yes' -a "$ref" = 'refs/heads/master' ] + and echo $branch_glyph + and return + + # truncate the middle of the branch name, but only if it's 25+ characters + set -l truncname $ref + [ "$theme_use_abbreviated_branch_name" = 'yes' ] + and set truncname (string replace -r '^(.{28}).{3,}(.{5})$' "\$1…\$2" $ref) + + string replace -r '^refs/heads/' "$branch_glyph " $truncname + and return + end + + set -l tag (command git describe --tags --exact-match 2>/dev/null) + and echo "$tag_glyph $tag" + and return + + set -l branch (command git show-ref --head -s --abbrev | head -n1 2>/dev/null) + echo "$detached_glyph $branch" +end + +function __bobthefish_hg_branch -S -d 'Get the current hg branch' + set -l branch (command hg branch 2>/dev/null) + set -l book (command hg book | command grep \* | cut -d\ -f3) + echo "$branch_glyph $branch @ $book" +end + +function __bobthefish_pretty_parent -S -a child_dir -d 'Print a parent directory, shortened to fit the prompt' + set -q fish_prompt_pwd_dir_length + or set -l fish_prompt_pwd_dir_length 1 + + # Replace $HOME with ~ + set -l real_home ~ + set -l parent_dir (string replace -r '^'(__bobthefish_escape_regex "$real_home")'($|/)' '~$1' (__bobthefish_dirname $child_dir)) + + # Must check whether `$parent_dir = /` if using native dirname + if [ -z "$parent_dir" ] + echo -n / + return + end + + if [ $fish_prompt_pwd_dir_length -eq 0 ] + echo -n "$parent_dir/" + return + end + + string replace -ar '(\.?[^/]{'"$fish_prompt_pwd_dir_length"'})[^/]*/' '$1/' "$parent_dir/" +end + +function __bobthefish_ignore_vcs_dir -a real_pwd -d 'Check whether the current directory should be ignored as a VCS segment' + for p in $theme_vcs_ignore_paths + set ignore_path (realpath $p 2>/dev/null) + switch $real_pwd/ + case $ignore_path/\* + echo 1 + return + end + end +end + +function __bobthefish_git_project_dir -S -a real_pwd -d 'Print the current git project base directory' + [ "$theme_display_git" = 'no' ] + and return + + set -q theme_vcs_ignore_paths + and [ (__bobthefish_ignore_vcs_dir $real_pwd) ] + and return + + if [ "$theme_git_worktree_support" != 'yes' ] + set -l git_toplevel (command git rev-parse --show-toplevel 2>/dev/null) + + [ -z "$git_toplevel" ] + and return + + # If there are no symlinks, just use git toplevel + switch $real_pwd/ + case $git_toplevel/\* + echo $git_toplevel + return + end + + # Otherwise, we need to find the equivalent directory in the $PWD + set -l d $real_pwd + while not [ -z "$d" ] + if [ (realpath "$d") = "$git_toplevel" ] + echo $d + return + end + + [ "$d" = '/' ] + and return + + set d (__bobthefish_dirname $d) + end + return + end + + set -l git_dir (command git rev-parse --git-dir 2>/dev/null) + or return + + pushd $git_dir + set git_dir $real_pwd + popd + + switch $real_pwd/ + case $git_dir/\* + # Nothing works quite right if we're inside the git dir + # TODO: fix the underlying issues then re-enable the stuff below + + # # if we're inside the git dir, sweet. just return that. + # set -l toplevel (command git rev-parse --show-toplevel 2>/dev/null) + # if [ "$toplevel" ] + # switch $git_dir/ + # case $toplevel/\* + # echo $git_dir + # end + # end + return + end + + set -l project_dir (__bobthefish_dirname $git_dir) + + switch $real_pwd/ + case $project_dir/\* + echo $project_dir + return + end + + set project_dir (command git rev-parse --show-toplevel 2>/dev/null) + switch $real_pwd/ + case $project_dir/\* + echo $project_dir + end +end + +function __bobthefish_hg_project_dir -S -a real_pwd -d 'Print the current hg project base directory' + [ "$theme_display_hg" = 'yes' ] + or return + + set -q theme_vcs_ignore_paths + and [ (__bobthefish_ignore_vcs_dir $real_pwd) ] + and return + + set -l d $real_pwd + while not [ -z "$d" ] + if [ -e $d/.hg ] + command hg root --cwd "$d" 2>/dev/null + return + end + + [ "$d" = '/' ] + and return + + set d (__bobthefish_dirname $d) + end +end + +function __bobthefish_project_pwd -S -a project_root_dir -a real_pwd -d 'Print the working directory relative to project root' + set -q theme_project_dir_length + or set -l theme_project_dir_length 0 + + set -l project_dir (string replace -r '^'(__bobthefish_escape_regex "$project_root_dir")'($|/)' '' $real_pwd) + + if [ $theme_project_dir_length -eq 0 ] + echo -n $project_dir + return + end + + string replace -ar '(\.?[^/]{'"$theme_project_dir_length"'})[^/]*/' '$1/' $project_dir +end + +function __bobthefish_git_ahead -S -d 'Print the ahead/behind state for the current branch' + if [ "$theme_display_git_ahead_verbose" = 'yes' ] + __bobthefish_git_ahead_verbose + return + end + + set -l ahead 0 + set -l behind 0 + for line in (command git rev-list --left-right '@{upstream}...HEAD' 2>/dev/null) + switch "$line" + case '>*' + if [ $behind -eq 1 ] + echo '±' + return + end + set ahead 1 + case '<*' + if [ $ahead -eq 1 ] + echo "$git_plus_minus_glyph" + return + end + set behind 1 + end + end + + if [ $ahead -eq 1 ] + echo "$git_plus_glyph" + else if [ $behind -eq 1 ] + echo "$git_minus_glyph" + end +end + +function __bobthefish_git_ahead_verbose -S -d 'Print a more verbose ahead/behind state for the current branch' + set -l commits (command git rev-list --left-right '@{upstream}...HEAD' 2>/dev/null) + or return + + set -l behind (count (for arg in $commits; echo $arg; end | command grep '^<')) + set -l ahead (count (for arg in $commits; echo $arg; end | command grep -v '^<')) + + switch "$ahead $behind" + case '' # no upstream + case '0 0' # equal to upstream + return + case '* 0' # ahead of upstream + echo "$git_ahead_glyph$ahead" + case '0 *' # behind upstream + echo "$git_behind_glyph$behind" + case '*' # diverged from upstream + echo "$git_ahead_glyph$ahead$git_behind_glyph$behind" + end +end + +function __bobthefish_git_dirty_verbose -S -d 'Print a more verbose dirty state for the current working tree' + set -l changes (command git diff --numstat | awk '{ added += $1; removed += $2 } END { print "+" added "/-" removed }') + or return + + echo "$changes " | string replace -r '(\+0/(-0)?|/-0)' '' +end + +function __bobthefish_git_stashed -S -d 'Print the stashed state for the current branch' + if [ "$theme_display_git_stashed_verbose" = 'yes' ] + set -l stashed (command git rev-list --walk-reflogs --count refs/stash 2>/dev/null) + or return + + echo -n "$git_stashed_glyph$stashed" + else + command git rev-parse --verify --quiet refs/stash >/dev/null + and echo -n "$git_stashed_glyph" + end +end + + +# ============================== +# Segment functions +# ============================== + +function __bobthefish_start_segment -S -d 'Start a prompt segment' + set -l bg $argv[1] + set -e argv[1] + set -l fg $argv[1] + set -e argv[1] + + set_color normal # clear out anything bold or underline... + set_color -b $bg $fg $argv + + switch "$__bobthefish_current_bg" + case '' + # If there's no background, just start one + echo -n ' ' + case "$bg" + # If the background is already the same color, draw a separator + echo -ns $right_arrow_glyph ' ' + case '*' + # otherwise, draw the end of the previous segment and the start of the next + set_color $__bobthefish_current_bg + echo -ns $right_black_arrow_glyph ' ' + set_color $fg $argv + end + + set __bobthefish_current_bg $bg +end + +function __bobthefish_path_segment -S -a segment_dir -d 'Display a shortened form of a directory' + set -l segment_color $color_path + set -l segment_basename_color $color_path_basename + + if not [ -w "$segment_dir" ] + set segment_color $color_path_nowrite + set segment_basename_color $color_path_nowrite_basename + end + + __bobthefish_start_segment $segment_color + + set -l directory + set -l parent + + switch "$segment_dir" + case / + set directory '/' + case "$HOME" + set directory '~' + case '*' + set parent (__bobthefish_pretty_parent "$segment_dir") + set directory (__bobthefish_basename "$segment_dir") + end + + echo -n $parent + set_color -b $segment_basename_color + echo -ns $directory ' ' +end + +function __bobthefish_finish_segments -S -d 'Close open prompt segments' + if [ -n "$__bobthefish_current_bg" ] + set_color normal + set_color $__bobthefish_current_bg + echo -ns $right_black_arrow_glyph ' ' + end + + if [ "$theme_newline_cursor" = 'yes' ] + echo -ens "\n" + set_color $fish_color_autosuggestion + + if set -q theme_newline_prompt + echo -ens "$theme_newline_prompt" + else if [ "$theme_powerline_fonts" = "no" -a "$theme_nerd_fonts" != "yes" ] + echo -ns '> ' + else + echo -ns "$right_arrow_glyph " + end + else if [ "$theme_newline_cursor" = 'clean' ] + echo -ens "\n" + end + + set_color normal + set __bobthefish_current_bg +end + + +# ============================== +# Status segment +# ============================== + +function __bobthefish_prompt_status -S -a last_status -d 'Display flags for a non-zero exit status, root user, and background jobs' + set -l nonzero + set -l superuser + set -l bg_jobs + + # Last exit was nonzero + [ $last_status -ne 0 ] + and set nonzero 1 + + # If superuser (uid == 0) + # + # Note that iff the current user is root and '/' is not writeable by root this + # will be wrong. But I can't think of a single reason that would happen, and + # it is literally 99.5% faster to check it this way, so that's a tradeoff I'm + # willing to make. + [ -w / -o -w /private/ ] + and [ (id -u) -eq 0 ] + and set superuser 1 + + # Jobs display + if set -q AUTOJUMP_SOURCED + # Autojump special case: check if there are jobs besides the `autojump` + # job, since that one is (briefly) backgrounded every time we `cd` + set bg_jobs (jobs -c | string match -v --regex '(Command|autojump)' | wc -l) + [ "$bg_jobs" -eq 0 ] + and set bg_jobs # clear it out so it doesn't show when `0` + else + if [ "$theme_display_jobs_verbose" = 'yes' ] + set bg_jobs (jobs -p | wc -l) + [ "$bg_jobs" -eq 0 ] + and set bg_jobs # clear it out so it doesn't show when `0` + else + # `jobs -p` is faster if we redirect to /dev/null, because it exits + # after the first match. We'll use that unless the user wants to + # display the actual job count + jobs -p >/dev/null + and set bg_jobs 1 + end + end + + if [ "$nonzero" -o "$superuser" -o "$bg_jobs" ] + __bobthefish_start_segment $color_initial_segment_exit + if [ "$nonzero" ] + set_color normal + set_color -b $color_initial_segment_exit + if [ "$theme_show_exit_status" = 'yes' ] + echo -ns $last_status ' ' + else + echo -n $nonzero_exit_glyph + end + end + + if [ "$superuser" ] + set_color normal + if [ -z "$FAKEROOTKEY" ] + set_color -b $color_initial_segment_su + else + set_color -b $color_initial_segment_exit + end + + echo -n $superuser_glyph + end + + if [ "$bg_jobs" ] + set_color normal + set_color -b $color_initial_segment_jobs + if [ "$theme_display_jobs_verbose" = 'yes' ] + echo -ns $bg_job_glyph $bg_jobs ' ' + else + echo -n $bg_job_glyph + end + end + end +end + + +# ============================== +# Container and VM segments +# ============================== + +function __bobthefish_prompt_vagrant -S -d 'Display Vagrant status' + [ "$theme_display_vagrant" = 'yes' -a -f Vagrantfile ] + or return + + # .vagrant/machines/$machine/$provider/id + for file in .vagrant/machines/*/*/id + read -l id <"$file" + + if [ -n "$id" ] + switch "$file" + case '*/virtualbox/id' + __bobthefish_prompt_vagrant_vbox $id + case '*/vmware_fusion/id' + __bobthefish_prompt_vagrant_vmware $id + case '*/parallels/id' + __bobthefish_prompt_vagrant_parallels $id + end + end + end +end + +function __bobthefish_prompt_vagrant_vbox -S -a id -d 'Display VirtualBox Vagrant status' + set -l vagrant_status + set -l vm_status (VBoxManage showvminfo --machinereadable $id 2>/dev/null | command grep 'VMState=' | tr -d '"' | cut -d '=' -f 2) + + switch "$vm_status" + case 'running' + set vagrant_status "$vagrant_status$vagrant_running_glyph" + case 'poweroff' + set vagrant_status "$vagrant_status$vagrant_poweroff_glyph" + case 'aborted' + set vagrant_status "$vagrant_status$vagrant_aborted_glyph" + case 'saved' + set vagrant_status "$vagrant_status$vagrant_saved_glyph" + case 'stopping' + set vagrant_status "$vagrant_status$vagrant_stopping_glyph" + case '' + set vagrant_status "$vagrant_status$vagrant_unknown_glyph" + end + + [ -z "$vagrant_status" ] + and return + + __bobthefish_start_segment $color_vagrant + echo -ns $vagrant_status ' ' +end + +function __bobthefish_prompt_vagrant_vmware -S -a id -d 'Display VMWare Vagrant status' + set -l vagrant_status + if [ (pgrep -f "$id") ] + set vagrant_status "$vagrant_status$vagrant_running_glyph" + else + set vagrant_status "$vagrant_status$vagrant_poweroff_glyph" + end + + [ -z "$vagrant_status" ] + and return + + __bobthefish_start_segment $color_vagrant + echo -ns $vagrant_status ' ' +end + +function __bobthefish_prompt_vagrant_parallels -S -d 'Display Parallels Vagrant status' + set -l vagrant_status + set -l vm_status (prlctl list $id -o status 2>/dev/null | command tail -1) + + switch "$vm_status" + case 'running' + set vagrant_status "$vagrant_status$vagrant_running_glyph" + case 'stopped' + set vagrant_status "$vagrant_status$vagrant_poweroff_glyph" + case 'paused' + set vagrant_status "$vagrant_status$vagrant_saved_glyph" + case 'suspended' + set vagrant_status "$vagrant_status$vagrant_saved_glyph" + case 'stopping' + set vagrant_status "$vagrant_status$vagrant_stopping_glyph" + case '' + set vagrant_status "$vagrant_status$vagrant_unknown_glyph" + end + + [ -z "$vagrant_status" ] + and return + + __bobthefish_start_segment $color_vagrant + echo -ns $vagrant_status ' ' +end + +function __bobthefish_prompt_docker -S -d 'Display Docker machine name' + [ "$theme_display_docker_machine" = 'no' -o -z "$DOCKER_MACHINE_NAME" ] + and return + + __bobthefish_start_segment $color_vagrant + echo -ns $DOCKER_MACHINE_NAME ' ' +end + +function __bobthefish_k8s_context -S -d 'Get the current k8s context' + set -l config_paths "$HOME/.kube/config" + [ -n "$KUBECONFIG" ] + and set config_paths (string split ':' "$KUBECONFIG") $config_paths + + for file in $config_paths + [ -f "$file" ] + or continue + + while read -l key val + if [ "$key" = 'current-context:' ] + set -l context (string trim -c '"\' ' -- $val) + [ -z "$context" ] + and return 1 + + echo $context + return + end + end <$file + end + + return 1 +end + +function __bobthefish_k8s_namespace -S -d 'Get the current k8s namespace' + kubectl config view --minify --output "jsonpath={..namespace}" +end + +function __bobthefish_prompt_k8s_context -S -d 'Show current Kubernetes context' + [ "$theme_display_k8s_context" = 'yes' ] + or return + + set -l context (__bobthefish_k8s_context) + or return + + [ "$theme_display_k8s_namespace" = 'yes' ] + and set -l namespace (__bobthefish_k8s_namespace) + + [ -z $context -o "$context" = 'default' ] + and [ -z $namespace -o "$namespace" = 'default' ] + and return + + set -l segment $k8s_glyph " " $context + [ -n "$namespace" ] + and set segment $segment ":" $namespace + + __bobthefish_start_segment $color_k8s + echo -ns $segment " " +end + + +# ============================== +# User / hostname info segments +# ============================== + +# Polyfill for fish < 2.5.0 +if not type -q prompt_hostname + if not set -q __bobthefish_prompt_hostname + set -g __bobthefish_prompt_hostname (hostname | string replace -r '\..*' '') + end + + function prompt_hostname + echo $__bobthefish_prompt_hostname + end +end + +function __bobthefish_prompt_user -S -d 'Display current user and hostname' + [ "$theme_display_user" = 'yes' -o \( "$theme_display_user" != 'no' -a -n "$SSH_CLIENT" \) -o \( -n "$default_user" -a "$USER" != "$default_user" \) ] + and set -l display_user + + [ "$theme_display_sudo_user" = 'yes' -a -n "$SUDO_USER" ] + and set -l display_sudo_user + + [ "$theme_display_hostname" = 'yes' -o \( "$theme_display_hostname" != 'no' -a -n "$SSH_CLIENT" \) ] + and set -l display_hostname + + if set -q display_user + __bobthefish_start_segment $color_username + echo -ns (whoami) + end + + if set -q display_sudo_user + if set -q display_user + echo -ns ' ' + else + __bobthefish_start_segment $color_username + end + echo -ns "($SUDO_USER)" + end + + if set -q display_hostname + if set -q display_user + or set -q display_sudo_user + # reset colors without starting a new segment... + # (so we can have a bold username and non-bold hostname) + set_color normal + set_color -b $color_hostname[1] $color_hostname[2..-1] + echo -ns '@' (prompt_hostname) + else + __bobthefish_start_segment $color_hostname + echo -ns (prompt_hostname) + end + end + + set -q display_user + or set -q display_sudo_user + or set -q display_hostname + and echo -ns ' ' +end + + +# ============================== +# Virtual environment segments +# ============================== + +function __bobthefish_rvm_parse_ruby -S -a ruby_string -a scope -d 'Parse RVM Ruby string' + # Function arguments: + # - 'ruby-2.2.3@rails', 'jruby-1.7.19'... + # - 'default' or 'current' + set -l IFS @ + echo "$ruby_string" | read __ruby __rvm_{$scope}_ruby_gemset __ + set IFS - + echo "$__ruby" | read __rvm_{$scope}_ruby_interpreter __rvm_{$scope}_ruby_version __ + set -e __ruby + set -e __ +end + +function __bobthefish_rvm_info -S -d 'Current Ruby information from RVM' + # look for rvm install path + set -q rvm_path + or set -l rvm_path ~/.rvm /usr/local/rvm + + # More `sed`/`grep`/`cut` magic... + set -l __rvm_default_ruby (grep GEM_HOME $rvm_path/environments/default 2>/dev/null | sed -e"s/'//g" | sed -e's/.*\///') + set -l __rvm_current_ruby (rvm-prompt i v g) + + [ "$__rvm_default_ruby" = "$__rvm_current_ruby" ] + and return + + set -l __rvm_default_ruby_gemset + set -l __rvm_default_ruby_interpreter + set -l __rvm_default_ruby_version + set -l __rvm_current_ruby_gemset + set -l __rvm_current_ruby_interpreter + set -l __rvm_current_ruby_version + + # Parse default and current Rubies to global variables + __bobthefish_rvm_parse_ruby $__rvm_default_ruby default + __bobthefish_rvm_parse_ruby $__rvm_current_ruby current + # Show unobtrusive RVM prompt + + # If interpreter differs form default interpreter, show everything: + if [ "$__rvm_default_ruby_interpreter" != "$__rvm_current_ruby_interpreter" ] + if [ "$__rvm_current_ruby_gemset" = 'global' ] + rvm-prompt i v + else + rvm-prompt i v g + end + # If version differs form default version + else if [ "$__rvm_default_ruby_version" != "$__rvm_current_ruby_version" ] + if [ "$__rvm_current_ruby_gemset" = 'global' ] + rvm-prompt v + else + rvm-prompt v g + end + # If gemset differs form default or 'global' gemset, just show it + else if [ "$__rvm_default_ruby_gemset" != "$__rvm_current_ruby_gemset" ] + rvm-prompt g + end +end + +function __bobthefish_prompt_rubies -S -d 'Display current Ruby information' + [ "$theme_display_ruby" = 'no' ] + and return + + set -l ruby_version + if type -fq rvm-prompt + set ruby_version (__bobthefish_rvm_info) + else if type -fq rbenv + set ruby_version (rbenv version-name) + # Don't show global ruby version... + set -q RBENV_ROOT + or set -l RBENV_ROOT $HOME/.rbenv + + [ -e "$RBENV_ROOT/version" ] + and read -l global_ruby_version <"$RBENV_ROOT/version" + + [ "$global_ruby_version" ] + or set -l global_ruby_version system + + [ "$ruby_version" = "$global_ruby_version" ] + and return + else if type -q chruby # chruby is implemented as a function, so omitting the -f is intentional + set ruby_version $RUBY_VERSION + else if type -fq asdf + set -l asdf_current_ruby (asdf current ruby 2>/dev/null) + or return + + echo "$asdf_current_ruby" | read -l asdf_ruby_version asdf_provenance + + # If asdf changes their ruby version provenance format, update this to match + [ (string trim -- "$asdf_provenance") = "(set by $HOME/.tool-versions)" ] + and return + + set ruby_version $asdf_ruby_version + end + + [ -z "$ruby_version" ] + and return + + __bobthefish_start_segment $color_rvm + echo -ns $ruby_glyph $ruby_version ' ' +end + +function __bobthefish_virtualenv_python_version -S -d 'Get current Python version' + switch (python --version 2>&1 | tr '\n' ' ') + case 'Python 2*PyPy*' + echo $pypy_glyph + case 'Python 3*PyPy*' + echo -s $pypy_glyph $superscript_glyph[3] + case 'Python 2*' + echo $superscript_glyph[2] + case 'Python 3*' + echo $superscript_glyph[3] + end +end + +function __bobthefish_prompt_virtualfish -S -d "Display current Python virtual environment (only for virtualfish, virtualenv's activate.fish changes prompt by itself) or conda environment." + [ "$theme_display_virtualenv" = 'no' -o -z "$VIRTUAL_ENV" -a -z "$CONDA_DEFAULT_ENV" ] + and return + + set -l version_glyph (__bobthefish_virtualenv_python_version) + + if [ "$version_glyph" ] + __bobthefish_start_segment $color_virtualfish + echo -ns $virtualenv_glyph $version_glyph ' ' + end + + if [ "$VIRTUAL_ENV" ] + echo -ns (basename "$VIRTUAL_ENV") ' ' + else if [ "$CONDA_DEFAULT_ENV" ] + echo -ns (basename "$CONDA_DEFAULT_ENV") ' ' + end +end + +function __bobthefish_prompt_virtualgo -S -d 'Display current Go virtual environment' + [ "$theme_display_virtualgo" = 'no' -o -z "$VIRTUALGO" ] + and return + + __bobthefish_start_segment $color_virtualgo + echo -ns $go_glyph ' ' (basename "$VIRTUALGO") ' ' + set_color normal +end + +function __bobthefish_prompt_desk -S -d 'Display current desk environment' + [ "$theme_display_desk" = 'no' -o -z "$DESK_ENV" ] + and return + + __bobthefish_start_segment $color_desk + echo -ns $desk_glyph ' ' (basename -a -s ".fish" "$DESK_ENV") ' ' + set_color normal +end + +function __bobthefish_prompt_nvm -S -d 'Display current node version through NVM' + [ "$theme_display_nvm" = 'yes' -a -n "$NVM_DIR" ] + or return + + set -l node_version (nvm current 2> /dev/null) + + [ -z $node_version -o "$node_version" = 'none' -o "$node_version" = 'system' ] + and return + + __bobthefish_start_segment $color_nvm + echo -ns $node_glyph $node_version ' ' + set_color normal +end + +function __bobthefish_prompt_nix -S -d 'Display current nix environment' + [ "$theme_display_nix" = 'no' -o -z "$IN_NIX_SHELL" ] + and return + + __bobthefish_start_segment $color_nix + echo -ns $nix_glyph $IN_NIX_SHELL ' ' + + set_color normal +end + +# ============================== +# VCS segments +# ============================== + +function __bobthefish_prompt_hg -S -a hg_root_dir -a real_pwd -d 'Display the actual hg state' + set -l dirty (command hg stat; or echo -n '*') + + set -l flags "$dirty" + [ "$flags" ] + and set flags "" + + set -l flag_colors $color_repo + if [ "$dirty" ] + set flag_colors $color_repo_dirty + end + + __bobthefish_path_segment $hg_root_dir + + __bobthefish_start_segment $flag_colors + echo -ns $hg_glyph ' ' + + __bobthefish_start_segment $flag_colors + echo -ns (__bobthefish_hg_branch) $flags ' ' + set_color normal + + set -l project_pwd (__bobthefish_project_pwd $hg_root_dir $real_pwd) + if [ "$project_pwd" ] + if [ -w "$real_pwd" ] + __bobthefish_start_segment $color_path + else + __bobthefish_start_segment $color_path_nowrite + end + + echo -ns $project_pwd ' ' + end +end + +function __bobthefish_prompt_git -S -a git_root_dir -a real_pwd -d 'Display the actual git state' + set -l dirty '' + if [ "$theme_display_git_dirty" != 'no' ] + set -l show_dirty (command git config --bool bash.showDirtyState 2>/dev/null) + if [ "$show_dirty" != 'false' ] + set dirty (command git diff --no-ext-diff --quiet --exit-code 2>/dev/null; or echo -n "$git_dirty_glyph") + if [ "$dirty" -a "$theme_display_git_dirty_verbose" = 'yes' ] + set dirty "$dirty"(__bobthefish_git_dirty_verbose) + end + end + end + + set -l staged (command git diff --cached --no-ext-diff --quiet --exit-code 2>/dev/null; or echo -n "$git_staged_glyph") + set -l stashed (__bobthefish_git_stashed) + set -l ahead (__bobthefish_git_ahead) + + set -l new '' + if [ "$theme_display_git_untracked" != 'no' ] + set -l show_untracked (command git config --bool bash.showUntrackedFiles 2>/dev/null) + if [ "$show_untracked" != 'false' ] + set new (command git ls-files --other --exclude-standard --directory --no-empty-directory 2>/dev/null) + if [ "$new" ] + set new "$git_untracked_glyph" + end + end + end + + set -l flags "$dirty$staged$stashed$ahead$new" + + [ "$flags" ] + and set flags " $flags" + + set -l flag_colors $color_repo + if [ "$dirty" ] + set flag_colors $color_repo_dirty + else if [ "$staged" ] + set flag_colors $color_repo_staged + end + + __bobthefish_path_segment $git_root_dir + + __bobthefish_start_segment $flag_colors + echo -ns (__bobthefish_git_branch) $flags ' ' + set_color normal + + if [ "$theme_git_worktree_support" != 'yes' ] + set -l project_pwd (__bobthefish_project_pwd $git_root_dir $real_pwd) + if [ "$project_pwd" ] + if [ -w "$real_pwd" ] + __bobthefish_start_segment $color_path + else + __bobthefish_start_segment $color_path_nowrite + end + + echo -ns $project_pwd ' ' + end + return + end + + set -l project_pwd (command git rev-parse --show-prefix 2>/dev/null | string trim --right --chars=/) + set -l work_dir (command git rev-parse --show-toplevel 2>/dev/null) + + # only show work dir if it's a parent… + if [ "$work_dir" ] + switch $real_pwd/ + case $work_dir/\* + string match "$git_root_dir*" $work_dir >/dev/null + and set work_dir (string sub -s (math 1 + (string length $git_root_dir)) $work_dir) + case \* + set -e work_dir + end + end + + if [ "$project_pwd" -o "$work_dir" ] + set -l colors $color_path + if not [ -w "$real_pwd" ] + set colors $color_path_nowrite + end + + __bobthefish_start_segment $colors + + # handle work_dir != project dir + if [ "$work_dir" ] + set -l work_parent (__bobthefish_dirname $work_dir) + if [ "$work_parent" ] + echo -n "$work_parent/" + end + + set_color normal + set_color -b $color_repo_work_tree + echo -n (__bobthefish_basename $work_dir) + + set_color normal + set_color -b $colors + [ "$project_pwd" ] + and echo -n '/' + end + + echo -ns $project_pwd ' ' + else + set project_pwd $real_pwd + + string match "$git_root_dir*" $project_pwd >/dev/null + and set project_pwd (string sub -s (math 1 + (string length $git_root_dir)) $project_pwd) + + set project_pwd (string trim --left --chars=/ -- $project_pwd) + + if [ "$project_pwd" ] + set -l colors $color_path + if not [ -w "$real_pwd" ] + set colors $color_path_nowrite + end + + __bobthefish_start_segment $colors + + echo -ns $project_pwd ' ' + end + end +end + +function __bobthefish_prompt_dir -S -a real_pwd -d 'Display a shortened form of the current directory' + __bobthefish_path_segment "$real_pwd" +end + + +# ============================== +# Apply theme +# ============================== + +function fish_prompt -d 'bobthefish, a fish theme optimized for awesome' + # Save the last status for later (do this before anything else) + set -l last_status $status + + # Use a simple prompt on dumb terminals. + if [ "$TERM" = "dumb" ] + echo "> " + return + end + + __bobthefish_glyphs + __bobthefish_colors $theme_color_scheme + + type -q bobthefish_colors + and bobthefish_colors + + # Start each line with a blank slate + set -l __bobthefish_current_bg + + # Status flags and input mode + __bobthefish_prompt_status $last_status + + # User / hostname info + __bobthefish_prompt_user + + # Containers and VMs + __bobthefish_prompt_vagrant + __bobthefish_prompt_docker + __bobthefish_prompt_k8s_context + + # Virtual environments + __bobthefish_prompt_nix + __bobthefish_prompt_desk + __bobthefish_prompt_rubies + __bobthefish_prompt_virtualfish + __bobthefish_prompt_virtualgo + __bobthefish_prompt_nvm + + set -l real_pwd (__bobthefish_pwd) + + # VCS + set -l git_root_dir (__bobthefish_git_project_dir $real_pwd) + set -l hg_root_dir (__bobthefish_hg_project_dir $real_pwd) + + if [ "$git_root_dir" -a "$hg_root_dir" ] + # only show the closest parent + switch $git_root_dir + case $hg_root_dir\* + __bobthefish_prompt_git $git_root_dir $real_pwd + case \* + __bobthefish_prompt_hg $hg_root_dir $real_pwd + end + else if [ "$git_root_dir" ] + __bobthefish_prompt_git $git_root_dir $real_pwd + else if [ "$hg_root_dir" ] + __bobthefish_prompt_hg $hg_root_dir $real_pwd + else + __bobthefish_prompt_dir $real_pwd + end + + __bobthefish_finish_segments +end diff --git a/files/fish/functions/fisher.fish b/files/fish/functions/fisher.fish new file mode 100644 index 0000000..1d63c33 --- /dev/null +++ b/files/fish/functions/fisher.fish @@ -0,0 +1,435 @@ +set -g fisher_version 3.2.10 + +function fisher -a cmd -d "fish package manager" + set -q XDG_CACHE_HOME; or set XDG_CACHE_HOME ~/.cache + set -q XDG_CONFIG_HOME; or set XDG_CONFIG_HOME ~/.config + + set -g fish_config $XDG_CONFIG_HOME/fish + set -g fisher_cache $XDG_CACHE_HOME/fisher + set -g fisher_config $XDG_CONFIG_HOME/fisher + + set -q fisher_path; or set -g fisher_path $fish_config + set -g fishfile $fish_config/fishfile + + for path in {$fish_config,$fisher_path}/{functions,completions,conf.d} $fisher_cache + if test ! -d $path + command mkdir -p $path + end + end + + if test ! -e $fisher_path/completions/fisher.fish + echo "fisher complete" >$fisher_path/completions/fisher.fish + _fisher_complete + end + + if test -e $fisher_path/conf.d/fisher.fish + switch "$version" + case \*-\* + command rm -f $fisher_path/conf.d/fisher.fish + case 2\* + case \* + command rm -f $fisher_path/conf.d/fisher.fish + end + else + switch "$version" + case \*-\* + case 2\* + echo "fisher copy-user-key-bindings" >$fisher_path/conf.d/fisher.fish + end + end + + # 2019-10-22: temp code, migrates fishfile from old path back to $fish_config + if test -e "$fisher_path/fishfile"; and test ! -e "$fishfile" + command mv -f "$fisher_path/fishfile" "$fishfile" + end + + switch "$cmd" + case {,self-}complete + _fisher_complete + case copy-user-key-bindings + _fisher_copy_user_key_bindings + case ls + set -e argv[1] + if test -s "$fishfile" + set -l file (_fisher_fmt <$fishfile | _fisher_parse -R | command sed "s|@.*||") + _fisher_ls | _fisher_fmt | command awk -v FILE="$file" " + BEGIN { for (n = split(FILE, f); ++i <= n;) file[f[i]] } \$0 in file && /$argv[1]/ + " | command sed "s|^$HOME|~|" + end + case self-update + _fisher_self_update (status -f) + case self-uninstall + _fisher_self_uninstall + case {,-}-v{ersion,} + echo "fisher version $fisher_version" (status -f | command sed "s|^$HOME|~|") + case {,-}-h{elp,} + _fisher_help + case "" + _fisher_commit -- + case add rm + if not isatty + while read -l arg + set argv $argv $arg + end + end + + if test (count $argv) = 1 + echo "fisher: invalid number of arguments" >&2 + _fisher_help >&2 + return 1 + end + + _fisher_commit $argv + case \* + echo "fisher: unknown flag or command \"$cmd\"" >&2 + _fisher_help >&2 + return 1 + end +end + +function _fisher_complete + complete -ec fisher + complete -xc fisher -n __fish_use_subcommand -a add -d "Add packages" + complete -xc fisher -n __fish_use_subcommand -a rm -d "Remove packages" + complete -xc fisher -n __fish_use_subcommand -a ls -d "List installed packages matching REGEX" + complete -xc fisher -n __fish_use_subcommand -a --help -d "Show usage help" + complete -xc fisher -n __fish_use_subcommand -a --version -d "$fisher_version" + complete -xc fisher -n __fish_use_subcommand -a self-update -d "Update to the latest version" + for pkg in (fisher ls) + complete -xc fisher -n "__fish_seen_subcommand_from rm" -a $pkg + end +end + +function _fisher_copy_user_key_bindings + if functions -q fish_user_key_bindings + functions -c fish_user_key_bindings fish_user_key_bindings_copy + end + function fish_user_key_bindings + for file in $fisher_path/conf.d/*_key_bindings.fish + source $file >/dev/null 2>/dev/null + end + if functions -q fish_user_key_bindings_copy + fish_user_key_bindings_copy + end + end +end + +function _fisher_ls + for pkg in $fisher_config/*/*/* + command readlink $pkg; or echo $pkg + end +end + +function _fisher_fmt + command sed "s|^[[:space:]]*||;s|^$fisher_config/||;s|^~|$HOME|;s|^\.\/*|$PWD/|;s|^https*:/*||;s|^github\.com/||;s|/*\$||" +end + +function _fisher_help + echo "usage: fisher add Add packages" + echo " fisher rm Remove packages" + echo " fisher Update all packages" + echo " fisher ls [] List installed packages matching " + echo " fisher --help Show this help" + echo " fisher --version Show the current version" + echo " fisher self-update Update to the latest version" + echo " fisher self-uninstall Uninstall from your system" + echo "examples:" + echo " fisher add jethrokuan/z rafaelrinaldi/pure" + echo " fisher add gitlab.com/foo/bar@v2" + echo " fisher add ~/path/to/local/pkg" + echo " fisher add &2 + command curl -s "$url?nocache" >$file. + + set -l next_version (command awk '{ print $4 } { exit }' <$file.) + switch "$next_version" + case "" $fisher_version + command rm -f $file. + if test -z "$next_version" + echo "fisher: cannot update fisher -- are you offline?" >&2 + return 1 + end + echo "fisher is already up-to-date" >&2 + case \* + echo "linking $file" | command sed "s|$HOME|~|" >&2 + command mv -f $file. $file + source $file + echo "updated to fisher $fisher_version -- hooray!" >&2 + _fisher_complete + end +end + +function _fisher_self_uninstall + for pkg in (_fisher_ls) + _fisher_rm $pkg + end + + for file in $fisher_cache $fisher_config $fisher_path/{functions,completions,conf.d}/fisher.fish $fishfile + echo "removing $file" + command rm -Rf $file 2>/dev/null + end | command sed "s|$HOME|~|" >&2 + + for name in (set -n | command awk '/^fisher_/') + set -e "$name" + end + + functions -e (functions -a | command awk '/^_fisher/') fisher + complete -c fisher --erase +end + +function _fisher_commit -a cmd + set -e argv[1] + set -l elapsed (_fisher_now) + + if test ! -e "$fishfile" + command touch $fishfile + echo "created new fishfile in $fishfile" | command sed "s|$HOME|~|" >&2 + end + + set -l old_pkgs (_fisher_ls | _fisher_fmt) + for pkg in (_fisher_ls) + _fisher_rm $pkg + end + command rm -Rf $fisher_config + command mkdir -p $fisher_config + + set -l next_pkgs (_fisher_fmt <$fishfile | _fisher_parse -R $cmd (printf "%s\n" $argv | _fisher_fmt)) + set -l actual_pkgs (_fisher_fetch $next_pkgs) + set -l updated_pkgs + for pkg in $old_pkgs + if contains -- $pkg $actual_pkgs + set updated_pkgs $updated_pkgs $pkg + end + end + + if test -z "$actual_pkgs$updated_pkgs$old_pkgs$next_pkgs" + echo "fisher: nothing to commit -- try adding some packages" >&2 + return 1 + end + + set -l out_pkgs + if test "$cmd" = "rm" + set out_pkgs $next_pkgs + else + for pkg in $next_pkgs + if contains -- (echo $pkg | command sed "s|@.*||") $actual_pkgs + set out_pkgs $out_pkgs $pkg + end + end + end + + printf "%s\n" (_fisher_fmt <$fishfile | _fisher_parse -W $cmd $out_pkgs | command sed "s|^$HOME|~|") >$fishfile + + _fisher_complete + + command awk -v A=(count $actual_pkgs) -v U=(count $updated_pkgs) -v O=(count $old_pkgs) -v E=(_fisher_now $elapsed) ' + BEGIN { + res = fmt("removed", O - U, fmt("updated", U, fmt("added", A - U))) + printf((res ? res : "done") " in %.2fs\n", E / 1000) + } + function fmt(action, n, s) { + return n ? (s ? s ", " : s) action " " n " package" (n > 1 ? "s" : "") : s + } + ' >&2 +end + +function _fisher_parse -a mode cmd + set -e argv[1..2] + command awk -v FS="[[:space:]]*#+" -v MODE="$mode" -v CMD="$cmd" -v ARGSTR="$argv" ' + BEGIN { + for (n = split(ARGSTR, a, " "); i++ < n;) pkgs[getkey(a[i])] = a[i] + } + !NF { next } { k = getkey($1) } + MODE == "-R" && !(k in pkgs) && $0 = $1 + MODE == "-W" && (/^#/ || k in pkgs || CMD != "rm") { print pkgs[k] (sub($1, "") ? $0 : "") } + MODE == "-W" || CMD == "rm" { delete pkgs[k] } + END { + for (k in pkgs) { + if (CMD != "rm" || MODE == "-W") print pkgs[k] + else print "fisher: cannot remove \""k"\" -- package is not in fishfile" > "/dev/stderr" + } + } + function getkey(s, a) { + return (split(s, a, /@+|:/) > 2) ? a[2]"/"a[1]"/"a[3] : a[1] + } + ' +end + +function _fisher_fetch + set -l pkg_jobs + set -l out_pkgs + set -l next_pkgs + set -l local_pkgs + set -q fisher_user_api_token; and set -l curl_opts -u $fisher_user_api_token + + for pkg in $argv + switch $pkg + case \~\* /\* + set -l path (echo "$pkg" | command sed "s|^~|$HOME|") + if test -e "$path" + set local_pkgs $local_pkgs $path + else + echo "fisher: cannot add \"$pkg\" -- is this a valid file?" >&2 + end + continue + end + + command awk -v PKG="$pkg" -v FS=/ ' + BEGIN { + if (split(PKG, tmp, /@+|:/) > 2) { + if (tmp[4]) sub("@"tmp[4], "", PKG) + print PKG "\t" tmp[2]"/"tmp[1]"/"tmp[3] "\t" (tmp[4] ? tmp[4] : "master") + } else { + pkg = split(PKG, _, "/") <= 2 ? "github.com/"tmp[1] : tmp[1] + tag = tmp[2] ? tmp[2] : "master" + print (\ + pkg ~ /^github/ ? "https://codeload."pkg"/tar.gz/"tag : \ + pkg ~ /^gitlab/ ? "https://"pkg"/-/archive/"tag"/"tmp[split(pkg, tmp, "/")]"-"tag".tar.gz" : \ + pkg ~ /^bitbucket/ ? "https://"pkg"/get/"tag".tar.gz" : pkg \ + ) "\t" pkg + } + } + ' | read -l url pkg branch + + if test ! -d "$fisher_config/$pkg" + fish -c " + echo fetching $url >&2 + command mkdir -p $fisher_config/$pkg $fisher_cache/(command dirname $pkg) + if test ! -z \"$branch\" + command git clone $url $fisher_config/$pkg --branch $branch --depth 1 2>/dev/null + or echo fisher: cannot clone \"$url\" -- is this a valid url\? >&2 + else if command curl $curl_opts -Ss -w \"\" $url 2>&1 | command tar -xzf- -C $fisher_config/$pkg 2>/dev/null + command rm -Rf $fisher_cache/$pkg + command mv -f $fisher_config/$pkg/* $fisher_cache/$pkg + command rm -Rf $fisher_config/$pkg + command cp -Rf {$fisher_cache,$fisher_config}/$pkg + else if test -d \"$fisher_cache/$pkg\" + echo fisher: cannot connect to server -- looking in \"$fisher_cache/$pkg\" | command sed 's|$HOME|~|' >&2 + command cp -Rf $fisher_cache/$pkg $fisher_config/$pkg/.. + else + command rm -Rf $fisher_config/$pkg + echo fisher: cannot add \"$pkg\" -- is this a valid package\? >&2 + end + " >/dev/null & + set pkg_jobs $pkg_jobs (_fisher_jobs --last) + set next_pkgs $next_pkgs "$fisher_config/$pkg" + end + end + + if set -q pkg_jobs[1] + while for job in $pkg_jobs + contains -- $job (_fisher_jobs); and break + end + end + for pkg in $next_pkgs + if test -d "$pkg" + set out_pkgs $out_pkgs $pkg + _fisher_add $pkg + end + end + end + + set -l local_prefix $fisher_config/local/$USER + if test ! -d "$local_prefix" + command mkdir -p $local_prefix + end + for pkg in $local_pkgs + set -l target $local_prefix/(command basename $pkg) + if test ! -L "$target" + command ln -sf $pkg $target + set out_pkgs $out_pkgs $pkg + _fisher_add $pkg --link + end + end + + if set -q out_pkgs[1] + _fisher_fetch ( + for pkg in $out_pkgs + if test -s "$pkg/fishfile" + _fisher_fmt <$pkg/fishfile | _fisher_parse -R + end + end) + printf "%s\n" $out_pkgs | _fisher_fmt + end +end + +function _fisher_add -a pkg opts + for src in $pkg/{functions,completions,conf.d}/**.* $pkg/*.fish + set -l target (command basename $src) + switch $src + case $pkg/conf.d\* + set target $fisher_path/conf.d/$target + case $pkg/completions\* + set target $fisher_path/completions/$target + case $pkg/{functions,}\* + switch $target + case uninstall.fish + continue + case {init,key_bindings}.fish + set target $fisher_path/conf.d/(command basename $pkg)\_$target + case \* + set target $fisher_path/functions/$target + end + end + echo "linking $target" | command sed "s|$HOME|~|" >&2 + if set -q opts[1] + command ln -sf $src $target + else + command cp -f $src $target + end + switch $target + case \*.fish + source $target >/dev/null 2>/dev/null + end + end +end + +function _fisher_rm -a pkg + for src in $pkg/{conf.d,completions,functions}/**.* $pkg/*.fish + set -l target (command basename $src) + set -l filename (command basename $target .fish) + switch $src + case $pkg/conf.d\* + test "$filename.fish" = "$target"; and emit "$filename"_uninstall + set target conf.d/$target + case $pkg/completions\* + test "$filename.fish" = "$target"; and complete -ec $filename + set target completions/$target + case $pkg/{,functions}\* + test "$filename.fish" = "$target"; and functions -e $filename + switch $target + case uninstall.fish + source $src + continue + case {init,key_bindings}.fish + set target conf.d/(command basename $pkg)\_$target + case \* + set target functions/$target + end + end + command rm -f $fisher_path/$target + end + if not functions -q fish_prompt + source "$__fish_datadir$__fish_data_dir/functions/fish_prompt.fish" + end +end + +function _fisher_jobs + jobs $argv | command awk '/^[0-9]+\t/ { print $1 }' +end + +function _fisher_now -a elapsed + switch (command uname) + case Darwin \*BSD + command perl -MTime::HiRes -e 'printf("%.0f\n", (Time::HiRes::time() * 1000) - $ARGV[0])' $elapsed + case \* + math (command date "+%s%3N") - "0$elapsed" + end +end diff --git a/files/fish/functions/l.fish b/files/fish/functions/l.fish new file mode 100644 index 0000000..172702c --- /dev/null +++ b/files/fish/functions/l.fish @@ -0,0 +1,4 @@ +# Defined in - @ line 1 +function l --wraps=la --description 'alias l la' + la $argv; +end diff --git a/files/fish/functions/p.fish b/files/fish/functions/p.fish new file mode 100644 index 0000000..679d332 --- /dev/null +++ b/files/fish/functions/p.fish @@ -0,0 +1,4 @@ +# Defined via `source` +function p --wraps=pnpm --description 'alias p pnpm' + pnpm $argv; +end diff --git a/files/fish/functions/px.fish b/files/fish/functions/px.fish new file mode 100644 index 0000000..7e5b106 --- /dev/null +++ b/files/fish/functions/px.fish @@ -0,0 +1,3 @@ +function px --wraps=pnpx --description 'alias px pnpx' + pnpx $argv; +end diff --git a/files/omf/bundle b/files/omf/bundle new file mode 100644 index 0000000..abef50c --- /dev/null +++ b/files/omf/bundle @@ -0,0 +1,2 @@ +theme bobthefish +theme default diff --git a/files/omf/channel b/files/omf/channel new file mode 100644 index 0000000..2bf5ad0 --- /dev/null +++ b/files/omf/channel @@ -0,0 +1 @@ +stable diff --git a/files/omf/theme b/files/omf/theme new file mode 100644 index 0000000..ff8a58d --- /dev/null +++ b/files/omf/theme @@ -0,0 +1 @@ +bobthefish diff --git a/install.conf.yaml b/install.conf.yaml index 4af5a18..0c1c59c 100644 --- a/install.conf.yaml +++ b/install.conf.yaml @@ -1,15 +1,17 @@ - defaults: - link: - create: true - relink: true - force: true + link: + create: true + relink: true + force: true - clean: ["~"] - link: - ~/.gitconfig: files/gitconfig - ~/.vim: files/vim - ~/.vimrc: files/vimrc + ~/.gitconfig: files/gitconfig + ~/.vim: files/vim + ~/.vimrc: files/vimrc + ~/.config/fish: files/fish + ~/.config/omf: files/omf - shell: - - [git submodule update --init --recursive, Installing submodules] + - [git submodule update --init --recursive, Installing submodules]