fzf/install
Junegunn Choi 6a65006f55
0.15.8
2016-11-19 23:13:26 +09:00

409 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
set -u
[[ "$@" =~ --pre ]] && version=0.15.8 pre=1 ||
version=0.15.8 pre=0
auto_completion=
key_bindings=
update_config=2
binary_arch=
allow_legacy=
help() {
cat << EOF
usage: $0 [OPTIONS]
--help Show this message
--bin Download fzf binary only; Do not generate ~/.fzf.{bash,zsh}
--all Download fzf binary and update configuration files
to enable key bindings and fuzzy completion
--[no-]key-bindings Enable/disable key bindings (CTRL-T, CTRL-R, ALT-C)
--[no-]completion Enable/disable fuzzy completion (bash & zsh)
--[no-]update-rc Whether or not to update shell configuration files
--32 Download 32-bit binary
--64 Download 64-bit binary
EOF
}
for opt in "$@"; do
case $opt in
--help)
help
exit 0
;;
--all)
auto_completion=1
key_bindings=1
update_config=1
allow_legacy=1
;;
--key-bindings) key_bindings=1 ;;
--no-key-bindings) key_bindings=0 ;;
--completion) auto_completion=1 ;;
--no-completion) auto_completion=0 ;;
--update-rc) update_config=1 ;;
--no-update-rc) update_config=0 ;;
--32) binary_arch=386 ;;
--64) binary_arch=amd64 ;;
--bin|--pre) ;;
*)
echo "unknown option: $opt"
help
exit 1
;;
esac
done
cd "$(dirname "${BASH_SOURCE[0]}")"
fzf_base="$(pwd)"
ask() {
# If stdin is a tty, we are "interactive".
# non-interactive shell: wait for a linefeed
# interactive shell: continue after a single keypress
read_n=$([ -t 0 ] && echo "-n 1")
read -p "$1 ([y]/n) " $read_n -r
echo
[[ $REPLY =~ ^[Nn]$ ]]
}
check_binary() {
echo -n " - Checking fzf executable ... "
local output
output=$("$fzf_base"/bin/fzf --version 2>&1)
if [ $? -ne 0 ]; then
echo "Error: $output"
binary_error="Invalid binary"
elif [ "$version" != "$output" ]; then
echo "$output != $version"
binary_error="Invalid version"
else
echo "$output"
binary_error=""
return 0
fi
rm -f "$fzf_base"/bin/fzf
return 1
}
symlink() {
echo " - Creating symlink: bin/$1 -> bin/fzf"
(cd "$fzf_base"/bin &&
rm -f fzf &&
ln -sf $1 fzf)
if [ $? -ne 0 ]; then
binary_error="Failed to create symlink"
return 1
fi
}
link_fzf_in_path() {
if which_fzf="$(command -v fzf)"; then
echo " - Found in \$PATH"
echo " - Creating symlink: $which_fzf -> bin/fzf"
(cd "$fzf_base"/bin && rm -f fzf && ln -sf "$which_fzf" fzf)
check_binary && return
fi
return 1
}
try_curl() {
command -v curl > /dev/null && curl -fL $1 | tar -xz
}
try_wget() {
command -v wget > /dev/null && wget -O - $1 | tar -xz
}
download() {
echo "Downloading bin/fzf ..."
if [ $pre = 0 ]; then
if [ -x "$fzf_base"/bin/fzf ]; then
echo " - Already exists"
check_binary && return
fi
if [ -x "$fzf_base"/bin/$1 ]; then
symlink $1 && check_binary && return
fi
link_fzf_in_path && return
fi
mkdir -p "$fzf_base"/bin && cd "$fzf_base"/bin
if [ $? -ne 0 ]; then
binary_error="Failed to create bin directory"
return
fi
local url=https://github.com/junegunn/fzf-bin/releases/download/$version/${1}.tgz
set -o pipefail
if ! (try_curl $url || try_wget $url); then
set +o pipefail
binary_error="Failed to download with curl and wget"
return
fi
set +o pipefail
if [ ! -f $1 ]; then
binary_error="Failed to download ${1}"
return
fi
chmod +x $1 && symlink $1 && check_binary
}
# Try to download binary executable
archi=$(uname -sm)
binary_available=1
binary_error=""
case "$archi" in
Darwin\ x86_64) download fzf-$version-darwin_${binary_arch:-amd64} ;;
Darwin\ i*86) download fzf-$version-darwin_${binary_arch:-386} ;;
Linux\ x86_64) download fzf-$version-linux_${binary_arch:-amd64} ;;
Linux\ i*86) download fzf-$version-linux_${binary_arch:-386} ;;
*) binary_available=0 binary_error=1 ;;
esac
install_ruby_fzf() {
if [ -z "$allow_legacy" ]; then
ask "Do you want to install legacy Ruby version instead?" && exit 1
fi
echo "Installing legacy Ruby version ..."
# ruby executable
echo -n "Checking Ruby executable ... "
ruby=$(command -v ruby)
if [ $? -ne 0 ]; then
echo "ruby executable not found !!!"
exit 1
fi
# System ruby is preferred
system_ruby=/usr/bin/ruby
if [ -x $system_ruby ] && [ $system_ruby != "$ruby" ]; then
$system_ruby --disable-gems -rcurses -e0 2> /dev/null
[ $? -eq 0 ] && ruby=$system_ruby
fi
echo "OK ($ruby)"
# Curses-support
echo -n "Checking Curses support ... "
"$ruby" -rcurses -e0 2> /dev/null
if [ $? -eq 0 ]; then
echo "OK"
else
echo "Not found"
echo "Installing 'curses' gem ... "
if (( EUID )); then
/usr/bin/env gem install curses --user-install
else
/usr/bin/env gem install curses
fi
if [ $? -ne 0 ]; then
echo
echo "Failed to install 'curses' gem."
if [[ $(uname -r) =~ 'ARCH' ]]; then
echo "Make sure that base-devel package group is installed."
fi
exit 1
fi
fi
# Ruby version
echo -n "Checking Ruby version ... "
"$ruby" -e 'exit RUBY_VERSION >= "1.9"'
if [ $? -eq 0 ]; then
echo ">= 1.9"
"$ruby" --disable-gems -rcurses -e0 2> /dev/null
if [ $? -eq 0 ]; then
fzf_cmd="$ruby --disable-gems $fzf_base/fzf"
else
fzf_cmd="$ruby $fzf_base/fzf"
fi
else
echo "< 1.9"
fzf_cmd="$ruby $fzf_base/fzf"
fi
# Create fzf script
echo -n "Creating wrapper script for fzf ... "
rm -f "$fzf_base"/bin/fzf
echo "#!/bin/sh" > "$fzf_base"/bin/fzf
echo "$fzf_cmd \"\$@\"" >> "$fzf_base"/bin/fzf
chmod +x "$fzf_base"/bin/fzf
echo "OK"
}
cd "$fzf_base"
if [ -n "$binary_error" ]; then
if [ $binary_available -eq 0 ]; then
echo "No prebuilt binary for $archi ..."
else
echo " - $binary_error !!!"
fi
if command -v go > /dev/null; then
echo -n "Building binary (go get -u github.com/junegunn/fzf/src/fzf) ... "
if [ -z "${GOPATH-}" ]; then
export GOPATH="${TMPDIR:-/tmp}/fzf-gopath"
mkdir -p "$GOPATH"
fi
if go get -u github.com/junegunn/fzf/src/fzf; then
echo "OK"
cp "$GOPATH/bin/fzf" "$fzf_base/bin/"
else
echo "Failed to build binary ..."
install_ruby_fzf
fi
else
echo "go executable not found. Cannot build binary ..."
install_ruby_fzf
fi
fi
[[ "$*" =~ "--bin" ]] && exit 0
# Auto-completion
if [ -z "$auto_completion" ]; then
ask "Do you want to enable fuzzy auto-completion?"
auto_completion=$?
fi
# Key-bindings
if [ -z "$key_bindings" ]; then
ask "Do you want to enable key bindings?"
key_bindings=$?
fi
echo
has_zsh=$(command -v zsh > /dev/null && echo 1 || echo 0)
shells=$([ $has_zsh -eq 1 ] && echo "bash zsh" || echo "bash")
for shell in $shells; do
echo -n "Generate ~/.fzf.$shell ... "
src=~/.fzf.${shell}
fzf_completion="[[ \$- == *i* ]] && source \"$fzf_base/shell/completion.${shell}\" 2> /dev/null"
if [ $auto_completion -eq 0 ]; then
fzf_completion="# $fzf_completion"
fi
fzf_key_bindings="source \"$fzf_base/shell/key-bindings.${shell}\""
if [ $key_bindings -eq 0 ]; then
fzf_key_bindings="# $fzf_key_bindings"
fi
cat > $src << EOF
# Setup fzf
# ---------
if [[ ! "\$PATH" == *$fzf_base/bin* ]]; then
export PATH="\$PATH:$fzf_base/bin"
fi
# Man path
# --------
if [[ ! "\$MANPATH" == *$fzf_base/man* && -d "$fzf_base/man" ]]; then
export MANPATH="\$MANPATH:$fzf_base/man"
fi
# Auto-completion
# ---------------
$fzf_completion
# Key bindings
# ------------
$fzf_key_bindings
EOF
echo "OK"
done
# fish
has_fish=$(command -v fish > /dev/null && echo 1 || echo 0)
if [ $has_fish -eq 1 ]; then
echo -n "Update fish_user_paths ... "
fish << EOF
echo \$fish_user_paths | grep $fzf_base/bin > /dev/null
or set --universal fish_user_paths \$fish_user_paths $fzf_base/bin
EOF
[ $? -eq 0 ] && echo "OK" || echo "Failed"
mkdir -p ~/.config/fish/functions
if [ -e ~/.config/fish/functions/fzf.fish ]; then
echo -n "Remove unnecessary ~/.config/fish/functions/fzf.fish ... "
rm -f ~/.config/fish/functions/fzf.fish && echo "OK" || echo "Failed"
fi
fish_binding=~/.config/fish/functions/fzf_key_bindings.fish
if [ $key_bindings -ne 0 ]; then
echo -n "Symlink $fish_binding ... "
ln -sf "$fzf_base/shell/key-bindings.fish" \
"$fish_binding" && echo "OK" || echo "Failed"
else
echo -n "Removing $fish_binding ... "
rm -f "$fish_binding"
echo "OK"
fi
fi
append_line() {
set -e
local update line file pat lno
update="$1"
line="$2"
file="$3"
pat="${4:-}"
echo "Update $file:"
echo " - $line"
[ -f "$file" ] || touch "$file"
if [ $# -lt 4 ]; then
lno=$(\grep -nF "$line" "$file" | sed 's/:.*//' | tr '\n' ' ')
else
lno=$(\grep -nF "$pat" "$file" | sed 's/:.*//' | tr '\n' ' ')
fi
if [ -n "$lno" ]; then
echo " - Already exists: line #$lno"
else
if [ $update -eq 1 ]; then
echo >> "$file"
echo "$line" >> "$file"
echo " + Added"
else
echo " ~ Skipped"
fi
fi
echo
set +e
}
if [ $update_config -eq 2 ]; then
echo
ask "Do you want to update your shell configuration files?"
update_config=$?
fi
echo
for shell in $shells; do
[ $shell = zsh ] && dest=${ZDOTDIR:-~}/.zshrc || dest=~/.bashrc
append_line $update_config "[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}" "$dest" "~/.fzf.${shell}"
done
if [ $key_bindings -eq 1 ] && [ $has_fish -eq 1 ]; then
bind_file=~/.config/fish/functions/fish_user_key_bindings.fish
append_line $update_config "fzf_key_bindings" "$bind_file"
fi
if [ $update_config -eq 1 ]; then
echo 'Finished. Restart your shell or reload config file.'
echo ' source ~/.bashrc # bash'
[ $has_zsh -eq 1 ] && echo " source ${ZDOTDIR:-~}/.zshrc # zsh"
[ $has_fish -eq 1 ] && [ $key_bindings -eq 1 ] && echo ' fzf_key_bindings # fish'
echo
echo 'Use uninstall script to remove fzf.'
echo
fi
echo 'For more information, see: https://github.com/junegunn/fzf'