Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embed shell integration scripts in fzf binary (--bash / --zsh / --fish) #3675

Merged
merged 16 commits into from
Mar 13, 2024
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
CHANGELOG
=========

0.48.0
------
- Shell integration scripts are now embedded in the fzf binary. This simplifies the distribution, and the users are less likely to have problems caused by using incompatible scripts and binaries.
- bash
```sh
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --bash)"
```
- zsh
```sh
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --zsh)"
```
- fish
```fish
# Set up fzf key bindings
fzf --fish | source
```

0.47.0
------
- Replaced ["the default find command"][find] with a built-in directory traversal to simplify the code and to achieve better performance and consistent behavior across platforms.
Expand Down
44 changes: 35 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Table of Contents
* [Using git](#using-git)
* [Using Linux package managers](#using-linux-package-managers)
* [Windows](#windows)
* [Setting up shell integration](#setting-up-shell-integration)
* [As Vim plugin](#as-vim-plugin)
* [Upgrading fzf](#upgrading-fzf)
* [Building fzf](#building-fzf)
Expand Down Expand Up @@ -104,7 +105,7 @@ fzf project consists of the following components:

- `fzf` executable
- `fzf-tmux` script for launching fzf in a tmux pane
- Shell extensions
- Shell integration
- Key bindings (`CTRL-T`, `CTRL-R`, and `ALT-C`) (bash, zsh, fish)
- Fuzzy auto-completion (bash, zsh)
- Vim/Neovim plugin
Expand All @@ -121,11 +122,11 @@ to install fzf.

```sh
brew install fzf

# To install useful key bindings and fuzzy completion:
$(brew --prefix)/opt/fzf/install
```

> :bulb: To set up shell integration (key bindings and fuzzy completion),
> see [the instructions below](#setting-up-shell-integration).

fzf is also available [via MacPorts][portfile]: `sudo port install fzf`

[portfile]: https://github.com/macports/macports-ports/blob/master/sysutils/fzf/Portfile
Expand All @@ -140,6 +141,9 @@ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
```

The install script will add lines to your shell configuration file to modify
`$PATH` and set up shell integration.

### Using Linux package managers

| Package Manager | Linux Distribution | Command |
Expand All @@ -158,10 +162,8 @@ git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
| XBPS | Void Linux | `sudo xbps-install -S fzf` |
| Zypper | openSUSE | `sudo zypper install fzf` |

> :warning: **Key bindings (CTRL-T / CTRL-R / ALT-C) and fuzzy auto-completion
> may not be enabled by default.**
>
> Refer to the package documentation for more information. (e.g. `apt show fzf`)
> :bulb: To set up shell integration (key bindings and fuzzy completion),
> see [the instructions below](#setting-up-shell-integration).

[![Packaging status](https://repology.org/badge/vertical-allrepos/fzf.svg)](https://repology.org/project/fzf/versions)

Expand All @@ -187,6 +189,30 @@ page][windows-wiki].

[windows-wiki]: https://github.com/junegunn/fzf/wiki/Windows

### Setting up shell integration

Add the following line to your shell configuration file.

* bash
```sh
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --bash)"
```
* zsh
```sh
# Set up fzf key bindings and fuzzy completion
eval "$(fzf --zsh)"
```
* fish
```fish
# Set up fzf key bindings
fzf --fish | source
```

> :warning: `--bash`, `--zsh`, and `--fish` options are only available in
> fzf 0.48.0 or above. If you have an older version of fzf, refer to the
> package documentation for more information. (e.g. `apt show fzf`)

### As Vim plugin

If you use
Expand Down Expand Up @@ -319,7 +345,7 @@ or `py`.
- `FZF_DEFAULT_COMMAND`
- Default command to use when input is tty
- e.g. `export FZF_DEFAULT_COMMAND='fd --type f'`
- > :warning: This variable is not used by shell extensions due to the
- > :warning: This variable is not used by shell integration due to the
> slight difference in requirements.
>
> (e.g. `CTRL-T` runs `$FZF_CTRL_T_COMMAND` instead, `vim **<tab>` runs
Expand Down
34 changes: 20 additions & 14 deletions install
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ if [[ ! "\$PATH" == *$fzf_base_esc/bin* ]]; then
PATH="\${PATH:+\${PATH}:}$fzf_base/bin"
fi

EOF

if [[ $auto_completion -eq 1 ]] && [[ $key_bindings -eq 1 ]]; then
echo "eval \"\$(fzf --$shell)\"" >> "$src"
else
cat >> "$src" << EOF
# Auto-completion
# ---------------
$fzf_completion
Expand All @@ -270,6 +276,7 @@ $fzf_completion
# ------------
$fzf_key_bindings
EOF
fi
echo "OK"
done

Expand All @@ -281,18 +288,6 @@ if [[ "$shells" =~ fish ]]; then
or set --universal fish_user_paths \$fish_user_paths "$fzf_base"/bin
EOF
[ $? -eq 0 ] && echo "OK" || echo "Failed"

mkdir -p "${fish_dir}/functions"
fish_binding="${fish_dir}/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() {
Expand Down Expand Up @@ -355,12 +350,23 @@ done
if [ $key_bindings -eq 1 ] && [[ "$shells" =~ fish ]]; then
bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
if [ ! -e "$bind_file" ]; then
mkdir -p "${fish_dir}/functions"
create_file "$bind_file" \
'function fish_user_key_bindings' \
' fzf_key_bindings' \
' fzf --fish | source' \
'end'
else
append_line $update_config "fzf_key_bindings" "$bind_file"
echo "Check $bind_file:"
lno=$(\grep -nF "fzf_key_bindings" "$bind_file" | sed 's/:.*//' | tr '\n' ' ')
if [[ -n $lno ]]; then
echo " ** Found 'fzf_key_bindings' in line #$lno"
echo " ** You have to replace the line to 'fzf --fish | source'"
echo
else
echo " - Clear"
echo
append_line $update_config "fzf --fish | source" "$bind_file"
fi
fi
fi

Expand Down
41 changes: 40 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
package main

import (
_ "embed"
"fmt"

fzf "github.com/junegunn/fzf/src"
"github.com/junegunn/fzf/src/protector"
)

var version string = "0.47"
var revision string = "devel"

//go:embed shell/key-bindings.bash
var bashKeyBindings []byte

//go:embed shell/completion.bash
var bashCompletion []byte

//go:embed shell/key-bindings.zsh
var zshKeyBindings []byte

//go:embed shell/completion.zsh
var zshCompletion []byte

//go:embed shell/key-bindings.fish
var fishKeyBindings []byte

func main() {
protector.Protect()
fzf.Run(fzf.ParseOptions(), version, revision)
options := fzf.ParseOptions()
if options.Bash {
fmt.Println("### key-bindings.bash ###")
fmt.Println(string(bashKeyBindings))
fmt.Println("### completion.bash ###")
fmt.Println(string(bashCompletion))
junegunn marked this conversation as resolved.
Show resolved Hide resolved
return
}
if options.Zsh {
fmt.Println("### key-bindings.zsh ###")
fmt.Println(string(zshKeyBindings))
fmt.Println("### completion.zsh ###")
fmt.Println(string(zshCompletion))
return
}
if options.Fish {
fmt.Println("### key-bindings.fish ###")
fmt.Println(string(fishKeyBindings))
fmt.Println("fzf_key_bindings")
return
}
fzf.Run(options, version, revision)
}
19 changes: 19 additions & 0 deletions man/man1/fzf.1
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,25 @@ Display version information and exit
.TP
Note that most options have the opposite versions with \fB--no-\fR prefix.

.SS Shell integration
.TP
.B "--bash"
Print script to set up Bash shell integration

e.g. \fBeval "$(fzf --bash)"\fR

.TP
.B "--zsh"
Print script to set up Zsh shell integration

e.g. \fBeval "$(fzf --zsh)"\fR

.TP
.B "--fish"
Print script to set up Fish shell integration

e.g. \fBfzf --fish | source\fR

.SH ENVIRONMENT VARIABLES
.TP
.B FZF_DEFAULT_COMMAND
Expand Down
26 changes: 26 additions & 0 deletions src/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ const usage = `usage: fzf [options]
(To allow remote process execution, use --listen-unsafe)
--version Display version information and exit

Shell integration
--bash Print script to set up Bash shell integration
--zsh Print script to set up Zsh shell integration
--fish Print script to set up Fish shell integration

Environment variables
FZF_DEFAULT_COMMAND Default command to use when input is tty
FZF_DEFAULT_OPTS Default options (e.g. '--layout=reverse --info=inline')
Expand Down Expand Up @@ -276,6 +281,9 @@ func firstLine(s string) string {

// Options stores the values of command-line options
type Options struct {
Bash bool
Zsh bool
Fish bool
Fuzzy bool
FuzzyAlgo algo.Algo
Scheme string
Expand Down Expand Up @@ -351,6 +359,9 @@ func defaultPreviewOpts(command string) previewOpts {

func defaultOptions() *Options {
return &Options{
Bash: false,
Zsh: false,
Fish: false,
Fuzzy: true,
FuzzyAlgo: algo.FuzzyMatchV2,
Scheme: "default",
Expand Down Expand Up @@ -1602,6 +1613,21 @@ func parseOptions(opts *Options, allArgs []string) {
for i := 0; i < len(allArgs); i++ {
arg := allArgs[i]
switch arg {
case "--bash":
opts.Bash = true
if opts.Zsh || opts.Fish {
errorExit("cannot specify --bash with --zsh or --fish")
}
case "--zsh":
opts.Zsh = true
if opts.Bash || opts.Fish {
errorExit("cannot specify --zsh with --bash or --fish")
}
case "--fish":
opts.Fish = true
if opts.Bash || opts.Zsh {
errorExit("cannot specify --fish with --bash or --zsh")
}
case "-h", "--help":
help(exitOk)
case "-x", "--extended":
Expand Down
1 change: 1 addition & 0 deletions uninstall
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ done
bind_file="${fish_dir}/functions/fish_user_key_bindings.fish"
if [ -f "$bind_file" ]; then
remove_line "$bind_file" "fzf_key_bindings"
remove_line "$bind_file" "fzf --fish | source"
fi

if [ -d "${fish_dir}/functions" ]; then
Expand Down