Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2023-04-19 17:44:27 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.2023 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Wed Apr 19 17:44:27 2023 rev:32 rq:1080294 version:0.39.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2023-04-13 14:10:59.432380290 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.2023/fzf.changes 2023-04-19 17:44:34.680751628 +0200 @@ -1,0 +2,20 @@ +Wed Apr 19 04:26:40 UTC 2023 - Luciano Santos <luc1...@opensuse.org> + +- Update to version 0.39.0: + * Added 'one' event that is triggered when there's only one + match. + * Added --track option that makes fzf track the current selection + when the result list is updated. This can be useful when + browsing logs using fzf with sorting disabled. + * If you use --listen option without a port number fzf will + automatically allocate an available port and export it as + $FZF_PORT environment variable. + * A carriage return and a line feed character will be rendered as + dim â and â respectively. + * fzf will stop rendering a non-displayable characters as a + space. This will likely cause less glitches in the preview + window. + * Other bug fixes and improvements. +- Update vendor tarball. + +------------------------------------------------------------------- Old: ---- fzf-0.38.0.tar.gz New: ---- fzf-0.39.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.VzgyC6/_old 2023-04-19 17:44:38.064771289 +0200 +++ /var/tmp/diff_new_pack.VzgyC6/_new 2023-04-19 17:44:38.072771336 +0200 @@ -18,7 +18,7 @@ %global _lto_cflags %nil Name: fzf -Version: 0.38.0 +Version: 0.39.0 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.38.0.tar.gz -> fzf-0.39.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/.github/workflows/linux.yml new/fzf-0.39.0/.github/workflows/linux.yml --- old/fzf-0.38.0/.github/workflows/linux.yml 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/.github/workflows/linux.yml 2023-04-02 16:33:37.000000000 +0200 @@ -20,7 +20,7 @@ fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.19 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/.github/workflows/macos.yml new/fzf-0.39.0/.github/workflows/macos.yml --- old/fzf-0.38.0/.github/workflows/macos.yml 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/.github/workflows/macos.yml 2023-04-02 16:33:37.000000000 +0200 @@ -20,7 +20,7 @@ fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: 1.18 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/.github/workflows/typos.yml new/fzf-0.39.0/.github/workflows/typos.yml --- old/fzf-0.38.0/.github/workflows/typos.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/fzf-0.39.0/.github/workflows/typos.yml 2023-04-02 16:33:37.000000000 +0200 @@ -0,0 +1,10 @@ +name: "Spell Check" +on: [pull_request] + +jobs: + typos: + name: Spell Check with Typos + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: crate-ci/typos@v1.13.16 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/.goreleaser.yml new/fzf-0.39.0/.goreleaser.yml --- old/fzf-0.38.0/.goreleaser.yml 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/.goreleaser.yml 2023-04-02 16:33:37.000000000 +0200 @@ -74,6 +74,7 @@ - arm64 - loong64 - ppc64le + - s390x goarm: - 5 - 6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/.tool-versions new/fzf-0.39.0/.tool-versions --- old/fzf-0.38.0/.tool-versions 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/.tool-versions 2023-04-02 16:33:37.000000000 +0200 @@ -1 +1 @@ -golang 1.19 +golang 1.20.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/CHANGELOG.md new/fzf-0.39.0/CHANGELOG.md --- old/fzf-0.38.0/CHANGELOG.md 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/CHANGELOG.md 2023-04-02 16:33:37.000000000 +0200 @@ -1,6 +1,42 @@ CHANGELOG ========= +0.39.0 +------ +- Added `one` event that is triggered when there's only one match + ```sh + # Automatically select the only match + seq 10 | fzf --bind one:accept + ``` +- Added `--track` option that makes fzf track the current selection when the + result list is updated. This can be useful when browsing logs using fzf with + sorting disabled. + ```sh + git log --oneline --graph --color=always | nl | + fzf --ansi --track --no-sort --layout=reverse-list + ``` +- If you use `--listen` option without a port number fzf will automatically + allocate an available port and export it as `$FZF_PORT` environment + variable. + ```sh + # Automatic port assignment + fzf --listen --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port' + + # Say hello + curl "localhost:$(cat /tmp/fzf-port)" -d 'preview:echo Hello, fzf is listening on $FZF_PORT.' + ``` +- A carriage return and a line feed character will be rendered as dim â and + â respectively. + ```sh + printf "foo\rbar\nbaz" | fzf --read0 --preview 'echo {}' + ``` +- fzf will stop rendering a non-displayable characters as a space. This will + likely cause less glitches in the preview window. + ```sh + fzf --preview 'head -1000 /dev/random' + ``` +- Bug fixes and improvements + 0.38.0 ------ - New actions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/Makefile new/fzf-0.39.0/Makefile --- old/fzf-0.38.0/Makefile 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/Makefile 2023-04-02 16:33:37.000000000 +0200 @@ -20,7 +20,7 @@ ifdef FZF_REVISION REVISION := $(FZF_REVISION) else -REVISION := $(shell git log -n 1 --pretty=format:%h -- $(SOURCES) 2> /dev/null) +REVISION := $(shell git log -n 1 --pretty=format:%h --abbrev=8 -- $(SOURCES) 2> /dev/null) endif ifeq ($(REVISION),) $(error Not on git repository; cannot determine $$FZF_REVISION) @@ -29,6 +29,7 @@ BINARY32 := fzf-$(GOOS)_386 BINARY64 := fzf-$(GOOS)_amd64 +BINARYS390 := fzf-$(GOOS)_s390x BINARYARM5 := fzf-$(GOOS)_arm5 BINARYARM6 := fzf-$(GOOS)_arm6 BINARYARM7 := fzf-$(GOOS)_arm7 @@ -43,6 +44,8 @@ BINARY := $(BINARY64) else ifeq ($(UNAME_M),amd64) BINARY := $(BINARY64) +else ifeq ($(UNAME_M),s390x) + BINARY := $(BINARYS390) else ifeq ($(UNAME_M),i686) BINARY := $(BINARY32) else ifeq ($(UNAME_M),i386) @@ -132,6 +135,8 @@ target/$(BINARY64): $(SOURCES) GOARCH=amd64 $(GO) build $(BUILD_FLAGS) -o $@ +target/$(BINARYS390): $(SOURCES) + GOARCH=s390x $(GO) build $(BUILD_FLAGS) -o $@ # https://github.com/golang/go/wiki/GoArm target/$(BINARYARM5): $(SOURCES) GOARCH=arm GOARM=5 $(GO) build $(BUILD_FLAGS) -o $@ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/README-VIM.md new/fzf-0.39.0/README-VIM.md --- old/fzf-0.38.0/README-VIM.md 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/README-VIM.md 2023-04-02 16:33:37.000000000 +0200 @@ -15,7 +15,7 @@ " If installed using Homebrew on Apple Silicon set rtp+=/opt/homebrew/opt/fzf -" If installed using git +" If you have cloned fzf on ~/.fzf directory set rtp+=~/.fzf ``` @@ -26,7 +26,7 @@ " If installed using Homebrew Plug '/usr/local/opt/fzf' -" If installed using git +" If you have cloned fzf on ~/.fzf directory Plug '~/.fzf' ``` @@ -118,7 +118,7 @@ " An action can be a reference to a function that processes selected lines function! s:build_quickfix_list(lines) - call setqflist(map(copy(a:lines), '{ "filename": v:val }')) + call setqflist(map(copy(a:lines), '{ "filename": v:val, "lnum": 1 }')) copen cc endfunction diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/README.md new/fzf-0.39.0/README.md --- old/fzf-0.38.0/README.md 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/README.md 2023-04-02 16:33:37.000000000 +0200 @@ -61,8 +61,8 @@ * [3. Interactive ripgrep integration](#3-interactive-ripgrep-integration) * [Preview window](#preview-window) * [Tips](#tips) - * [Respecting `.gitignore`](#respecting-gitignore) - * [Fish shell](#fish-shell) + * [Respecting `.gitignore`](#respecting-gitignore) + * [Fish shell](#fish-shell) * [Related projects](#related-projects) * [License](#license) @@ -124,6 +124,7 @@ | pkg | FreeBSD | `pkg install fzf` | | pkgin | NetBSD | `pkgin install fzf` | | pkg_add | OpenBSD | `pkg_add fzf` | +| Portage | Gentoo | `emerge --ask app-shells/fzf` | | XBPS | Void Linux | `sudo xbps-install -S fzf` | | Zypper | openSUSE | `sudo zypper install fzf` | @@ -723,7 +724,7 @@ Tips ---- -#### Respecting `.gitignore` +### Respecting `.gitignore` You can use [fd](https://github.com/sharkdp/fd), [ripgrep](https://github.com/BurntSushi/ripgrep), or [the silver @@ -752,7 +753,7 @@ export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix --hidden --follow --exclude .git' ``` -#### Fish shell +### Fish shell `CTRL-T` key binding of fish, unlike those of bash and zsh, will use the last token on the command-line as the root directory for the recursive search. For diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/bin/fzf-tmux new/fzf-0.39.0/bin/fzf-tmux --- old/fzf-0.38.0/bin/fzf-tmux 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/bin/fzf-tmux 2023-04-02 16:33:37.000000000 +0200 @@ -179,12 +179,15 @@ envs="export TERM=$TERM " if [[ "$opt" =~ "-E" ]]; then - tmux_version=$(tmux -V) - if [[ $tmux_version =~ ^tmux\ 3\.2[a-z]?$ ]]; then - FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS" - else + tmux_version=$(tmux -V | sed 's/[^0-9.]//g') + if [[ $(bc -l <<< "$tmux_version > 3.2") = 1 ]]; then FZF_DEFAULT_OPTS="--border $FZF_DEFAULT_OPTS" opt="-B $opt" + elif [[ $tmux_version = 3.2 ]]; then + FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS" + else + echo "fzf-tmux: tmux 3.2 or above is required for popup mode" >&2 + exit 2 fi fi [[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/doc/fzf.txt new/fzf-0.39.0/doc/fzf.txt --- old/fzf-0.38.0/doc/fzf.txt 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/doc/fzf.txt 2023-04-02 16:33:37.000000000 +0200 @@ -1,4 +1,4 @@ -fzf.txt fzf Last change: May 19 2021 +fzf.txt fzf Last change: Mar 20 2023 FZF - TABLE OF CONTENTS *fzf* *fzf-toc* ============================================================================== @@ -32,7 +32,7 @@ " If installed using Homebrew set rtp+=/usr/local/opt/fzf - " If installed using git + " If you have cloned fzf on ~/.fzf directory set rtp+=~/.fzf < If you use {vim-plug}{1}, the same can be written as: @@ -40,7 +40,7 @@ " If installed using Homebrew Plug '/usr/local/opt/fzf' - " If installed using git + " If you have cloned fzf on ~/.fzf directory Plug '~/.fzf' < But if you want the latest Vim plugin file from GitHub rather than the one @@ -143,7 +143,7 @@ " An action can be a reference to a function that processes selected lines function! s:build_quickfix_list(lines) - call setqflist(map(copy(a:lines), '{ "filename": v:val }')) + call setqflist(map(copy(a:lines), '{ "filename": v:val, "lnum": 1 }')) copen cc endfunction diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/go.mod new/fzf-0.39.0/go.mod --- old/fzf-0.38.0/go.mod 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/go.mod 2023-04-02 16:33:37.000000000 +0200 @@ -5,10 +5,10 @@ github.com/mattn/go-isatty v0.0.17 github.com/mattn/go-runewidth v0.0.14 github.com/mattn/go-shellwords v1.0.12 - github.com/rivo/uniseg v0.4.2 + github.com/rivo/uniseg v0.4.4 github.com/saracen/walker v0.1.3 - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab - golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 + golang.org/x/sys v0.6.0 + golang.org/x/term v0.6.0 ) require ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/go.sum new/fzf-0.39.0/go.sum --- old/fzf-0.38.0/go.sum 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/go.sum 2023-04-02 16:33:37.000000000 +0200 @@ -11,8 +11,8 @@ github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= -github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/saracen/walker v0.1.3 h1:YtcKKmpRPy6XJTHJ75J2QYXXZYWnZNQxPCVqZSHVV/g= github.com/saracen/walker v0.1.3/go.mod h1:FU+7qU8DeQQgSZDmmThMJi93kPkLFgy0oVAcLxurjIk= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -31,11 +31,13 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/install new/fzf-0.39.0/install --- old/fzf-0.38.0/install 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/install 2023-04-02 16:33:37.000000000 +0200 @@ -2,7 +2,7 @@ set -u -version=0.38.0 +version=0.39.0 auto_completion= key_bindings= update_config=2 @@ -178,6 +178,7 @@ Linux\ loongarch64) download fzf-$version-linux_loong64.tar.gz ;; Linux\ ppc64le) download fzf-$version-linux_ppc64le.tar.gz ;; Linux\ *64) download fzf-$version-linux_amd64.tar.gz ;; + Linux\ s390x) download fzf-$version-linux_s390x.tar.gz ;; FreeBSD\ *64) download fzf-$version-freebsd_amd64.tar.gz ;; OpenBSD\ *64) download fzf-$version-openbsd_amd64.tar.gz ;; CYGWIN*\ *64) download fzf-$version-windows_amd64.zip ;; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/install.ps1 new/fzf-0.39.0/install.ps1 --- old/fzf-0.38.0/install.ps1 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/install.ps1 2023-04-02 16:33:37.000000000 +0200 @@ -1,4 +1,4 @@ -$version="0.38.0" +$version="0.39.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/main.go new/fzf-0.39.0/main.go --- old/fzf-0.38.0/main.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/main.go 2023-04-02 16:33:37.000000000 +0200 @@ -5,7 +5,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version string = "0.38" +var version string = "0.39" var revision string = "devel" func main() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/man/man1/fzf-tmux.1 new/fzf-0.39.0/man/man1/fzf-tmux.1 --- old/fzf-0.38.0/man/man1/fzf-tmux.1 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/man/man1/fzf-tmux.1 2023-04-02 16:33:37.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf-tmux 1 "Feb 2023" "fzf 0.38.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Apr 2023" "fzf 0.39.0" "fzf-tmux - open fzf in tmux split pane" .SH NAME fzf-tmux - open fzf in tmux split pane diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/man/man1/fzf.1 new/fzf-0.39.0/man/man1/fzf.1 --- old/fzf-0.38.0/man/man1/fzf.1 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/man/man1/fzf.1 2023-04-02 16:33:37.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Feb 2023" "fzf 0.38.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Apr 2023" "fzf 0.39.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -92,6 +92,16 @@ .B "+s, --no-sort" Do not sort the result .TP +.B "--track" +Make fzf track the current selection when the result list is updated. +This can be useful when browsing logs using fzf with sorting disabled. + +.RS +e.g. + \fBgit log --oneline --graph --color=always | nl | + fzf --ansi --track --no-sort --layout=reverse-list\fR +.RE +.TP .B "--tac" Reverse the order of the input @@ -738,9 +748,12 @@ e.g. \fBfzf --multi | fzf --sync\fR .RE .TP -.B "--listen=HTTP_PORT" +.B "--listen[=HTTP_PORT]" Start HTTP server on the given port. It allows external processes to send -actions to perform via POST method. +actions to perform via POST method. If the port number is omitted or given as +0, fzf will choose the port automatically and export it as \fBFZF_PORT\fR +environment variable to the child processes started via \fBexecute\fR and +\fBexecute-silent\fR actions. e.g. \fB# Start HTTP server on port 6266 @@ -748,6 +761,9 @@ # Send action to the server curl -XPOST localhost:6266 -d 'reload(seq 100)+change-prompt(hundred> )' + + # Choose port automatically and export it as $FZF_PORT to the child process + fzf --listen --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port' \fR .TP .B "--version" @@ -977,6 +993,17 @@ # Beware not to introduce an infinite loop seq 10 | fzf --bind 'focus:up' --cycle\fR .RE +\fIone\fR +.RS +Triggered when there's only one match. \fBone:accept\fR binding is comparable +to \fB--select-1\fR option, but the difference is that \fB--select-1\fR is only +effective before the interactive finder starts but \fBone\fR event is triggered +by the interactive finder. + +e.g. + \fB# Automatically select the only match + seq 10 | fzf --bind one:accept\fR +.RE \fIbackward-eof\fR .RS @@ -1145,7 +1172,7 @@ POSIX-compliant. \fBbecome(...)\fR action is similar to \fBexecute(...)\fR, but it replaces the -current fzf process with the specifed command using \fBexecve(2)\fR system +current fzf process with the specified command using \fBexecve(2)\fR system call. \fBfzf --bind "enter:become(vim {})"\fR diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/shell/completion.bash new/fzf-0.39.0/shell/completion.bash --- old/fzf-0.38.0/shell/completion.bash 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/shell/completion.bash 2023-04-02 16:33:37.000000000 +0200 @@ -270,8 +270,9 @@ } _fzf_proc_completion() { - _fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <( - command ps -ef | sed 1d + _fzf_complete -m --header-lines=1 --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <( + command ps -eo user,pid,ppid,start,time,command 2> /dev/null || + command ps -eo user,pid,ppid,time,args # For BusyBox ) } @@ -309,7 +310,7 @@ d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}" a_cmds=" - awk cat diff diff3 + 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 sed sftp sort source tail tee uniq vi view vim wc xdg-open diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/shell/completion.zsh new/fzf-0.39.0/shell/completion.zsh --- old/fzf-0.38.0/shell/completion.zsh 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/shell/completion.zsh 2023-04-02 16:33:37.000000000 +0200 @@ -251,8 +251,9 @@ } _fzf_complete_kill() { - _fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <( - command ps -ef | sed 1d + _fzf_complete -m --header-lines=1 --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <( + command ps -eo user,pid,ppid,start,time,command 2> /dev/null || + command ps -eo user,pid,ppid,time,args # For BusyBox ) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/core.go new/fzf-0.39.0/src/core.go --- old/fzf-0.38.0/src/core.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/core.go 2023-04-02 16:33:37.000000000 +0200 @@ -219,6 +219,7 @@ determine := func(final bool) { if heightUnknown { if total >= maxFit || final { + deferred = false heightUnknown = false terminal.startChan <- fitpad{util.Min(total, maxFit), padHeight} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/merger.go new/fzf-0.39.0/src/merger.go --- old/fzf-0.38.0/src/merger.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/merger.go 2023-04-02 16:33:37.000000000 +0200 @@ -17,6 +17,7 @@ tac bool final bool count int + pass bool } // PassMerger returns a new Merger that simply returns the items in the @@ -26,7 +27,8 @@ pattern: nil, chunks: chunks, tac: tac, - count: 0} + count: 0, + pass: true} for _, chunk := range *mg.chunks { mg.count += chunk.count @@ -58,6 +60,19 @@ return mg.count } +// FindIndex returns the index of the item with the given item index +func (mg *Merger) FindIndex(itemIndex int32) int { + if mg.pass { + return int(itemIndex) + } + for i := 0; i < mg.count; i++ { + if mg.Get(i).item.Index() == itemIndex { + return i + } + } + return -1 +} + // Get returns the pointer to the Result object indexed by the given integer func (mg *Merger) Get(idx int) Result { if mg.chunks != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/options.go new/fzf-0.39.0/src/options.go --- old/fzf-0.38.0/src/options.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/options.go 2023-04-02 16:33:37.000000000 +0200 @@ -33,6 +33,7 @@ field index expressions -d, --delimiter=STR Field delimiter regex (default: AWK-style) +s, --no-sort Do not sort the result + --track Track the current selection when the result is updated --tac Reverse the order of the input --disabled Do not perform search --tiebreak=CRI[,..] Comma-separated list of sort criteria to apply @@ -116,7 +117,7 @@ --read0 Read input delimited by ASCII NUL characters --print0 Print output delimited by ASCII NUL characters --sync Synchronous search for multi-staged filtering - --listen=HTTP_PORT Start HTTP server to receive actions (POST /) + --listen[=HTTP_PORT] Start HTTP server to receive actions (POST /) --version Display version information and exit Environment variables @@ -266,6 +267,7 @@ WithNth []Range Delimiter Delimiter Sort int + Track bool Tac bool Criteria []criterion Multi int @@ -316,7 +318,7 @@ PreviewLabel labelOpts Unicode bool Tabstop int - ListenPort int + ListenPort *int ClearOnExit bool Version bool } @@ -338,6 +340,7 @@ WithNth: make([]Range, 0), Delimiter: Delimiter{}, Sort: 1000, + Track: false, Tac: false, Criteria: []criterion{byScore, byLength}, Multi: 0, @@ -619,6 +622,8 @@ add(tui.Load) case "focus": add(tui.Focus) + case "one": + add(tui.One) case "alt-enter", "alt-return": chords[tui.CtrlAltKey('m')] = key case "alt-space": @@ -1562,6 +1567,10 @@ opts.Sort = optionalNumeric(allArgs, &i, 1) case "+s", "--no-sort": opts.Sort = 0 + case "--track": + opts.Track = true + case "--no-track": + opts.Track = false case "--tac": opts.Tac = true case "--no-tac": @@ -1756,9 +1765,10 @@ case "--tabstop": opts.Tabstop = nextInt(allArgs, &i, "tab stop required") case "--listen": - opts.ListenPort = nextInt(allArgs, &i, "listen port required") + port := optionalNumeric(allArgs, &i, 0) + opts.ListenPort = &port case "--no-listen": - opts.ListenPort = 0 + opts.ListenPort = nil case "--clear": opts.ClearOnExit = true case "--no-clear": @@ -1849,7 +1859,8 @@ } else if match, value := optString(arg, "--tabstop="); match { opts.Tabstop = atoi(value) } else if match, value := optString(arg, "--listen="); match { - opts.ListenPort = atoi(value) + port := atoi(value) + opts.ListenPort = &port } else if match, value := optString(arg, "--hscroll-off="); match { opts.HscrollOff = atoi(value) } else if match, value := optString(arg, "--scroll-off="); match { @@ -1879,7 +1890,7 @@ errorExit("tab stop must be a positive integer") } - if opts.ListenPort < 0 || opts.ListenPort > 65535 { + if opts.ListenPort != nil && (*opts.ListenPort < 0 || *opts.ListenPort > 65535) { errorExit("invalid listen port") } @@ -2001,9 +2012,7 @@ theme := opts.Theme boldify := func(c tui.ColorAttr) tui.ColorAttr { dup := c - if !theme.Colored { - dup.Attr |= tui.Bold - } else if (c.Attr & tui.AttrRegular) == 0 { + if (c.Attr & tui.AttrRegular) == 0 { dup.Attr |= tui.Bold } return dup diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/server.go new/fzf-0.39.0/src/server.go --- old/fzf-0.38.0/src/server.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/server.go 2023-04-02 16:33:37.000000000 +0200 @@ -19,14 +19,26 @@ maxContentLength = 1024 * 1024 ) -func startHttpServer(port int, channel chan []*action) error { - if port == 0 { - return nil +func startHttpServer(port int, channel chan []*action) (error, int) { + if port < 0 { + return nil, port } listener, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) if err != nil { - return fmt.Errorf("port not available: %d", port) + return fmt.Errorf("port not available: %d", port), port + } + if port == 0 { + addr := listener.Addr().String() + parts := strings.SplitN(addr, ":", 2) + if len(parts) < 2 { + return fmt.Errorf("cannot extract port: %s", addr), port + } + var err error + port, err = strconv.Atoi(parts[1]) + if err != nil { + return err, port + } } go func() { @@ -45,7 +57,7 @@ listener.Close() }() - return nil + return nil, port } // Here we are writing a simplistic HTTP server without using net/http diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/terminal.go new/fzf-0.39.0/src/terminal.go --- old/fzf-0.38.0/src/terminal.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/terminal.go 2023-04-02 16:33:37.000000000 +0200 @@ -183,6 +183,7 @@ multi int sort bool toggleSort bool + track bool delimiter Delimiter expect map[tui.Event]string keymap map[tui.Event][]*action @@ -201,9 +202,8 @@ tabstop int margin [4]sizeSpec padding [4]sizeSpec - strong tui.Attr unicode bool - listenPort int + listenPort *int borderShape tui.BorderShape cleanExit bool paused bool @@ -538,13 +538,9 @@ } var previewBox *util.EventBox // We need to start previewer if HTTP server is enabled even when --preview option is not specified - if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenPort > 0 { + if len(opts.Preview.command) > 0 || hasPreviewAction(opts) || opts.ListenPort != nil { previewBox = util.NewEventBox() } - strongAttr := tui.Bold - if !opts.Bold { - strongAttr = tui.AttrRegular - } var renderer tui.Renderer fullscreen := !opts.Height.auto && (opts.Height.size == 0 || opts.Height.percent && opts.Height.size == 100) if fullscreen { @@ -604,6 +600,7 @@ multi: opts.Multi, sort: opts.Sort > 0, toggleSort: opts.ToggleSort, + track: opts.Track, delimiter: opts.Delimiter, expect: opts.Expect, keymap: opts.Keymap, @@ -623,7 +620,6 @@ previewLabelOpts: opts.PreviewLabel, cleanExit: opts.ClearOnExit, paused: opts.Phony, - strong: strongAttr, cycle: opts.Cycle, headerFirst: opts.HeaderFirst, headerLines: opts.HeaderLines, @@ -694,13 +690,25 @@ _, t.hasLoadActions = t.keymap[tui.Load.AsEvent()] - if err := startHttpServer(t.listenPort, t.serverChan); err != nil { - errorExit(err.Error()) + if t.listenPort != nil { + err, port := startHttpServer(*t.listenPort, t.serverChan) + if err != nil { + errorExit(err.Error()) + } + t.listenPort = &port } return &t } +func (t *Terminal) environ() []string { + env := os.Environ() + if t.listenPort != nil { + env = append(env, fmt.Sprintf("FZF_PORT=%d", *t.listenPort)) + } + return env +} + func borderLines(shape tui.BorderShape) int { switch shape { case tui.BorderHorizontal, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderDouble: @@ -740,7 +748,7 @@ // Simpler printer for strings without ANSI colors or tab characters if colors == nil && strings.IndexRune(str, '\t') < 0 { - length := runewidth.StringWidth(str) + length := util.StringWidth(str) if length == 0 { return nil, 0 } @@ -898,6 +906,10 @@ // UpdateList updates Merger to display the list func (t *Terminal) UpdateList(merger *Merger, reset bool) { t.mutex.Lock() + var prevIndex int32 = -1 + if !reset && t.track && t.merger.Length() > 0 { + prevIndex = t.merger.Get(t.cy).item.Index() + } t.progress = 100 t.merger = merger if reset { @@ -908,6 +920,24 @@ t.triggerLoad = false t.eventChan <- tui.Load.AsEvent() } + if prevIndex >= 0 { + pos := t.cy - t.offset + count := t.merger.Length() + i := t.merger.FindIndex(prevIndex) + if i >= 0 { + t.cy = i + t.offset = t.cy - pos + } else if t.cy > count { + // Try to keep the vertical position when the list shrinks + t.cy = count - util.Min(count, t.maxItems()) + pos + } + } + if !t.reading && t.merger.Length() == 1 { + one := tui.One.AsEvent() + if _, prs := t.keymap[one]; prs { + t.eventChan <- one + } + } t.mutex.Unlock() t.reqBox.Set(reqInfo, nil) t.reqBox.Set(reqList, nil) @@ -1338,8 +1368,7 @@ _, overflow := t.trimLeft(t.input[:t.cx], maxWidth) minOffset := int(overflow) - maxOffset := util.Min(util.Min(len(t.input), minOffset+maxWidth), t.cx) - + maxOffset := minOffset + (maxWidth-util.Max(0, maxWidth-t.cx))/2 t.xoffset = util.Constrain(t.xoffset, minOffset, maxOffset) before, _ := t.trimLeft(t.input[t.xoffset:t.cx], maxWidth) beforeLen := t.displayWidth(before) @@ -1404,7 +1433,7 @@ pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1 str := t.infoSep maxWidth := t.window.Width() - pos - width := runewidth.StringWidth(str) + width := util.StringWidth(str) if width > maxWidth { trimmed, _ := t.trimRight([]rune(str), maxWidth) str = string(trimmed) @@ -1829,12 +1858,14 @@ trimmed, isTrimmed = t.trimRight(trimmed, maxWidth-t.pwindow.X()) } str, width := t.processTabs(trimmed, prefixWidth) - prefixWidth += width - if t.theme.Colored && ansi != nil && ansi.colored() { - lbg = ansi.lbg - fillRet = t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str) - } else { - fillRet = t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, str) + if width > prefixWidth { + prefixWidth = width + if t.theme.Colored && ansi != nil && ansi.colored() { + lbg = ansi.lbg + fillRet = t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str) + } else { + fillRet = t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, str) + } } return !isTrimmed && (fillRet == tui.FillContinue || t.previewOpts.wrap && fillRet == tui.FillNextLine) @@ -1937,7 +1968,7 @@ w = t.tabstop - l%t.tabstop strbuf.WriteString(strings.Repeat(" ", w)) } else { - w = runewidth.StringWidth(str) + w = util.StringWidth(str) strbuf.WriteString(str) } l += w @@ -2247,6 +2278,7 @@ } command := t.replacePlaceholder(template, forcePlus, string(t.input), list) cmd := util.ExecCommand(command, false) + cmd.Env = t.environ() t.executing.Set(true) if !background { cmd.Stdin = tui.TtyIn() @@ -2493,17 +2525,17 @@ _, query := t.Input() command := t.replacePlaceholder(commandTemplate, false, string(query), items) cmd := util.ExecCommand(command, true) + env := t.environ() if pwindow != nil { height := pwindow.Height() - env := os.Environ() lines := fmt.Sprintf("LINES=%d", height) columns := fmt.Sprintf("COLUMNS=%d", pwindow.Width()) env = append(env, lines) env = append(env, "FZF_PREVIEW_"+lines) env = append(env, columns) env = append(env, "FZF_PREVIEW_"+columns) - cmd.Env = env } + cmd.Env = env out, _ := cmd.StdoutPipe() cmd.Stderr = cmd.Stdout @@ -3289,7 +3321,7 @@ break } - // Prevew scrollbar dragging + // Preview scrollbar dragging headerLines := t.previewOpts.headerLines pbarDragging = me.Down && (pbarDragging || clicked && t.hasPreviewWindow() && my >= t.pwindow.Top()+headerLines && my < t.pwindow.Top()+t.pwindow.Height() && mx == t.pwindow.Left()+t.pwindow.Width()) if pbarDragging { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/tui/light.go new/fzf-0.39.0/src/tui/light.go --- old/fzf-0.38.0/src/tui/light.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/tui/light.go 2023-04-02 16:33:37.000000000 +0200 @@ -32,20 +32,26 @@ var offsetRegexpBegin *regexp.Regexp = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R") func (r *LightRenderer) stderr(str string) { - r.stderrInternal(str, true) + r.stderrInternal(str, true, "") } -// FIXME: Need better handling of non-displayable characters -func (r *LightRenderer) stderrInternal(str string, allowNLCR bool) { +const CR string = "\x1b[2mâ" +const LF string = "\x1b[2mâ" + +func (r *LightRenderer) stderrInternal(str string, allowNLCR bool, resetCode string) { bytes := []byte(str) runes := []rune{} for len(bytes) > 0 { r, sz := utf8.DecodeRune(bytes) nlcr := r == '\n' || r == '\r' if r >= 32 || r == '\x1b' || nlcr { - if r == utf8.RuneError || nlcr && !allowNLCR { - runes = append(runes, ' ') - } else { + if nlcr && !allowNLCR { + if r == '\r' { + runes = append(runes, []rune(CR+resetCode)...) + } else { + runes = append(runes, []rune(LF+resetCode)...) + } + } else if r != utf8.RuneError { runes = append(runes, r) } } @@ -54,8 +60,10 @@ r.queued.WriteString(string(runes)) } -func (r *LightRenderer) csi(code string) { - r.stderr("\x1b[" + code) +func (r *LightRenderer) csi(code string) string { + fullcode := "\x1b[" + code + r.stderr(fullcode) + return fullcode } func (r *LightRenderer) flush() { @@ -825,12 +833,12 @@ w.CPrint(color, string(w.border.bottomLeft)+repeat(w.border.horizontal, (w.width-bcw)/hw)+repeat(' ', rem)+string(w.border.bottomRight)) } -func (w *LightWindow) csi(code string) { - w.renderer.csi(code) +func (w *LightWindow) csi(code string) string { + return w.renderer.csi(code) } -func (w *LightWindow) stderrInternal(str string, allowNLCR bool) { - w.renderer.stderrInternal(str, allowNLCR) +func (w *LightWindow) stderrInternal(str string, allowNLCR bool, resetCode string) { + w.renderer.stderrInternal(str, allowNLCR, resetCode) } func (w *LightWindow) Top() int { @@ -936,10 +944,10 @@ return codes } -func (w *LightWindow) csiColor(fg Color, bg Color, attr Attr) bool { +func (w *LightWindow) csiColor(fg Color, bg Color, attr Attr) (bool, string) { codes := append(attrCodes(attr), colorCodes(fg, bg)...) - w.csi(";" + strings.Join(codes, ";") + "m") - return len(codes) > 0 + code := w.csi(";" + strings.Join(codes, ";") + "m") + return len(codes) > 0, code } func (w *LightWindow) Print(text string) { @@ -951,16 +959,17 @@ } func (w *LightWindow) CPrint(pair ColorPair, text string) { - w.csiColor(pair.Fg(), pair.Bg(), pair.Attr()) - w.stderrInternal(cleanse(text), false) + _, code := w.csiColor(pair.Fg(), pair.Bg(), pair.Attr()) + w.stderrInternal(cleanse(text), false, code) w.csi("m") } func (w *LightWindow) cprint2(fg Color, bg Color, attr Attr, text string) { - if w.csiColor(fg, bg, attr) { + hasColors, code := w.csiColor(fg, bg, attr) + if hasColors { defer w.csi("m") } - w.stderrInternal(cleanse(text), false) + w.stderrInternal(cleanse(text), false, code) } type wrappedLine struct { @@ -980,6 +989,8 @@ if len(rs) == 1 && rs[0] == '\t' { w = tabstop - (prefixLength+width)%tabstop str = repeat(' ', w) + } else if rs[0] == '\r' { + w++ } else { w = runewidth.StringWidth(str) } @@ -998,12 +1009,12 @@ return lines } -func (w *LightWindow) fill(str string, onMove func()) FillReturn { +func (w *LightWindow) fill(str string, resetCode string) FillReturn { allLines := strings.Split(str, "\n") for i, line := range allLines { lines := wrapLine(line, w.posx, w.width, w.tabstop) for j, wl := range lines { - w.stderrInternal(wl.text, false) + w.stderrInternal(wl.text, false, resetCode) w.posx += wl.displayWidth // Wrap line @@ -1013,7 +1024,7 @@ } w.MoveAndClear(w.posy, w.posx) w.Move(w.posy+1, 0) - onMove() + w.renderer.stderr(resetCode) } } } @@ -1022,22 +1033,26 @@ return FillSuspend } w.Move(w.posy+1, 0) - onMove() + w.renderer.stderr(resetCode) return FillNextLine } return FillContinue } -func (w *LightWindow) setBg() { +func (w *LightWindow) setBg() string { if w.bg != colDefault { - w.csiColor(colDefault, w.bg, AttrRegular) + _, code := w.csiColor(colDefault, w.bg, AttrRegular) + return code } + // Should clear dim attribute after â in the preview window + // e.g. printf "foo\rbar" | fzf --ansi --preview 'printf "foo\rbar"' + return "\x1b[m" } func (w *LightWindow) Fill(text string) FillReturn { w.Move(w.posy, w.posx) - w.setBg() - return w.fill(text, w.setBg) + code := w.setBg() + return w.fill(text, code) } func (w *LightWindow) CFill(fg Color, bg Color, attr Attr, text string) FillReturn { @@ -1048,11 +1063,11 @@ if bg == colDefault { bg = w.bg } - if w.csiColor(fg, bg, attr) { + if hasColors, resetCode := w.csiColor(fg, bg, attr); hasColors { defer w.csi("m") - return w.fill(text, func() { w.csiColor(fg, bg, attr) }) + return w.fill(text, resetCode) } - return w.fill(text, w.setBg) + return w.fill(text, w.setBg()) } func (w *LightWindow) FinishFill() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/tui/tcell.go new/fzf-0.39.0/src/tui/tcell.go --- old/fzf-0.38.0/src/tui/tcell.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/tui/tcell.go 2023-04-02 16:33:37.000000000 +0200 @@ -8,6 +8,7 @@ "github.com/gdamore/tcell/v2" "github.com/gdamore/tcell/v2/encoding" + "github.com/junegunn/fzf/src/util" "github.com/mattn/go-runewidth" "github.com/rivo/uniseg" @@ -572,26 +573,27 @@ gr := uniseg.NewGraphemes(text) for gr.Next() { + st := style rs := gr.Runes() if len(rs) == 1 { r := rs[0] - if r < rune(' ') { // ignore control characters - continue + if r == '\r' { + st = style.Dim(true) + rs[0] = 'â' } else if r == '\n' { - w.lastY++ - lx = 0 - continue - } else if r == '\u000D' { // skip carriage return + st = style.Dim(true) + rs[0] = 'â' + } else if r < rune(' ') { // ignore control characters continue } } var xPos = w.left + w.lastX + lx var yPos = w.top + w.lastY if xPos < (w.left+w.width) && yPos < (w.top+w.height) { - _screen.SetContent(xPos, yPos, rs[0], rs[1:], style) + _screen.SetContent(xPos, yPos, rs[0], rs[1:], st) } - lx += runewidth.StringWidth(string(rs)) + lx += util.StringWidth(string(rs)) } w.lastX += lx } @@ -620,13 +622,22 @@ Italic(a&Attr(tcell.AttrItalic) != 0) gr := uniseg.NewGraphemes(text) +Loop: for gr.Next() { + st := style rs := gr.Runes() - if len(rs) == 1 && rs[0] == '\n' { - w.lastY++ - w.lastX = 0 - lx = 0 - continue + if len(rs) == 1 { + r := rs[0] + switch r { + case '\r': + st = style.Dim(true) + rs[0] = 'â' + case '\n': + w.lastY++ + w.lastX = 0 + lx = 0 + continue Loop + } } // word wrap: @@ -643,8 +654,8 @@ return FillSuspend } - _screen.SetContent(xPos, yPos, rs[0], rs[1:], style) - lx += runewidth.StringWidth(string(rs)) + _screen.SetContent(xPos, yPos, rs[0], rs[1:], st) + lx += util.StringWidth(string(rs)) } w.lastX += lx if w.lastX == w.width { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/tui/tui.go new/fzf-0.39.0/src/tui/tui.go --- old/fzf-0.38.0/src/tui/tui.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/tui/tui.go 2023-04-02 16:33:37.000000000 +0200 @@ -93,6 +93,7 @@ Start Load Focus + One AltBS @@ -525,28 +526,28 @@ func NoColorTheme() *ColorTheme { return &ColorTheme{ Colored: false, - Input: ColorAttr{colDefault, AttrRegular}, - Fg: ColorAttr{colDefault, AttrRegular}, - Bg: ColorAttr{colDefault, AttrRegular}, - DarkBg: ColorAttr{colDefault, AttrRegular}, - Prompt: ColorAttr{colDefault, AttrRegular}, + Input: ColorAttr{colDefault, AttrUndefined}, + Fg: ColorAttr{colDefault, AttrUndefined}, + Bg: ColorAttr{colDefault, AttrUndefined}, + DarkBg: ColorAttr{colDefault, AttrUndefined}, + Prompt: ColorAttr{colDefault, AttrUndefined}, Match: ColorAttr{colDefault, Underline}, Current: ColorAttr{colDefault, Reverse}, CurrentMatch: ColorAttr{colDefault, Reverse | Underline}, - Spinner: ColorAttr{colDefault, AttrRegular}, - Info: ColorAttr{colDefault, AttrRegular}, - Cursor: ColorAttr{colDefault, AttrRegular}, - Selected: ColorAttr{colDefault, AttrRegular}, - Header: ColorAttr{colDefault, AttrRegular}, - Border: ColorAttr{colDefault, AttrRegular}, - BorderLabel: ColorAttr{colDefault, AttrRegular}, - Disabled: ColorAttr{colDefault, AttrRegular}, - PreviewFg: ColorAttr{colDefault, AttrRegular}, - PreviewBg: ColorAttr{colDefault, AttrRegular}, - Gutter: ColorAttr{colDefault, AttrRegular}, - PreviewLabel: ColorAttr{colDefault, AttrRegular}, - Separator: ColorAttr{colDefault, AttrRegular}, - Scrollbar: ColorAttr{colDefault, AttrRegular}, + Spinner: ColorAttr{colDefault, AttrUndefined}, + Info: ColorAttr{colDefault, AttrUndefined}, + Cursor: ColorAttr{colDefault, AttrUndefined}, + Selected: ColorAttr{colDefault, AttrUndefined}, + Header: ColorAttr{colDefault, AttrUndefined}, + Border: ColorAttr{colDefault, AttrUndefined}, + BorderLabel: ColorAttr{colDefault, AttrUndefined}, + Disabled: ColorAttr{colDefault, AttrUndefined}, + PreviewFg: ColorAttr{colDefault, AttrUndefined}, + PreviewBg: ColorAttr{colDefault, AttrUndefined}, + Gutter: ColorAttr{colDefault, AttrUndefined}, + PreviewLabel: ColorAttr{colDefault, AttrUndefined}, + Separator: ColorAttr{colDefault, AttrUndefined}, + Scrollbar: ColorAttr{colDefault, AttrUndefined}, } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/util/util.go new/fzf-0.39.0/src/util/util.go --- old/fzf-0.38.0/src/util/util.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/util/util.go 2023-04-02 16:33:37.000000000 +0200 @@ -11,6 +11,11 @@ "github.com/rivo/uniseg" ) +// StringWidth returns string width where each CR/LF character takes 1 column +func StringWidth(s string) int { + return runewidth.StringWidth(s) + strings.Count(s, "\n") + strings.Count(s, "\r") +} + // RunesWidth returns runes width func RunesWidth(runes []rune, prefixWidth int, tabstop int, limit int) (int, int) { width := 0 @@ -22,8 +27,7 @@ if len(rs) == 1 && rs[0] == '\t' { w = tabstop - (prefixWidth+width)%tabstop } else { - s := string(rs) - w = runewidth.StringWidth(s) + strings.Count(s, "\n") + w = StringWidth(string(rs)) } width += w if width > limit { @@ -41,7 +45,7 @@ gr := uniseg.NewGraphemes(input) for gr.Next() { rs := gr.Runes() - w := runewidth.StringWidth(string(rs)) + w := StringWidth(string(rs)) if width+w > limit { return runes, width } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/src/util/util_test.go new/fzf-0.39.0/src/util/util_test.go --- old/fzf-0.38.0/src/util/util_test.go 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/src/util/util_test.go 2023-04-02 16:33:37.000000000 +0200 @@ -70,7 +70,7 @@ } } -func TestContrain(t *testing.T) { +func TestConstrain(t *testing.T) { if Constrain(-3, -1, 3) != -1 { t.Error("Expected", -1) } @@ -83,7 +83,7 @@ } } -func TestContrain32(t *testing.T) { +func TestConstrain32(t *testing.T) { if Constrain32(-3, -1, 3) != -1 { t.Error("Expected", -1) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/test/test_go.rb new/fzf-0.39.0/test/test_go.rb --- old/fzf-0.38.0/test/test_go.rb 2023-02-15 15:24:42.000000000 +0100 +++ new/fzf-0.39.0/test/test_go.rb 2023-04-02 16:33:37.000000000 +0200 @@ -1930,7 +1930,7 @@ def test_keep_right tmux.send_keys "seq 10000 | #{FZF} --read0 --keep-right", :Enter - tmux.until { |lines| assert lines.any_include?('9999 10000') } + tmux.until { |lines| assert lines.any_include?('9999â10000') } end def test_backward_eof @@ -2629,11 +2629,17 @@ end def test_listen - tmux.send_keys 'seq 10 | fzf --listen 6266', :Enter - tmux.until { |lines| assert_equal 10, lines.item_count } - Net::HTTP.post(URI('http://localhost:6266'), 'change-query(yo)+reload(seq 100)+change-prompt:hundred> ') - tmux.until { |lines| assert_equal 100, lines.item_count } - tmux.until { |lines| assert_equal 'hundred> yo', lines[-1] } + { '--listen 6266' => -> { URI('http://localhost:6266') }, + "--listen --sync --bind 'start:execute-silent:echo $FZF_PORT > /tmp/fzf-port'" => + -> { URI("http://localhost:#{File.read('/tmp/fzf-port').chomp}") } }.each do |opts, fn| + tmux.send_keys "seq 10 | fzf #{opts}", :Enter + tmux.until { |lines| assert_equal 10, lines.item_count } + Net::HTTP.post(fn.call, 'change-query(yo)+reload(seq 100)+change-prompt:hundred> ') + tmux.until { |lines| assert_equal 100, lines.item_count } + tmux.until { |lines| assert_equal 'hundred> yo', lines[-1] } + teardown + setup + end end def test_toggle_alternative_preview_window @@ -2656,6 +2662,67 @@ tmux.send_keys :Enter tmux.until { |lines| assert_equal 99, lines.item_count } end + + def test_no_extra_newline_issue_3209 + tmux.send_keys(%(seq 100 | #{FZF} --height 10 --preview-window up,wrap --preview 'printf "â%.0s" $(seq 1 "$((FZF_PREVIEW_COLUMNS - 5))"); printf $"\\e[7m%s\\e[0m" title; echo; echo something'), :Enter) + expected = <<~OUTPUT + âââââââââââ + â âââââââââ + â something + â + â°ââââââââââ + 3 + 2 + > 1 + 100/100 â + > + OUTPUT + tmux.until { assert_block(expected, _1) } + end + + def test_track + tmux.send_keys "seq 1000 | #{FZF} --query 555 --track", :Enter + tmux.until do |lines| + assert_equal 1, lines.match_count + assert_includes lines, '> 555' + end + tmux.send_keys :BSpace + index = tmux.until do |lines| + assert_equal 28, lines.match_count + assert_includes lines, '> 555' + end.index('> 555') + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 271, lines.match_count + assert_equal '> 555', lines[index] + end + tmux.send_keys :BSpace + tmux.until do |lines| + assert_equal 1000, lines.match_count + assert_equal '> 555', lines[index] + end + end + + def test_one + tmux.send_keys "seq 10 | #{FZF} --bind 'one:preview:echo {} is the only match'", :Enter + tmux.send_keys '1' + tmux.until do |lines| + assert_equal 2, lines.match_count + refute(lines.any? { _1.include?('only match') }) + end + tmux.send_keys '0' + tmux.until do |lines| + assert_equal 1, lines.match_count + assert(lines.any? { _1.include?('only match') }) + end + end + + def test_height_range_with_exit_0 + tmux.send_keys "seq 10 | #{FZF} --height ~10% --exit-0", :Enter + tmux.until { |lines| assert_equal 10, lines.item_count } + tmux.send_keys :c + tmux.until { |lines| assert_equal 0, lines.match_count } + end end module TestShell @@ -2784,9 +2851,9 @@ tmux.send_keys 'C-r' tmux.until { |lines| assert_equal '>', lines[-1] } tmux.send_keys 'foo bar' - tmux.until { |lines| assert lines[-3]&.end_with?('bar"') } + tmux.until { |lines| assert lines[-3]&.match?(/bar"â?/) } tmux.send_keys :Enter - tmux.until { |lines| assert lines[-1]&.end_with?('bar"') } + tmux.until { |lines| assert lines[-1]&.match?(/bar"â?/) } tmux.send_keys :Enter tmux.until { |lines| assert_equal %w[foo bar], lines[-2..] } end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.38.0/typos.toml new/fzf-0.39.0/typos.toml --- old/fzf-0.38.0/typos.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/fzf-0.39.0/typos.toml 2023-04-02 16:33:37.000000000 +0200 @@ -0,0 +1,6 @@ +# See https://github.com/crate-ci/typos/blob/master/docs/reference.md to configure typos +[default.extend-words] +ba = "ba" +fo = "fo" +enew = "enew" +tabe = "tabe" ++++++ vendor.tar.zst ++++++ Binary files /var/tmp/diff_new_pack.VzgyC6/_old and /var/tmp/diff_new_pack.VzgyC6/_new differ