Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2025-03-18 17:41:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Tue Mar 18 17:41:51 2025 rev:66 rq:1253955 version:0.60.3 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2025-02-16 22:49:49.103277422 +0100 +++ /work/SRC/openSUSE:Factory/.fzf.new.19136/fzf.changes 2025-03-18 17:43:52.712012621 +0100 @@ -1,0 +2,23 @@ +Mon Mar 17 21:55:35 UTC 2025 - Avindra Goolcharan <avin...@opensuse.org> + +- Update to 0.60.3: + * [fish] Enable multiple history commands insertion (#4280) (@bitraid) + * [walker] Append '/' to directory entries on MSYS2 (#4281) + * Trim trailing whitespaces after processing ANSI sequences (#4282) + * Remove temp files before `become` when using `--tmux` option (#4283) + * Fix condition for using item numlines cache (#4285) + * Make `--accept-nth` compatible with `--select-1` (#4287) + * Increase the query length limit from 300 to 1000 (#4292) + * [windows] Prevent fzf from consuming user input while paused (#4260) +- Updates from 0.60.2: + * Template for `--with-nth` and `--accept-nth` now supports `{n }` + which evaluates to the zero-based ordinal index of the item + * Fixed a regression that caused the last field in the "nth" + expression to be trimmed when a regular expression delimiter is used + * Fixed 'jump' action when the pointer is an empty string +- Updates from 0.60.1: + * Built-in walker now prints directory entries with a trailing slash + * Fixed a bug causing unexpected behavior with [fzf-tab](https + ://github.com/Aloxaf/fzf-tab). Please upgrade if you use it. + +------------------------------------------------------------------- Old: ---- fzf-0.60.0.tar.gz New: ---- fzf-0.60.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.7j66Nv/_old 2025-03-18 17:43:53.208033433 +0100 +++ /var/tmp/diff_new_pack.7j66Nv/_new 2025-03-18 17:43:53.212033601 +0100 @@ -18,7 +18,7 @@ %global _lto_cflags %{nil} Name: fzf -Version: 0.60.0 +Version: 0.60.3 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.60.0.tar.gz -> fzf-0.60.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/CHANGELOG.md new/fzf-0.60.3/CHANGELOG.md --- old/fzf-0.60.0/CHANGELOG.md 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/CHANGELOG.md 2025-03-03 09:10:49.000000000 +0100 @@ -1,6 +1,32 @@ CHANGELOG ========= +0.60.3 +------ +- Bug fixes and improvements + - [fish] Enable multiple history commands insertion (#4280) (@bitraid) + - [walker] Append '/' to directory entries on MSYS2 (#4281) + - Trim trailing whitespaces after processing ANSI sequences (#4282) + - Remove temp files before `become` when using `--tmux` option (#4283) + - Fix condition for using item numlines cache (#4285) (@alex-huff) + - Make `--accept-nth` compatible with `--select-1` (#4287) + - Increase the query length limit from 300 to 1000 (#4292) + - [windows] Prevent fzf from consuming user input while paused (#4260) + +0.60.2 +------ +- Template for `--with-nth` and `--accept-nth` now supports `{n}` which evaluates to the zero-based ordinal index of the item +- Fixed a regression that caused the last field in the "nth" expression to be trimmed when a regular expression delimiter is used + - Thanks to @phanen for the fix +- Fixed 'jump' action when the pointer is an empty string + +0.60.1 +------ +- Bug fixes and minor improvements + - Built-in walker now prints directory entries with a trailing slash + - Fixed a bug causing unexpected behavior with [fzf-tab](https://github.com/Aloxaf/fzf-tab). Please upgrade if you use it. +- Thanks to @alexeisersun, @bitraid, @Lompik, and @fsc0 for the contributions + 0.60.0 ------ _Release highlights: https://junegunn.github.io/fzf/releases/0.60.0/_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/README.md new/fzf-0.60.3/README.md --- old/fzf-0.60.0/README.md 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/README.md 2025-03-03 09:10:49.000000000 +0100 @@ -7,7 +7,7 @@ </a> ### [Warp, the intelligent terminal for developers](https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=fzf) -[Available for MacOS and Linux](https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=fzf)<br> +[Available for MacOS, Linux, & Windows](https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=fzf)<br> </div> <hr> @@ -39,7 +39,7 @@ If you'd like to sponsor this project, please visit https://github.com/sponsors/junegunn. -<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="User avatar: miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="User avatar: Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="User avatar: Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="User avatar: Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="User avatar: Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="User avatar: Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https:/& #x2F;github.com/pldubouilh.png" width="60px" alt="User avatar: Pierre Dubouilh" /></a><a href="https://github.com/trantor"><img src="https://github.com/trantor.png" width="60px" alt="User avatar: Fulvio Scapin" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="User avatar: Ryan Roden-Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="User avatar: Jordan Arentsen" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="User avatar: Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="User avatar: David Balatero" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/benela n"><img src="https://github.com/benelan.png" width="60px" alt="User avatar: Ben Elan" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="User avatar: PaweÅ Duda" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="User avatar: Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="User avatar: ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="User avatar: Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https:/ ;/github.com/dariusjonda.png" width="60px" alt="User avatar: Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="User avatar: Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="User avatar: Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="User avatar: Ben Lechlitner" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="User avatar: george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="User avatar: Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="User avatar: Paul OLeary McCann" /></a>< a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="User avatar: Robert Beeger" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="User avatar: Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="User avatar: Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="User avatar: Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="User avatar: thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="User avatar: Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="User avatar: Guilla ume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="User avatar: Rob Levy" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="User avatar: Gloria Zhao" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="User avatar: Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="User avatar: jamesob" /></a><a href="https://github.com/jlebray"><img src="https://github.com/jlebray.png" width="60px" alt="User avatar: Johan Le Bray" /></a>< a href="https://github.com/panosl1"><img src="https://github.com/panosl1.png" width="60px" alt="User avatar: Panos Lampropoulos" /></a><a href="https://github.com/bespinian"><img src="https://github.com/bespinian.png" width="60px" alt="User avatar: bespinian" /></a><a href="https://github.com/scosu"><img src="https://github.com/scosu.png" width="60px" alt="User avatar: Markus Schneider-Pargmann" /></a><a href="https://github.com/smithbm2316"><img src="https://github.com/smithbm2316.png" width="60px" alt="User avatar: Ben Smith" /></a><a href="https://github.com/charlieegan3"><img src="https://github.com/charlieegan3.png" width="60px" alt="User avatar: Charlie Egan" /></a><a href="https://github.com/thobbs"><img src="https://github.com/thobbs.png" width="60px" alt="User avatar: Tyler Hobbs" /></a><a href="https://github.com/neilparikh"><img src="https://github.com/neilparikh.png" width="60px" alt="User avatar: Neil Parikh" /></a><a href="https://github.com/shkm"><img src="https://github.com/shkm.png" width="60px" alt="User avatar: Jamie Schembri" /></a><a href="https://github.com/BasedScience"><img src="https://github.com/BasedScience.png" width="60px" alt="User avatar: dockien" /></a><a href="https://github.com/RussellGilmore"><img src="https://github.com/RussellGilmore.png" width="60px" alt="User avatar: Russell Gilmore" /></a><a href="https://github.com/meribold"><img src="https://github.com/meribold.png" width="60px" alt="User avatar: Lukas Waymann" /></a><a href="https://github.com/terminaldweller"><img src="https://github.com/terminaldweller.png" width="60px" alt="User avatar: Farzad Sadeghi" /></a><a href="https://github.com/jaydee-coder"><img src="https://github.com/jaydee-coder.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/brpaz"><img src="https://github.com/brpaz.png" width="60px" alt="User avatar: Bruno Paz" /></a><a href="https://github.com/timobenn"><img src="https://github.com/timobenn.png" width="60px" alt="User avatar: Timothy Bennett" /></a><a href="https://github.com/danhorner"><img src="https://github.com/danhorner.png" width="60px" alt="User avatar: Daniel Horner" /></a><a href="https://github.com/rdmarsh"><img src="https://github.com/rdmarsh.png" width="60px" alt="User avatar: David Marsh" /></a><a href="https://github.com/Sacquer"><img src="https://github.com/Sacquer.png" width="60px" alt="User avatar: Gökhan Alkacir" /></a><a href="https://github.com/bitlux"><img src="https://github.com/bitlux.png" width="60px" alt="User avatar: Adam" /></a><!-- sponsors --> +<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="User avatar: miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="User avatar: Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="User avatar: Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="User avatar: Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="User avatar: Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="User avatar: Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https:/& #x2F;github.com/pldubouilh.png" width="60px" alt="User avatar: Pierre Dubouilh" /></a><a href="https://github.com/trantor"><img src="https://github.com/trantor.png" width="60px" alt="User avatar: Fulvio Scapin" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="User avatar: Ryan Roden-Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="User avatar: Jordan Arentsen" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="User avatar: Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="User avatar: David Balatero" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/benela n"><img src="https://github.com/benelan.png" width="60px" alt="User avatar: Ben Elan" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="User avatar: PaweÅ Duda" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="User avatar: Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="User avatar: ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="User avatar: Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="User avatar: Darius Jonda" /></a><a href="https://github.com/cristian d391"><img src="https://github.com/cristiand391.png" width="60px" alt="User avatar: Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="User avatar: Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="User avatar: Ben Lechlitner" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="User avatar: george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="User avatar: Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="User avatar: Paul OLeary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="User avatar: Rob ert Beeger" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="User avatar: Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="User avatar: Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="User avatar: Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="User avatar: thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="User avatar: Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="User avatar: Guillaume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="User a vatar: " /></a><a href="https://github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="User avatar: Rob Levy" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="User avatar: Gloria Zhao" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="User avatar: Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="User avatar: jamesob" /></a><a href="https://github.com/jlebray"><img src="https://github.com/jlebray.png" width="60px" alt="User avatar: Johan Le Bray" /></a><a href="https://github.com/panosl1"><img src="https://github.com/panosl1.png" width="60px" alt="User avatar: Pan os Lampropoulos" /></a><a href="https://github.com/bespinian"><img src="https://github.com/bespinian.png" width="60px" alt="User avatar: bespinian" /></a><a href="https://github.com/scosu"><img src="https://github.com/scosu.png" width="60px" alt="User avatar: Markus Schneider-Pargmann" /></a><a href="https://github.com/smithbm2316"><img src="https://github.com/smithbm2316.png" width="60px" alt="User avatar: Ben Smith" /></a><a href="https://github.com/charlieegan3"><img src="https://github.com/charlieegan3.png" width="60px" alt="User avatar: Charlie Egan" /></a><a href="https://github.com/thobbs"><img src="https://github.com/thobbs.png" width="60px" alt="User avatar: Tyler Hobbs" /></a><a href="https://github.com/neilparikh"><img src="https://github.com/neilparikh.png" width="60px" alt="User avatar: Neil Parikh" /></a><a href="https://github.com/shkm"><img src="https://github.com/ ;shkm.png" width="60px" alt="User avatar: Jamie Schembri" /></a><a href="https://github.com/BasedScience"><img src="https://github.com/BasedScience.png" width="60px" alt="User avatar: dockien" /></a><a href="https://github.com/RussellGilmore"><img src="https://github.com/RussellGilmore.png" width="60px" alt="User avatar: Russell Gilmore" /></a><a href="https://github.com/meribold"><img src="https://github.com/meribold.png" width="60px" alt="User avatar: Lukas Waymann" /></a><a href="https://github.com/terminaldweller"><img src="https://github.com/terminaldweller.png" width="60px" alt="User avatar: Farzad Sadeghi" /></a><a href="https://github.com/jaydee-coder"><img src="https://github.com/jaydee-coder.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/brpaz"><img src="https://github.com/brpaz.png" width="60px" alt="User avatar: Bruno Paz" /></a><a href="https://github.com/t imobenn"><img src="https://github.com/timobenn.png" width="60px" alt="User avatar: Timothy Bennett" /></a><a href="https://github.com/danhorner"><img src="https://github.com/danhorner.png" width="60px" alt="User avatar: Daniel Horner" /></a><a href="https://github.com/bitlux"><img src="https://github.com/bitlux.png" width="60px" alt="User avatar: Adam" /></a><a href="https://github.com/syeo66"><img src="https://github.com/syeo66.png" width="60px" alt="User avatar: Red Ochsenbein" /></a><a href="https://github.com/nekhaevskiy"><img src="https://github.com/nekhaevskiy.png" width="60px" alt="User avatar: Yury" /></a><a href="https://github.com/cange"><img src="https://github.com/cange.png" width="60px" alt="User avatar: Christian Angermann" /></a><a href="https://github.com/lajarre"><img src="https://github.com/lajarre.png" width="60px" alt="User avatar: " /></a><!-- sponsors --> Table of Contents ----------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/install new/fzf-0.60.3/install --- old/fzf-0.60.0/install 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/install 2025-03-03 09:10:49.000000000 +0100 @@ -2,7 +2,7 @@ set -u -version=0.60.0 +version=0.60.3 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/install.ps1 new/fzf-0.60.3/install.ps1 --- old/fzf-0.60.0/install.ps1 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/install.ps1 2025-03-03 09:10:49.000000000 +0100 @@ -1,4 +1,4 @@ -$version="0.60.0" +$version="0.60.3" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/man/man1/fzf-tmux.1 new/fzf-0.60.3/man/man1/fzf-tmux.1 --- old/fzf-0.60.0/man/man1/fzf-tmux.1 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/man/man1/fzf-tmux.1 2025-03-03 09:10:49.000000000 +0100 @@ -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 2025" "fzf 0.60.0" "fzf\-tmux - open fzf in tmux split pane" +.TH fzf\-tmux 1 "Mar 2025" "fzf 0.60.3" "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.60.0/man/man1/fzf.1 new/fzf-0.60.3/man/man1/fzf.1 --- old/fzf-0.60.0/man/man1/fzf.1 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/man/man1/fzf.1 2025-03-03 09:10:49.000000000 +0100 @@ -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 2025" "fzf 0.60.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Mar 2025" "fzf 0.60.3" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -56,7 +56,9 @@ Case-sensitive match .TP .B "\-\-smart\-case" -Smart-case match (default) +Smart-case match (default). In this mode, the search is case-insensitive by +default, but it becomes case-sensitive if the query contains any uppercase +letters. .TP .B "\-\-literal" Do not normalize latin script letters for matching. @@ -120,7 +122,9 @@ .BI "\-\-with\-nth=" "N[,..] or TEMPLATE" Transform the presentation of each line using the field index expressions. For advanced transformation, you can provide a template containing field index -expressions in curly braces. +expressions in curly braces. When you use a template, the trailing delimiter is +stripped from each expression, giving you more control over the output. +\fB{n}\fR in template evaluates to the zero-based ordinal index of the line. .RS e.g. @@ -128,13 +132,16 @@ echo foo bar baz | fzf --with-nth 2.. # Use template to rearrange fields - echo foo,bar,baz | fzf --delimiter , --with-nth '{1},{3},{2},{1..2}' + echo foo,bar,baz | fzf --delimiter , --with-nth '{n},{1},{3},{2},{1..2}' .RE .TP .BI "\-\-accept\-nth=" "N[,..] or TEMPLATE" Define which fields to print on accept. The last delimiter is stripped from the output. For advanced transformation, you can provide a template containing -field index expressions in curly braces. +field index expressions in curly braces. When you use a template, the trailing +delimiter is stripped from each expression, giving you more control over the +output. \fB{n}\fR in template evaluates to the zero-based ordinal index of the +line. .RS e.g. @@ -142,7 +149,7 @@ echo foo bar baz | fzf --accept-nth 2 # Template - echo foo bar baz | fzf --accept-nth '1st: {1}, 2nd: {2}, 3rd: {3}' + echo foo bar baz | fzf --accept-nth 'Index: {n}, 1st: {1}, 2nd: {2}, 3rd: {3}' .RE .TP .B "+s, \-\-no\-sort" @@ -1717,6 +1724,9 @@ \fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all+accept'\fR \fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all' \-\-bind 'ctrl\-a:+accept'\fR +Any action after a terminal action that exits fzf, such as \fBaccept\fR or +\fBabort\fR, is ignored. + .SS ACTION ARGUMENT An action denoted with \fB(...)\fR suffix takes an argument. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/shell/completion.zsh new/fzf-0.60.3/shell/completion.zsh --- old/fzf-0.60.0/shell/completion.zsh 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/shell/completion.zsh 2025-03-03 09:10:49.000000000 +0100 @@ -99,9 +99,9 @@ __fzf_defaults() { # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - echo "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1" + echo -E "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1" command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null - echo "${FZF_DEFAULT_OPTS-} $2" + echo -E "${FZF_DEFAULT_OPTS-} $2" } __fzf_comprun() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/shell/key-bindings.fish new/fzf-0.60.3/shell/key-bindings.fish --- old/fzf-0.60.0/shell/key-bindings.fish 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/shell/key-bindings.fish 2025-03-03 09:10:49.000000000 +0100 @@ -14,102 +14,24 @@ # Key bindings # ------------ +# For compatibility with fish versions down to 3.1.2, the script does not use: +# - The -f/--function switch of command: set +# - The process substitution syntax: $(cmd) +# - Ranges that omit start/end indexes: $var[$start..] $var[..$end] $var[..] function fzf_key_bindings function __fzf_defaults - # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40% - echo "--height $FZF_TMUX_HEIGHT --min-height 20+ --bind=ctrl-z:ignore" $argv[1] - test -r "$FZF_DEFAULT_OPTS_FILE"; and string collect -N -- <$FZF_DEFAULT_OPTS_FILE - echo $FZF_DEFAULT_OPTS $argv[2] - end - - # Store current token in $dir as root for the 'find' command - function fzf-file-widget -d "List files and folders" - set -l commandline (__fzf_parse_commandline) - set -lx dir $commandline[1] - set -l fzf_query $commandline[2] - set -l prefix $commandline[3] - set -l result - - test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40% - begin - set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_CTRL_T_OPTS") - set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND" - set -lx FZF_DEFAULT_OPTS_FILE '' - set result (eval (__fzfcmd) -m --query=$fzf_query) - end - if test -z "$result" - commandline -f repaint - return - else - # Remove last token from commandline. - commandline -t "" - end - for i in $result - commandline -it -- $prefix - commandline -it -- (string escape -- $i) - commandline -it -- ' ' - end - commandline -f repaint - end - - function fzf-history-widget -d "Show command history" - test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40% - begin - # merge history from other sessions before searching - test -z "$fish_private_mode"; and builtin history merge - - set -lx FZF_DEFAULT_OPTS (__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"\t"â³ ' --highlight-line +m $FZF_CTRL_R_OPTS") - set -lx FZF_DEFAULT_OPTS_FILE '' - set -lx FZF_DEFAULT_COMMAND - set -a -- FZF_DEFAULT_OPTS --with-shell=(status fish-path)\\ -c - - if type -q perl - set -a FZF_DEFAULT_OPTS '--tac' - set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\'' - else - set FZF_DEFAULT_COMMAND \ - 'set -l h (builtin history -z --reverse | string split0);' \ - 'for i in (seq (count $h) -1 1);' \ - 'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \ - 'end' - end - set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --read0 --print0 -q (commandline | string escape) "--bind=enter:become:'string replace -a -- \n\t \n {2..} | string collect'") - and commandline -- $result - end - commandline -f repaint - end - - function fzf-cd-widget -d "Change directory" - set -l commandline (__fzf_parse_commandline) - set -lx dir $commandline[1] - set -l fzf_query $commandline[2] - set -l prefix $commandline[3] - - test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40% - begin - set -lx FZF_DEFAULT_OPTS (__fzf_defaults "--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" "$FZF_ALT_C_OPTS") - set -lx FZF_DEFAULT_OPTS_FILE '' - set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND" - set -l result (eval (__fzfcmd) +m --query=$fzf_query) - - if test -n "$result" - cd -- $result - - # Remove last token from commandline. - commandline -t "" - commandline -it -- $prefix - end - end - - commandline -f repaint + # $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + # $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40% + string join ' ' -- \ + "--height $FZF_TMUX_HEIGHT --min-height=20+ --bind=ctrl-z:ignore" $argv[1] \ + (test -r "$FZF_DEFAULT_OPTS_FILE"; and string join -- ' ' <$FZF_DEFAULT_OPTS_FILE) \ + $FZF_DEFAULT_OPTS $argv[2..-1] end function __fzfcmd - test -n "$FZF_TMUX"; or set FZF_TMUX 0 - test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40% + test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40% if test -n "$FZF_TMUX_OPTS" echo "fzf-tmux $FZF_TMUX_OPTS -- " else if test "$FZF_TMUX" = "1" @@ -119,56 +41,42 @@ end end - bind \cr fzf-history-widget - if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND" - bind \ct fzf-file-widget - end - if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND" - bind \ec fzf-cd-widget - end - - bind -M insert \cr fzf-history-widget - if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND" - bind -M insert \ct fzf-file-widget - end - if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND" - bind -M insert \ec fzf-cd-widget - end - function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix' - set -l commandline (commandline -t) + set -l dir '.' + set -l query + set -l commandline (commandline -t | string unescape -n) - # strip -option= from token if present + # Strip -option= from token if present set -l prefix (string match -r -- '^-[^\s=]+=' $commandline) set commandline (string replace -- "$prefix" '' $commandline) # Enable home directory expansion of leading ~/ set commandline (string replace -r -- '^~/' '\$HOME/' $commandline) - # escape special characters, except for the $ sign of valid variable names, - # so that after eval, the original string is returned, but with the - # variable names replaced by their values. + # Escape special characters, except for the $ sign of valid variable names, + # so that the original string with expanded variables is returned after eval. set commandline (string escape -n -- $commandline) - set commandline (string replace -r -a -- '\x5c\$(?=[\w])' '\$' $commandline) + set commandline (string replace -r -a -- '\\\\\$(?=[\w])' '\$' $commandline) # eval is used to do shell expansion on paths eval set commandline $commandline - # Combine multiple consecutive slashes into one, and unescape. - set commandline (string replace -r -a -- '/+' '/' $commandline | string unescape -n) + # Combine multiple consecutive slashes into one. + set commandline (string replace -r -a -- '/+' '/' $commandline) - if test -z "$commandline" - # Default to current directory with no --query - set dir '.' - set fzf_query '' - else - set dir (__fzf_get_dir $commandline) + if test -n "$commandline" + # Strip trailing slash, unless $dir is root dir (/) + set dir (string replace -r -- '(?<!^)/$' '' $commandline) + + # Set $dir to the longest existing filepath + while not test -d "$dir" + # If path is absolute, this can keep going until ends up at / + # If path is relative, this can keep going until entire input is consumed, dirname returns "." + set dir (dirname -- $dir) + end - # BUG: on combined expressions, if a left argument is a single `!`, the - # builtin test command of fish will treat it as the ! operator. To - # overcome this, have the variable parts on the right. - if test "." = "$dir" -a "./" != (string sub -l 2 -- $commandline) - # if $dir is "." but commandline is not a relative path, this means no file path found + if test "$dir" = '.'; and test (string sub -l 2 -- $commandline) != './' + # If $dir is "." but commandline is not a relative path, this means no file path found set fzf_query $commandline else # Also remove trailing slash after dir, to "split" input properly @@ -176,25 +84,101 @@ end end - echo -- $dir - string escape -- $fzf_query - echo -- $prefix + string escape -n -- "$dir" "$fzf_query" "$prefix" + end + + # Store current token in $dir as root for the 'find' command + function fzf-file-widget -d "List files and folders" + set -l commandline (__fzf_parse_commandline) + set -lx dir $commandline[1] + set -l fzf_query $commandline[2] + set -l prefix $commandline[3] + + set -lx FZF_DEFAULT_OPTS (__fzf_defaults \ + "--reverse --walker=file,dir,follow,hidden --scheme=path --walker-root=$dir" \ + "$FZF_CTRL_T_OPTS --multi") + + set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND" + set -lx FZF_DEFAULT_OPTS_FILE + + if set -l result (eval (__fzfcmd) --query=$fzf_query) + # Remove last token from commandline. + commandline -t '' + for i in $result + commandline -it -- $prefix(string escape -- $i)' ' + end + end + + commandline -f repaint end - function __fzf_get_dir -d 'Find the longest existing filepath from input string' - set dir $argv + function fzf-history-widget -d "Show command history" + set -l fzf_query (commandline | string escape) + + set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \ + '--nth=2..,.. --scheme=history --multi --wrap-sign="\tâ³ "' \ + "--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \ + '--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c) + + set -lx FZF_DEFAULT_OPTS_FILE + set -lx FZF_DEFAULT_COMMAND + + if type -q perl + set -a FZF_DEFAULT_OPTS '--tac' + set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\'' + else + set FZF_DEFAULT_COMMAND \ + 'set -l h (builtin history -z --reverse | string split0);' \ + 'for i in (seq (count $h) -1 1);' \ + 'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \ + 'end' + end + + # Merge history from other sessions before searching + test -z "$fish_private_mode"; and builtin history merge + + if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0) + commandline -- (string replace -a -- \n\t \n $result[1]) + test (count $result) -gt 1; and for i in $result[2..-1] + commandline -i -- (string replace -a -- \n\t \n \n$i) + end + end + + commandline -f repaint + end - # Strip trailing slash, unless $dir is root dir (/) - set dir (string replace -r -- '(?<!^)/$' '' $dir) + function fzf-cd-widget -d "Change directory" + set -l commandline (__fzf_parse_commandline) + set -lx dir $commandline[1] + set -l fzf_query $commandline[2] + set -l prefix $commandline[3] - # Iteratively check if dir exists and strip tail end of path - while test ! -d "$dir" - # If path is absolute, this can keep going until ends up at / - # If path is relative, this can keep going until entire input is consumed, dirname returns "." - set dir (dirname -- "$dir") + set -lx FZF_DEFAULT_OPTS (__fzf_defaults \ + "--reverse --walker=dir,follow,hidden --scheme=path --walker-root=$dir" \ + "$FZF_ALT_C_OPTS --no-multi") + + set -lx FZF_DEFAULT_OPTS_FILE + set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND" + + if set -l result (eval (__fzfcmd) --query=$fzf_query) + cd -- $result + commandline -rt -- $prefix end - string escape -n -- $dir + commandline -f repaint + end + + bind \cr fzf-history-widget + bind -M insert \cr fzf-history-widget + + if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND" + bind \ct fzf-file-widget + bind -M insert \ct fzf-file-widget + end + + if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND" + bind \ec fzf-cd-widget + bind -M insert \ec fzf-cd-widget end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/shell/key-bindings.zsh new/fzf-0.60.3/shell/key-bindings.zsh --- old/fzf-0.60.0/shell/key-bindings.zsh 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/shell/key-bindings.zsh 2025-03-03 09:10:49.000000000 +0100 @@ -41,9 +41,9 @@ __fzf_defaults() { # $1: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS # $2: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS - echo "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1" + echo -E "--height ${FZF_TMUX_HEIGHT:-40%} --min-height 20+ --bind=ctrl-z:ignore $1" command cat "${FZF_DEFAULT_OPTS_FILE-}" 2> /dev/null - echo "${FZF_DEFAULT_OPTS-} $2" + echo -E "${FZF_DEFAULT_OPTS-} $2" } # CTRL-T - Paste the selected file path(s) into the command line diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/algo/algo.go new/fzf-0.60.3/src/algo/algo.go --- old/fzf-0.60.0/src/algo/algo.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/algo/algo.go 2025-03-03 09:10:49.000000000 +0100 @@ -767,6 +767,9 @@ char = unicode.To(unicode.LowerCase, char) } } + if normalize { + char = normalizeRune(char) + } pidx_ := indexAt(pidx, lenPattern, forward) pchar := pattern[pidx_] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/algo/algo_test.go new/fzf-0.60.3/src/algo/algo_test.go --- old/fzf-0.60.0/src/algo/algo_test.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/algo/algo_test.go 2025-03-03 09:10:49.000000000 +0100 @@ -200,3 +200,12 @@ bytes[math.MaxUint16] = 'z' assertMatch(t, FuzzyMatchV2, true, true, string(bytes), "zx", math.MaxUint16, math.MaxUint16+2, scoreMatch*2+bonusConsecutive) } + +func TestLongStringWithNormalize(t *testing.T) { + bytes := make([]byte, 30000) + for i := range bytes { + bytes[i] = 'x' + } + unicodeString := string(bytes) + " MinÃmal example" + assertMatch2(t, FuzzyMatchV1, false, true, false, unicodeString, "minim", 30001, 30006, 140) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/constants.go new/fzf-0.60.3/src/constants.go --- old/fzf-0.60.0/src/constants.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/constants.go 2025-03-03 09:10:49.000000000 +0100 @@ -26,7 +26,7 @@ previewCancelWait = 500 * time.Millisecond previewChunkDelay = 100 * time.Millisecond previewDelayed = 500 * time.Millisecond - maxPatternLength = 300 + maxPatternLength = 1000 maxMulti = math.MaxInt32 // Matcher diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/core.go new/fzf-0.60.3/src/core.go --- old/fzf-0.60.0/src/core.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/core.go 2025-03-03 09:10:49.000000000 +0100 @@ -128,13 +128,14 @@ } } } - transformed := nthTransformer(tokens) + transformed := nthTransformer(tokens, itemIndex) if len(header) < opts.HeaderLines { header = append(header, transformed) eventBox.Set(EvtHeader, header) return false } item.text, item.colors = ansiProcessor(stringBytes(transformed)) + item.text.TrimTrailingWhitespaces() item.text.Index = itemIndex item.origText = &data itemIndex++ @@ -476,8 +477,17 @@ if len(opts.Expect) > 0 { opts.Printer("") } + transformer := func(item *Item) string { + return item.AsString(opts.Ansi) + } + if opts.AcceptNth != nil { + fn := opts.AcceptNth(opts.Delimiter) + transformer = func(item *Item) string { + return item.acceptNth(opts.Ansi, opts.Delimiter, fn) + } + } for i := 0; i < count; i++ { - opts.Printer(val.Get(i).item.AsString(opts.Ansi)) + opts.Printer(transformer(val.Get(i).item)) } if count == 0 { exitCode = ExitNoMatch diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/item.go new/fzf-0.60.3/src/item.go --- old/fzf-0.60.0/src/item.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/item.go 2025-03-03 09:10:49.000000000 +0100 @@ -51,3 +51,9 @@ } return item.text.ToString() } + +func (item *Item) acceptNth(stripAnsi bool, delimiter Delimiter, transformer func([]Token, int32) string) string { + tokens := Tokenize(item.AsString(stripAnsi), delimiter) + transformed := transformer(tokens, item.Index()) + return StripLastDelimiter(transformed, delimiter) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/options.go new/fzf-0.60.3/src/options.go --- old/fzf-0.60.0/src/options.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/options.go 2025-03-03 09:10:49.000000000 +0100 @@ -544,8 +544,8 @@ Case Case Normalize bool Nth []Range - WithNth func(Delimiter) func([]Token) string - AcceptNth func(Delimiter) func([]Token) string + WithNth func(Delimiter) func([]Token, int32) string + AcceptNth func(Delimiter) func([]Token, int32) string Delimiter Delimiter Sort int Track trackOption @@ -769,30 +769,31 @@ return ranges, nil } -func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) { +func nthTransformer(str string) (func(Delimiter) func([]Token, int32) string, error) { // ^[0-9,-.]+$" if match, _ := regexp.MatchString("^[0-9,-.]+$", str); match { nth, err := splitNth(str) if err != nil { return nil, err } - return func(Delimiter) func([]Token) string { - return func(tokens []Token) string { + return func(Delimiter) func([]Token, int32) string { + return func(tokens []Token, index int32) string { return JoinTokens(Transform(tokens, nth)) } }, nil } // {...} {...} ... - placeholder := regexp.MustCompile("{[0-9,-.]+}") + placeholder := regexp.MustCompile("{[0-9,-.]+}|{n}") indexes := placeholder.FindAllStringIndex(str, -1) if indexes == nil { return nil, errors.New("template should include at least 1 placeholder: " + str) } type NthParts struct { - str string - nth []Range + str string + index bool + nth []Range } parts := make([]NthParts, len(indexes)) @@ -801,7 +802,10 @@ if idx < index[0] { parts = append(parts, NthParts{str: str[idx:index[0]]}) } - if nth, err := splitNth(str[index[0]+1 : index[1]-1]); err == nil { + expr := str[index[0]+1 : index[1]-1] + if expr == "n" { + parts = append(parts, NthParts{index: true}) + } else if nth, err := splitNth(expr); err == nil { parts = append(parts, NthParts{nth: nth}) } idx = index[1] @@ -810,12 +814,16 @@ parts = append(parts, NthParts{str: str[idx:]}) } - return func(delimiter Delimiter) func([]Token) string { - return func(tokens []Token) string { + return func(delimiter Delimiter) func([]Token, int32) string { + return func(tokens []Token, index int32) string { str := "" for _, holder := range parts { if holder.nth != nil { str += StripLastDelimiter(JoinTokens(Transform(tokens, holder.nth)), delimiter) + } else if holder.index { + if index >= 0 { + str += strconv.Itoa(int(index)) + } } else { str += holder.str } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/proxy.go new/fzf-0.60.3/src/proxy.go --- old/fzf-0.60.0/src/proxy.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/proxy.go 2025-03-03 09:10:49.000000000 +0100 @@ -59,12 +59,12 @@ }) }() - var command string + var command, input string commandPrefix += ` --no-force-tty-in --proxy-script "$0"` if opts.Input == nil && (opts.ForceTtyIn || util.IsTty(os.Stdin)) { command = fmt.Sprintf(`%s > %q`, commandPrefix, output) } else { - input, err := fifo("proxy-input") + input, err = fifo("proxy-input") if err != nil { return ExitError, err } @@ -148,6 +148,9 @@ if err != nil { return ExitError, err } + os.Remove(temp) + os.Remove(input) + os.Remove(output) executor.Become(ttyin, env, command) } return code, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/reader.go new/fzf-0.60.3/src/reader.go --- old/fzf-0.60.0/src/reader.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/reader.go 2025-03-03 09:10:49.000000000 +0100 @@ -277,6 +277,9 @@ ignoresFull := []string{} ignoresSuffix := []string{} sep := string(os.PathSeparator) + if _, ok := os.LookupEnv("MSYSTEM"); ok { + sep = "/" + } for _, ignore := range ignores { if strings.ContainsRune(ignore, os.PathSeparator) { if strings.HasPrefix(ignore, sep) { @@ -320,6 +323,7 @@ return filepath.SkipDir } } + path += sep } if ((opts.file && !isDir) || (opts.dir && isDir)) && r.pusher(stringBytes(path)) { atomic.StoreInt32(&r.event, int32(EvtReadNew)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/terminal.go new/fzf-0.60.3/src/terminal.go --- old/fzf-0.60.0/src/terminal.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/terminal.go 2025-03-03 09:10:49.000000000 +0100 @@ -305,7 +305,7 @@ nthAttr tui.Attr nth []Range nthCurrent []Range - acceptNth func([]Token) string + acceptNth func([]Token, int32) string tabstop int margin [4]sizeSpec padding [4]sizeSpec @@ -638,6 +638,7 @@ scrollOffset int list []*Item env []string + query string } type previewResult struct { @@ -1346,7 +1347,7 @@ } if cached, prs := t.numLinesCache[item.Index()]; prs { // Can we use this cache? Let's be conservative. - if cached.atMost >= atMost { + if cached.atMost <= atMost { return cached.numLines, false } } @@ -1574,9 +1575,7 @@ } if t.acceptNth != nil { transform = func(item *Item) string { - tokens := Tokenize(item.AsString(t.ansi), t.delimiter) - transformed := t.acceptNth(tokens) - return StripLastDelimiter(transformed, t.delimiter) + return item.acceptNth(t.ansi, t.delimiter, t.acceptNth) } } found := len(t.selected) > 0 @@ -2287,7 +2286,11 @@ } func (t *Terminal) truncateQuery() { - t.input, _ = t.trimRight(t.input, maxPatternLength) + // We're limiting the length of the query not to make fzf unresponsive when + // the user accidentally pastes a huge chunk of text. Therefore, we're not + // interested in the exact display width of the query. We just limit the + // number of runes. + t.input = t.input[:util.Min(len(t.input), maxPatternLength)] t.cx = util.Constrain(t.cx, 0, len(t.input)) } @@ -2754,11 +2757,15 @@ item := result.item _, selected := t.selected[item.Index()] label := "" + extraWidth := 0 if t.jumping != jumpDisabled { if index < len(t.jumpLabels) { // Striped current = index%2 == 0 - label = t.jumpLabels[index:index+1] + strings.Repeat(" ", t.pointerLen-1) + label = t.jumpLabels[index:index+1] + strings.Repeat(" ", util.Max(0, t.pointerLen-1)) + if t.pointerLen == 0 { + extraWidth = 1 + } } } else if current { label = t.pointer @@ -2787,6 +2794,7 @@ maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1) postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) { + width += extraWidth if (current || selected) && t.highlightLine { color := tui.ColSelected if current { @@ -3099,8 +3107,15 @@ maxWidth := t.window.Width() - (indentSize + 1) wasWrapped := false if wrapped { - maxWidth -= t.wrapSignWidth - t.window.CPrint(colBase.WithAttr(tui.Dim), t.wrapSign) + wrapSign := t.wrapSign + if maxWidth < t.wrapSignWidth { + runes, _ := util.Truncate(wrapSign, maxWidth) + wrapSign = string(runes) + maxWidth = 0 + } else { + maxWidth -= t.wrapSignWidth + } + t.window.CPrint(colBase.WithAttr(tui.Dim), wrapSign) wrapped = false wasWrapped = true } @@ -3165,7 +3180,9 @@ displayWidth = t.displayWidthWithLimit(line, 0, displayWidth) } - t.printColoredString(t.window, line, offsets, colBase) + if maxWidth > 0 { + t.printColoredString(t.window, line, offsets, colBase) + } if postTask != nil { postTask(actualLineNum, displayWidth, wasWrapped, forceRedraw) } else { @@ -3374,8 +3391,10 @@ wiped := false image := false wireframe := false + var index int + var line string Loop: - for _, line := range lines { + for index, line = range lines { var lbg tui.Color = -1 if ansi != nil { ansi.lbg = -1 @@ -3518,6 +3537,7 @@ } lineNo++ } + t.previewer.scrollable = t.previewer.scrollable || index < len(lines)-1 t.previewed.image = image t.previewed.wireframe = wireframe } @@ -4376,6 +4396,7 @@ var items []*Item var commandTemplate string var env []string + var query string initialOffset := 0 t.previewBox.Wait(func(events *util.Events) { for req, value := range *events { @@ -4389,6 +4410,7 @@ initialOffset = request.scrollOffset items = request.list env = request.env + query = request.query } } events.Clear() @@ -4402,8 +4424,7 @@ version++ // We don't display preview window if no match if items[0] != nil { - _, query := t.Input() - command, tempFiles := t.replacePlaceholder(commandTemplate, false, string(query), items) + command, tempFiles := t.replacePlaceholder(commandTemplate, false, query, items) cmd := t.executor.ExecCommand(command, true) cmd.Env = env @@ -4531,7 +4552,7 @@ if len(command) > 0 && t.canPreview() { _, list := t.buildPlusList(command, false) t.cancelPreview() - t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview()}) + t.previewBox.Set(reqPreviewEnqueue, previewRequest{command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)}) } } @@ -4963,7 +4984,7 @@ if valid { t.cancelPreview() t.previewBox.Set(reqPreviewEnqueue, - previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview()}) + previewRequest{t.previewOpts.command, t.evaluateScrollOffset(), list, t.environForPreview(), string(t.input)}) } } else { // Discard the preview content so that it won't accidentally appear diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/tokenizer.go new/fzf-0.60.3/src/tokenizer.go --- old/fzf-0.60.0/src/tokenizer.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/tokenizer.go 2025-03-03 09:10:49.000000000 +0100 @@ -225,7 +225,9 @@ locs := delimiter.regex.FindAllStringIndex(str, -1) if len(locs) > 0 { lastLoc := locs[len(locs)-1] - str = str[:lastLoc[0]] + if lastLoc[1] == len(str) { + str = str[:lastLoc[0]] + } } } return strings.TrimRightFunc(str, unicode.IsSpace) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/tui/light.go new/fzf-0.60.3/src/tui/light.go --- old/fzf-0.60.0/src/tui/light.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/tui/light.go 2025-03-03 09:10:49.000000000 +0100 @@ -8,6 +8,7 @@ "regexp" "strconv" "strings" + "sync" "time" "unicode/utf8" @@ -29,7 +30,7 @@ const consoleDevice string = "/dev/tty" -var offsetRegexp = regexp.MustCompile("(.*)\x1b\\[([0-9]+);([0-9]+)R") +var offsetRegexp = regexp.MustCompile("(.*?)\x00?\x1b\\[([0-9]+);([0-9]+)R") var offsetRegexpBegin = regexp.MustCompile("^\x1b\\[[0-9]+;[0-9]+R") func (r *LightRenderer) Bell() { @@ -95,7 +96,6 @@ // Light renderer type LightRenderer struct { - closed *util.AtomicBool theme *ColorTheme mouse bool forceBlack bool @@ -120,6 +120,7 @@ showCursor bool // Windows only + mutex sync.Mutex ttyinChannel chan byte inHandle uintptr outHandle uintptr @@ -151,7 +152,6 @@ out = os.Stderr } r := LightRenderer{ - closed: util.NewAtomicBool(false), theme: theme, forceBlack: forceBlack, mouse: mouse, @@ -775,9 +775,8 @@ } r.disableMouse() r.flush() - r.closePlatform() r.restoreTerminal() - r.closed.Set(true) + r.closePlatform() } func (r *LightRenderer) Top() int { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/tui/light_windows.go new/fzf-0.60.3/src/tui/light_windows.go --- old/fzf-0.60.0/src/tui/light_windows.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/tui/light_windows.go 2025-03-03 09:10:49.000000000 +0100 @@ -18,6 +18,7 @@ var ( consoleFlagsInput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_INPUT | windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_EXTENDED_FLAGS) consoleFlagsOutput = uint32(windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | windows.ENABLE_PROCESSED_OUTPUT | windows.DISABLE_NEWLINE_AUTO_RETURN) + counter = uint64(0) ) // IsLightRendererSupported checks to see if the Light renderer is supported @@ -61,27 +62,11 @@ } r.inHandle = uintptr(inHandle) - r.setupTerminal() - // channel for non-blocking reads. Buffer to make sure // we get the ESC sets: r.ttyinChannel = make(chan byte, 1024) - // the following allows for non-blocking IO. - // syscall.SetNonblock() is a NOOP under Windows. - go func() { - fd := int(r.inHandle) - b := make([]byte, 1) - for !r.closed.Get() { - // HACK: if run from PSReadline, something resets ConsoleMode to remove ENABLE_VIRTUAL_TERMINAL_INPUT. - _ = windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput) - - _, err := util.Read(fd, b) - if err == nil { - r.ttyinChannel <- b[0] - } - } - }() + r.setupTerminal() return nil } @@ -100,18 +85,42 @@ return os.Stderr, nil } -func (r *LightRenderer) setupTerminal() error { - if err := windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput); err != nil { - return err - } - return windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput) +func (r *LightRenderer) setupTerminal() { + windows.SetConsoleMode(windows.Handle(r.outHandle), consoleFlagsOutput) + windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput) + + // The following allows for non-blocking IO. + // syscall.SetNonblock() is a NOOP under Windows. + current := counter + go func() { + fd := int(r.inHandle) + b := make([]byte, 1) + for { + if _, err := util.Read(fd, b); err == nil { + r.mutex.Lock() + // This condition prevents the goroutine from running after the renderer + // has been closed or paused. + if current != counter { + r.mutex.Unlock() + break + } + r.ttyinChannel <- b[0] + // HACK: if run from PSReadline, something resets ConsoleMode to remove ENABLE_VIRTUAL_TERMINAL_INPUT. + windows.SetConsoleMode(windows.Handle(r.inHandle), consoleFlagsInput) + r.mutex.Unlock() + } + } + }() } -func (r *LightRenderer) restoreTerminal() error { - if err := windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput); err != nil { - return err - } - return windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput) +func (r *LightRenderer) restoreTerminal() { + r.mutex.Lock() + counter++ + // We're setting ENABLE_VIRTUAL_TERMINAL_INPUT to allow escape sequences to be read during 'execute'. + // e.g. fzf --bind 'enter:execute:less {}' + windows.SetConsoleMode(windows.Handle(r.inHandle), r.origStateInput|windows.ENABLE_VIRTUAL_TERMINAL_INPUT) + windows.SetConsoleMode(windows.Handle(r.outHandle), r.origStateOutput) + r.mutex.Unlock() } func (r *LightRenderer) Size() TermSize { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/src/util/chars.go new/fzf-0.60.3/src/util/chars.go --- old/fzf-0.60.0/src/util/chars.go 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/src/util/chars.go 2025-03-03 09:10:49.000000000 +0100 @@ -184,6 +184,11 @@ return whitespaces } +func (chars *Chars) TrimTrailingWhitespaces() { + whitespaces := chars.TrailingWhitespaces() + chars.slice = chars.slice[0 : len(chars.slice)-whitespaces] +} + func (chars *Chars) TrimSuffix(runes []rune) { lastIdx := len(chars.slice) firstIdx := lastIdx - len(runes) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/test/test_core.rb new/fzf-0.60.3/test/test_core.rb --- old/fzf-0.60.0/test/test_core.rb 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/test/test_core.rb 2025-03-03 09:10:49.000000000 +0100 @@ -238,6 +238,11 @@ assert_equal %w[5555 55], fzf_output_lines end + def test_select_1_accept_nth + tmux.send_keys "seq 1 100 | #{fzf(:with_nth, '..,..', :print_query, :q, 5555, :'1', :accept_nth, '"{1} // {1}"')}", :Enter + assert_equal ['5555', '55 // 55'], fzf_output_lines + end + def test_exit_0 tmux.send_keys "seq 1 100 | #{fzf(:with_nth, '..,..', :print_query, :q, 555_555, :'0')}", :Enter assert_equal %w[555555], fzf_output_lines @@ -827,6 +832,24 @@ tmux.until { |lines| assert(lines.any? { it.include?('jump cancelled at 3') }) } end + def test_jump_no_pointer + tmux.send_keys "seq 100 | #{FZF} --pointer= --jump-labels 12345 --bind ctrl-j:jump", :Enter + tmux.until { |lines| assert_equal 100, lines.match_count } + tmux.send_keys 'C-j' + tmux.until { |lines| assert_equal '5 5', lines[-7] } + tmux.send_keys 'C-c' + tmux.until { |lines| assert_equal ' 5', lines[-7] } + end + + def test_jump_no_pointer_no_marker + tmux.send_keys "seq 100 | #{FZF} --pointer= --marker= --jump-labels 12345 --bind ctrl-j:jump", :Enter + tmux.until { |lines| assert_equal 100, lines.match_count } + tmux.send_keys 'C-j' + tmux.until { |lines| assert_equal '55', lines[-7] } + tmux.send_keys 'C-c' + tmux.until { |lines| assert_equal '5', lines[-7] } + end + def test_pointer tmux.send_keys "seq 10 | #{fzf("--pointer '>>'")}", :Enter # Assert that specified pointer is displayed @@ -1773,12 +1796,21 @@ end end + def test_accept_nth_regex_delimiter_strip_last + tmux.send_keys %((echo "foo:,bar:,baz"; echo "foo:,bar:,baz:,qux:,") | #{FZF} --multi --delimiter='[:,]+' --accept-nth 2.. --sync --bind 'load:select-all+accept' > #{tempname}), :Enter + wait do + assert_path_exists tempname + # Last delimiter and the whitespaces are removed + assert_equal ['bar:,baz', 'bar:,baz:,qux'], File.readlines(tempname, chomp: true) + end + end + def test_accept_nth_template - tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter + tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '[{n}] 1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter wait do assert_path_exists tempname # Last delimiter and the whitespaces are removed - assert_equal ['1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true) + assert_equal ['[0] 1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true) end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/test/test_preview.rb new/fzf-0.60.3/test/test_preview.rb --- old/fzf-0.60.0/test/test_preview.rb 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/test/test_preview.rb 2025-03-03 09:10:49.000000000 +0100 @@ -544,4 +544,18 @@ tmux.send_keys :Up tmux.until { |lines| assert_includes lines, '> 2' } end + + def test_preview_query_should_not_be_affected_by_search + tmux.send_keys "seq 1 | #{FZF} --bind 'change:transform-search(echo {q:1})' --preview 'echo [{q}/{}]'", :Enter + tmux.until { |lines| assert_equal 1, lines.match_count } + tmux.send_keys '1' + tmux.until { |lines| assert lines.any_include?('[1/1]') } + tmux.send_keys :Space + tmux.until { |lines| assert lines.any_include?('[1 /1]') } + tmux.send_keys '2' + tmux.until do |lines| + assert lines.any_include?('[1 2/1]') + assert_equal 1, lines.match_count + end + end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.60.0/test/test_shell_integration.rb new/fzf-0.60.3/test/test_shell_integration.rb --- old/fzf-0.60.0/test/test_shell_integration.rb 2025-02-12 16:54:21.000000000 +0100 +++ new/fzf-0.60.3/test/test_shell_integration.rb 2025-03-03 09:10:49.000000000 +0100 @@ -73,7 +73,7 @@ tmux.prepare tmux.send_keys :Escape, :c lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 } - expected = lines.reverse.find { |l| l.start_with?('> ') }[2..] + expected = lines.reverse.find { |l| l.start_with?('> ') }[2..].chomp('/') tmux.send_keys :Enter tmux.prepare tmux.send_keys :pwd, :Enter @@ -241,7 +241,7 @@ tmux.until do |lines| assert_equal 1, lines.match_count assert_includes lines, '> 55' - assert_includes lines, '> /tmp/fzf-test/d55' + assert_includes lines, '> /tmp/fzf-test/d55/' end tmux.send_keys :Enter tmux.until(true) { |lines| assert_equal 'cd /tmp/fzf-test/d55/', lines[-1] } @@ -482,4 +482,36 @@ tmux.send_keys "set -g #{name} '#{val}'", :Enter tmux.prepare end + + def test_ctrl_r_multi + tmux.send_keys ':', :Enter + tmux.send_keys 'echo "foo', :Enter, 'bar"', :Enter + tmux.prepare + tmux.send_keys 'echo "bar', :Enter, 'foo"', :Enter + tmux.prepare + tmux.send_keys 'C-l', 'C-r' + block = <<~BLOCK + echo "foo + bar" + echo "bar + foo" + BLOCK + tmux.until do |lines| + block.lines.each_with_index do |line, idx| + assert_includes lines[-6 + idx], line.chomp + end + end + tmux.send_keys :BTab, :BTab + tmux.until { |lines| assert_includes lines[-2], '(2)' } + tmux.send_keys :Enter + block = <<~BLOCK + echo "bar + foo" + echo "foo + bar" + BLOCK + tmux.until do |lines| + assert_equal block.lines.map(&:chomp), lines + end + end end