summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-03-13 23:59:34 +0900
committerGitHub <noreply@github.com>2024-03-13 23:59:34 +0900
commite74b1251c0f579335e03b3e7182cd7a9f88dbe37 (patch)
tree635d9bd3d4be38ca5623b8ce7241c2674c01b532
parentd282a1649d7d953f028306f13d6616958f3fd1f3 (diff)
Embed shell integration scripts in fzf binary (`--bash` / `--zsh` / `--fish`) (#3675)
This simplifies the distribution, and the users are less likely to have problems caused by using incompatible scripts and binaries. # Set up fzf key bindings and fuzzy completion eval "$(fzf --bash)" # Set up fzf key bindings and fuzzy completion eval "$(fzf --zsh)" # Set up fzf key bindings fzf --fish | source
-rw-r--r--CHANGELOG.md18
-rw-r--r--README.md106
-rwxr-xr-xinstall34
-rw-r--r--main.go43
-rw-r--r--man/man1/fzf.123
-rw-r--r--src/options.go26
-rwxr-xr-xuninstall1
7 files changed, 197 insertions, 54 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 662f0d87..f902833e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,22 @@ 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
+ ```
- Added options for customizing the behavior of the built-in walker
| Option | Description | Default |
| --- | --- | --- |
@@ -28,7 +44,7 @@ CHANGELOG
export FZF_DEFAULT_COMMAND='seq 100'
fzf --walker=dir
```
-- The shell extensions (key bindings and fuzzy completion) have been updated to use the built-in walker with these new options and they are now much faster out of the box.
+- Shell integration scripts have been updated to use the built-in walker with these new options and they are now much faster out of the box.
0.47.0
------
diff --git a/README.md b/README.md
index 3c68962e..e539ea2f 100644
--- a/README.md
+++ b/README.md
@@ -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)
@@ -104,9 +105,9 @@ 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)
+ - Fuzzy completion (bash, zsh)
- Vim/Neovim plugin
You can [download fzf executable][bin] alone if you don't need the extra
@@ -121,11 +122,12 @@ to install fzf.
```sh
brew install fzf
-
-# To install useful key bindings and fuzzy completion:
-$(brew --prefix)/opt/fzf/install
```
+> [!IMPORTANT]
+> 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
@@ -140,6 +142,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 |
@@ -158,10 +163,9 @@ 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`)
+> [!IMPORTANT]
+> 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)
@@ -187,6 +191,31 @@ 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
+ ```
+
+> [!NOTE]
+> `--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
@@ -237,18 +266,20 @@ directory to get the list of files.
vim $(fzf)
```
+> [!NOTE]
> You can override the default behavior
> * Either by setting `$FZF_DEFAULT_COMMAND` to a command that generates the desired list
> * Or by setting `--walker`, `--walker-root`, and `--walker-skip` options in `$FZF_DEFAULT_OPTS`
-> *:bulb: A more robust solution would be to use `xargs` but we've presented
-> the above as it's easier to grasp*
+> [!WARNING]
+> A more robust solution would be to use `xargs` but we've presented
+> the above as it's easier to grasp
> ```sh
> fzf --print0 | xargs -0 -o vim
> ```
->
-> *:bulb: fzf also has the ability to turn itself into a different process.*
+> [!TIP]
+> fzf also has the ability to turn itself into a different process.
>
> ```sh
> fzf --bind 'enter:become(vim {})'
@@ -322,13 +353,6 @@ 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
- > slight difference in requirements.
- >
- > (e.g. `CTRL-T` runs `$FZF_CTRL_T_COMMAND` instead, `vim **<tab>` runs
- > `_fzf_compgen_path()`, and `cd **<tab>` runs `_fzf_compgen_dir()`)
- >
- > The available options are described later in this document.
- `FZF_DEFAULT_OPTS`
- Default options
- e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"`
@@ -337,6 +361,17 @@ or `py`.
point to the location of the file
- e.g. `export FZF_DEFAULT_OPTS_FILE=~/.fzfrc`
+> [!WARNING]
+> `FZF_DEFAULT_COMMAND` is not used by shell integration due to the
+> slight difference in requirements.
+>
+> * `CTRL-T` runs `$FZF_CTRL_T_COMMAND` to get a list of files and directories
+> * `ALT-C` runs `$FZF_ALT_C_COMMAND` to get a list of directories
+> * `vim ~/**<tab>` runs `fzf_compgen_path()` with the prefix (`~/`) as the first argument
+> * `cd foo**<tab>` runs `fzf_compgen_dir()` with the prefix (`foo`) as the first argument
+>
+> The available options are described later in this document.
+
### Options
See the man page (`man fzf`) for the full list of options.
@@ -749,22 +784,21 @@ See the man page (`man fzf`) for the full list of options.
More advanced examples can be found [here](https://github.com/junegunn/fzf/blob/master/ADVANCED.md).
-----
-
-Since fzf is a general-purpose text filter rather than a file finder, **it is
-not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
-
-```sh
-# *********************
-# ** DO NOT DO THIS! **
-# *********************
-export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always --line-range :500 {}"'
-
-# bat doesn't work with any input other than the list of files
-ps -ef | fzf
-seq 100 | fzf
-history | fzf
-```
+> [!WARNING]
+> Since fzf is a general-purpose text filter rather than a file finder, **it is
+> not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
+>
+> ```sh
+> # *********************
+> # ** DO NOT DO THIS! **
+> # *********************
+> export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always --line-range :500 {}"'
+>
+> # bat doesn't work with any input other than the list of files
+> ps -ef | fzf
+> seq 100 | fzf
+> history | fzf
+> ```
### Previewing an image
diff --git a/install b/install
index e790b749..22a0c0be 100755
--- a/install
+++ b/install
@@ -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
@@ -270,6 +276,7 @@ $fzf_completion
# ------------
$fzf_key_bindings
EOF
+ fi
echo "OK"
done
@@ -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() {
@@ -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
diff --git a/main.go b/main.go
index d0350601..debd2408 100644
--- a/main.go
+++ b/main.go
@@ -1,6 +1,10 @@
package main
import (
+ _ "embed"
+ "fmt"
+ "strings"
+
fzf "github.com/junegunn/fzf/src"
"github.com/junegunn/fzf/src/protector"
)
@@ -8,7 +12,44 @@ import (
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 printScript(label string, content []byte) {
+ fmt.Println("### " + label + " ###")
+ fmt.Println(strings.TrimSpace(string(content)))
+ fmt.Println("### end: " + label + " ###")
+}
+
func main() {
protector.Protect()
- fzf.Run(fzf.ParseOptions(), version, revision)
+ options := fzf.ParseOptions()
+ if options.Bash {
+ printScript("key-bindings.bash", bashKeyBindings)
+ printScript("completion.bash", bashCompletion)
+ return
+ }
+ if options.Zsh {
+ printScript("key-bindings.zsh", zshKeyBindings)
+ printScript("completion.zsh", zshCompletion)
+ return
+ }
+ if options.Fish {
+ printScript("key-bindings.fish", fishKeyBindings)
+ fmt.Println("fzf_key_bindings")
+ return
+ }
+ fzf.Run(options, version, revision)
}
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index c29f1e23..56aeeea5 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -33,6 +33,10 @@ fzf [options]
fzf is a general-purpose command-line fuzzy finder.
.SH OPTIONS
+.SS Note
+.TP
+Most long options have the opposite version with \fB--no-\fR prefix.
+
.SS Search mode
.TP
.B "-x, --extended"
@@ -879,9 +883,24 @@ The default value is the current working directory.
Comma-separated list of directory names to skip during the directory walk.
The default value is \fB.git,node_modules\fR.
-.SS Note
+.SS Shell integration
.TP
-Most options have the opposite versions with \fB--no-\fR prefix.
+.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
diff --git a/src/options.go b/src/options.go
index fdad058d..692ce6b2 100644
--- a/src/options.go
+++ b/src/options.go
@@ -130,6 +130,11 @@ const usage = `usage: fzf [options]
--walker-skip=DIRS Comma-separated list of directory names to skip
(default: .git,node_modules)
+ 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')
@@ -289,6 +294,9 @@ type walkerOpts struct {
// Options stores the values of command-line options
type Options struct {
+ Bash bool
+ Zsh bool
+ Fish bool
Fuzzy bool
FuzzyAlgo algo.Algo
Scheme string
@@ -377,6 +385,9 @@ func defaultPreviewOpts(command string) previewOpts {
func defaultOptions() *Options {
return &Options{
+ Bash: false,
+ Zsh: false,
+ Fish: false,
Fuzzy: true,
FuzzyAlgo: algo.FuzzyMatchV2,
Scheme: "default",
@@ -1655,6 +1666,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":
diff --git a/uninstall b/uninstall
index 4e587211..1d338cb4 100755
--- a/uninstall
+++ b/uninstall
@@ -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