fisher/fisher.fish
Jorge Bucaran d6986af3a6
Add new sub command ls-remote to list what plugins you can install.
Running fisher ls-remote will query the GitHub API for all the
repos in the fisherman org and retrieve the JSON file which is
saved to .cache/fisherman/.index.json.

This file is updated every half and hour whenever you run the
command again. This number is subject to change in the future
as we learn how people are actually using this option.

The ls-remote option can take --format=<fmt string> option used
to customize the list output.

By default, it shows only names and breaks it into columns as
wide as your terminal window.

<fmt string> can contain \t tabs or \n line breaks and one or
more of the following variables with information about plugins.

  *  %name
  *  %info
  *  %url
  *  %stars
2016-04-29 04:10:21 +09:00

2014 lines
50 KiB
Fish

function fisher
set -g fisher_version "2.1.13"
set -g fisher_spinners ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏
function __fisher_show_spinner
if not set -q __fisher_fg_spinner[1]
set -g __fisher_fg_spinner $fisher_spinners
end
printf " $__fisher_fg_spinner[1]\r" > /dev/stderr
set -e __fisher_fg_spinner[1]
end
set -l config_home $XDG_CONFIG_HOME
set -l cache_home $XDG_CACHE_HOME
if test -z "$config_home"
set config_home ~/.config
end
if test -z "$cache_home"
set cache_home ~/.cache
end
if test -z "$fish_config"
set -g fish_config "$config_home/fish"
end
if test -z "$fisher_config"
set -g fisher_config "$config_home/fisherman"
end
if test -z "$fisher_cache"
set -g fisher_cache "$cache_home/fisherman"
end
if test -z "$fisher_bundle"
set -g fisher_bundle "$fish_config/fishfile"
end
if not command mkdir -p "$fish_config/"{conf.d,functions,completions} "$fisher_config" "$fisher_cache"
__fisher_log error "
I couldn't create the fisherman configuration.
You need write permissions in these directories:
$fish_config
$fisher_config
$fisher_cache
" > /dev/stderr
return 1
end
set -l completions "$fish_config/completions/fisher.fish"
if test ! -e "$completions"
__fisher_completions_write > "$completions"
source "$completions"
end
set -g __fisher_stdout /dev/stdout
set -g __fisher_stderr /dev/stderr
for i in -q --quiet
if set -l index (builtin contains --index -- $i $argv)
set -e argv[$index]
set __fisher_stdout /dev/null
set __fisher_stderr /dev/null
break
end
end
set -l cmd
set -l value
switch "$argv[1]"
case i install
set -e argv[1]
set cmd "install"
case u up update
set -e argv[1]
set cmd "update"
case r rm remove uninstall
set -e argv[1]
set cmd "rm"
case l ls list
set -e argv[1]
set cmd "ls"
case ls-remote
set -e argv[1]
set cmd "ls-remote"
switch "$argv[1]"
case --format\*
set value (printf "%s\n" "$argv" | command sed 's|^--[^= ]*[= ]\(.*\)|\1|')
end
case h help
set -e argv[1]
__fisher_help $argv
case --help
set -e argv[1]
__fisher_help
case -h
__fisher_usage > /dev/stderr
case -v --version
set -l home ~
printf "fisherman version $fisher_version %s\n" (__fisher_plugin_normalize_path (status -f) | command awk -v home="$home" '{ sub(home, "~") } //')
return
case -- ""
set -e argv[1]
if test -z "$argv"
set cmd "default"
else
set cmd "install"
end
case self-uninstall
set -e argv[1]
__fisher_self_uninstall $argv
return
case -\*\?
printf "fisher: '%s' is not a valid option\n" "$argv[1]" > /dev/stderr
__fisher_usage > /dev/stderr
return 1
case \*
set cmd "install"
end
set -l elapsed (__fisher_get_epoch_in_ms)
set -l items (
if test ! -z "$argv"
printf "%s\n" $argv | command awk '
/^(--|-).*/ { next }
/^omf\// {
sub(/^omf\//, "oh-my-fish/")
if ($0 !~ /(theme|plugin)-/) {
sub(/^oh-my-fish\//, "oh-my-fish/plugin-")
}
}
!seen[$0]++
'
end
)
if test -z "$items" -a "$cmd" = "default"
if isatty
touch "$fisher_bundle"
set items (__fisher_read_bundle_file < "$fisher_bundle")
set cmd "install"
if test -z "$items"
__fisher_usage > /dev/stderr
return
end
end
end
switch "$cmd"
case install
if not __fisher_install $items
return
end
__fisher_log okay "Done in @"(__fisher_get_epoch_in_ms $elapsed | __fisher_humanize_duration)"@" $__fisher_stderr
case update
if isatty
if test -z "$items"
__fisher_self_update
set items (__fisher_list | command sed 's/^[@* ]*//')
end
else
__fisher_parse_column_output | __fisher_read_bundle_file | read -laz _items
set items $items $_items
end
__fisher_update $items
__fisher_log okay "Done in @"(__fisher_get_epoch_in_ms $elapsed | __fisher_humanize_duration)"@" $__fisher_stderr
case ls
if test "$argv" -ge 0 -o "$argv" = -
set items (__fisher_list)
set -l count (count $items)
if test "$count" -ge 10
printf "%s\n" $items | column -c$argv
else if test "$count" -ge 1
printf "%s\n" $items
end
else
__fisher_list_plugin_directory $argv
end
case ls-remote
__fisher_list_remote "$value"
case rm
if test -z "$items"
__fisher_parse_column_output | __fisher_read_bundle_file | read -az items
end
if test (count $items) -le 1
function __fisher_show_spinner
end
end
if test ! -z "$items"
for i in $items
set -l name (__fisher_plugin_get_names "$i")[1]
__fisher_plugin_disable "$fisher_config/$name"
__fisher_show_spinner
end
__fisher_log okay "Done in @"(__fisher_get_epoch_in_ms $elapsed | __fisher_humanize_duration)"@" $__fisher_stderr
end
end
complete -c fisher --erase
set -l config $fisher_config/*
set -l cache $fisher_cache/*
if test -z "$config"
echo > $fisher_bundle
else
__fisher_plugin_get_url_info -- $config > $fisher_bundle
complete -xc fisher -n "__fish_seen_subcommand_from u up update r rm remove uninstall" -a "(printf '%s\n' $config | command sed 's|.*/||')"
complete -xc fisher -n "__fish_seen_subcommand_from u up update r rm remove uninstall" -a "$fisher_active_prompt" -d "Prompt"
end
if test ! -z "$cache"
printf "%s\n" $cache | command awk -v _config="$config" '
BEGIN {
count = split(_config, config, " ")
}
{
sub(/.*\//, "")
for (i = 1; i <= count; i++) {
sub(/.*\//, "", config[i])
if (config[i] == $0) {
next
}
}
}
//
' | while read -l plugin
if __fisher_plugin_is_prompt "$fisher_cache/$plugin"
complete -xc fisher -n "__fish_seen_subcommand_from i in install" -a "$plugin" -d "Prompt"
complete -xc fisher -n "not __fish_seen_subcommand_from u up update r rm remove uninstall l ls list h help" -a "$plugin" -d "Prompt"
else
complete -xc fisher -n "__fish_seen_subcommand_from i in install" -a "$plugin" -d "Plugin"
complete -xc fisher -n "not __fish_seen_subcommand_from u up update r rm remove uninstall l ls list h help" -a "$plugin" -d "Plugin"
end
end
end
return 0
end
function __fisher_install
if test -z "$argv"
__fisher_read_bundle_file | read -az argv
end
set -e __fisher_fetch_plugins_state
if set -l fetched (__fisher_plugin_fetch_items (__fisher_plugin_get_missing $argv))
if test -z "$fetched"
set -l count (count $argv)
__fisher_log okay "
No plugins to install or dependencies missing.
" $__fisher_stderr
return 1
end
for i in $fetched
__fisher_plugin_enable "$fisher_config/$i"
end
else
__fisher_log error "
There was an error cloning @$fetched@ or more plugin/s.
" $__fisher_stderr
__fisher_log info "
Try using a namespace before the plugin name: @omf@/$fetched
" $__fisher_stderr
return 1
end
end
function __fisher_plugin_fetch_items
__fisher_show_spinner
set -l jobs
set -l links
set -l white
set -l count (count $argv)
if test "$count" -eq 0
return
end
switch "$__fisher_fetch_plugins_state"
case ""
if test "$count" = 1 -a -d "$argv[1]"
if test "$argv[1]" = "$PWD"
set -l home ~
set -l name (printf "%s\n" "$argv[1]" | command sed "s|$home|~|")
__fisher_log info "Installing @""$name""@ " $__fisher_stderr
else
set -l name (printf "%s\n" "$argv[1]" | command sed "s|$PWD/||")
__fisher_log info "Installing @""$name""@ " $__fisher_stderr
end
else
__fisher_log info "Installing @$count@ plugin/s" $__fisher_stderr
end
set -g __fisher_fetch_plugins_state "fetching"
case "fetching"
__fisher_log info "Installing @$count@ dependencies" $__fisher_stderr
set -g __fisher_fetch_plugins_state "done"
case "done"
end
for i in $argv
set -l names
switch "$i"
case \*gist.github.com\*
__fisher_log okay "Resolving gist name."
if not set names (__fisher_get_plugin_name_from_gist "$i") ""
__fisher_log error "
I couldn't clone your gist:
@$i@
"
continue
end
case \*
set names (__fisher_plugin_get_names "$i")
end
if test -d "$i"
command ln -sf "$i" "$fisher_config/$names[1]"
set links $links "$names[1]"
continue
end
set -l source "$fisher_cache/$names[1]"
if test -z "$names[2]"
if test -d "$source"
if test -L "$source"
command ln -sf "$source" "$fisher_config"
else
command cp -rf "$source" "$fisher_config"
end
else
set jobs $jobs (__fisher_plugin_url_clone_async "$i" "$names[1]")
end
else
if test -d "$source"
set -l real_namespace (__fisher_plugin_get_url_info --dirname "$source" )
if test "$real_namespace" = "$names[2]"
command cp -rf "$source" "$fisher_config"
else
set jobs $jobs (__fisher_plugin_url_clone_async "$i" "$names[1]")
end
else
set jobs $jobs (__fisher_plugin_url_clone_async "$i" "$names[1]")
end
end
set fetched $fetched "$names[1]"
end
__fisher_jobs_await $jobs
for i in $fetched
if test ! -d "$fisher_cache/$i"
printf "%s\n" "$i"
return 1
end
end
if test ! -z "$fetched"
__fisher_plugin_fetch_items (__fisher_plugin_get_missing $fetched)
printf "%s\n" $fetched
end
if test ! -z "$links"
__fisher_plugin_fetch_items (__fisher_plugin_get_missing $links)
printf "%s\n" $links
end
end
function __fisher_plugin_url_clone_async -a url name
switch "$url"
case https://\*
case github.com/\*
set url "https://$url"
case \?\*/\?\*
set url "https://github.com/$url"
case \*
set url "https://github.com/fisherman/$url"
end
set -l nc (set_color normal)
set -l error (set_color red)
set -l okay (set_color green)
set -l hm_url (printf "%s\n" "$url" | command sed 's|^https://||')
fish -c "
set -lx GIT_ASKPASS /bin/echo
if command git clone -q --depth 1 '$url' '$fisher_cache/$name' ^ /dev/null
printf '$okay""OKAY""$nc Fetching $okay%s$nc %s\n' '$name' '→ $hm_url' > $__fisher_stderr
command cp -rf '$fisher_cache/$name' '$fisher_config'
else
printf '$error""ARGH""$nc Fetching $error%s$nc %s\n' '$name' '→ $hm_url' > $__fisher_stderr
end
" > /dev/stderr &
__fisher_jobs_get -l
end
function __fisher_update
set -l jobs
set -l count (count $argv)
set -l updated
set -l links 0
if test "$count" = 0
return
end
if test "$count" -eq 1
__fisher_log info "Updating @$count@ plugin" $__fisher_stderr
else
__fisher_log info "Updating @$count@ plugins" $__fisher_stderr
end
for i in $argv
set -l path "$fisher_config/$i"
if test -d "$path"
set updated $updated "$i"
if test -L "$fisher_config/$i"
set links (math "$links + 1")
continue
end
set jobs $jobs (__fisher_update_path_async "$i" "$path")
else
__fisher_log warn "@$i@ is not installed"
end
end
__fisher_jobs_await $jobs
set -g __fisher_fetch_plugins_state "fetching"
set -l fetched (__fisher_plugin_fetch_items (__fisher_plugin_get_missing $updated))
for i in $updated $fetched
if test "$i" = "$fisher_active_prompt"
set fisher_active_prompt
end
__fisher_plugin_enable "$fisher_config/$i"
end
if test "$links" -gt 0
__fisher_log info "Synced @$links@ symlink/s" $__fisher_stderr
end
end
function __fisher_self_update
set -l file (status --current-filename)
if test "$file" != "$fish_config/functions/fisher.fish"
return 1
end
set -l completions "$fish_config/completions/fisher.fish"
set -l raw_url "https://raw.githubusercontent.com/fisherman/fisherman/master/fisher.fish"
set -l fake_qs (date "+%s")
set -l previous_version "$fisher_version"
fish -c "curl --max-time 5 -sS '$raw_url?$fake_qs' > $file.$fake_qs" &
__fisher_jobs_await (__fisher_jobs_get -l)
if test -s "$file.$fake_qs"
command mv "$file.$fake_qs" "$file"
end
source "$file"
fisher -v > /dev/null
set -l new_version "$fisher_version"
__fisher_completions_write > "$completions"
source "$completions"
if test "$previous_version" = "$fisher_version"
__fisher_log okay "fisherman is up to date" $__fisher_stderr
else
__fisher_log okay "You are running fisherman @$fisher_version@" $__fisher_stderr
__fisher_log info "See github.com/fisherman/fisherman/releases" $__fisher_stderr
end
end
function __fisher_update_path_async -a name path
set -l nc (set_color normal)
set -l error (set_color red)
set -l uline (set_color -u)
set -l okay (set_color green)
fish -c "
pushd $path
if not command git fetch -q origin master ^ /dev/null
printf '$error""ARGH""$nc Fetching $error%s$nc\n' '$name' > $__fisher_stderr
exit
end
set -l commits (command git rev-list --left-right --count master..FETCH_HEAD ^ /dev/null | cut -d\t -f2)
command git reset -q --hard FETCH_HEAD ^ /dev/null
command git clean -qdfx
command cp -rf '$path/.' '$fisher_cache/$name'
if test -z \"\$commits\" -o \"\$commits\" -eq 0
printf '$okay""OKAY""$nc Latest $okay%s$nc\n' '$name' > $__fisher_stderr
else
printf '$okay""OKAY""$nc $okay%s$nc new commits $okay%s$nc\n' \$commits '$name' > $__fisher_stderr
end
" > /dev/stderr &
__fisher_jobs_get -l
end
function __fisher_plugin_enable -a path
if __fisher_plugin_is_prompt "$path"
if test ! -z "$fisher_active_prompt"
__fisher_plugin_disable "$fisher_config/$fisher_active_prompt"
end
set -U fisher_active_prompt (basename "$path")
end
set -l plugin_name (basename $path)
for file in $path/{functions/*,}*.fish
set -l base (basename "$file")
if test "$base" = "uninstall.fish"
continue
end
switch "$base"
case {,fish_}key_bindings.fish
__fisher_key_bindings_append "$plugin_name" "$file"
continue
end
set -l dir "functions"
if test "$base" = "init.fish"
set dir "conf.d"
set base "$plugin_name.$base"
end
set -l target "$fish_config/$dir/$base"
command ln -sf "$file" "$target"
builtin source "$target"
if test "$base" = "set_color_custom.fish"
printf "%s\n" "$fish_color_normal" "$fish_color_command" "$fish_color_param" "$fish_color_redirection" "$fish_color_comment" "$fish_color_error" "$fish_color_escape" "$fish_color_operator" "$fish_color_end" "$fish_color_quote" "$fish_color_autosuggestion" "$fish_color_user" "$fish_color_valid_path" "$fish_color_cwd" "$fish_color_cwd_root" "$fish_color_match" "$fish_color_search_match" "$fish_color_selection" "$fish_pager_color_prefix" "$fish_pager_color_completion" "$fish_pager_color_description" "$fish_pager_color_progress" "$fish_color_history_current" "$fish_color_host" > "$fish_config/fish_colors"
set_color_custom
end
end
for file in $path/conf.d/*.{py,awk}
set -l base (basename "$file")
command ln -sf "$file" "$fish_config/conf.d/$base"
end
for file in $path/{functions/,}*.{py,awk}
set -l base (basename "$file")
command ln -sf "$file" "$fish_config/functions/$base"
end
for file in $path/conf.d/*.fish
set -l base (basename "$file")
set -l target "$fish_config/conf.d/$base"
command ln -sf "$file" "$target"
builtin source "$target"
end
for file in $path/completions/*.fish
set -l base (basename "$file")
set -l target "$fish_config/completions/$base"
command ln -sf "$file" "$target"
builtin source "$target"
end
return 0
end
function __fisher_plugin_disable -a path
set -l plugin_name (basename $path)
for file in $path/{functions/*,}*.fish
set -l name (basename "$file" .fish)
set -l base "$name.fish"
if test "$base" = "uninstall.fish"
builtin source "$file"
continue
end
switch "$base"
case {,fish_}key_bindings.fish
__fisher_key_bindings_remove "$plugin_name"
continue
end
set -l dir "functions"
if test "$base" = "init.fish"
set dir "conf.d"
set base "$plugin_name.$base"
end
command rm -f "$fish_config/$dir/$base"
functions -e "$name"
if test "$base" = "set_color_custom.fish"
set -l fish_colors_config "$fish_config/fish_colors"
if test ! -f "$fish_colors_config"
__fisher_reset_default_fish_colors
continue
end
set -l IFS \n
read -laz colors < $fish_colors_config
set colors[25] ""
set -l IFS " "
echo "$colors[1]" | read -a -U fish_color_normal
echo "$colors[2]" | read -a -U fish_color_command
echo "$colors[3]" | read -a -U fish_color_param
echo "$colors[4]" | read -a -U fish_color_redirection
echo "$colors[5]" | read -a -U fish_color_comment
echo "$colors[6]" | read -a -U fish_color_error
echo "$colors[7]" | read -a -U fish_color_escape
echo "$colors[8]" | read -a -U fish_color_operator
echo "$colors[9]" | read -a -U fish_color_end
echo "$colors[10]" | read -a -U fish_color_quote
echo "$colors[11]" | read -a -U fish_color_autosuggestion
echo "$colors[12]" | read -a -U fish_color_user
echo "$colors[13]" | read -a -U fish_color_valid_path
echo "$colors[14]" | read -a -U fish_color_cwd
echo "$colors[15]" | read -a -U fish_color_cwd_root
echo "$colors[16]" | read -a -U fish_color_match
echo "$colors[17]" | read -a -U fish_color_search_match
echo "$colors[18]" | read -a -U fish_color_selection
echo "$colors[19]" | read -a -U fish_pager_color_prefix
echo "$colors[20]" | read -a -U fish_pager_color_completion
echo "$colors[21]" | read -a -U fish_pager_color_description
echo "$colors[22]" | read -a -U fish_pager_color_progress
echo "$colors[23]" | read -a -U fish_color_history_current
echo "$colors[24]" | read -a -U fish_color_host
command rm -f $fish_colors_config
end
end
for file in $path/conf.d/*.{py,awk}
set -l base (basename "$file")
command rm -f "$fish_config/conf.d/$base"
end
for file in $path/{functions/,}*.{py,awk}
set -l base (basename "$file")
command rm -f "$fish_config/functions/$base"
end
for file in $path/conf.d/*.fish
set -l base (basename "$file")
command rm -f "$fish_config/conf.d/$base"
end
for file in $path/completions/*.fish
set -l name (basename "$file" .fish)
set -l base "$name.fish"
command rm -f "$fish_config/completions/$base"
complete -c "$name" --erase
end
if __fisher_plugin_is_prompt "$path"
set -U fisher_active_prompt
builtin source $__fish_datadir/functions/fish_prompt.fish ^ /dev/null
end
command rm -rf "$path" > /dev/stderr
end
function __fisher_get_plugin_name_from_gist -a url
set -l gist_id (printf "%s\n" "$url" | command sed 's|.*/||')
set -l name (fish -c "
fisher -v > /dev/null
curl -Ss https://api.github.com/gists/$gist_id &
__fisher_jobs_await (__fisher_jobs_get -l)
" | command awk '
/"files": / {
files++
}
/"[^ ]+.fish": / && files {
gsub("^ *\"|\.fish.*", "")
print
}
')
if test -z "$name"
return 1
end
printf "%s\n" $name
end
function __fisher_remote_index_update
set -l index "$fisher_cache/.index.json"
set -l interval 2160
if test ! -z "$fisher_index_update_interval"
set interval "$fin_index_update_interval"
end
if test -s "$index"
if test (__fisher_get_file_age "$index") -lt "$interval"
return
end
end
fish -c "curl -s 'https://api.github.com/orgs/fisherman/repos?per_page=100' > '$index'" &
__fisher_jobs_await (__fisher_jobs_get -l)
if test ! -s "$index"
return 1
end
end
function __fisher_list_remote -a format
set -l index "$fisher_cache/.index.json"
if not __fisher_remote_index_update
__fisher_log error "I could not update the remote index."
__fisher_log info "
This is most likely a problem with http://api.github.com/
or a connection timeout. If the problem persists, open an
issue in: <github.com/fisherman/fisherman/issues>
"
return 1
end
set -l column_options
if test -z "$format"
set format "%name\n"
else
set column_options -c0
end
set -l config "$fisher_config"/*
command awk -v format_s="$format" -v config="$config" '
function qsort(A, L, R, pivot, j, i, t) {
pivot = j = i = t
if (L >= R) {
return
}
pivot = L
i = L
j = R
while (i < j) {
while (A[i] <= A[pivot] && i < R) i++
while (A[j] > A[pivot]) j--
if (i < j) {
t = A[i]
A[i] = A[j]
A[j] = t
}
}
t = A[pivot]
A[pivot] = A[j]
A[j] = t
qsort(A, L, j - 1)
qsort(A, j + 1, R)
}
function basename(s, n, a) {
n = split(s, a, "/")
return a[n]
}
function in_config(item, i) {
for (i = 1; i <= config_n; i++) {
if (item == config_a[i]) {
return 1
}
}
return 0
}
function print_record_with_format(name, stars, url, info, fmt) {
gsub(/%name/, name, fmt)
gsub(/%stars/, stars, fmt)
gsub(/%url/, url, fmt)
gsub(/%info/, info, fmt)
printf(fmt)
}
function json_get_field(s) {
if ($0 ~ "^" s ":") {
return substr($0, length(s) + 3)
}
}
BEGIN {
config_n = split(config, config_a)
for (i = 1; i <= config_n; i++) {
config_a[i] = basename(config_a[i])
}
}
{
gsub(/[\[\],{}"]|^[\t ]+/, "")
s = json_get_field("name")
name = s != "" ? s : name
s = json_get_field("description")
info = s != "" ? s : info
s = json_get_field("stargazers_count")
stars = s != "" ? s : stars
if (name != "" && info != "" && stars != "" && !in_config(name)) {
if (name !~ /^awesome-fish|^fisherman|^index|logo/) {
info = (info == "null") ? "No description." : info
records[++record_index] = name ";" info ";" stars
}
name = info = stars = ""
}
}
END {
qsort(records, 1, record_index)
for (i = 1; i <= record_index; i++) {
n = split(records[i], r, ";")
if (n == 3) {
print_record_with_format(r[1], r[2], "github.com/fisherman/"r[1], r[3], format_s)
}
}
}
' < "$index" | column $column_options
end
function __fisher_list
set -l config "$fisher_config"/*
if test -z "$config"
return 1
end
set -l white
set -l links (command find $config -maxdepth 0 -type l ! -name "$fisher_active_prompt" ^ /dev/null)
set -l names (command find $config -maxdepth 0 -type d ! -name "$fisher_active_prompt" ^ /dev/null)
if test ! -z "$links"
set white " "
printf "%s\n" $links | command sed "s|.*/|@ |"
end
if test ! -z "$fisher_active_prompt"
set white " "
printf "* %s\n" "$fisher_active_prompt"
end
if test ! -z "$names"
printf "%s\n" $names | command sed "s|.*/|$white|"
end
end
function __fisher_list_plugin_directory -a item
set -l fd $__fisher_stderr
set -e argv[1]
set -l path "$fisher_config/$item"
if test ! -d "$path"
__fisher_log error "$item is not installed" $__fisher_stderr
return 1
end
pushd "$path"
set -l color (set_color $fish_color_command)
set -l nc (set_color normal)
set -l previous_tree
if contains -- --no-color $argv
set color
set nc
set fd $__fisher_stdout
end
printf "$color%s$nc\n" "$PWD" > $fd
for file in .* **
if test -f "$file"
switch "$file"
case \*/\*
set -l current_tree (dirname $file)
if test "$previous_tree" != "$current_tree"
printf " $color%s/$nc\n" $current_tree
end
printf " %s\n" (basename $file)
set previous_tree $current_tree
case \*
printf " %s\n" $file
end
end
end > $fd
popd
end
function __fisher_log -a log message fd
set -l nc (set_color normal)
set -l okay (set_color green)
set -l info (set_color green)
set -l warn (set_color yellow)
set -l error (set_color red)
switch "$fd"
case "/dev/null"
return
case "" "/dev/stderr"
set fd "/dev/stderr"
case \*
set nc ""
set okay ""
set info ""
set warn ""
set error ""
end
printf "%s\n" "$message" | command awk '
function okay(s) {
printf("'$okay'%s'$nc' %s\n", "OKAY", s)
}
function info(s) {
printf("'$info'%s'$nc' %s\n", "INFO", s)
}
function warn(s) {
printf("'$warn'%s'$nc' %s\n", "WARN", s)
}
function error(s) {
printf("'$error'%s'$nc' %s\n", "ARGH", s)
}
{
sub(/^[ ]+/, "")
gsub("``", " ")
if (/@[^@]+@/) {
n = match($0, /@[^@]+@/)
if (n) {
sub(/@[^@]+@/, "'"$$log"'" substr($0, RSTART + 1, RLENGTH - 2) "'$nc'", $0)
}
}
s[++len] = $0
}
END {
for (i = 1; i <= len; i++) {
if ((i == 1 || i == len) && (s[i] == "")) {
continue
}
if (s[i] == "") {
print
} else {
'$log'(s[i])
}
}
}
' > "$fd"
end
function __fisher_jobs_get
jobs $argv | command awk -v FS=\t '
/[0-9]+\t/{
jobs[++job_count] = $1
}
END {
for (i = 1; i <= job_count; i++) {
print(jobs[i])
}
exit job_count == 0
}
'
end
function __fisher_jobs_await
if test -z "$argv"
return
end
while true
for spinner in $fisher_spinners
printf " $spinner \r" > /dev/stderr
sleep 0.04
end
set -l currently_active_jobs (__fisher_jobs_get)
if test -z "$currently_active_jobs"
break
end
set -l has_jobs
for i in $argv
if builtin contains -- $i $currently_active_jobs
set has_jobs "*"
break
end
end
if test -z "$has_jobs"
break
end
end
end
function __fisher_key_bindings_remove -a plugin_name
set -l user_key_bindings "$fish_config/functions/fish_user_key_bindings.fish"
set -l tmp (date "+%s")
fish_indent < "$user_key_bindings" | command sed -n "/### $plugin_name ###/,/### $plugin_name ###/{s/^ *bind /bind -e /p;};" | source ^ /dev/null
command sed "/### $plugin_name ###/,/### $plugin_name ###/d" < "$user_key_bindings" > "$user_key_bindings.$tmp"
command mv -f "$user_key_bindings.$tmp" "$user_key_bindings"
if awk '
/^$/ { next }
/^function fish_user_key_bindings/ {
i++
next
}
/^end$/ && 1 == i {
exit 0
}
// {
exit 1
}
' < "$user_key_bindings"
command rm -f "$user_key_bindings"
end
end
function __fisher_key_bindings_append -a plugin_name file
set -l user_key_bindings "$fish_config/functions/fish_user_key_bindings.fish"
command mkdir -p (dirname "$user_key_bindings")
touch "$user_key_bindings"
set -l key_bindings_source (
fish_indent < "$user_key_bindings" | awk '
/^function fish_user_key_bindings/ {
reading_function_source = 1
next
}
/^end$/ {
exit
}
reading_function_source {
print $0
next
}
'
)
set -l plugin_key_bindings_source (
fish_indent < "$file" | awk -v name="$plugin_name" '
BEGIN {
printf("### %s ###\n", name)
}
END {
printf("### %s ###\n", name)
}
/^function fish_user_key_bindings$/ {
check_for_and_keyword = 1
next
}
/^end$/ && check_for_and_keyword {
end = 0
next
}
!/^ *(#.*)*$/ {
gsub("#.*", "")
printf("%s\n", $0)
}
'
)
printf "%s\n" $key_bindings_source $plugin_key_bindings_source | awk '
BEGIN {
print "function fish_user_key_bindings"
}
//
END {
print "end"
}
' | fish_indent > "$user_key_bindings"
end
function __fisher_plugin_is_prompt -a path
if test -e $path/fish_prompt.fish
return
end
if test -e $path/functions/fish_prompt.fish
return
end
if test -e $path/fish_right_prompt.fish
return
end
if test -e $path/functions/fish_right_prompt.fish
return
end
return 1
end
function __fisher_plugin_get_names
printf "%s\n" $argv | command awk '
{
sub(/\/$/, "")
n = split($0, s, "/")
sub(/^(omf|omf-theme|omf-plugin|plugin|theme|fish|fisher)-/, "", s[n])
printf("%s\n%s\n", s[n], s[n - 1])
}
'
end
function __fisher_plugin_get_url_info -a option
set -e argv[1]
if test -z "$argv"
return
end
cat {$argv}/.git/config ^ /dev/null | command awk -v option="$option" '
/url/ {
n = split($3, s, "/")
if ($3 ~ /https:\/\/gist/) {
printf("# %s\n", $3)
next
}
if (option == "--dirname") {
printf("%s\n", s[n - 1])
} else if (option == "--basename") {
printf("%s\n", s[n])
} else {
printf("%s/%s\n", s[n - 1], s[n])
}
}
'
end
function __fisher_plugin_normalize_path
printf "%s\n" $argv | command awk -v pwd="$PWD" '
/^\.$/ {
print(pwd)
next
}
/^\// {
sub(/\/$/, "")
print($0)
next
}
{
print(pwd "/" $0)
next
}
'
end
function __fisher_plugin_get_missing
for i in $argv
if test -d "$i"
set i (__fisher_plugin_normalize_path "$i")
end
set -l name (__fisher_plugin_get_names "$i")[1]
if set -l path (__fisher_plugin_is_installed "$name")
for file in fishfile bundle
if test -s "$path/$file"
__fisher_plugin_get_missing (__fisher_read_bundle_file < "$path/$file")
end
end
else
printf "%s\n" "$i"
end
end
__fisher_show_spinner
end
function __fisher_plugin_is_installed -a name
if test -z "$name" -o ! -d "$fisher_config/$name"
return 1
end
printf "%s\n" "$fisher_config/$name"
end
function __fisher_reset_default_fish_colors
set -U fish_color_normal normal
set -U fish_color_command 005fd7 purple
set -U fish_color_param 00afff cyan
set -U fish_color_redirection 005fd7
set -U fish_color_comment 600
set -U fish_color_error red --bold
set -U fish_color_escape cyan
set -U fish_color_operator cyan
set -U fish_color_end green
set -U fish_color_quote brown
set -U fish_color_autosuggestion 555 yellow
set -U fish_color_user green
set -U fish_color_valid_path --underline
set -U fish_color_cwd green
set -U fish_color_cwd_root red
set -U fish_color_match cyan
set -U fish_color_search_match --background=purple
set -U fish_color_selection --background=purple
set -U fish_pager_color_prefix cyan
set -U fish_pager_color_completion normal
set -U fish_pager_color_description 555 yellow
set -U fish_pager_color_progress cyan
set -U fish_color_history_current cyan
set -U fish_color_host normal
end
function __fisher_read_bundle_file
command awk -v FS=\t '
/^$/ || /^[ \t]*#/ {
next
}
/^[ \t]*package / {
sub("^[ \t]*package ", "oh-my-fish/plugin-")
}
{
sub("^[@* \t]*", "")
if (!seen[$0]++) {
printf("%s\n", $0)
}
}
'
end
function __fisher_completions_write
functions __fisher_completions_write | fish_indent | __fisher_parse_comments_from_function
# complete -xc fisher -s q -l quiet -d "Enable quiet mode"
# complete -xc fisher -n "__fish_use_subcommand" -s h -l help -d "Show usage help"
# complete -xc fisher -n "__fish_use_subcommand" -s v -l version -d "Show version information"
# complete -xc fisher -n "__fish_use_subcommand" -a install -d "Install plugins"
# complete -xc fisher -n "__fish_use_subcommand" -a update -d "Upgrade and update plugins"
# complete -xc fisher -n "__fish_use_subcommand" -a rm -d "Remove plugins"
# complete -xc fisher -n "__fish_use_subcommand" -a ls -d "List what's installed"
# complete -xc fisher -n "__fish_use_subcommand" -a ls-remote -d "List what can be installed"
# complete -xc fisher -n "__fish_use_subcommand" -a help -d "Show help"
end
function __fisher_humanize_duration
awk '
function hmTime(time, stamp) {
split("h:m:s:ms", units, ":")
for (i = 2; i >= -1; i--) {
if (t = int( i < 0 ? time % 1000 : time / (60 ^ i * 1000) % 60 )) {
stamp = stamp t units[sqrt((i - 2) ^ 2) + 1] " "
}
}
if (stamp ~ /^ *$/) {
return "0ms"
}
return substr(stamp, 1, length(stamp) - 1)
}
{
print hmTime($0)
}
'
end
function __fisher_get_key
stty -icanon -echo ^ /dev/null
printf "$argv" > /dev/stderr
while true
dd bs=1 count=1 ^ /dev/null | read -p "" -l yn
switch "$yn"
case y Y n N
printf "\n" > /dev/stderr
printf "%s\n" $yn > /dev/stdout
break
end
end
stty icanon echo > /dev/stderr ^ /dev/null
end
function __fisher_get_epoch_in_ms -a elapsed
if test -z "$elapsed"
set elapsed 0
end
perl -MTime::HiRes -e 'printf("%.0f\n", (Time::HiRes::time() * 1000) - '$elapsed')'
end
function __fisher_parse_column_output
command awk -v FS=\t '
{
for (i = 1; i <= NF; i++) {
if ($i != "") {
print $i
}
}
}
'
end
function __fisher_parse_comments_from_function
command awk '
/^[\t ]*# ?/ {
sub(/^[\t ]*# ?/, "")
a[++n] = $0
}
END {
for (i = 1; i <= n; i++) {
printf("%s\n", a[i])
}
}
'
end
function __fisher_get_file_age -a file
if not type -q python
return 1
end
python -c "import os, time; print int(time.time() - os.path.getmtime('$file'))" ^ /dev/null
end
function __fisher_usage
set -l u (set_color -u)
set -l nc (set_color normal)
echo "Usage: fisher [<command>] [<plugins>] [--quiet] [--version]"
echo
echo "where <command> can be one of:"
echo " "$u"i"$nc"nstall (default)"
echo " "$u"u"$nc"pdate"
echo " "$u"r"$nc"m"
echo " "$u"l"$nc"s (or ls-remote)"
echo " "$u"h"$nc"elp"
end
function __fisher_help -a cmd number
if test -z "$argv"
set -l page "$fisher_cache/fisher.1"
if test ! -s "$page"
__fisher_man_page_write > "$page"
end
set -l pager "/usr/bin/less -s"
if test ! -z "$PAGER"
set pager "$PAGER"
end
man -P "$pager" -- "$page"
command rm -f "$page"
else
if test -z "$number"
set number 1
end
set -l page "$fisher_config/$cmd/man/man$number/$cmd.$number"
if not man "$page" ^ /dev/null
__fisher_log error "No manual entry for $cmd" $__fisher_stderr
if test -d "$fisher_config/$cmd"
set -l url (__fisher_plugin_get_url_info -- $fisher_config/$cmd)
if test ! -z "$url"
__fisher_log info "Visit the online repository for help:" $__fisher_stderr
__fisher_log info "@https://github.com/$url@" $__fisher_stderr
end
else
__fisher_log error "$cmd is not installed" $__fisher_stderr
end
return 1
end
end
end
function __fisher_self_uninstall -a yn
set -l file (status --current-filename)
if test -z "$fish_config" -o -z "$fisher_cache" -o -z "$fisher_config" -o -L "$fisher_cache" -o -L "$fisher_config" -o "$file" != "$fish_config/functions/fisher.fish"
__fisher_log warn "Global or non-standard setup detected."
__fisher_log says "Use your package manager to remove fisherman." /dev/stderr
return 1
end
set -l u (set_color -u)
set -l nc (set_color normal)
switch "$yn"
case -y --yes
case \*
__fisher_log warn "
This will permanently remove fisherman from your system.
The following directories and files will be erased:
$fisher_cache
$fisher_config
$fish_config/functions/fisher.fish
$fish_config/completions/fisher.fish
" /dev/stderr
echo -sn "Do you wish to continue? [Y/n] " > /dev/stderr
__fisher_get_key | read -l yn
switch "$yn"
case n N
set -l username
if test ! -z "$USER"
set username " $USER"
end
__fisher_log okay "As you wish cap!"
return 1
end
end
complete -c fisher --erase
__fisher_show_spinner
fisher ls | fisher rm
__fisher_show_spinner
command rm -rf "$fisher_cache" "$fisher_config"
command rm -f "$fish_config"/{functions,completions}/fisher.fish "$fisher_bundle"
__fisher_show_spinner
set -e fisher_active_prompt
set -e fisher_cache
set -e fisher_config
set -e fish_config
set -e fisher_bundle
set -e fisher_version
set -e fisher_spinners
for func in __fisher_jobs_await __fisher_plugin_url_clone_async __fisher_completions_write __fisher_plugin_fetch_items __fisher_get_epoch_in_ms __fisher_jobs_get __fisher_get_key __fisher_get_plugin_name_from_gist __fisher_plugin_get_names __fisher_plugin_get_url_info __fisher_plugin_get_missing __fisher_help __fisher_humanize_duration __fisher_install __fisher_list __fisher_list_plugin_directory __fisher_man_page_write __fisher_plugin_normalize_path __fisher_parse_column_output __fisher_parse_comments_from_function __fisher_plugin_is_prompt __fisher_plugin_disable __fisher_plugin_enable __fisher_plugin_is_installed __fisher_read_bundle_file __fisher_reset_default_fish_colors __fisher_self_uninstall __fisher_self_update __fisher_usage __fisher_update __fisher_update_path_async
__fisher_show_spinner
functions -e "$func"
end
__fisher_show_spinner
functions -e __fisher_show_spinner
__fisher_log okay "Arrr! So long and thanks for all the fish." $__fisher_stderr
functions -e __fisher_log
functions -e fisher
end
function __fisher_man_page_write
functions __fisher_man_page_write | fish_indent | __fisher_parse_comments_from_function
# .
# .TH "FISHERMAN" "1" "April 2016" "" "fisherman"
# .
# .SH "NAME"
# \fBfisherman\fR \- fish shell plugin manager
# .
# .SH "SYNOPSIS"
# fisher [\fIcommand\fR] [\fIplugins\fR] [\-\-quiet] [\-\-version]
# .
# .br
# .
# .P
# where \fIcommand\fR can be one of: \fBi\fRnstall, \fBu\fRpdate, \fBls\fR, \fBrm\fR and \fBh\fRelp
# .
# .SH "USAGE"
# Install a plugin\.
# .
# .IP "" 4
# .
# .nf
#
# fisher simple
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Install from multiple sources\.
# .
# .IP "" 4
# .
# .nf
#
# fisher z fzf omf/{grc,thefuck}
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Install from a url\.
# .
# .IP "" 4
# .
# .nf
#
# fisher https://github\.com/edc/bass
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Install from a gist\.
# .
# .IP "" 4
# .
# .nf
#
# fisher https://gist\.github\.com/username/1f40e1c6e0551b2666b2
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Install from a local directory\.
# .
# .IP "" 4
# .
# .nf
#
# fisher ~/my_aliases
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Use it a la vundle\. Edit your fishfile and run \fBfisher\fR to satisfy changes\.
# .
# .P
# See \fIFAQ\fR#What is a fishfile and how do I use it?
# .
# .IP "" 4
# .
# .nf
#
# $EDITOR fishfile # add plugins
# fisher
# .
# .fi
# .
# .IP "" 0
# .
# .P
# See what\'s installed\.
# .
# .IP "" 4
# .
# .nf
#
# fisher ls
# @ my_aliases # this plugin is a local directory
# * simple # this plugin is the current prompt
# bass
# fzf
# grc
# thefuck
# z
# .
# .fi
# .
# .IP "" 0
# .
# .P
# See what you can install\.
# .
# .IP "" 4
# .
# .nf
#
# fisher ls\-remote
# \.\.\.
# spin roach git_util pwd_info
# submit flash pyenv host_info
# \.\.\.
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Update everything\.
# .
# .IP "" 4
# .
# .nf
#
# fisher up
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Update some plugins\.
# .
# .IP "" 4
# .
# .nf
#
# fisher up bass z fzf thefuck
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Remove plugins\.
# .
# .IP "" 4
# .
# .nf
#
# fisher rm simple
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Remove all the plugins\.
# .
# .IP "" 4
# .
# .nf
#
# fisher ls | fisher rm
# .
# .fi
# .
# .IP "" 0
# .
# .P
# Get help\.
# .
# .IP "" 4
# .
# .nf
#
# fisher help z
# .
# .fi
# .
# .IP "" 0
# .
# .SH "OPTIONS"
# .
# .IP "\(bu" 4
# \-v, \-\-version Show version information\.
# .
# .IP "\(bu" 4
# \-h, \-\-help Show usage help\. Use the long form to display this page instead\.
# .
# .IP "\(bu" 4
# \-q, \-\-quiet Enable quiet mode\. Use to suppress output\.
# .
# .IP "" 0
# .
# .SH "FAQ"
# .
# .SS "1\. What is the required fish version?"
# fisherman was built for fish >= 2\.3\.0\. If you are using 2\.2\.0, append the following code to your \fB~/\.config/fish/config\.fish\fR for snippet support\.
# .
# .IP "" 4
# .
# .nf
#
# for file in ~/\.config/fish/conf\.d/*\.fish
# source $file
# end
# .
# .fi
# .
# .IP "" 0
# .
# .SS "2\. How do I use fish as my default shell?"
# Add fish to the list of login shells in \fB/etc/shells\fR and make it your default shell\.
# .
# .IP "" 4
# .
# .nf
#
# echo "/usr/local/bin/fish" | sudo tee \-a /etc/shells
# chsh \-s /usr/local/bin/fish
# .
# .fi
# .
# .IP "" 0
# .
# .SS "3\. How do I uninstall fisherman?"
# Run
# .
# .IP "" 4
# .
# .nf
#
# fisher self\-uninstall
# .
# .fi
# .
# .IP "" 0
# .
# .SS "4\. Is fisherman compatible with oh my fish themes and plugins?"
# Yes\.
# .
# .SS "5\. Where does fisherman put stuff?"
# fisherman goes in \fB~/\.config/fish/functions/fisher\.fish\fR\.
# .
# .P
# The cache and plugin configuration is created in \fB~/\.cache/fisherman\fR and \fB~/\.config/fisherman\fR respectively\.
# .
# .P
# The fishfile is saved to \fB~/\.config/fish/fishfile\fR\.
# .
# .SS "6\. What is a fishfile and how do I use it?"
# The fishfile \fB~/\.config/fish/fishfile\fR lists all the installed plugins\.
# .
# .P
# You can let fisherman take care of this file for you automatically, or write in the plugins you want and run \fBfisher\fR to satisfy the changes\.
# .
# .IP "" 4
# .
# .nf
#
# fisherman/simple
# fisherman/z
# omf/thefuck
# omf/grc
# .
# .fi
# .
# .IP "" 0
# .
# .P
# This mechanism only installs plugins and missing dependencies\. To remove a plugin, use \fBfisher rm\fR instead\.
# .
# .SS "6\. Where can I find a list of fish plugins?"
# Browse \fIhttps://github\.com/fisherman\fR or use \fIhttp://fisherman\.sh/#search\fR to discover content\.
# .
# .SS "7\. What is a plugin?"
# A plugin is:
# .
# .IP "1." 4
# a directory or git repo with a function \fB\.fish\fR file either at the root level of the project or inside a \fBfunctions\fR directory
# .
# .IP "2." 4
# a theme or prompt, i\.e, a \fBfish_prompt\.fish\fR, \fBfish_right_prompt\.fish\fR or both files
# .
# .IP "3." 4
# a snippet, i\.e, one or more \fB\.fish\fR files inside a directory named \fBconf\.d\fR that are evaluated by fish at the start of the shell
# .
# .IP "" 0
# .
# .SS "8\. How can I list plugins as dependencies to my plugin?"
# Create a new \fBfishfile\fR file at the root level of your project and write in the plugin dependencies\.
# .
# .IP "" 4
# .
# .nf
#
# owner/repo
# https://github\.com/dude/sweet
# https://gist\.github\.com/bucaran/c256586044fea832e62f02bc6f6daf32
# .
# .fi
# .
# .IP "" 0
# .
# .SS "9\. I have a question or request not addressed here\. Where should I put it?"
# Create a new ticket on the issue tracker:
# .
# .IP "\(bu" 4
# \fIhttps://github\.com/fisherman/fisherman/issues\fR
# .
# .IP "" 0
end