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-07-07 14:46:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.1903 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Mon Jul 7 14:46:12 2025 rev:71 rq:1290911 version:0.64.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2025-06-30 13:06:10.061113404 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.1903/fzf.changes 2025-07-07 14:46:14.599633731 +0200 @@ -1,0 +2,15 @@ +Sun Jul 6 18:43:48 UTC 2025 - Avindra Goolcharan <avin...@opensuse.org> + +- Update to version 0.64.0: + * Added `multi` event that is triggered when the multi- + selection has changed. + * Halfwidth and fullwidth alphanumeric and punctuation + characters are now internally normalized to their ASCII + equivalents to allow matching with ASCII queries. + * Renamed `clear-selection` action to `clear-multi` for consistency. + * Fixed a bug that could cause fzf to abort due to incorrect + update ordering. + * Fixed a bug where some multi-selections were lost when using + `exclude` or `change-nth`. + +------------------------------------------------------------------- Old: ---- fzf-0.63.0.tar.gz New: ---- fzf-0.64.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.038DoF/_old 2025-07-07 14:46:15.495671140 +0200 +++ /var/tmp/diff_new_pack.038DoF/_new 2025-07-07 14:46:15.495671140 +0200 @@ -19,7 +19,7 @@ %global _lto_cflags %{nil} Name: fzf -Version: 0.63.0 +Version: 0.64.0 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.63.0.tar.gz -> fzf-0.64.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/.tool-versions new/fzf-0.64.0/.tool-versions --- old/fzf-0.63.0/.tool-versions 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/.tool-versions 2025-07-06 15:11:36.000000000 +0200 @@ -1,2 +1,2 @@ -golang 1.20.13 +golang 1.20.14 ruby 3.4.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/CHANGELOG.md new/fzf-0.64.0/CHANGELOG.md --- old/fzf-0.63.0/CHANGELOG.md 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/CHANGELOG.md 2025-07-06 15:11:36.000000000 +0200 @@ -1,6 +1,24 @@ CHANGELOG ========= +0.64.0 +------ +- Added `multi` event that is triggered when the multi-selection has changed. + ```sh + fzf --multi \ + --bind 'ctrl-a:select-all,ctrl-d:deselect-all' \ + --bind 'multi:transform-footer:(( FZF_SELECT_COUNT )) && echo "Selected $FZF_SELECT_COUNT item(s)"' + ``` +- [Halfwidth and fullwidth alphanumeric and punctuation characters](https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block)) are now internally normalized to their ASCII equivalents to allow matching with ASCII queries. + ```sh + echo ABC| fzf -q abc + ``` +- Renamed `clear-selection` action to `clear-multi` for consistency. + - `clear-selection` remains supported as an alias for backward compatibility. +- Bug fixes + - Fixed a bug that could cause fzf to abort due to incorrect update ordering. + - Fixed a bug where some multi-selections were lost when using `exclude` or `change-nth`. + 0.63.0 ------ _Release highlights: https://junegunn.github.io/fzf/releases/0.63.0/_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/LICENSE new/fzf-0.64.0/LICENSE --- old/fzf-0.63.0/LICENSE 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/LICENSE 2025-07-06 15:11:36.000000000 +0200 @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/README-VIM.md new/fzf-0.64.0/README-VIM.md --- old/fzf-0.63.0/README-VIM.md 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/README-VIM.md 2025-07-06 15:11:36.000000000 +0200 @@ -493,4 +493,4 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/README.md new/fzf-0.64.0/README.md --- old/fzf-0.63.0/README.md 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/README.md 2025-07-06 15:11:36.000000000 +0200 @@ -981,7 +981,7 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi Sponsors :heart: ---------------- @@ -990,7 +990,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/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/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/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/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 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:&# x2F;/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/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/lajarre"><img src="https://github.com/lajarre.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/vidhatre"><img src="https://github.com/vidhatre.png" width="60px" alt="User avatar: Vidhatre Gathey" /></a><a href="https://github.com/NightsPaladin"><img src="https://github.com/NightsPaladin.png" width="60px" alt="User avatar: Chris G." /></a><a href="https://github.com/lzell"><img src="https://github.com/lzell.png" width="60px" alt="User avatar: Lou Zell" /></a><a href="https://github.com/yolabingo"><img src="https://github.com/yolabingo.png" width="60px" alt="User avatar: Todd Jacobsen" /></a><a href="https://github.com/3ximus"><img src="https://github.com/3ximus.png" width="60px" alt="User avatar: Fabio" /></a><a href=" https://github.com/bladeacer"><img src="https://github.com/bladeacer.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/tylerdak"><img src="https://github.com/tylerdak.png" width="60px" alt="User avatar: Tyler Dakin" /></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/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="User avatar: Pierre Dubouilh" /></a><a href="https://github.com/trantor"><img src="https:&# x2F;/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/benelan"><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/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="User avatar: Cristian Dominguez" /></a><a href="https://gith ub.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/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/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/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 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" w idth="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/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/lajarre"><img src="https://github.com/lajarre.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/vidhatre"><img src="https://github.com/vidhatre.png" width="60px" alt="User avatar: Vidhatre Gathey" /></a><a href="https://github.com/NightsPaladin"><img src="https://github.com/NightsPaladin.png" width="60px" alt="User avatar: Chris G." /></a><a href="https://github.com/lzell"><img src="https://github.com/lzell.png" width="60px" alt="User avatar: Lou Zell" /></a><a href="https://github.com/3ximus"><img src="https://github.com/3ximus.png" width="60px" alt="User avatar: Fabio" /></a><a href="https://github.com/bladeacer"><img src="https://github.com/bladeacer.png" width="60px" alt="User avatar: " /></a><a href="https://github.com/tylerdak"><img src="https://github.com/tylerdak.png" width="60px" alt="User avatar: Tyler Dakin" /></a><a href="https://githu b.com/justinlubin"><img src="https://github.com/justinlubin.png" width="60px" alt="User avatar: Justin Lubin" /></a><a href="https://github.com/gpoma"><img src="https://github.com/gpoma.png" width="60px" alt="User avatar: Gabriel" /></a><!-- sponsors --> --- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/doc/fzf.txt new/fzf-0.64.0/doc/fzf.txt --- old/fzf-0.63.0/doc/fzf.txt 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/doc/fzf.txt 2025-07-06 15:11:36.000000000 +0200 @@ -503,7 +503,7 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi ============================================================================== vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/install new/fzf-0.64.0/install --- old/fzf-0.63.0/install 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/install 2025-07-06 15:11:36.000000000 +0200 @@ -2,7 +2,7 @@ set -u -version=0.63.0 +version=0.64.0 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/install.ps1 new/fzf-0.64.0/install.ps1 --- old/fzf-0.63.0/install.ps1 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/install.ps1 2025-07-06 15:11:36.000000000 +0200 @@ -1,4 +1,4 @@ -$version="0.63.0" +$version="0.64.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/main.go new/fzf-0.64.0/main.go --- old/fzf-0.63.0/main.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/main.go 2025-07-06 15:11:36.000000000 +0200 @@ -11,7 +11,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version = "0.63" +var version = "0.64" var revision = "devel" //go:embed shell/key-bindings.bash diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/man/man1/fzf-tmux.1 new/fzf-0.64.0/man/man1/fzf-tmux.1 --- old/fzf-0.63.0/man/man1/fzf-tmux.1 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/man/man1/fzf-tmux.1 2025-07-06 15:11:36.000000000 +0200 @@ -1,7 +1,7 @@ .ig The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -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 "Jun 2025" "fzf 0.63.0" "fzf\-tmux - open fzf in tmux split pane" +.TH fzf\-tmux 1 "Jul 2025" "fzf 0.64.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.63.0/man/man1/fzf.1 new/fzf-0.64.0/man/man1/fzf.1 --- old/fzf-0.63.0/man/man1/fzf.1 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/man/man1/fzf.1 2025-07-06 15:11:36.000000000 +0200 @@ -1,7 +1,7 @@ .ig The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Jun 2025" "fzf 0.63.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Jul 2025" "fzf 0.64.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -1609,6 +1609,10 @@ # Beware not to introduce an infinite loop seq 10 | fzf \-\-bind 'focus:up' \-\-cycle\fR .RE +\fImulti\fR +.RS +Triggered when the multi\-selection has changed. +.RE \fIone\fR .RS @@ -1711,13 +1715,13 @@ \fBchange\-prompt(...)\fR (change prompt to the given string) \fBchange\-query(...)\fR (change query string to the given string) \fBclear\-screen\fR \fIctrl\-l\fR - \fBclear\-selection\fR (clear multi\-selection) + \fBclear\-multi\fR (clear multi\-selection) \fBclose\fR (close preview window if open, abort fzf otherwise) \fBclear\-query\fR (clear query string) \fBdelete\-char\fR \fIdel\fR \fBdelete\-char/eof\fR \fIctrl\-d\fR (same as \fBdelete\-char\fR except aborts fzf if query is empty) \fBdeselect\fR - \fBdeselect\-all\fR (deselect all matches) + \fBdeselect\-all\fR (deselect all matches; to also clear non-matched selections, use \fBclear\-multi\fR) \fBdisable\-search\fR (disable search functionality) \fBdown\fR \fIctrl\-j ctrl\-n down\fR \fBenable\-search\fR (enable search functionality) @@ -1938,6 +1942,17 @@ echo "change\-header:Invalid selection"' \fR +A common mistake when writing a \fBtransform\fR action is not escaping +placeholder expressions when passing them back to fzf. In the following +example, if you don't escape \fB{}\fR, fzf will immediately replace it with the +single-quoted string of the current item. This causes single quotes to appear +in the header and footer, and the script will break if any item contains +double-quote characters. + + \fBfzf \-\-bind 'focus:transform:[[ $FZF_ACTION =~ up ]] && + echo "change\-header()+transform\-footer:echo \\{}" || + echo "change\-footer()+transform\-header:echo \\{}"'\fR + .SS TRANSFORM IN THE BACKGROUND Transform actions are synchronous, meaning fzf becomes unresponsive while the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/plugin/fzf.vim new/fzf-0.64.0/plugin/fzf.vim --- old/fzf-0.63.0/plugin/fzf.vim 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/plugin/fzf.vim 2025-07-06 15:11:36.000000000 +0200 @@ -1,4 +1,4 @@ -" Copyright (c) 2013-2024 Junegunn Choi +" Copyright (c) 2013-2025 Junegunn Choi " " MIT License " diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/LICENSE new/fzf-0.64.0/src/LICENSE --- old/fzf-0.63.0/src/LICENSE 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/LICENSE 2025-07-06 15:11:36.000000000 +0200 @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Junegunn Choi +Copyright (c) 2013-2025 Junegunn Choi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/algo/algo.go new/fzf-0.64.0/src/algo/algo.go --- old/fzf-0.63.0/src/algo/algo.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/algo/algo.go 2025-07-06 15:11:36.000000000 +0200 @@ -303,7 +303,7 @@ } func normalizeRune(r rune) rune { - if r < 0x00C0 || r > 0x2184 { + if r < 0x00C0 || r > 0xFF61 { return r } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/algo/normalize.go new/fzf-0.64.0/src/algo/normalize.go --- old/fzf-0.63.0/src/algo/normalize.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/algo/normalize.go 2025-07-06 15:11:36.000000000 +0200 @@ -473,6 +473,103 @@ 'ử': 'u', 'ữ': 'u', 'ự': 'u', + + // https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) + 0xFF01: '!', // Fullwidth exclamation + 0xFF02: '"', // Fullwidth quotation mark + 0xFF03: '#', // Fullwidth number sign + 0xFF04: '$', // Fullwidth dollar sign + 0xFF05: '%', // Fullwidth percent + 0xFF06: '&', // Fullwidth ampersand + 0xFF07: '\'', // Fullwidth apostrophe + 0xFF08: '(', // Fullwidth left parenthesis + 0xFF09: ')', // Fullwidth right parenthesis + 0xFF0A: '*', // Fullwidth asterisk + 0xFF0B: '+', // Fullwidth plus + 0xFF0C: ',', // Fullwidth comma + 0xFF0D: '-', // Fullwidth hyphen-minus + 0xFF0E: '.', // Fullwidth period + 0xFF0F: '/', // Fullwidth slash + 0xFF10: '0', + 0xFF11: '1', + 0xFF12: '2', + 0xFF13: '3', + 0xFF14: '4', + 0xFF15: '5', + 0xFF16: '6', + 0xFF17: '7', + 0xFF18: '8', + 0xFF19: '9', + 0xFF1A: ':', // Fullwidth colon + 0xFF1B: ';', // Fullwidth semicolon + 0xFF1C: '<', // Fullwidth less-than + 0xFF1D: '=', // Fullwidth equal + 0xFF1E: '>', // Fullwidth greater-than + 0xFF1F: '?', // Fullwidth question mark + 0xFF20: '@', // Fullwidth at sign + 0xFF21: 'A', + 0xFF22: 'B', + 0xFF23: 'C', + 0xFF24: 'D', + 0xFF25: 'E', + 0xFF26: 'F', + 0xFF27: 'G', + 0xFF28: 'H', + 0xFF29: 'I', + 0xFF2A: 'J', + 0xFF2B: 'K', + 0xFF2C: 'L', + 0xFF2D: 'M', + 0xFF2E: 'N', + 0xFF2F: 'O', + 0xFF30: 'P', + 0xFF31: 'Q', + 0xFF32: 'R', + 0xFF33: 'S', + 0xFF34: 'T', + 0xFF35: 'U', + 0xFF36: 'V', + 0xFF37: 'W', + 0xFF38: 'X', + 0xFF39: 'Y', + 0xFF3A: 'Z', + 0xFF3B: '[', // Fullwidth left bracket + 0xFF3C: '\\', // Fullwidth backslash + 0xFF3D: ']', // Fullwidth right bracket + 0xFF3E: '^', // Fullwidth circumflex + 0xFF3F: '_', // Fullwidth underscore + 0xFF40: '`', // Fullwidth grave accent + 0xFF41: 'a', + 0xFF42: 'b', + 0xFF43: 'c', + 0xFF44: 'd', + 0xFF45: 'e', + 0xFF46: 'f', + 0xFF47: 'g', + 0xFF48: 'h', + 0xFF49: 'i', + 0xFF4A: 'j', + 0xFF4B: 'k', + 0xFF4C: 'l', + 0xFF4D: 'm', + 0xFF4E: 'n', + 0xFF4F: 'o', + 0xFF50: 'p', + 0xFF51: 'q', + 0xFF52: 'r', + 0xFF53: 's', + 0xFF54: 't', + 0xFF55: 'u', + 0xFF56: 'v', + 0xFF57: 'w', + 0xFF58: 'x', + 0xFF59: 'y', + 0xFF5A: 'z', + 0xFF5B: '{', // Fullwidth left brace + 0xFF5C: '|', // Fullwidth vertical bar + 0xFF5D: '}', // Fullwidth right brace + 0xFF5E: '~', // Fullwidth tilde + 0xFF61: '.', // Halfwidth ideographic full stop } // NormalizeRunes normalizes latin script letters @@ -480,7 +577,7 @@ ret := make([]rune, len(runes)) copy(ret, runes) for idx, r := range runes { - if r < 0x00C0 || r > 0x2184 { + if r < 0x00C0 || r > 0xFF61 { continue } n := normalized[r] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/chunklist.go new/fzf-0.64.0/src/chunklist.go --- old/fzf-0.63.0/src/chunklist.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/chunklist.go 2025-07-06 15:11:36.000000000 +0200 @@ -41,6 +41,13 @@ return c.count == chunkSize } +func (c *Chunk) lastIndex(minValue int32) int32 { + if c.count == 0 { + return minValue + } + return c.items[c.count-1].Index() + 1 // Exclusive +} + func (cl *ChunkList) lastChunk() *Chunk { return cl.chunks[len(cl.chunks)-1] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/matcher.go new/fzf-0.64.0/src/matcher.go --- old/fzf-0.63.0/src/matcher.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/matcher.go 2025-07-06 15:11:36.000000000 +0200 @@ -165,6 +165,7 @@ } minIndex := request.chunks[0].items[0].Index() + maxIndex := request.chunks[numChunks-1].lastIndex(minIndex) cancelled := util.NewAtomicBool(false) slices := m.sliceChunks(request.chunks) @@ -236,7 +237,7 @@ partialResult := <-resultChan partialResults[partialResult.index] = partialResult.matches } - return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex), false + return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex), false } // Reset is called to interrupt/signal the ongoing search diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/merger.go new/fzf-0.64.0/src/merger.go --- old/fzf-0.63.0/src/merger.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/merger.go 2025-07-06 15:11:36.000000000 +0200 @@ -4,7 +4,7 @@ // EmptyMerger is a Merger with no data func EmptyMerger(revision revision) *Merger { - return NewMerger(nil, [][]Result{}, false, false, revision, 0) + return NewMerger(nil, [][]Result{}, false, false, revision, 0, 0) } // Merger holds a set of locally sorted lists of items and provides the view of @@ -22,14 +22,16 @@ pass bool revision revision minIndex int32 + maxIndex int32 } // PassMerger returns a new Merger that simply returns the items in the // original order func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger { - var minIndex int32 + var minIndex, maxIndex int32 if len(*chunks) > 0 { minIndex = (*chunks)[0].items[0].Index() + maxIndex = (*chunks)[len(*chunks)-1].lastIndex(minIndex) } mg := Merger{ pattern: nil, @@ -38,7 +40,8 @@ count: 0, pass: true, revision: revision, - minIndex: minIndex} + minIndex: minIndex, + maxIndex: maxIndex} for _, chunk := range *mg.chunks { mg.count += chunk.count @@ -47,7 +50,7 @@ } // NewMerger returns a new Merger -func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revision revision, minIndex int32) *Merger { +func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revision revision, minIndex int32, maxIndex int32) *Merger { mg := Merger{ pattern: pattern, lists: lists, @@ -59,7 +62,8 @@ final: false, count: 0, revision: revision, - minIndex: minIndex} + minIndex: minIndex, + maxIndex: maxIndex} for _, list := range mg.lists { mg.count += len(list) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/merger_test.go new/fzf-0.64.0/src/merger_test.go --- old/fzf-0.63.0/src/merger_test.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/merger_test.go 2025-07-06 15:11:36.000000000 +0200 @@ -58,7 +58,7 @@ cnt := len(items) // Not sorted: same order - mg := NewMerger(nil, lists, false, false, revision{}, 0) + mg := NewMerger(nil, lists, false, false, revision{}, 0, 0) assert(t, cnt == mg.Length(), "Invalid Length") for i := 0; i < cnt; i++ { assert(t, items[i] == mg.Get(i), "Invalid Get") @@ -70,7 +70,7 @@ cnt := len(items) // Sorted sorted order - mg := NewMerger(nil, lists, true, false, revision{}, 0) + mg := NewMerger(nil, lists, true, false, revision{}, 0, 0) assert(t, cnt == mg.Length(), "Invalid Length") sort.Sort(ByRelevance(items)) for i := 0; i < cnt; i++ { @@ -80,7 +80,7 @@ } // Inverse order - mg2 := NewMerger(nil, lists, true, false, revision{}, 0) + mg2 := NewMerger(nil, lists, true, false, revision{}, 0, 0) for i := cnt - 1; i >= 0; i-- { if items[i] != mg2.Get(i) { t.Error("Not sorted", items[i], mg2.Get(i)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/options.go new/fzf-0.64.0/src/options.go --- old/fzf-0.63.0/src/options.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/options.go 2025-07-06 15:11:36.000000000 +0200 @@ -1008,6 +1008,8 @@ add(tui.JumpCancel) case "click-header": add(tui.ClickHeader) + case "multi": + add(tui.Multi) case "alt-enter", "alt-return": chords[tui.CtrlAltKey('m')] = key case "alt-space": @@ -1561,7 +1563,7 @@ appendAction(actCancel) case "clear-query": appendAction(actClearQuery) - case "clear-selection": + case "clear-multi", "clear-selection": appendAction(actClearSelection) case "forward-char": appendAction(actForwardChar) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/terminal.go new/fzf-0.64.0/src/terminal.go --- old/fzf-0.63.0/src/terminal.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/terminal.go 2025-07-06 15:11:36.000000000 +0200 @@ -450,31 +450,35 @@ return a[i].at.Before(a[j].at) } +// EventTypes are listed in the order of their priority. const ( - reqPrompt util.EventType = iota + reqResize util.EventType = iota + reqReinit + reqFullRedraw + reqRedraw + + reqJump + reqPrompt reqInfo reqHeader reqFooter reqList - reqJump - reqActivate - reqReinit - reqFullRedraw - reqResize - reqRedraw reqRedrawInputLabel reqRedrawHeaderLabel reqRedrawFooterLabel reqRedrawListLabel reqRedrawBorderLabel reqRedrawPreviewLabel - reqClose - reqPrintQuery + reqPreviewReady reqPreviewEnqueue reqPreviewDisplay reqPreviewRefresh reqPreviewDelayed + + reqActivate + reqClose + reqPrintQuery reqBecome reqQuit reqFatal @@ -1624,14 +1628,12 @@ return needFullRedraw } -func (t *Terminal) changeFooter(footer string) bool { +func (t *Terminal) changeFooter(footer string) { var lines []string if len(footer) > 0 { lines = strings.Split(strings.TrimSuffix(footer, "\n"), "\n") } - needFullRedraw := len(t.footer) != len(lines) t.footer = lines - return needFullRedraw } // UpdateHeader updates the header @@ -1678,12 +1680,12 @@ // Trimmed by --tail: filter selection by index filtered := make(map[int32]selectedItem) minIndex := merger.minIndex - maxIndex := minIndex + int32(merger.Length()) + maxIndex := merger.maxIndex for k, v := range t.selected { var included bool if maxIndex > minIndex { included = k >= minIndex && k < maxIndex - } else { // int32 overflow [==> <==] + } else if maxIndex < minIndex { // int32 overflow [==> <==] included = k >= minIndex || k < maxIndex } if included { @@ -2889,19 +2891,29 @@ return true } + // Check footer window + if len(t.footer) > 0 && (t.footerWindow == nil || t.footerWindow.Height() != len(t.footer)) || + len(t.footer) == 0 && t.footerWindow != nil { + t.printAll() + return true + } + // Check if the header borders are used and header has changed allHeaderLines := t.visibleHeaderLines() primaryHeaderLines := allHeaderLines - if t.hasHeaderLinesWindow() { + needHeaderWindow := t.hasHeaderWindow() + needHeaderLinesWindow := t.hasHeaderLinesWindow() + if needHeaderLinesWindow { primaryHeaderLines -= t.headerLines } // FIXME: Full redraw is triggered if there are too many lines in the header // so that the header window cannot display all of them. - needHeaderLinesWindow := t.hasHeaderLinesWindow() - if (t.headerBorderShape.Visible() || needHeaderLinesWindow) && - (t.headerWindow == nil && primaryHeaderLines > 0 || t.headerWindow != nil && primaryHeaderLines != t.headerWindow.Height()) || - needHeaderLinesWindow && (t.headerLinesWindow == nil || t.headerLinesWindow != nil && t.headerLines != t.headerLinesWindow.Height()) || - !needHeaderLinesWindow && t.headerLinesWindow != nil { + if (needHeaderWindow && t.headerWindow == nil) || + (!needHeaderWindow && t.headerWindow != nil) || + (needHeaderWindow && t.headerWindow != nil && primaryHeaderLines != t.headerWindow.Height()) || + (needHeaderLinesWindow && t.headerLinesWindow == nil) || + (!needHeaderLinesWindow && t.headerLinesWindow != nil) || + (needHeaderLinesWindow && t.headerLinesWindow != nil && t.headerLines != t.headerLinesWindow.Height()) { t.printAll() return true } @@ -5116,6 +5128,8 @@ t.uiMutex.Lock() t.mutex.Lock() info := false + header := false + footer := false for _, key := range keys { req := util.EventType(key) value := (*events)[req] @@ -5153,13 +5167,9 @@ } t.printList() case reqHeader: - if !t.resizeIfNeeded() { - t.printHeader() - } + header = true case reqFooter: - if !t.resizeIfNeeded() { - t.printFooter() - } + footer = true case reqActivate: t.suppress = false if t.hasPreviewer() { @@ -5177,10 +5187,10 @@ t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, true) case reqRedrawPreviewLabel: t.printLabel(t.pborder, t.previewLabel, t.previewLabelOpts, t.previewLabelLen, t.activePreviewOpts.Border(), true) - case reqReinit: - t.tui.Resume(t.fullscreen, true) - t.fullRedraw() - case reqResize, reqFullRedraw, reqRedraw: + case reqReinit, reqResize, reqFullRedraw, reqRedraw: + if req == reqReinit { + t.tui.Resume(t.fullscreen, true) + } if req == reqResize { t.termSize = t.tui.Size() } @@ -5243,8 +5253,16 @@ return } } - if info && !t.resizeIfNeeded() { - t.printInfo() + if (info || header || footer) && !t.resizeIfNeeded() { + if info { + t.printInfo() + } + if header { + t.printHeader() + } + if footer { + t.printFooter() + } } t.flush() t.mutex.Unlock() @@ -5384,6 +5402,7 @@ } previousInput := t.input previousCx := t.cx + previousVersion := t.version t.lastKey = event.KeyName() updatePreviewWindow := func(forcePreview bool) { t.resizeWindows(forcePreview, false) @@ -5670,24 +5689,17 @@ t.cx = len(t.input) case actChangeHeader, actTransformHeader, actBgTransformHeader: capture(false, func(header string) { + // When a dedicated header window is not used, we may need to + // update other elements as well. if t.changeHeader(header) { - if t.headerWindow != nil { - // Need to resize header window - req(reqRedraw) - } else { - req(reqHeader, reqList, reqPrompt, reqInfo) - } - } else { - req(reqHeader) + req(reqList, reqPrompt, reqInfo) } + req(reqHeader) }) case actChangeFooter, actTransformFooter, actBgTransformFooter: capture(false, func(footer string) { - if t.changeFooter(footer) { - req(reqRedraw) - } else { - req(reqFooter) - } + t.changeFooter(footer) + req(reqFooter) }) case actChangeHeaderLabel, actTransformHeaderLabel, actBgTransformHeaderLabel: capture(true, func(label string) { @@ -6648,6 +6660,9 @@ if onEOFs, prs := t.keymap[tui.BackwardEOF.AsEvent()]; beof && prs && !doActions(onEOFs) { continue } + if onMultis, prs := t.keymap[tui.Multi.AsEvent()]; t.version != previousVersion && prs && !doActions(onMultis) { + continue + } } else { jumpEvent := tui.JumpCancel if event.Type == tui.Rune { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/tui/eventtype_string.go new/fzf-0.64.0/src/tui/eventtype_string.go --- old/fzf-0.63.0/src/tui/eventtype_string.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/tui/eventtype_string.go 2025-07-06 15:11:36.000000000 +0200 @@ -110,11 +110,12 @@ _ = x[Jump-99] _ = x[JumpCancel-100] _ = x[ClickHeader-101] + _ = x[Multi-102] } -const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeader" +const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderMulti" -var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684} +var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684, 689} func (i EventType) String() string { if i < 0 || i >= EventType(len(_EventType_index)-1) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/src/tui/tui.go new/fzf-0.64.0/src/tui/tui.go --- old/fzf-0.63.0/src/tui/tui.go 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/src/tui/tui.go 2025-07-06 15:11:36.000000000 +0200 @@ -132,6 +132,7 @@ Jump JumpCancel ClickHeader + Multi ) func (t EventType) AsEvent() Event { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.63.0/test/test_core.rb new/fzf-0.64.0/test/test_core.rb --- old/fzf-0.63.0/test/test_core.rb 2025-06-27 18:11:00.000000000 +0200 +++ new/fzf-0.64.0/test/test_core.rb 2025-07-06 15:11:36.000000000 +0200 @@ -1930,7 +1930,10 @@ def test_change_header_on_header_window tmux.send_keys %(seq 100 | #{FZF} --list-border --input-border --bind 'start:change-header(foo),space:change-header(bar)'), :Enter - tmux.until { |lines| assert lines.any_include?('foo') } + tmux.until do |lines| + assert lines.any_include?('100/100') + assert lines.any_include?('foo') + end tmux.send_keys :Space tmux.until { |lines| assert lines.any_include?('bar') } end @@ -1981,4 +1984,55 @@ refute lines.any_include?('[1]') end end + + def test_render_order + tmux.send_keys %(seq 100 | #{FZF} --bind='focus:preview(echo boom)+change-footer(bam)'), :Enter + tmux.until { assert_equal 100, it.match_count } + tmux.until { assert it.any_include?('boom') } + tmux.until { assert it.any_include?('bam') } + end + + def test_multi_event + tmux.send_keys %(seq 100 | #{FZF} --multi --bind 'multi:transform-footer:(( FZF_SELECT_COUNT )) && echo "Selected $FZF_SELECT_COUNT item(s)"'), :Enter + tmux.until { assert_equal 100, it.match_count } + tmux.send_keys :Tab + tmux.until { assert_equal 1, it.select_count } + tmux.until { assert it.any_include?('Selected 1 item(s)') } + tmux.send_keys :Tab + tmux.until { assert_equal 0, it.select_count } + tmux.until { refute it.any_include?('Selected') } + end + + def test_preserve_selection_on_revision_bump + tmux.send_keys %(seq 100 | #{FZF} --multi --sync --query "'1" --bind 'a:select-all+change-header(pressed a),b:change-header(pressed b)+change-nth(1),c:exclude'), :Enter + tmux.until do + assert_equal 20, it.match_count + assert_equal 0, it.select_count + end + tmux.send_keys :a + tmux.until do + assert_equal 20, it.match_count + assert_equal 20, it.select_count + assert it.any_include?('pressed a') + end + tmux.send_keys :b + tmux.until do + assert_equal 20, it.match_count + assert_equal 20, it.select_count + refute it.any_include?('pressed a') + assert it.any_include?('pressed b') + end + tmux.send_keys :a + tmux.until do + assert_equal 20, it.match_count + assert_equal 20, it.select_count + assert it.any_include?('pressed a') + refute it.any_include?('pressed b') + end + tmux.send_keys :c + tmux.until do + assert_equal 19, it.match_count + assert_equal 19, it.select_count + end + end end