diff options
-rw-r--r-- | .github/workflows/typos.yml | 2 | ||||
-rw-r--r-- | .goreleaser.yml | 6 | ||||
-rw-r--r-- | CHANGELOG.md | 62 | ||||
-rw-r--r-- | Dockerfile | 4 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rwxr-xr-x | bin/fzf-tmux | 2 | ||||
-rwxr-xr-x | install | 2 | ||||
-rw-r--r-- | install.ps1 | 2 | ||||
-rw-r--r-- | main.go | 2 | ||||
-rw-r--r-- | man/man1/fzf-tmux.1 | 2 | ||||
-rw-r--r-- | man/man1/fzf.1 | 22 | ||||
-rw-r--r-- | shell/completion.bash | 101 | ||||
-rw-r--r-- | shell/completion.zsh | 27 | ||||
-rw-r--r-- | shell/key-bindings.bash | 34 | ||||
-rw-r--r-- | shell/key-bindings.fish | 18 | ||||
-rw-r--r-- | shell/key-bindings.zsh | 30 | ||||
-rw-r--r-- | src/actiontype_string.go | 187 | ||||
-rw-r--r-- | src/core.go | 14 | ||||
-rw-r--r-- | src/options.go | 22 | ||||
-rw-r--r-- | src/reader.go | 9 | ||||
-rw-r--r-- | src/reader_test.go | 3 | ||||
-rw-r--r-- | src/server.go | 2 | ||||
-rw-r--r-- | src/terminal.go | 72 | ||||
-rw-r--r-- | src/terminal_test.go | 10 | ||||
-rw-r--r-- | src/terminal_unix.go | 19 | ||||
-rw-r--r-- | src/terminal_windows.go | 26 | ||||
-rw-r--r-- | src/util/util_unix.go | 56 | ||||
-rw-r--r-- | src/util/util_windows.go | 157 | ||||
-rwxr-xr-x | test/test_go.rb | 41 |
30 files changed, 571 insertions, 376 deletions
diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 752c58c6..91f21864 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: crate-ci/typos@v1.19.0 + - uses: crate-ci/typos@v1.20.9 diff --git a/.goreleaser.yml b/.goreleaser.yml index 1ac56108..86e821f0 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -12,6 +12,8 @@ builds: - darwin goarch: - amd64 + flags: + - -trimpath ldflags: - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}" hooks: @@ -36,6 +38,8 @@ builds: - darwin goarch: - arm64 + flags: + - -trimpath ldflags: - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}" hooks: @@ -71,6 +75,8 @@ builds: - 5 - 6 - 7 + flags: + - -trimpath ldflags: - "-s -w -X main.version={{ .Version }} -X main.revision={{ .ShortCommit }}" ignore: diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de28297..911f043a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,41 +1,44 @@ CHANGELOG ========= -0.50.0 +0.51.0 ------ -- Search performance optimization. You can observe 50%+ improvement in some scenarios. +- Added a new environment variable `$FZF_POS` exported to the child processes. It's the vertical position of the cursor in the list starting from 1. ```sh - $ time wc < $DATA - 5520118 26862362 897487793 - - real 0m1.320s - user 0m1.236s - sys 0m0.075s + # Toggle selection to the top or to the bottom + seq 30 | fzf --multi --bind 'load:pos(10)' \ + --bind 'shift-up:transform:for _ in $(seq $FZF_POS $FZF_MATCH_COUNT); do echo -n +toggle+up; done' \ + --bind 'shift-down:transform:for _ in $(seq 1 $FZF_POS); do echo -n +toggle+down; done' + ``` +- Added `--with-shell` option to start child processes with a custom shell command and flags + ```sh + gem list | fzf --with-shell 'ruby -e' \ + --preview 'pp Gem::Specification.find_by_name({1})' \ + --bind 'ctrl-o:execute-silent: + spec = Gem::Specification.find_by_name({1}) + [spec.homepage, *spec.metadata.filter { _1.end_with?("uri") }.values].uniq.each do + system "open", _1 + end + ' + ``` +- Added `change-multi` action for dynamically changing `--multi` option + - `change-multi` - enable multi-select mode with no limit + - `change-multi(NUM)` - enable multi-select mode with a limit + - `change-multi(0)` - disable multi-select mode +- `become` action is now supported on Windows + - Unlike in *nix, this does not use `execve(2)`. Instead it spawns a new process and waits for it to finish, so the exact behavior may differ. +- Bug fixes and improvements - $ time fzf --sync --bind load:abort < $DATA +0.50.0 +------ +- Search performance optimization. You can observe 50%+ improvement in some scenarios. + ``` + $ rg --line-number --no-heading --smart-case . > $DATA - real 0m0.479s - user 0m0.427s - sys 0m0.176s + $ wc < $DATA + 5520118 26862362 897487793 $ hyperfine -w 1 -L bin fzf-0.49.0,fzf-7ce6452,fzf-a5447b8,fzf '{bin} --filter "///" < $DATA | head -30' - - Benchmark 1: fzf-0.49.0 --filter "///" < $DATA | head -30 - Time (mean ± σ): 2.002 s ± 0.024 s [User: 14.447 s, System: 0.300 s] - Range (min … max): 1.964 s … 2.042 s 10 runs - - Benchmark 2: fzf-7ce6452 --filter "///" < $DATA | head -30 - Time (mean ± σ): 1.627 s ± 0.019 s [User: 10.828 s, System: 0.271 s] - Range (min … max): 1.596 s … 1.651 s 10 runs - - Benchmark 3: fzf-a5447b8 --filter "///" < $DATA | head -30 - Time (mean ± σ): 1.524 s ± 0.025 s [User: 9.818 s, System: 0.269 s] - Range (min … max): 1.478 s … 1.569 s 10 runs - - Benchmark 4: fzf --filter "///" < $DATA | head -30 - Time (mean ± σ): 1.318 s ± 0.025 s [User: 8.005 s, System: 0.262 s] - Range (min … max): 1.282 s … 1.366 s 10 runs - Summary fzf --filter "///" < $DATA | head -30 ran 1.16 ± 0.03 times faster than fzf-a5447b8 --filter "///" < $DATA | head -30 @@ -60,6 +63,7 @@ CHANGELOG ```sh fzf --bind 'space:jump,jump:accept,jump-cancel:transform:[[ $FZF_KEY =~ ctrl-c ]] && echo abort' ``` +- fzf can be built with profiling options. See [BUILD.md](BUILD.md) for more information. - Bug fixes 0.49.0 @@ -1,6 +1,6 @@ -FROM --platform=linux/amd64 ubuntu:22.04 +FROM ubuntu:24.04 RUN apt-get update -y && apt install -y git make golang zsh fish ruby tmux -RUN gem install --no-document -v 5.14.2 minitest +RUN gem install --no-document -v 5.22.3 minitest RUN echo '. /usr/share/bash-completion/completions/git' >> ~/.bashrc RUN echo '. ~/.bashrc' >> ~/.bash_profile @@ -25,7 +25,7 @@ endif ifeq ($(REVISION),) $(error Not on git repository; cannot determine $$FZF_REVISION) endif -BUILD_FLAGS := -a -ldflags "-s -w -X main.version=$(VERSION) -X main.revision=$(REVISION)" -tags "$(TAGS)" +BUILD_FLAGS := -a -ldflags "-s -w -X main.version=$(VERSION) -X main.revision=$(REVISION)" -tags "$(TAGS)" -trimpath BINARY32 := fzf-$(GOOS)_386 BINARY64 := fzf-$(GOOS)_amd64 @@ -174,12 +174,12 @@ bin/fzf: target/$(BINARY) | bin cp -f target/$(BINARY) bin/fzf docker: - docker build -t fzf-arch . - docker run -it fzf-arch tmux + docker build -t fzf-ubuntu . + docker run -it fzf-ubuntu tmux docker-test: - docker build -t fzf-arch . - docker run -it fzf-arch + docker build -t fzf-ubuntu . + docker run -it fzf-ubuntu update: $(GO) get -u @@ -44,7 +44,7 @@ I would like to thank all the sponsors of this project who make it possible for If you'd like to sponsor this project, please visit https://github.com/sponsors/junegunn. -<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden-Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav Marohnić" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://github.com/benelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="Paweł Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><img src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="https://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><a href="https://github.com/khuedoan"><img src="https://github.com/khuedoan.png" width="60px" alt="Khue Doan" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="Guillaume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="" /></a><a href="https://github.com/mrcnski"><img src="https://github.com/mrcnski.png" width="60px" alt="Marcin S." /></a><a href="https://github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="Rob Levy" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="Gloria Zhao" /></a><a href="https://github.com/wjt"><img src="https://github.com/wjt.png" width="60px" alt="Will Thompson" /></a><a href="https://github.com/mauricelam"><img src="https://github.com/mauricelam.png" width="60px" alt="Maurice Lam" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="" /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="James O'Beirne" /></a><a href="https://github.com/joshuatz"><img src="https://github.com/joshuatz.png" width="60px" alt="Joshua Tzucker" /></a><!-- sponsors --> +<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden-Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav Marohnić" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://github.com/benelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="Paweł Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><img src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="https://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><a href="https://github.com/khuedoan"><img src="https://github.com/khuedoan.png" width="60px" alt="Khue Doan" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="Guillaume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="" /></a><a href="https://github.com/mrcnski"><img src="https://github.com/mrcnski.png" width="60px" alt="Marcin S." /></a><a href="https://github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="Rob Levy" /></a><a href="https://github.com/warpdotdev"><img src="https://github.com/warpdotdev.png" width="60px" alt="Warp" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="Gloria Zhao" /></a><a href="https://github.com/wjt"><img src="https://github.com/wjt.png" width="60px" alt="Will Thompson" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="" /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="James O'Beirne" /></a><a href="https://github.com/joshuatz"><img src="https://github.com/joshuatz.png" width="60px" alt="Joshua Tzucker" /></a><a href="https://github.com/gpopides"><img src="https://github.com/gpopides.png" width="60px" alt="gpopides" /></a><a href="https://github.com/jlebray"><img src="https://github.com/jlebray.png" width="60px" alt="Johan Le Bray" /></a><!-- sponsors --> Table of Contents ----------------- @@ -122,6 +122,7 @@ to install fzf. ```sh brew install fzf + # To build fzf from the latest source: brew install --HEAD fzf ``` > [!IMPORTANT] diff --git a/bin/fzf-tmux b/bin/fzf-tmux index 1c3c38cc..e66dcda5 100755 --- a/bin/fzf-tmux +++ b/bin/fzf-tmux @@ -7,7 +7,7 @@ fail() { exit 2 } -fzf="$(command -v fzf 2> /dev/null)" || fzf="$(dirname "$0")/fzf" +fzf="$(command which fzf)" || fzf="$(dirname "$0")/fzf" [[ -x "$fzf" ]] || fail 'fzf executable not found' args=() @@ -2,7 +2,7 @@ set -u -version=0.49.0 +version=0.50.0 auto_completion= key_bindings= update_config=2 diff --git a/install.ps1 b/install.ps1 index c4331f8c..deb97490 100644 --- a/install.ps1 +++ b/install.ps1 @@ -1,4 +1,4 @@ -$version="0.49.0" +$version="0.50.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition @@ -9,7 +9,7 @@ import ( "github.com/junegunn/fzf/src/protector" ) -var version string = "0.49" +var version string = "0.50" var revision string = "devel" //go:embed shell/key-bindings.bash diff --git a/man/man1/fzf-tmux.1 b/man/man1/fzf-tmux.1 index 03a3d729..750a5904 100644 --- a/man/man1/fzf-tmux.1 +++ b/man/man1/fzf-tmux.1 @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf-tmux 1 "Apr 2024" "fzf 0.49.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Apr 2024" "fzf 0.50.0" "fzf-tmux - open fzf in tmux split pane" .SH NAME fzf-tmux - open fzf in tmux split pane diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index fc621c3e..8e79c2e4 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Apr 2024" "fzf 0.49.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Apr 2024" "fzf 0.50.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -812,12 +812,22 @@ e.g. .TP .B "--sync" Synchronous search for multi-staged filtering. If specified, fzf will launch -ncurses finder only after the input stream is complete. +the finder only after the input stream is complete. .RS e.g. \fBfzf --multi | fzf --sync\fR .RE .TP +.B "--with-shell=STR" +Shell command and flags to start child processes with. On *nix Systems, the +default value is \fB$SHELL -c\fR if \fB$SHELL\fR is set, otherwise \fBsh -c\fR. +On Windows, the default value is \fBcmd /v:on/s/c\fR when \fB$SHELL\fR is not +set. + +.RS +e.g. \fBgem list | fzf --with-shell 'ruby -e' --preview 'pp Gem::Specification.find_by_name({1})'\fR +.RE +.TP .B "--listen[=[ADDR:]PORT]" "--listen-unsafe[=[ADDR:]PORT]" Start HTTP server and listen on the given address. It allows external processes to send actions to perform via POST method. @@ -932,6 +942,8 @@ you need to protect against DNS rebinding and privilege escalation attacks. .br .BR 2 " Error" .br +.BR 127 " Invalid shell command for \fBbecome\fR action" +.br .BR 130 " Interrupted with \fBCTRL-C\fR or \fBESC\fR" .SH FIELD INDEX EXPRESSION @@ -972,6 +984,8 @@ fzf exports the following environment variables to its child processes. .br .BR FZF_SELECT_COUNT " Number of selected items" .br +.BR FZF_POS " Vertical position of the cursor in the list starting from 1" +.br .BR FZF_QUERY " Current query string" .br .BR FZF_PROMPT " Prompt string" @@ -1282,6 +1296,8 @@ A key or an event can be bound to one or more of the following actions. \fBcancel\fR (clear query string if not empty, abort fzf otherwise) \fBchange-border-label(...)\fR (change \fB--border-label\fR to the given string) \fBchange-header(...)\fR (change header to the given string; doesn't affect \fB--header-lines\fR) + \fBchange-multi\fR (enable multi-select mode with no limit) + \fBchange-multi(...)\fR (enable multi-select mode with a limit or disable it with 0) \fBchange-preview(...)\fR (change \fB--preview\fR option) \fBchange-preview-label(...)\fR (change \fB--preview-label\fR to the given string) \fBchange-preview-window(...)\fR (change \fB--preview-window\fR option; rotate through the multiple option sets separated by '|') @@ -1439,8 +1455,6 @@ call. \fBfzf --bind "enter:become(vim {})"\fR -\fBbecome(...)\fR is not supported on Windows. - .SS RELOAD INPUT \fBreload(...)\fR action is used to dynamically update the input list diff --git a/shell/completion.bash b/shell/completion.bash index 5786d046..43fa46af 100644 --- a/shell/completion.bash +++ b/shell/completion.bash @@ -32,6 +32,14 @@ if [[ $- =~ i ]]; then # To redraw line after fzf closes (printf '\e[5n') bind '"\e[0n": redraw-current-line' 2> /dev/null +__fzf_defaults() { + # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + echo "--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $1" + command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null + echo "${FZF_DEFAULT_OPTS-} $2" +} + __fzf_comprun() { if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then _fzf_comprun "$@" @@ -92,128 +100,77 @@ _fzf_opts_completion() { prev="${COMP_WORDS[COMP_CWORD-1]}" opts=" -h --help - -x --extended -e --exact - --extended-exact +x --no-extended - +e --no-exact -q --query -f --filter --literal - --no-literal - --algo --scheme --expect - --no-expect - --enabled --no-phony - --disabled --phony + --disabled --tiebreak --bind --color - --toggle-sort -d --delimiter -n --nth --with-nth - -s --sort +s --no-sort --track - --no-track --tac - --no-tac -i +i -m --multi - +m --no-multi --ansi - --no-ansi --no-mouse +c --no-color - +2 --no-256 - --black - --no-black - --bold --no-bold --layout --reverse - --no-reverse --cycle - --no-cycle --keep-right - --no-keep-right - --hscroll --no-hscroll --hscroll-off --scroll-off --filepath-word - --no-filepath-word --info - --no-info - --inline-info - --no-inline-info --separator --no-separator - --scrollbar --no-scrollbar --jump-labels -1 --select-1 - +1 --no-select-1 -0 --exit-0 - +0 --no-exit-0 --read0 - --no-read0 --print0 - --no-print0 --print-query - --no-print-query --prompt --pointer --marker --sync - --no-sync - --async - --no-history --history --history-size - --no-header - --no-header-lines --header --header-lines --header-first - --no-header-first --ellipsis --preview - --no-preview --preview-window --height --min-height - --no-height - --no-margin - --no-padding - --no-border --border - --no-border-label --border-label --border-label-pos - --no-preview-label --preview-label --preview-label-pos --no-unicode - --unicode --margin --padding --tabstop --listen - --no-listen - --clear --no-clear --version --" case "${prev}" in - --algo) - COMPREPLY=( $(compgen -W "v1 v2" -- "$cur") ) - return 0 - ;; --scheme) COMPREPLY=( $(compgen -W "default path history" -- "$cur") ) return 0 @@ -335,8 +292,8 @@ __fzf_generic_path_completion() { [[ -z "$dir" ]] && dir='.' [[ "$dir" != "/" ]] && dir="${dir/%\//}" matches=$( - unset FZF_DEFAULT_COMMAND - export FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --scheme=path --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $2" + export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-} $2") + unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE if declare -F "$1" > /dev/null; then eval "$1 $(printf %q "$dir")" | __fzf_comprun "$4" -q "$leftover" else @@ -399,7 +356,10 @@ _fzf_complete() { if [[ "$cur" == *"$trigger" ]] && [[ $cur != *'$('* ]] && [[ $cur != *':='* ]] && [[ $cur != *'`'* ]]; then cur=${cur:0:${#cur}-${#trigger}} - selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | command tr '\n' ' ') + selected=$( + FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \ + FZF_DEFAULT_OPTS_FILE='' \ + __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | command tr '\n' ' ') selected=${selected% } # Strip trailing space not to repeat "-o nospace" if [[ -n "$selected" ]]; then COMPREPLY=("$selected") @@ -503,8 +463,11 @@ complete -o default -F _fzf_opts_completion fzf # fzf-tmux specific options (like `-w WIDTH`) are left as a future patch. complete -o default -F _fzf_opts_completion fzf-tmux -d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}" -a_cmds=" +d_cmds="${FZF_COMPLETION_DIR_COMMANDS-cd pushd rmdir}" + +# NOTE: $FZF_COMPLETION_PATH_COMMANDS and $FZF_COMPLETION_VAR_COMMANDS are +# undocumented and subject to change in the future. +a_cmds="${FZF_COMPLETION_PATH_COMMANDS-" awk bat cat diff diff3 emacs emacsclient ex file ftp g++ gcc gvim head hg hx java javac ld less more mvim nvim patch perl python ruby @@ -512,10 +475,11 @@ a_cmds=" basename bunzip2 bzip2 chmod chown curl cp dirname du find git grep gunzip gzip hg jar ln ls mv open rm rsync scp - svn tar unzip zip" + svn tar unzip zip"}" +v_cmds="${FZF_COMPLETION_VAR_COMMANDS-export unset printenv}" # Preserve existing completion -__fzf_orig_completion < <(complete -p $d_cmds $a_cmds ssh 2> /dev/null) +__fzf_orig_completion < <(complete -p $d_cmds $a_cmds $v_cmds unalias kill ssh 2> /dev/null) if type _comp_load > /dev/null 2>&1; then # _comp_load was added in bash-completion 2.12 to replace _completion_loader. @@ -551,10 +515,21 @@ for cmd in $d_cmds; do __fzf_defc "$cmd" _fzf_dir_completion "-o bashdefault -o nospace -o dirnames" done +# Variables +for cmd in $v_cmds; do + __fzf_defc "$cmd" _fzf_var_completion "-o default -o nospace -v" +done + +# Aliases +__fzf_defc unalias _fzf_alias_completion "-a" + +# Processes +__fzf_defc kill _fzf_proc_completion "-o default -o bashdefault" + # ssh __fzf_defc ssh _fzf_complete_ssh "-o default -o bashdefault" -unset cmd d_cmds a_cmds +unset cmd d_cmds a_cmds v_cmds _fzf_setup_completion() { local kind fn cmd @@ -576,10 +551,4 @@ _fzf_setup_completion() { done } -# Environment variables / Aliases / Hosts / Process -_fzf_setup_completion 'var' export unset printenv -_fzf_setup_completion 'alias' unalias -_fzf_setup_completion 'host' telnet -_fzf_setup_completion 'proc' kill - fi diff --git a/shell/completion.zsh b/shell/completion.zsh index 7067b06f..ddf5f4bb 100644 --- a/shell/completion.zsh +++ b/shell/completion.zsh @@ -9,8 +9,6 @@ # - $FZF_COMPLETION_TRIGGER (default: '**') # - $FZF_COMPLETION_OPTS (default: empty) -if [[ -o interactive ]]; then - # Both branches of the following `if` do the same thing -- define # __fzf_completion_options such that `eval $__fzf_completion_options` sets @@ -75,6 +73,9 @@ fi # This brace is the start of try-always block. The `always` part is like # `finally` in lesser languages. We use it to *always* restore user options. { +# The 'emulate' command should not be placed inside the interactive if check; +# placing it there fails to disable alias expansion. See #3731. +if [[ -o interactive ]]; then # To use custom commands instead of find, override _fzf_compgen_{path,dir} # @@ -93,6 +94,14 @@ fi ########################################################### +__fzf_defaults() { + # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + echo "--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $1" + command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null + echo "${FZF_DEFAULT_OPTS-} $2" +} + __fzf_comprun() { if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then _fzf_comprun "$@" @@ -146,8 +155,8 @@ __fzf_generic_path_completion() { [ -z "$dir" ] && dir='.' [ "$dir" != "/" ] && dir="${dir/%\//}" matches=$( - unset FZF_DEFAULT_COMMAND - export FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --scheme=path --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-}" + export FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --scheme=path" "${FZF_COMPLETION_OPTS-}") + unset FZF_DEFAULT_COMMAND FZF_DEFAULT_OPTS_FILE if declare -f "$compgen" > /dev/null; then eval "$compgen $(printf %q "$dir")" | __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" else @@ -217,7 +226,10 @@ _fzf_complete() { type $post > /dev/null 2>&1 || post=cat _fzf_feed_fifo "$fifo" - matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore ${FZF_DEFAULT_OPTS-} ${FZF_COMPLETION_OPTS-} $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ') + matches=$( + FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse" "${FZF_COMPLETION_OPTS-} $str_arg") \ + FZF_DEFAULT_OPTS_FILE='' \ + __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post |