#!/usr/bin/env bash version=0.9.8 cd $(dirname $BASH_SOURCE) fzf_base=$(pwd) # If stdin is a tty, we are "interactive". [ -t 0 ] && interactive=yes ask() { # non-interactive shell: wait for a linefeed # interactive shell: continue after a single keypress [ -n "$interactive" ] && read_n='-n 1' || read_n= read -p "$1 ([y]/n) " $read_n -r echo [[ ! $REPLY =~ ^[Nn]$ ]] } check_binary() { echo -n " - Checking fzf executable ... " local output=$("$fzf_base"/bin/fzf --version 2>&1) if [ "$version" = "$output" ]; then echo "$output" binary_error="" else echo "$output != $version" rm -f "$fzf_base"/bin/fzf binary_error="Invalid binary" return 1 fi } 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 } download() { echo "Downloading bin/fzf ..." if [[ ! $1 =~ dev && -x "$fzf_base"/bin/fzf ]]; then echo " - Already exists" check_binary && return elif [ -x "$fzf_base"/bin/$1 ]; then symlink $1 && check_binary && 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 if which curl > /dev/null; then curl -fL $url | tar -xz elif which wget > /dev/null; then wget -O - $url | tar -xz else binary_error="curl or wget not found" return fi 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_amd64 ;; Darwin\ i*86) download fzf-$version-darwin_386 ;; Linux\ x86_64) download fzf-$version-linux_amd64 ;; Linux\ i*86) download fzf-$version-linux_386 ;; *) binary_available=0 binary_error=1 ;; esac 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 echo "Installing legacy Ruby version ..." # ruby executable echo -n "Checking Ruby executable ... " ruby=`which 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 -a $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" fi # Auto-completion ask "Do you want to add auto-completion support?" auto_completion=$? # Key-bindings ask "Do you want to add key bindings?" key_bindings=$? echo for shell in bash zsh; do echo -n "Generate ~/.fzf.$shell ... " src=~/.fzf.${shell} fzf_completion="[[ \$- =~ i ]] && source \"$fzf_base/shell/completion.${shell}\"" if [ $shell != bash -o $auto_completion -ne 0 ]; then fzf_completion="# $fzf_completion" fi fzf_key_bindings="source \"$fzf_base/shell/key-bindings.${shell}\"" if [ $key_bindings -ne 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=0 if [ -n "$(which fish 2> /dev/null)" ]; then has_fish=1 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 if [ $key_bindings -eq 0 ]; then echo -n "Symlink ~/.config/fish/functions/fzf_key_bindings.fish ... " ln -sf $fzf_base/shell/key-bindings.fish \ ~/.config/fish/functions/fzf_key_bindings.fish && echo "OK" || echo "Failed" fi fi append_line() { echo "Update $2:" echo " - $1" [ -f "$2" ] || touch "$2" if [ $# -lt 3 ]; then line=$(\grep -nF "$1" "$2" | sed 's/:.*//' | tr '\n' ' ') else line=$(\grep -nF "$3" "$2" | sed 's/:.*//' | tr '\n' ' ') fi if [ -n "$line" ]; then echo " - Already exists: line #$line" else echo "$1" >> "$2" echo " + Added" fi echo } echo for shell in bash zsh; do append_line "[ -f ~/.fzf.${shell} ] && source ~/.fzf.${shell}" ~/.${shell}rc "~/.fzf.${shell}" done if [ $key_bindings -eq 0 -a $has_fish -eq 1 ]; then bind_file=~/.config/fish/functions/fish_user_key_bindings.fish append_line "fzf_key_bindings" "$bind_file" fi cat << EOF Finished. Restart your shell or reload config file. source ~/.bashrc # bash source ~/.zshrc # zsh EOF [ $has_fish -eq 1 ] && echo " fzf_key_bindings # fish"; cat << EOF Use uninstall script to remove fzf. For more information, see: https://github.com/junegunn/fzf EOF