m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-14 22:33:47 -05:00

Compare commits

...

29 Commits

Author SHA1 Message Date
Junegunn Choi
b49f22cdf9 0.16.8 2017-06-05 23:21:50 +09:00
Jan Edmund Lazo
7e483b0c25 [vim] Add support for Cygwin (#933) 2017-06-05 13:54:47 +09:00
Junegunn Choi
3cf9ae04c7 [fzf-tmux] Fix cleanup of temporary files
Close #935
2017-06-04 23:24:57 +09:00
Junegunn Choi
bf0cb4bfe2 Use find as the default command on Cygwin environment 2017-06-04 16:23:47 +09:00
Junegunn Choi
773133c4ce [vim] Allow running install --bin on Cygwin 2017-06-04 15:15:46 +09:00
Junegunn Choi
ca0b3b6fd7 Fixes for Cygwin
- Update install script to download Windows binary if $TERM == cygwin
- Unset TERM if $TERM == cygwin (#933)
- Always use cmd.exe instead of $SHELL when running commands
2017-06-03 19:47:53 +09:00
Junegunn Choi
f4731c0514 Merge branch 'master' into devel 2017-06-03 19:42:26 +09:00
Junegunn Choi
34f16e5b7d Fix Makefile and install script for the new project layout 2017-06-02 18:19:21 +09:00
Junegunn Choi
83e9af6601 Add git revision to --version output 2017-06-02 17:59:12 +09:00
Junegunn Choi
8bbf9335e1 Restructuring: main package in project root 2017-06-02 17:59:01 +09:00
Junegunn Choi
159f30b37f Merge branch 'glide' of https://github.com/hinshun/fzf into hinshun-glide 2017-06-02 13:35:40 +09:00
Junegunn Choi
2e3dc75425 Fix inconsistent tiebreak scores when --nth is used
Make sure to consistently calculate tiebreak scores based on the
original line.

This change may not be preferable if you filter aligned tabular input on
a subset of columns using --nth. However, if we calculate length
tiebreak only on the matched components instead of the entire line, the
result can be very confusing when multiple --nth components are
specified, so let's keep it simple and consistent.

Close #926
2017-06-02 13:25:35 +09:00
Edgar Lee
7d3575b362 Use glide to handle go dependencies 2017-06-01 17:08:47 -07:00
Junegunn Choi
35d407021c [vim] Replace invalid s:escape calls with fzf#shellescape 2017-05-31 23:59:11 +09:00
Junegunn Choi
076f49d447 [vim] Make sure to delete temporary batchfile on Windows 2017-05-31 10:03:23 +09:00
Junegunn Choi
0665fe0413 [vim] Remove unnecessary ternary expression
Related: https://github.com/junegunn/fzf.vim/issues/378
2017-05-31 10:02:04 +09:00
Jan Edmund Lazo
669a6fee40 [vim] Use utf-8 for cmd.exe (#929) 2017-05-31 09:56:01 +09:00
Jan Edmund Lazo
8aab0fc189 [vim] Replace s:fzf_shellescape and s:shellesc with fzf#shellescape (#916) 2017-05-29 10:06:06 +09:00
Junegunn Choi
5d6eb5bfd6 Respect ANSI color state from the previous line in preview output 2017-05-28 02:26:42 +09:00
Junegunn Choi
cf4711d878 Fix display of tab characters in --prompt 2017-05-26 19:02:49 +09:00
Junegunn Choi
21d664d670 Update extra bash completion example 2017-05-25 19:09:04 +09:00
Tw
ab182e276b Use read syscall directly to get character (#931)
Due to go std lib uses poller for os.File introducing in this commit:
c05b06a12d
There are two changes to watch out:
1. os.File.Fd will always return a blocking fd except on bsd.
2. os.File.Read won't return EAGAIN error for nonblocking fd.

So
For 1, we just get tty's fd in advance and then set its block mode.
For 2, we use read syscall directly to get what we wanted error(EAGAIN).

Fix issue #910.

Signed-off-by: Tw <tw19881113@gmail.com>
2017-05-25 01:36:59 +09:00
Junegunn Choi
96a3250152 Update test case for --cycle 2017-05-24 13:20:13 +09:00
Junegunn Choi
f5746002fd Do not "--cycle" on page-up/page-down
Close #928
2017-05-24 02:43:39 +09:00
Junegunn Choi
e1e3339770 Implement bindable "change" event and "top" action
# Move cursor to the top result whenever the query string is changed
    fzf --bind change:top

Close #925
2017-05-22 17:07:05 +09:00
Junegunn Choi
3a5086796d [vim] Prevent 'wildignore' from affecting expand() (#917) 2017-05-22 01:23:59 +09:00
Junegunn Choi
11300913a4 [vim] Do not expand s:fzf_go
expand() may return an empty string depending on the value of
&wildignore. Since expand('<sfile>') always returns an absolute path, we
can remove expand() call here. Close #917.
2017-05-22 01:04:04 +09:00
Aurelien Rainone
e65f14cbed Update README: Add table of contents (#927) 2017-05-20 19:08:56 +09:00
Theodore Dubois
6898849e3e Mention that the fish bug has been fixed (#912) 2017-05-05 10:48:28 +09:00
37 changed files with 514 additions and 477 deletions

6
.gitignore vendored
View File

@@ -1,7 +1,7 @@
bin
src/fzf/fzf-*
gopath
bin/fzf
target
pkg
Gemfile.lock
.DS_Store
doc/tags
vendor

View File

@@ -16,13 +16,6 @@ install:
- sudo apt-get install -y zsh fish
script: |
export GOPATH=~/go
export FZF_BASE=$GOPATH/src/github.com/junegunn/fzf
mkdir -p $GOPATH/src/github.com/junegunn
ln -s $(pwd) $FZF_BASE
cd $FZF_BASE/src && make test fzf/fzf-linux_amd64 install &&
cd $FZF_BASE/bin && ln -sf fzf-linux_amd64 fzf-$(./fzf --version)-linux_amd64 &&
cd $FZF_BASE && yes | ./install && rm -f fzf &&
make test install &&
./install --all &&
tmux new "ruby test/test_go.rb > out && touch ok" && cat out && [ -e ok ]

View File

@@ -13,19 +13,16 @@ Build instructions
Makefile will set up and use its own `$GOPATH` under the project root.
```sh
# Source files are located in src directory
cd src
# Build fzf binary for your platform in src/fzf
# Build fzf binary for your platform in target
make
# Build fzf binary and copy it to bin directory
make install
# Build 32-bit and 64-bit executables and tarballs
# Build 32-bit and 64-bit executables and tarballs in target
make release
# Make release archives for all supported platforms
# Make release archives for all supported platforms in target
make release-all
```
@@ -35,7 +32,7 @@ Alternatively, you can build fzf directly with `go get` command without
manually cloning the repository.
```sh
go get -u github.com/junegunn/fzf/src/fzf
go get -u github.com/junegunn/fzf
```
Third-party libraries used

View File

@@ -1,6 +1,20 @@
CHANGELOG
=========
0.16.8
------
- New `change` event and `top` action for `--bind`
- `fzf --bind change:top`
- Move cursor to the top result whenever the query string is changed
- `fzf --bind ctrl-u:unix-word-rubout+top`
- `top` combined with `unix-word-rubout`
- Fixed inconsistent tiebreak scores when `--nth` is used
- Proper display of tab characters in `--prompt`
- Fixed not to `--cycle` on page-up/page-down to prevent overshoot
- Git revision in `--version` output
- Basic support for Cygwin environment
- Many fixes in Vim plugin on Windows/Cygwin (thanks to @janlazo)
0.16.7
------
- Added support for `ctrl-alt-[a-z]` key chords

138
Makefile Normal file
View File

@@ -0,0 +1,138 @@
ifndef GOOS
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
GOOS := darwin
else ifeq ($(UNAME_S),Linux)
GOOS := linux
else
$(error "$$GOOS is not defined.")
endif
endif
MAKEFILE := $(realpath $(lastword $(MAKEFILE_LIST)))
ROOT_DIR := $(shell dirname $(MAKEFILE))
GOPATH := $(ROOT_DIR)/gopath
SRC_LINK := $(GOPATH)/src/github.com/junegunn/fzf/src
VENDOR_LINK := $(GOPATH)/src/github.com/junegunn/fzf/vendor
export GOPATH
GLIDE_YAML := glide.yaml
GLIDE_LOCK := glide.lock
SOURCES := $(wildcard *.go src/*.go src/*/*.go) $(SRC_LINK) $(VENDOR_LINK) $(GLIDE_LOCK) $(MAKEFILE)
REVISION := $(shell git log -n 1 --pretty=format:%h -- $(SOURCES))
BUILD_FLAGS := -a -ldflags "-X main.revision=$(REVISION) -w -extldflags=$(LDFLAGS)" -tags "$(TAGS)"
BINARY32 := fzf-$(GOOS)_386
BINARY64 := fzf-$(GOOS)_amd64
BINARYARM5 := fzf-$(GOOS)_arm5
BINARYARM6 := fzf-$(GOOS)_arm6
BINARYARM7 := fzf-$(GOOS)_arm7
BINARYARM8 := fzf-$(GOOS)_arm8
VERSION := $(shell awk -F= '/version =/ {print $$2}' src/constants.go | tr -d "\" ")
RELEASE32 := fzf-$(VERSION)-$(GOOS)_386
RELEASE64 := fzf-$(VERSION)-$(GOOS)_amd64
RELEASEARM5 := fzf-$(VERSION)-$(GOOS)_arm5
RELEASEARM6 := fzf-$(VERSION)-$(GOOS)_arm6
RELEASEARM7 := fzf-$(VERSION)-$(GOOS)_arm7
RELEASEARM8 := fzf-$(VERSION)-$(GOOS)_arm8
# https://en.wikipedia.org/wiki/Uname
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_M),x86_64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),amd64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),i686)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),i386)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),armv5l)
BINARY := $(BINARYARM5)
else ifeq ($(UNAME_M),armv6l)
BINARY := $(BINARYARM6)
else ifeq ($(UNAME_M),armv7l)
BINARY := $(BINARYARM7)
else
$(error "Build on $(UNAME_M) is not supported, yet.")
endif
all: target/$(BINARY)
target:
mkdir -p $@
ifeq ($(GOOS),windows)
release: target/$(BINARY32) target/$(BINARY64)
cd target && cp -f $(BINARY32) fzf.exe && zip $(RELEASE32).zip fzf.exe
cd target && cp -f $(BINARY64) fzf.exe && zip $(RELEASE64).zip fzf.exe
cd target && rm -f fzf.exe
else ifeq ($(GOOS),linux)
release: target/$(BINARY32) target/$(BINARY64) target/$(BINARYARM5) target/$(BINARYARM6) target/$(BINARYARM7) target/$(BINARYARM8)
cd target && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
cd target && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd target && cp -f $(BINARYARM5) fzf && tar -czf $(RELEASEARM5).tgz fzf
cd target && cp -f $(BINARYARM6) fzf && tar -czf $(RELEASEARM6).tgz fzf
cd target && cp -f $(BINARYARM7) fzf && tar -czf $(RELEASEARM7).tgz fzf
cd target && cp -f $(BINARYARM8) fzf && tar -czf $(RELEASEARM8).tgz fzf
cd target && rm -f fzf
else
release: target/$(BINARY32) target/$(BINARY64)
cd target && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
cd target && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd target && rm -f fzf
endif
release-all: clean test
GOOS=darwin make release
GOOS=linux make release
GOOS=freebsd make release
GOOS=openbsd make release
GOOS=windows make release
$(SRC_LINK):
mkdir -p $(shell dirname $(SRC_LINK))
ln -sf $(ROOT_DIR)/src $(SRC_LINK)
$(VENDOR_LINK):
mkdir -p $(shell dirname $(VENDOR_LINK))
ln -sf $(ROOT_DIR)/vendor $(VENDOR_LINK)
vendor: $(GLIDE_YAML)
go get -u github.com/Masterminds/glide && $(GOPATH)/bin/glide install && touch $@
test: $(SOURCES) vendor
SHELL=/bin/sh GOOS= go test -v -tags "$(TAGS)" \
github.com/junegunn/fzf/src \
github.com/junegunn/fzf/src/algo \
github.com/junegunn/fzf/src/tui \
github.com/junegunn/fzf/src/util
install: bin/fzf
clean:
rm -rf target
target/$(BINARY32): $(SOURCES) vendor
GOARCH=386 go build $(BUILD_FLAGS) -o $@
target/$(BINARY64): $(SOURCES) vendor
GOARCH=amd64 go build $(BUILD_FLAGS) -o $@
# https://github.com/golang/go/wiki/GoArm
target/$(BINARYARM5): $(SOURCES) vendor
GOARCH=arm GOARM=5 go build $(BUILD_FLAGS) -o $@
target/$(BINARYARM6): $(SOURCES) vendor
GOARCH=arm GOARM=6 go build $(BUILD_FLAGS) -o $@
target/$(BINARYARM7): $(SOURCES) vendor
GOARCH=arm GOARM=7 go build $(BUILD_FLAGS) -o $@
target/$(BINARYARM8): $(SOURCES) vendor
GOARCH=arm64 go build $(BUILD_FLAGS) -o $@
bin/fzf: target/$(BINARY) | bin
cp -f target/$(BINARY) bin/fzf
.PHONY: all release release-all test install clean

View File

@@ -15,6 +15,39 @@ Pros
- Batteries included
- Vim/Neovim plugin, key bindings and fuzzy auto-completion
Table of Contents
-----------------
* [Installation](#installation)
* [Using git](#using-git)
* [Using Homebrew](#using-homebrew)
* [As Vim plugin](#as-vim-plugin)
* [Windows](#windows)
* [Upgrading fzf](#upgrading-fzf)
* [Building fzf](#building-fzf)
* [Usage](#usage)
* [Using the finder](#using-the-finder)
* [Layout](#layout)
* [Search syntax](#search-syntax)
* [Environment variables](#environment-variables)
* [Options](#options)
* [Examples](#examples)
* [fzf-tmux script](#fzf-tmux-script)
* [Key bindings for command line](#key-bindings-for-command-line)
* [Fuzzy completion for bash and zsh](#fuzzy-completion-for-bash-and-zsh)
* [Files and directories](#files-and-directories)
* [Process IDs](#process-ids)
* [Host names](#host-names)
* [Environment variables / Aliases](#environment-variables--aliases)
* [Settings](#settings)
* [Supported commands](#supported-commands)
* [Vim plugin](#vim-plugin)
* [Tips](#tips)
* [Respecting .gitignore, <code>.hgignore</code>, and <code>svn:ignore</code>](#respecting-gitignore-hgignore-and-svnignore)
* [git ls-tree for fast traversal](#git-ls-tree-for-fast-traversal)
* [Fish shell](#fish-shell)
* [<a href="LICENSE">License</a>](#license)
Installation
------------
@@ -341,8 +374,8 @@ On bash, fuzzy completion is enabled only for a predefined set of commands
commands as well like follows.
```sh
# There are also _fzf_path_completion and _fzf_dir_completion
complete -F _fzf_file_completion -o default -o bashdefault doge
complete -F _fzf_path_completion -o default -o bashdefault ag
complete -F _fzf_dir_completion -o default -o bashdefault tree
```
Vim plugin
@@ -394,9 +427,9 @@ export FZF_DEFAULT_COMMAND='
#### Fish shell
It's [a known bug of fish](https://github.com/fish-shell/fish-shell/issues/1362)
that it doesn't allow reading from STDIN in command substitution, which means
simple `vim (fzf)` won't work as expected. The workaround is to use the `read`
fish command:
(will be fixed in 2.6.0) that it doesn't allow reading from STDIN in command
substitution, which means simple `vim (fzf)` won't work as expected. The
workaround is to use the `read` fish command:
```sh
fzf | read -l result; and vim $result

View File

@@ -134,7 +134,7 @@ fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
cleanup() {
rm -f $argsf $fifo1 $fifo2 $fifo3
\rm -f $argsf $fifo1 $fifo2 $fifo3
# Remove temp window if we were zoomed
if [[ -n "$zoomed" ]]; then
@@ -150,6 +150,7 @@ cleanup() {
fi
}
trap 'cleanup 1' SIGUSR1
trap 'cleanup' EXIT
envs="env TERM=$TERM "
[[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
@@ -169,7 +170,7 @@ for arg in "${args[@]}"; do
done
pppid=$$
trap_set="trap 'kill -SIGUSR1 $pppid' EXIT SIGINT SIGTERM"
trap_set="trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM"
trap_unset="trap - EXIT SIGINT SIGTERM"
if [[ -n "$term" ]] || [[ -t 0 ]]; then

38
glide.lock generated Normal file
View File

@@ -0,0 +1,38 @@
hash: d68dd0bd779ac4ffca1e0c49ca38d85f90d5d68fa8e2d5d7db70a8ce8c662ec1
updated: 2017-06-01T15:48:41.653745249-07:00
imports:
- name: github.com/gdamore/encoding
version: b23993cbb6353f0e6aa98d0ee318a34728f628b9
- name: github.com/gdamore/tcell
version: 44772c121bb7838819d3ba4a7e84c0c2d617328e
subpackages:
- encoding
- name: github.com/lucasb-eyer/go-colorful
version: c900de9dbbc73129068f5af6a823068fc5f2308c
- name: github.com/mattn/go-isatty
version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
- name: github.com/mattn/go-runewidth
version: 14207d285c6c197daabb5c9793d63e7af9ab2d50
- name: github.com/mattn/go-shellwords
version: 02e3cf038dcea8290e44424da473dd12be796a8a
- name: golang.org/x/crypto
version: e1a4589e7d3ea14a3352255d04b6f1a418845e5e
subpackages:
- ssh/terminal
- name: golang.org/x/sys
version: b90f89a1e7a9c1f6b918820b3daa7f08488c8594
subpackages:
- unix
- name: golang.org/x/text
version: 4ee4af566555f5fbe026368b75596286a312663a
subpackages:
- encoding
- encoding/charmap
- encoding/internal
- encoding/internal/identifier
- encoding/japanese
- encoding/korean
- encoding/simplifiedchinese
- encoding/traditionalchinese
- transform
testImports: []

16
glide.yaml Normal file
View File

@@ -0,0 +1,16 @@
package: github.com/junegunn/fzf
import:
- package: github.com/mattn/go-isatty
version: 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
- package: github.com/mattn/go-runewidth
version: 14207d285c6c197daabb5c9793d63e7af9ab2d50
- package: github.com/mattn/go-shellwords
version: 02e3cf038dcea8290e44424da473dd12be796a8a
- package: github.com/gdamore/tcell
version: 44772c121bb7838819d3ba4a7e84c0c2d617328e
subpackages:
- encoding
- package: golang.org/x/crypto
version: e1a4589e7d3ea14a3352255d04b6f1a418845e5e
subpackages:
- ssh/terminal

54
install
View File

@@ -2,7 +2,7 @@
set -u
version=0.16.7
version=0.16.8
auto_completion=
key_bindings=
update_config=2
@@ -72,7 +72,7 @@ ask() {
check_binary() {
echo -n " - Checking fzf executable ... "
local output
output=$("$fzf_base"/bin/fzf --version 2>&1)
output=$("$fzf_base"/bin/fzf --version 2>&1 | awk '{print $1}')
if [ $? -ne 0 ]; then
echo "Error: $output"
binary_error="Invalid binary"
@@ -99,11 +99,23 @@ link_fzf_in_path() {
}
try_curl() {
command -v curl > /dev/null && curl -fL $1 | tar -xzf -
command -v curl > /dev/null &&
if [[ $1 =~ tgz$ ]]; then
curl -fL $1 | tar -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
curl -fLo "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
}
try_wget() {
command -v wget > /dev/null && wget -O - $1 | tar -xzf -
command -v wget > /dev/null &&
if [[ $1 =~ tgz$ ]]; then
wget -O - $1 | tar -xzf -
else
local temp=${TMPDIR:-/tmp}/fzf.zip
wget -O "$temp" $1 && unzip -o "$temp" && rm -f "$temp"
fi
}
download() {
@@ -123,8 +135,8 @@ download() {
local url
[[ "$version" =~ alpha ]] &&
url=https://github.com/junegunn/fzf-bin/releases/download/alpha/${1}.tgz ||
url=https://github.com/junegunn/fzf-bin/releases/download/$version/${1}.tgz
url=https://github.com/junegunn/fzf-bin/releases/download/alpha/${1} ||
url=https://github.com/junegunn/fzf-bin/releases/download/$version/${1}
set -o pipefail
if ! (try_curl $url || try_wget $url); then
set +o pipefail
@@ -146,18 +158,19 @@ archi=$(uname -sm)
binary_available=1
binary_error=""
case "$archi" in
Darwin\ *64) download fzf-$version-darwin_${binary_arch:-amd64} ;;
Darwin\ *86) download fzf-$version-darwin_${binary_arch:-386} ;;
Linux\ *64) download fzf-$version-linux_${binary_arch:-amd64} ;;
Linux\ *86) download fzf-$version-linux_${binary_arch:-386} ;;
Linux\ armv5*) download fzf-$version-linux_${binary_arch:-arm5} ;;
Linux\ armv6*) download fzf-$version-linux_${binary_arch:-arm6} ;;
Linux\ armv7*) download fzf-$version-linux_${binary_arch:-arm7} ;;
Linux\ armv8*) download fzf-$version-linux_${binary_arch:-arm8} ;;
FreeBSD\ *64) download fzf-$version-freebsd_${binary_arch:-amd64} ;;
FreeBSD\ *86) download fzf-$version-freebsd_${binary_arch:-386} ;;
OpenBSD\ *64) download fzf-$version-openbsd_${binary_arch:-amd64} ;;
OpenBSD\ *86) download fzf-$version-openbsd_${binary_arch:-386} ;;
Darwin\ *64) download fzf-$version-darwin_${binary_arch:-amd64}.tgz ;;
Darwin\ *86) download fzf-$version-darwin_${binary_arch:-386}.tgz ;;
Linux\ *64) download fzf-$version-linux_${binary_arch:-amd64}.tgz ;;
Linux\ *86) download fzf-$version-linux_${binary_arch:-386}.tgz ;;
Linux\ armv5*) download fzf-$version-linux_${binary_arch:-arm5}.tgz ;;
Linux\ armv6*) download fzf-$version-linux_${binary_arch:-arm6}.tgz ;;
Linux\ armv7*) download fzf-$version-linux_${binary_arch:-arm7}.tgz ;;
Linux\ armv8*) download fzf-$version-linux_${binary_arch:-arm8}.tgz ;;
FreeBSD\ *64) download fzf-$version-freebsd_${binary_arch:-amd64}.tgz ;;
FreeBSD\ *86) download fzf-$version-freebsd_${binary_arch:-386}.tgz ;;
OpenBSD\ *64) download fzf-$version-openbsd_${binary_arch:-amd64}.tgz ;;
OpenBSD\ *86) download fzf-$version-openbsd_${binary_arch:-386}.tgz ;;
CYGWIN*\ *64) download fzf-$version-windows_${binary_arch:-amd64}.zip ;;
*) binary_available=0 binary_error=1 ;;
esac
@@ -169,12 +182,12 @@ if [ -n "$binary_error" ]; then
echo " - $binary_error !!!"
fi
if command -v go > /dev/null; then
echo -n "Building binary (go get -u github.com/junegunn/fzf/src/fzf) ... "
echo -n "Building binary (go get -u github.com/junegunn/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
if go get -u github.com/junegunn/fzf; then
echo "OK"
cp "$GOPATH/bin/fzf" "$fzf_base/bin/"
else
@@ -341,4 +354,3 @@ if [ $update_config -eq 1 ]; then
echo
fi
echo 'For more information, see: https://github.com/junegunn/fzf'

View File

@@ -2,6 +2,8 @@ package main
import "github.com/junegunn/fzf/src"
var revision string
func main() {
fzf.Run(fzf.ParseOptions())
fzf.Run(fzf.ParseOptions(), revision)
}

View File

@@ -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 2017" "fzf 0.16.7" "fzf-tmux - open fzf in tmux split pane"
.TH fzf-tmux 1 "Jun 2017" "fzf 0.16.8" "fzf-tmux - open fzf in tmux split pane"
.SH NAME
fzf-tmux - open fzf in tmux split pane

View File

@@ -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 2017" "fzf 0.16.7" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Jun 2017" "fzf 0.16.8" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -467,6 +467,11 @@ e.g. \fBfzf --bind=ctrl-j:accept,ctrl-k:kill-line\fR
\fIdouble-click\fR
or any single character
Additionally, a special event named \fIchange\fR is available which is
triggered whenever the query string is changed.
e.g. \fBfzf --bind change:top\fR
\fBACTION: DEFAULT BINDINGS (NOTES):
\fBabort\fR \fIctrl-c ctrl-g ctrl-q esc\fR
\fBaccept\fR \fIenter double-click\fR
@@ -513,6 +518,7 @@ e.g. \fBfzf --bind=ctrl-j:accept,ctrl-k:kill-line\fR
\fBtoggle-preview-wrap\fR
\fBtoggle-sort\fR
\fBtoggle+up\fR \fIbtab (shift-tab)\fR
\fBtop\fR (move to the top result)
\fBunix-line-discard\fR \fIctrl-u\fR
\fBunix-word-rubout\fR \fIctrl-w\fR
\fBup\fR \fIctrl-k ctrl-p up\fR

View File

@@ -45,19 +45,39 @@ if s:is_win
endtry
endfunction
function! s:fzf_shellescape(path)
return substitute(s:fzf_call('shellescape', a:path), '[^\\]\zs\\"$', '\\\\"', '')
" Use utf-8 for fzf.vim commands
" Return array of shell commands for cmd.exe
function! s:wrap_cmds(cmds)
return ['@echo off', 'for /f "tokens=4" %%a in (''chcp'') do set origchcp=%%a', 'chcp 65001 > nul'] +
\ (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) +
\ ['chcp %origchcp% > nul']
endfunction
else
function! s:fzf_call(fn, ...)
return call(a:fn, a:000)
endfunction
function! s:fzf_shellescape(path)
return shellescape(a:path)
function! s:wrap_cmds(cmds)
return a:cmds
endfunction
endif
function! s:shellesc_cmd(arg)
let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
let escaped = substitute(escaped, '%', '%%', 'g')
let escaped = substitute(escaped, '"', '\\^&', 'g')
let escaped = substitute(escaped, '\\\+\(\\^\)', '\\\\\1', 'g')
return '^"'.substitute(escaped, '[^\\]\zs\\$', '\\\\', '').'^"'
endfunction
function! fzf#shellescape(arg, ...)
let shell = get(a:000, 0, &shell)
if shell =~# 'cmd.exe$'
return s:shellesc_cmd(a:arg)
endif
return s:fzf_call('shellescape', a:arg)
endfunction
function! s:fzf_getcwd()
return s:fzf_call('getcwd')
endfunction
@@ -67,7 +87,7 @@ function! s:fzf_fnamemodify(fname, mods)
endfunction
function! s:fzf_expand(fmt)
return s:fzf_call('expand', a:fmt)
return s:fzf_call('expand', a:fmt, 1)
endfunction
function! s:fzf_tempname()
@@ -87,10 +107,10 @@ set cpo&vim
function! s:fzf_exec()
if !exists('s:exec')
if executable(s:fzf_go)
let s:exec = s:fzf_expand(s:fzf_go)
let s:exec = s:fzf_go
elseif executable('fzf')
let s:exec = 'fzf'
elseif s:is_win
elseif s:is_win && !has('win32unix')
call s:warn('fzf executable not found.')
call s:warn('Download fzf binary for Windows from https://github.com/junegunn/fzf-bin/releases/')
call s:warn('and place it as '.s:base_dir.'\bin\fzf.exe')
@@ -108,7 +128,7 @@ function! s:fzf_exec()
throw 'fzf executable not found'
endif
endif
return s:is_win ? s:exec : s:shellesc(s:exec)
return fzf#shellescape(s:exec)
endfunction
function! s:tmux_enabled()
@@ -128,10 +148,6 @@ function! s:tmux_enabled()
return s:tmux
endfunction
function! s:shellesc(arg)
return '"'.substitute(a:arg, '"', '\\"', 'g').'"'
endfunction
function! s:escape(path)
let escaped_chars = '$%#''"'
@@ -250,7 +266,7 @@ endfunction
function! s:evaluate_opts(options)
return type(a:options) == type([]) ?
\ join(map(copy(a:options), 's:fzf_shellescape(v:val)')) : a:options
\ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options
endfunction
" [name string,] [opts dict,] [fullscreen boolean]
@@ -297,7 +313,7 @@ function! fzf#wrap(...)
if !isdirectory(dir)
call mkdir(dir, 'p')
endif
let history = s:is_win ? s:fzf_shellescape(dir.'\'.name) : s:escape(dir.'/'.name)
let history = fzf#shellescape(dir.'/'.name)
let opts.options = join(['--history', history, opts.options])
endif
@@ -348,8 +364,8 @@ try
if !has_key(dict, 'source') && !empty($FZF_DEFAULT_COMMAND)
let temps.source = s:fzf_tempname().(s:is_win ? '.bat' : '')
call writefile((s:is_win ? ['@echo off'] : []) + split($FZF_DEFAULT_COMMAND, "\n"), temps.source)
let dict.source = (empty($SHELL) ? &shell : $SHELL) . (s:is_win ? ' /c ' : ' ') . s:shellesc(temps.source)
call writefile(s:wrap_cmds(split($FZF_DEFAULT_COMMAND, "\n")), temps.source)
let dict.source = (empty($SHELL) ? &shell : $SHELL) . (s:is_win ? ' /c ' : ' ') . fzf#shellescape(temps.source)
endif
if has_key(dict, 'source')
@@ -360,7 +376,7 @@ try
elseif type == 3
let temps.input = s:fzf_tempname()
call writefile(source, temps.input)
let prefix = (s:is_win ? 'type ' : 'cat ').s:shellesc(temps.input).'|'
let prefix = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input).'|'
else
throw 'Invalid source type'
endif
@@ -370,10 +386,10 @@ try
let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0)
let use_height = has_key(dict, 'down') &&
\ !(has('nvim') || s:is_win || s:present(dict, 'up', 'left', 'right')) &&
\ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right')) &&
\ executable('tput') && filereadable('/dev/tty')
let use_term = has('nvim') && !s:is_win
let use_tmux = (!use_height && !use_term || prefer_tmux) && s:tmux_enabled() && s:splittable(dict)
let use_tmux = (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:tmux_enabled() && s:splittable(dict)
if prefer_tmux && use_tmux
let use_height = 0
let use_term = 0
@@ -424,7 +440,7 @@ function! s:fzf_tmux(dict)
endif
endfor
return printf('LINES=%d COLUMNS=%d %s %s %s --',
\ &lines, &columns, s:shellesc(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
\ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
endfunction
function! s:splittable(dict)
@@ -469,7 +485,7 @@ function! s:xterm_launcher()
\ &columns, &lines/2, getwinposx(), getwinposy())
endfunction
unlet! s:launcher
if s:is_win
if s:is_win || has('win32unix')
let s:launcher = '%s'
else
let s:launcher = function('s:xterm_launcher')
@@ -493,7 +509,7 @@ function! s:execute(dict, command, use_height, temps) abort
if has('unix') && !a:use_height
silent! !clear 2> /dev/null
endif
let escaped = escape(substitute(a:command, '\n', '\\n', 'g'), '%#!')
let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!')
if has('gui_running')
let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher)))
let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher
@@ -502,12 +518,13 @@ function! s:execute(dict, command, use_height, temps) abort
endif
let command = printf(fmt, escaped)
else
let command = a:use_height ? a:command : escaped
let command = escaped
endif
if s:is_win
let batchfile = s:fzf_tempname().'.bat'
call writefile(['@echo off', command], batchfile)
call writefile(s:wrap_cmds(command), batchfile)
let command = batchfile
let a:temps.batchfile = batchfile
if has('nvim')
let s:dict = a:dict
let s:temps = a:temps
@@ -520,6 +537,11 @@ function! s:execute(dict, command, use_height, temps) abort
call jobstart(cmd, fzf)
return []
endif
elseif has('win32unix') && $TERM !=# 'cygwin'
let shellscript = s:fzf_tempname()
call writefile([command], shellscript)
let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
let a:temps.shellscript = shellscript
endif
if a:use_height
let stdin = has_key(a:dict, 'source') ? '' : '< /dev/tty'
@@ -536,7 +558,7 @@ function! s:execute_tmux(dict, command, temps) abort
let command = a:command
if s:pushd(a:dict)
" -c '#{pane_current_path}' is only available on tmux 1.9 or above
let command = 'cd '.s:escape(a:dict.dir).' && '.command
let command = join(['cd', fzf#shellescape(a:dict.dir), '&&', command])
endif
call system(command)
@@ -743,6 +765,8 @@ function! s:cmd(bang, ...) abort
let opts.dir = substitute(substitute(remove(args, -1), '\\\(["'']\)', '\1', 'g'), '[/\\]*$', '/', '')
if s:is_win && !&shellslash
let opts.dir = substitute(opts.dir, '/', '\\', 'g')
elseif has('win32unix')
let opts.dir = fnamemodify(opts.dir, ':p')
endif
let prompt = opts.dir
else

View File

@@ -1,127 +0,0 @@
ifndef GOOS
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
GOOS := darwin
else ifeq ($(UNAME_S),Linux)
GOOS := linux
else
$(error "$$GOOS is not defined.")
endif
endif
SOURCES := $(wildcard *.go */*.go)
ROOTDIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
BINDIR := $(shell dirname $(ROOTDIR))/bin
GOPATH := $(shell dirname $(ROOTDIR))/gopath
SRCDIR := $(GOPATH)/src/github.com/junegunn/fzf/src
BINARY32 := fzf-$(GOOS)_386
BINARY64 := fzf-$(GOOS)_amd64
BINARYARM5 := fzf-$(GOOS)_arm5
BINARYARM6 := fzf-$(GOOS)_arm6
BINARYARM7 := fzf-$(GOOS)_arm7
BINARYARM8 := fzf-$(GOOS)_arm8
VERSION := $(shell awk -F= '/version =/ {print $$2}' constants.go | tr -d "\" ")
RELEASE32 := fzf-$(VERSION)-$(GOOS)_386
RELEASE64 := fzf-$(VERSION)-$(GOOS)_amd64
RELEASEARM5 := fzf-$(VERSION)-$(GOOS)_arm5
RELEASEARM6 := fzf-$(VERSION)-$(GOOS)_arm6
RELEASEARM7 := fzf-$(VERSION)-$(GOOS)_arm7
RELEASEARM8 := fzf-$(VERSION)-$(GOOS)_arm8
export GOPATH
# https://en.wikipedia.org/wiki/Uname
UNAME_M := $(shell uname -m)
ifeq ($(UNAME_M),x86_64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),amd64)
BINARY := $(BINARY64)
else ifeq ($(UNAME_M),i686)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),i386)
BINARY := $(BINARY32)
else ifeq ($(UNAME_M),armv5l)
BINARY := $(BINARYARM5)
else ifeq ($(UNAME_M),armv6l)
BINARY := $(BINARYARM6)
else ifeq ($(UNAME_M),armv7l)
BINARY := $(BINARYARM7)
else
$(error "Build on $(UNAME_M) is not supported, yet.")
endif
all: fzf/$(BINARY)
ifeq ($(GOOS),windows)
release: fzf/$(BINARY32) fzf/$(BINARY64)
cd fzf && cp -f $(BINARY32) fzf.exe && zip $(RELEASE32).zip fzf.exe
cd fzf && cp -f $(BINARY64) fzf.exe && zip $(RELEASE64).zip fzf.exe
cd fzf && rm -f fzf.exe
else ifeq ($(GOOS),linux)
release: fzf/$(BINARY32) fzf/$(BINARY64) fzf/$(BINARYARM5) fzf/$(BINARYARM6) fzf/$(BINARYARM7) fzf/$(BINARYARM8)
cd fzf && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
cd fzf && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd fzf && cp -f $(BINARYARM5) fzf && tar -czf $(RELEASEARM5).tgz fzf
cd fzf && cp -f $(BINARYARM6) fzf && tar -czf $(RELEASEARM6).tgz fzf
cd fzf && cp -f $(BINARYARM7) fzf && tar -czf $(RELEASEARM7).tgz fzf
cd fzf && cp -f $(BINARYARM8) fzf && tar -czf $(RELEASEARM8).tgz fzf
cd fzf && rm -f fzf
else
release: fzf/$(BINARY32) fzf/$(BINARY64)
cd fzf && cp -f $(BINARY32) fzf && tar -czf $(RELEASE32).tgz fzf
cd fzf && cp -f $(BINARY64) fzf && tar -czf $(RELEASE64).tgz fzf
cd fzf && rm -f fzf
endif
release-all: clean test
GOOS=darwin make release
GOOS=linux make release
GOOS=freebsd make release
GOOS=openbsd make release
GOOS=windows make release
$(SRCDIR):
mkdir -p $(shell dirname $(SRCDIR))
ln -s $(ROOTDIR) $(SRCDIR)
deps: $(SRCDIR) $(SOURCES)
cd $(SRCDIR) && go get -tags "$(TAGS)"
./deps
test: deps
SHELL=/bin/sh GOOS= go test -v -tags "$(TAGS)" ./...
install: $(BINDIR)/fzf
uninstall:
rm -f $(BINDIR)/fzf $(BINDIR)/$(BINARY)
clean:
cd fzf && rm -f fzf-*
fzf/$(BINARY32): deps
cd fzf && GOARCH=386 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARY32)
fzf/$(BINARY64): deps
cd fzf && GOARCH=amd64 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARY64)
# https://github.com/golang/go/wiki/GoArm
fzf/$(BINARYARM5): deps
cd fzf && GOARCH=arm GOARM=5 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARYARM5)
fzf/$(BINARYARM6): deps
cd fzf && GOARCH=arm GOARM=6 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARYARM6)
fzf/$(BINARYARM7): deps
cd fzf && GOARCH=arm GOARM=7 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARYARM7)
fzf/$(BINARYARM8): deps
cd fzf && GOARCH=arm64 go build -a -ldflags "-w -extldflags=$(LDFLAGS)" -tags "$(TAGS)" -o $(BINARYARM8)
$(BINDIR)/fzf: fzf/$(BINARY) | $(BINDIR)
cp -f fzf/$(BINARY) $(BINDIR)
cd $(BINDIR) && ln -sf $(BINARY) fzf
$(BINDIR):
mkdir -p $@
.PHONY: all deps release release-all test install uninstall clean

View File

@@ -1,106 +0,0 @@
fzf in Go
=========
<img src="https://cloud.githubusercontent.com/assets/700826/5725028/028ea834-9b93-11e4-9198-43088c3f295d.gif" height="463" alt="fzf in go">
This directory contains the source code for the new fzf implementation in
[Go][go].
Upgrade from Ruby version
-------------------------
The install script has been updated to download the right binary for your
system. If you already have installed fzf, simply git-pull the repository and
rerun the install script.
```sh
cd ~/.fzf
git pull
./install
```
Otherwise, follow [the instruction][install] as before. You can also install
fzf using Homebrew if you prefer that way.
Motivations
-----------
### No Ruby dependency
There have always been complaints about fzf being a Ruby script. To make
matters worse, Ruby 2.1 removed ncurses binding from its standard libary.
Because of the change, users running Ruby 2.1 or above are forced to build C
extensions of curses gem to meet the requirement of fzf. The new Go version
will be distributed as an executable binary so it will be much more accessible
and should be easier to setup.
### Performance
Many people have been surprised to see how fast fzf is even when it was
written in Ruby. It stays quite responsive even for 100k+ lines, which is
well above the size of the usual input.
The new Go version, of course, is significantly faster than that. It has all
the performance optimization techniques used in Ruby implementation and more.
It also doesn't suffer from [GIL][gil], so the search performance scales
proportional to the number of CPU cores. On my MacBook Pro (Mid 2012), the new
version was shown to be an order of magnitude faster on certain cases. It also
starts much faster though the difference may not be noticeable.
Build
-----
See [BUILD.md](../BUILD.md)
Test
----
Unit tests can be run with `make test`. Integration tests are written in Ruby
script that should be run on tmux.
```sh
cd src
# Unit tests
make test
# Integration tests
ruby ../test/test_go.rb
# Build binary for the platform
make
# Install the executable to ../bin directory
make install
# Make release archives
make release
# Make release archives for all supported platforms
make release-all
```
Third-party libraries used
--------------------------
- ~[ncurses][ncurses]~
- [mattn/go-runewidth](https://github.com/mattn/go-runewidth)
- Licensed under [MIT](http://mattn.mit-license.org)
- [mattn/go-shellwords](https://github.com/mattn/go-shellwords)
- Licensed under [MIT](http://mattn.mit-license.org)
- [mattn/go-isatty](https://github.com/mattn/go-isatty)
- Licensed under [MIT](http://mattn.mit-license.org)
- [tcell](https://github.com/gdamore/tcell)
- Licensed under [Apache License 2.0](https://github.com/gdamore/tcell/blob/master/LICENSE)
License
-------
[MIT](LICENSE)
[install]: https://github.com/junegunn/fzf#installation
[go]: https://golang.org/
[gil]: http://en.wikipedia.org/wiki/Global_Interpreter_Lock
[ncurses]: https://www.gnu.org/software/ncurses/
[req]: http://golang.org/doc/install
[tcell]: https://github.com/gdamore/tcell

View File

@@ -1,6 +1,7 @@
package fzf
import (
"os"
"time"
"github.com/junegunn/fzf/src/util"
@@ -8,7 +9,7 @@ import (
const (
// Current version
version = "0.16.7"
version = "0.16.8"
// Core
coordinatorDelayMax time.Duration = 100 * time.Millisecond
@@ -47,6 +48,18 @@ const (
defaultJumpLabels string = "asdfghjklqwertyuiopzxcvbnm1234567890ASDFGHJKLQWERTYUIOPZXCVBNM`~;:,<.>/?'\"!@#$%^&*()[{]}-_=+"
)
var defaultCommand string
func init() {
if !util.IsWindows() {
defaultCommand = `command find -L . -mindepth 1 \( -path '*/\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-`
} else if os.Getenv("TERM") == "cygwin" {
defaultCommand = `sh -c "command find -L . -mindepth 1 -path '*/\.*' -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-"`
} else {
defaultCommand = `dir /s/b`
}
}
// fzf events
const (
EvtReadNew util.EventType = iota

View File

@@ -1,8 +0,0 @@
// +build !windows
package fzf
const (
// Reader
defaultCommand = `command find -L . -mindepth 1 \( -path '*/\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \) -prune -o -type f -print -o -type l -print 2> /dev/null | cut -b3-`
)

View File

@@ -1,8 +0,0 @@
// +build windows
package fzf
const (
// Reader
defaultCommand = `dir /s/b`
)

View File

@@ -43,12 +43,16 @@ Matcher -> EvtHeader -> Terminal (update header)
*/
// Run starts fzf
func Run(opts *Options) {
func Run(opts *Options, revision string) {
sort := opts.Sort > 0
sortCriteria = opts.Criteria
if opts.Version {
fmt.Println(version)
if len(revision) > 0 {
fmt.Printf("%s (%s)\n", version, revision)
} else {
fmt.Println(version)
}
os.Exit(exitOk)
}
@@ -95,9 +99,10 @@ func Run(opts *Options) {
}
chars, colors := ansiProcessor(data)
return &Item{
index: int32(index),
text: chars,
colors: colors}
index: int32(index),
trimLength: -1,
text: chars,
colors: colors}
})
} else {
chunkList = NewChunkList(func(data []byte, index int) *Item {
@@ -110,9 +115,10 @@ func Run(opts *Options) {
}
textRunes := joinTokens(trans)
item := Item{
index: int32(index),
origText: &data,
colors: nil}
index: int32(index),
trimLength: -1,
origText: &data,
colors: nil}
trimmed, colors := ansiProcessorRunes(textRunes)
item.text = trimmed

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
if [ -z "$GOPATH" ]; then
echo '$GOPATH not defined'
exit 1
fi
reset() (
cd "$GOPATH/src/$1"
export GIT_DIR="$(pwd)/.git"
[ "$(git rev-parse HEAD)" = "$2" ] ||
(git fetch && git reset --hard "$2")
)
reset github.com/junegunn/go-isatty 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
reset github.com/junegunn/go-runewidth 14207d285c6c197daabb5c9793d63e7af9ab2d50
reset github.com/junegunn/go-shellwords 02e3cf038dcea8290e44424da473dd12be796a8a
reset golang.org/x/crypto abc5fa7ad02123a41f02bf1391c9760f7586e608

View File

@@ -7,6 +7,7 @@ import (
// Item represents each input line
type Item struct {
index int32
trimLength int32
text util.Chars
origText *[]byte
colors *[]ansiOffset
@@ -18,6 +19,14 @@ func (item *Item) Index() int32 {
return item.index
}
func (item *Item) TrimLength() int32 {
if item.trimLength >= 0 {
return item.trimLength
}
item.trimLength = int32(item.text.TrimLength())
return item.trimLength
}
// Colors returns ansiOffsets of the Item
func (item *Item) Colors() []ansiOffset {
if item.colors == nil {

View File

@@ -12,7 +12,7 @@ import (
"github.com/junegunn/fzf/src/tui"
"github.com/junegunn/fzf/src/util"
"github.com/junegunn/go-shellwords"
"github.com/mattn/go-shellwords"
)
const usage = `usage: fzf [options]
@@ -400,6 +400,8 @@ func parseKeyChords(str string, message string) map[int]string {
chord = tui.BSpace
case "ctrl-space":
chord = tui.CtrlSpace
case "change":
chord = tui.Change
case "alt-enter", "alt-return":
chord = tui.CtrlAltM
case "alt-space":
@@ -714,6 +716,8 @@ func parseKeymap(keymap map[int][]action, str string) {
appendAction(actDown)
case "up":
appendAction(actUp)
case "top":
appendAction(actTop)
case "page-up":
appendAction(actPageUp)
case "page-down":

View File

@@ -299,20 +299,20 @@ func (p *Pattern) matchChunk(chunk *Chunk, space []*Result, slab *util.Slab) []*
// MatchItem returns true if the Item is a match
func (p *Pattern) MatchItem(item *Item, withPos bool, slab *util.Slab) (*Result, []Offset, *[]int) {
if p.extended {
if offsets, bonus, trimLen, pos := p.extendedMatch(item, withPos, slab); len(offsets) == len(p.termSets) {
return buildResult(item, offsets, bonus, trimLen), offsets, pos
if offsets, bonus, pos := p.extendedMatch(item, withPos, slab); len(offsets) == len(p.termSets) {
return buildResult(item, offsets, bonus), offsets, pos
}
return nil, nil, nil
}
offset, bonus, trimLen, pos := p.basicMatch(item, withPos, slab)
offset, bonus, pos := p.basicMatch(item, withPos, slab)
if sidx := offset[0]; sidx >= 0 {
offsets := []Offset{offset}
return buildResult(item, offsets, bonus, trimLen), offsets, pos
return buildResult(item, offsets, bonus), offsets, pos
}
return nil, nil, nil
}
func (p *Pattern) basicMatch(item *Item, withPos bool, slab *util.Slab) (Offset, int, int, *[]int) {
func (p *Pattern) basicMatch(item *Item, withPos bool, slab *util.Slab) (Offset, int, *[]int) {
input := p.prepareInput(item)
if p.fuzzy {
return p.iter(p.fuzzyAlgo, input, p.caseSensitive, p.normalize, p.forward, p.text, withPos, slab)
@@ -320,11 +320,10 @@ func (p *Pattern) basicMatch(item *Item, withPos bool, slab *util.Slab) (Offset,
return p.iter(algo.ExactMatchNaive, input, p.caseSensitive, p.normalize, p.forward, p.text, withPos, slab)
}
func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Offset, int, int, *[]int) {
func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Offset, int, *[]int) {
input := p.prepareInput(item)
offsets := []Offset{}
var totalScore int
var totalTrimLen int
var allPos *[]int
if withPos {
allPos = &[]int{}
@@ -332,16 +331,15 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
for _, termSet := range p.termSets {
var offset Offset
var currentScore int
var trimLen int
matched := false
for _, term := range termSet {
pfun := p.procFun[term.typ]
off, score, tLen, pos := p.iter(pfun, input, term.caseSensitive, p.normalize, p.forward, term.text, withPos, slab)
off, score, pos := p.iter(pfun, input, term.caseSensitive, p.normalize, p.forward, term.text, withPos, slab)
if sidx := off[0]; sidx >= 0 {
if term.inv {
continue
}
offset, currentScore, trimLen = off, score, tLen
offset, currentScore = off, score
matched = true
if withPos {
if pos != nil {
@@ -354,7 +352,7 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
}
break
} else if term.inv {
offset, currentScore, trimLen = Offset{0, 0}, 0, 0
offset, currentScore = Offset{0, 0}, 0
matched = true
continue
}
@@ -362,10 +360,9 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of
if matched {
offsets = append(offsets, offset)
totalScore += currentScore
totalTrimLen += trimLen
}
}
return offsets, totalScore, totalTrimLen, allPos
return offsets, totalScore, allPos
}
func (p *Pattern) prepareInput(item *Item) []Token {
@@ -375,7 +372,7 @@ func (p *Pattern) prepareInput(item *Item) []Token {
var ret []Token
if len(p.nth) == 0 {
ret = []Token{Token{text: &item.text, prefixLength: 0, trimLength: int32(item.text.TrimLength())}}
ret = []Token{Token{text: &item.text, prefixLength: 0}}
} else {
tokens := Tokenize(item.text, p.delimiter)
ret = Transform(tokens, p.nth)
@@ -384,7 +381,7 @@ func (p *Pattern) prepareInput(item *Item) []Token {
return ret
}
func (p *Pattern) iter(pfun algo.Algo, tokens []Token, caseSensitive bool, normalize bool, forward bool, pattern []rune, withPos bool, slab *util.Slab) (Offset, int, int, *[]int) {
func (p *Pattern) iter(pfun algo.Algo, tokens []Token, caseSensitive bool, normalize bool, forward bool, pattern []rune, withPos bool, slab *util.Slab) (Offset, int, *[]int) {
for _, part := range tokens {
if res, pos := pfun(caseSensitive, normalize, forward, *part.text, pattern, withPos, slab); res.Start >= 0 {
sidx := int32(res.Start) + part.prefixLength
@@ -394,8 +391,8 @@ func (p *Pattern) iter(pfun algo.Algo, tokens []Token, caseSensitive bool, norma
(*pos)[idx] += int(part.prefixLength)
}
}
return Offset{sidx, eidx}, res.Score, int(part.trimLength), pos
return Offset{sidx, eidx}, res.Score, pos
}
}
return Offset{-1, -1}, 0, -1, nil
return Offset{-1, -1}, 0, nil
}

View File

@@ -29,7 +29,7 @@ type Result struct {
rank rank
}
func buildResult(item *Item, offsets []Offset, score int, trimLen int) *Result {
func buildResult(item *Item, offsets []Offset, score int) *Result {
if len(offsets) > 1 {
sort.Sort(ByOrder(offsets))
}
@@ -57,8 +57,7 @@ func buildResult(item *Item, offsets []Offset, score int, trimLen int) *Result {
// Higher is better
val = math.MaxUint16 - util.AsUint16(score)
case byLength:
// If offsets is empty, trimLen will be 0, but we don't care
val = util.AsUint16(trimLen)
val = util.AsUint16(int(item.TrimLength()))
case byBegin, byEnd:
if validOffsetFound {
whitePrefixLen := 0
@@ -72,7 +71,7 @@ func buildResult(item *Item, offsets []Offset, score int, trimLen int) *Result {
if criterion == byBegin {
val = util.AsUint16(minEnd - whitePrefixLen)
} else {
val = util.AsUint16(math.MaxUint16 - math.MaxUint16*(maxEnd-whitePrefixLen)/trimLen)
val = util.AsUint16(math.MaxUint16 - math.MaxUint16*(maxEnd-whitePrefixLen)/int(item.TrimLength()))
}
}
}

View File

@@ -52,7 +52,7 @@ func TestResultRank(t *testing.T) {
sortCriteria = []criterion{byScore, byLength}
strs := [][]rune{[]rune("foo"), []rune("foobar"), []rune("bar"), []rune("baz")}
item1 := buildResult(&Item{text: util.RunesToChars(strs[0]), index: 1}, []Offset{}, 2, 3)
item1 := buildResult(&Item{text: util.RunesToChars(strs[0]), index: 1, trimLength: -1}, []Offset{}, 2)
if item1.rank.points[0] != math.MaxUint16-2 || // Bonus
item1.rank.points[1] != 3 || // Length
item1.rank.points[2] != 0 || // Unused
@@ -61,7 +61,7 @@ func TestResultRank(t *testing.T) {
t.Error(item1.rank)
}
// Only differ in index
item2 := buildResult(&Item{text: util.RunesToChars(strs[0])}, []Offset{}, 2, 3)
item2 := buildResult(&Item{text: util.RunesToChars(strs[0])}, []Offset{}, 2)
items := []*Result{item1, item2}
sort.Sort(ByRelevance(items))
@@ -77,10 +77,10 @@ func TestResultRank(t *testing.T) {
}
// Sort by relevance
item3 := buildResult(&Item{index: 2}, []Offset{Offset{1, 3}, Offset{5, 7}}, 3, 0)
item4 := buildResult(&Item{index: 2}, []Offset{Offset{1, 2}, Offset{6, 7}}, 4, 0)
item5 := buildResult(&Item{index: 2}, []Offset{Offset{1, 3}, Offset{5, 7}}, 5, 0)
item6 := buildResult(&Item{index: 2}, []Offset{Offset{1, 2}, Offset{6, 7}}, 6, 0)
item3 := buildResult(&Item{index: 2}, []Offset{Offset{1, 3}, Offset{5, 7}}, 3)
item4 := buildResult(&Item{index: 2}, []Offset{Offset{1, 2}, Offset{6, 7}}, 4)
item5 := buildResult(&Item{index: 2}, []Offset{Offset{1, 3}, Offset{5, 7}}, 5)
item6 := buildResult(&Item{index: 2}, []Offset{Offset{1, 2}, Offset{6, 7}}, 6)
items = []*Result{item1, item2, item3, item4, item5, item6}
sort.Sort(ByRelevance(items))
if !(items[0] == item6 && items[1] == item5 &&

View File

@@ -58,6 +58,7 @@ type Terminal struct {
initDelay time.Duration
inlineInfo bool
prompt string
promptLen int
reverse bool
fullscreen bool
hscroll bool
@@ -133,7 +134,6 @@ func (a byTimeOrder) Less(i, j int) bool {
}
var _spinner = []string{`-`, `\`, `|`, `/`, `-`, `\`, `|`, `/`}
var _tabStop int
const (
reqPrompt util.EventType = iota
@@ -213,6 +213,7 @@ const (
actExecuteSilent
actExecuteMulti // Deprecated
actSigStop
actTop
)
func toActions(types ...actionType) []action {
@@ -339,10 +340,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
wordRubout = fmt.Sprintf("%s[^%s]", sep, sep)
wordNext = fmt.Sprintf("[^%s]%s|(.$)", sep, sep)
}
return &Terminal{
t := Terminal{
initDelay: delay,
inlineInfo: opts.InlineInfo,
prompt: opts.Prompt,
reverse: opts.Reverse,
fullscreen: fullscreen,
hscroll: opts.Hscroll,
@@ -389,6 +389,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
startChan: make(chan bool, 1),
tui: renderer,
initFunc: func() { renderer.Init() }}
t.prompt, t.promptLen = t.processTabs([]rune(opts.Prompt), 0)
return &t
}
// Input returns current query string
@@ -632,7 +634,7 @@ func (t *Terminal) move(y int, x int, clear bool) {
}
func (t *Terminal) placeCursor() {
t.move(0, t.displayWidth([]rune(t.prompt))+t.displayWidth(t.input[:t.cx]), false)
t.move(0, t.promptLen+t.displayWidth(t.input[:t.cx]), false)
}
func (t *Terminal) printPrompt() {
@@ -644,7 +646,7 @@ func (t *Terminal) printPrompt() {
func (t *Terminal) printInfo() {
pos := 0
if t.inlineInfo {
pos = t.displayWidth([]rune(t.prompt)) + t.displayWidth(t.input) + 1
pos = t.promptLen + t.displayWidth(t.input) + 1
if pos+len(" < ") > t.window.Width() {
return
}
@@ -952,6 +954,7 @@ func (t *Terminal) printPreview() {
}
reader := bufio.NewReader(strings.NewReader(t.previewer.text))
lineNo := -t.previewer.offset
var ansi *ansiState
for {
line, err := reader.ReadString('\n')
eof := err == io.EOF
@@ -963,7 +966,7 @@ func (t *Terminal) printPreview() {
break
} else if lineNo > 0 {
var fillRet tui.FillReturn
extractColor(line, nil, func(str string, ansi *ansiState) bool {
_, _, ansi = extractColor(line, ansi, func(str string, ansi *ansiState) bool {
trimmed := []rune(str)
if !t.preview.wrap {
trimmed, _ = t.trimRight(trimmed, maxWidth-t.pwindow.X())
@@ -1240,7 +1243,7 @@ func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item
}
func (t *Terminal) truncateQuery() {
maxPatternLength := util.Max(1, t.window.Width()-t.displayWidth([]rune(t.prompt))-1)
maxPatternLength := util.Max(1, t.window.Width()-t.promptLen-1)
t.input, _ = t.trimRight(t.input, maxPatternLength)
t.cx = util.Constrain(t.cx, 0, len(t.input))
}
@@ -1590,25 +1593,28 @@ func (t *Terminal) Loop() {
case actToggleDown:
if t.multi && t.merger.Length() > 0 {
toggle()
t.vmove(-1)
t.vmove(-1, true)
req(reqList)
}
case actToggleUp:
if t.multi && t.merger.Length() > 0 {
toggle()
t.vmove(1)
t.vmove(1, true)
req(reqList)
}
case actDown:
t.vmove(-1)
t.vmove(-1, true)
req(reqList)
case actUp:
t.vmove(1)
t.vmove(1, true)
req(reqList)
case actAccept:
req(reqClose)
case actClearScreen:
req(reqRedraw)
case actTop:
t.vset(0)
req(reqList)
case actUnixLineDiscard:
if t.cx > 0 {
t.yanked = copySlice(t.input[:t.cx])
@@ -1628,16 +1634,16 @@ func (t *Terminal) Loop() {
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
t.cx += len(t.yanked)
case actPageUp:
t.vmove(t.maxItems() - 1)
t.vmove(t.maxItems()-1, false)
req(reqList)
case actPageDown:
t.vmove(-(t.maxItems() - 1))
t.vmove(-(t.maxItems() - 1), false)
req(reqList)
case actHalfPageUp:
t.vmove(t.maxItems() / 2)
t.vmove(t.maxItems()/2, false)
req(reqList)
case actHalfPageDown:
t.vmove(-(t.maxItems() / 2))
t.vmove(-(t.maxItems() / 2), false)
req(reqList)
case actJump:
t.jumping = jumpEnabled
@@ -1695,7 +1701,7 @@ func (t *Terminal) Loop() {
if t.multi && me.Mod {
toggle()
}
t.vmove(me.S)
t.vmove(me.S, true)
req(reqList)
} else if t.hasPreviewWindow() && t.pwindow.Enclose(my, mx) {
scrollPreview(-me.S)
@@ -1703,7 +1709,7 @@ func (t *Terminal) Loop() {
} else if t.window.Enclose(my, mx) {
mx -= t.window.Left()
my -= t.window.Top()
mx = util.Constrain(mx-t.displayWidth([]rune(t.prompt)), 0, len(t.input))
mx = util.Constrain(mx-t.promptLen, 0, len(t.input))
if !t.reverse {
my = t.window.Height() - my - 1
}
@@ -1749,6 +1755,11 @@ func (t *Terminal) Loop() {
}
t.truncateQuery()
changed = string(previousInput) != string(t.input)
if onChanges, prs := t.keymap[tui.Change]; changed && prs {
if !doActions(onChanges, tui.Change) {
continue
}
}
} else {
if mapkey == tui.Rune {
if idx := strings.IndexRune(t.jumpLabels, event.Char); idx >= 0 && idx < t.maxItems() && idx < t.merger.Length() {
@@ -1787,12 +1798,12 @@ func (t *Terminal) constrain() {
t.offset = util.Max(0, t.offset)
}
func (t *Terminal) vmove(o int) {
func (t *Terminal) vmove(o int, allowCycle bool) {
if t.reverse {
o *= -1
}
dest := t.cy + o
if t.cycle {
if t.cycle && allowCycle {
max := t.merger.Length() - 1
if dest > max {
if t.cy == max {

View File

@@ -20,7 +20,6 @@ type Range struct {
type Token struct {
text *util.Chars
prefixLength int32
trimLength int32
}
// Delimiter for tokenizing the input
@@ -81,7 +80,7 @@ func withPrefixLengths(tokens []util.Chars, begin int) []Token {
prefixLength := begin
for idx, token := range tokens {
// NOTE: &tokens[idx] instead of &tokens
ret[idx] = Token{&tokens[idx], int32(prefixLength), int32(token.TrimLength())}
ret[idx] = Token{&tokens[idx], int32(prefixLength)}
prefixLength += token.Length()
}
return ret
@@ -242,7 +241,7 @@ func Transform(tokens []Token, withNth []Range) []Token {
} else {
prefixLength = 0
}
transTokens[idx] = Token{&merged, prefixLength, int32(merged.TrimLength())}
transTokens[idx] = Token{&merged, prefixLength}
}
return transTokens
}

View File

@@ -48,22 +48,22 @@ func TestTokenize(t *testing.T) {
// AWK-style
input := " abc: def: ghi "
tokens := Tokenize(util.RunesToChars([]rune(input)), Delimiter{})
if tokens[0].text.ToString() != "abc: " || tokens[0].prefixLength != 2 || tokens[0].trimLength != 4 {
if tokens[0].text.ToString() != "abc: " || tokens[0].prefixLength != 2 {
t.Errorf("%s", tokens)
}
// With delimiter
tokens = Tokenize(util.RunesToChars([]rune(input)), delimiterRegexp(":"))
if tokens[0].text.ToString() != " abc:" || tokens[0].prefixLength != 0 || tokens[0].trimLength != 4 {
if tokens[0].text.ToString() != " abc:" || tokens[0].prefixLength != 0 {
t.Errorf("%s", tokens)
}
// With delimiter regex
tokens = Tokenize(util.RunesToChars([]rune(input)), delimiterRegexp("\\s+"))
if tokens[0].text.ToString() != " " || tokens[0].prefixLength != 0 || tokens[0].trimLength != 0 ||
tokens[1].text.ToString() != "abc: " || tokens[1].prefixLength != 2 || tokens[1].trimLength != 4 ||
tokens[2].text.ToString() != "def: " || tokens[2].prefixLength != 8 || tokens[2].trimLength != 4 ||
tokens[3].text.ToString() != "ghi " || tokens[3].prefixLength != 14 || tokens[3].trimLength != 3 {
if tokens[0].text.ToString() != " " || tokens[0].prefixLength != 0 ||
tokens[1].text.ToString() != "abc: " || tokens[1].prefixLength != 2 ||
tokens[2].text.ToString() != "def: " || tokens[2].prefixLength != 8 ||
tokens[3].text.ToString() != "ghi " || tokens[3].prefixLength != 14 {
t.Errorf("%s", tokens)
}
}

View File

@@ -251,8 +251,9 @@ func (r *LightRenderer) updateTerminalSize() {
func (r *LightRenderer) getch(nonblock bool) (int, bool) {
b := make([]byte, 1)
fd := r.fd()
util.SetNonblock(r.ttyin, nonblock)
_, err := r.ttyin.Read(b)
_, err := util.Read(fd, b)
if err != nil {
return 0, false
}

View File

@@ -3,16 +3,16 @@
package tui
import (
"os"
"time"
"unicode/utf8"
"runtime"
// https://github.com/gdamore/tcell/pull/135
"github.com/junegunn/tcell"
"github.com/junegunn/tcell/encoding"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/encoding"
"github.com/junegunn/go-runewidth"
"github.com/mattn/go-runewidth"
)
func HasFullscreenRenderer() bool {
@@ -141,6 +141,9 @@ func (r *FullscreenRenderer) initScreen() {
}
func (r *FullscreenRenderer) Init() {
if os.Getenv("TERM") == "cygwin" {
os.Setenv("TERM", "")
}
encoding.Register()
r.initScreen()

View File

@@ -75,6 +75,8 @@ const (
F11
F12
Change
AltSpace
AltSlash
AltBS

View File

@@ -5,8 +5,8 @@ import (
"os"
"time"
"github.com/junegunn/go-isatty"
"github.com/junegunn/go-runewidth"
"github.com/mattn/go-isatty"
"github.com/mattn/go-runewidth"
)
var _runeWidths = make(map[rune]int)

View File

@@ -26,3 +26,8 @@ func IsWindows() bool {
func SetNonblock(file *os.File, nonblock bool) {
syscall.SetNonblock(int(file.Fd()), nonblock)
}
// Read executes syscall.Read on file descriptor
func Read(fd int, b []byte) (int, error) {
return syscall.Read(int(fd), b)
}

View File

@@ -7,20 +7,16 @@ import (
"os/exec"
"syscall"
"github.com/junegunn/go-shellwords"
"github.com/mattn/go-shellwords"
)
// ExecCommand executes the given command with $SHELL
func ExecCommand(command string) *exec.Cmd {
shell := os.Getenv("SHELL")
if len(shell) == 0 {
shell = "cmd"
}
args, _ := shellwords.Parse(command)
allArgs := make([]string, len(args)+1)
allArgs[0] = "/c"
copy(allArgs[1:], args)
return exec.Command(shell, allArgs...)
return exec.Command("cmd", allArgs...)
}
// IsWindows returns true on Windows
@@ -32,3 +28,8 @@ func IsWindows() bool {
func SetNonblock(file *os.File, nonblock bool) {
syscall.SetNonblock(syscall.Handle(file.Fd()), nonblock)
}
// Read executes syscall.Read on file descriptor
func Read(fd int, b []byte) (int, error) {
return syscall.Read(syscall.Handle(fd), b)
}

View File

@@ -147,6 +147,24 @@ Execute (fzf#wrap):
let opts = fzf#wrap({})
Assert opts.options =~ '^--color=fg:'
Execute (fzf#shellescape with sh):
AssertEqual '''''', fzf#shellescape('', 'sh')
AssertEqual '''""''', fzf#shellescape('""', 'sh')
AssertEqual '''foobar>''', fzf#shellescape('foobar>', 'sh')
AssertEqual '''\"''', fzf#shellescape('\"', 'sh')
AssertEqual '''echo ''\''''a''\'''' && echo ''\''''b''\''''''', fzf#shellescape('echo ''a'' && echo ''b''', 'sh')
Execute (fzf#shellescape with cmd.exe):
AssertEqual '^"^"', fzf#shellescape('', 'cmd.exe')
AssertEqual '^"\^"\^"^"', fzf#shellescape('""', 'cmd.exe')
AssertEqual '^"foobar^>^"', fzf#shellescape('foobar>', 'cmd.exe')
AssertEqual '^"\\\^"\\^"', fzf#shellescape('\\\\\\\\"\', 'cmd.exe')
AssertEqual '^"echo ''a'' ^&^& echo ''b''^"', fzf#shellescape('echo ''a'' && echo ''b''', 'cmd.exe')
AssertEqual '^"C:\Program Files ^(x86^)\\^"', fzf#shellescape('C:\Program Files (x86)\', 'cmd.exe')
AssertEqual '^"C:/Program Files ^(x86^)/^"', fzf#shellescape('C:/Program Files (x86)/', 'cmd.exe')
" AssertEqual '^"%%USERPROFILE%%^", fzf#shellescape('%USERPROFILE%', 'cmd.exe')
Execute (Cleanup):
unlet g:dir
Restore

View File

@@ -683,62 +683,10 @@ class TestGoFZF < TestBase
]
assert_equal output, `#{FZF} -fh < #{tempname}`.split($/)
output = %w[
1234567:h
12345:he
1:hell
123:hello
]
# Since 0.16.8, --nth doesn't affect --tiebreak
assert_equal output, `#{FZF} -fh -n2 -d: < #{tempname}`.split($/)
end
def test_tiebreak_length_with_nth_trim_length
input = [
"apple juice bottle 1",
"apple ui bottle 2",
"app ice bottle 3",
"app ic bottle 4",
]
writelines tempname, input
# len(1)
output = [
"app ice bottle 3",
"app ic bottle 4",
"apple juice bottle 1",
"apple ui bottle 2",
]
assert_equal output, `#{FZF} -fa -n1 < #{tempname}`.split($/)
# len(1 ~ 2)
output = [
"app ic bottle 4",
"app ice bottle 3",
"apple ui bottle 2",
"apple juice bottle 1",
]
assert_equal output, `#{FZF} -fai -n1..2 < #{tempname}`.split($/)
# len(1) + len(2)
output = [
"app ic bottle 4",
"app ice bottle 3",
"apple ui bottle 2",
"apple juice bottle 1",
]
assert_equal output, `#{FZF} -x -f"a i" -n1,2 < #{tempname}`.split($/)
# len(2)
output = [
"app ic bottle 4",
"app ice bottle 3",
"apple ui bottle 2",
"apple juice bottle 1",
]
assert_equal output, `#{FZF} -fi -n2 < #{tempname}`.split($/)
assert_equal output, `#{FZF} -fi -n2,1..2 < #{tempname}`.split($/)
end
def test_invalid_cache
tmux.send_keys "(echo d; echo D; echo x) | #{fzf '-q d'}", :Enter
tmux.until { |lines| lines[-2].include? '2/3' }
@@ -975,15 +923,15 @@ class TestGoFZF < TestBase
tmux.until { |lines| lines[-10].start_with? '>' }
tmux.send_keys :Down
tmux.until { |lines| lines[-9].start_with? '>' }
tmux.send_keys :PgUp
tmux.send_keys :Up
tmux.until { |lines| lines[-10].start_with? '>' }
tmux.send_keys :PgUp
tmux.until { |lines| lines[-3].start_with? '>' }
tmux.until { |lines| lines[-10].start_with? '>' }
tmux.send_keys :Up
tmux.until { |lines| lines[-4].start_with? '>' }
tmux.send_keys :PgDn
tmux.until { |lines| lines[-3].start_with? '>' }
tmux.send_keys :PgDn
tmux.until { |lines| lines[-3].start_with? '>' }
tmux.send_keys :Down
tmux.until { |lines| lines[-10].start_with? '>' }
end
@@ -1304,6 +1252,20 @@ class TestGoFZF < TestBase
tmux.send_keys :Enter
tmux.until { |lines| lines[-2] == prompt && lines[-1] == '1' }
end
def test_change_top
tmux.send_keys %[seq 1000 | #{FZF} --bind change:top], :Enter
tmux.until { |lines| lines.match_count == 1000 }
tmux.send_keys :Up
tmux.until { |lines| lines[-4] == '> 2' }
tmux.send_keys 1
tmux.until { |lines| lines[-3] == '> 1' }
tmux.send_keys :Up
tmux.until { |lines| lines[-4] == '> 10' }
tmux.send_keys 1
tmux.until { |lines| lines[-3] == '> 11' }
tmux.send_keys :Enter
end
end
module TestShell