Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2022-08-06 22:08:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.1521 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fzf" Sat Aug 6 22:08:33 2022 rev:24 rq:993542 version:0.32.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2022-07-22 19:21:54.516724192 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.1521/fzf.changes 2022-08-06 22:08:45.254760528 +0200 @@ -1,0 +2,33 @@ +Wed Aug 3 14:31:08 UTC 2022 - Matej Cepl <mc...@suse.com> + +- Update to 0.32.0: + - Updated the scoring algorithm + - Different bonus points to different categories of word + boundaries (listed higher to lower bonus point) + - Word after whitespace characters or beginning of the string + - Word after common delimiter characters (/,:;|) + - Word after other non-word characters + # foo/bar.sh` is preferred over `foo-bar.sh` on `bar` + fzf --query=bar --height=4 << EOF + foo-bar.sh + foo/bar.sh + EOF + - Added a new tiebreak chunk + - Favors the line with shorter matched chunk. A chunk is a + set of consecutive non-whitespace characters. + - Unlike the default length, this scheme works well with + tabular input + # length prefers item #1, because the whole line is shorter, + # chunk prefers item #2, because the matched chunk ("foo") is shorter + fzf --height=6 --header-lines=2 --tiebreak=chunk --reverse --query=fo << "EOF" + N | Field1 | Field2 | Field3 + - | ------ | ------ | ------ + 1 | hello | foobar | baz + 2 | world | foo | bazbaz + EOF + - If the input does not contain any spaces, chunk is + equivalent to length. But we're not going to set it as the + default because it is computationally more expensive. + - Bug fixes and improvements + +------------------------------------------------------------------- Old: ---- fzf-0.31.0.tar.gz vendor.tar.gz New: ---- fzf-0.32.0.tar.gz vendor.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.eCiucR/_old 2022-08-06 22:08:45.878762342 +0200 +++ /var/tmp/diff_new_pack.eCiucR/_new 2022-08-06 22:08:45.886762365 +0200 @@ -17,14 +17,14 @@ Name: fzf -Version: 0.31.0 +Version: 0.32.0 Release: 0 Summary: A command-line fuzzy finder License: MIT Group: Productivity/File utilities URL: https://github.com/junegunn/fzf Source0: https://github.com/junegunn/fzf/archive/refs/tags/%{version}.tar.gz#/%{name}-%{version}.tar.gz -Source1: vendor.tar.gz +Source1: vendor.tar.xz BuildRequires: golang(API) = 1.18 %description ++++++ fzf-0.31.0.tar.gz -> fzf-0.32.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/.github/FUNDING.yml new/fzf-0.32.0/.github/FUNDING.yml --- old/fzf-0.31.0/.github/FUNDING.yml 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/.github/FUNDING.yml 2022-08-02 14:56:14.000000000 +0200 @@ -1 +1 @@ -custom: ["https://paypal.me/junegunn", "https://www.buymeacoffee.com/junegunn"] +github: junegunn diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/.goreleaser.yml new/fzf-0.32.0/.goreleaser.yml --- old/fzf-0.31.0/.goreleaser.yml 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/.goreleaser.yml 2022-08-02 14:56:14.000000000 +0200 @@ -18,7 +18,7 @@ post: | sh -c ' cat > /tmp/fzf-gon-amd64.hcl << EOF - source = ["./dist/fzf-macos_darwin_amd64/fzf"] + source = ["./dist/fzf-macos_darwin_amd64_v1/fzf"] bundle_id = "kr.junegunn.fzf" apple_id { username = "junegun...@gmail.com" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/CHANGELOG.md new/fzf-0.32.0/CHANGELOG.md --- old/fzf-0.31.0/CHANGELOG.md 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/CHANGELOG.md 2022-08-02 14:56:14.000000000 +0200 @@ -1,6 +1,40 @@ CHANGELOG ========= +0.32.0 +------ +- Updated the scoring algorithm + - Different bonus points to different categories of word boundaries + (listed higher to lower bonus point) + - Word after whitespace characters or beginning of the string + - Word after common delimiter characters (`/,:;|`) + - Word after other non-word characters + ```sh + # foo/bar.sh` is preferred over `foo-bar.sh` on `bar` + fzf --query=bar --height=4 << EOF + foo-bar.sh + foo/bar.sh + EOF + ``` +- Added a new tiebreak `chunk` + - Favors the line with shorter matched chunk. A chunk is a set of + consecutive non-whitespace characters. + - Unlike the default `length`, this scheme works well with tabular input + ```sh + # length prefers item #1, because the whole line is shorter, + # chunk prefers item #2, because the matched chunk ("foo") is shorter + fzf --height=6 --header-lines=2 --tiebreak=chunk --reverse --query=fo << "EOF" + N | Field1 | Field2 | Field3 + - | ------ | ------ | ------ + 1 | hello | foobar | baz + 2 | world | foo | bazbaz + EOF + ``` + - If the input does not contain any spaces, `chunk` is equivalent to + `length`. But we're not going to set it as the default because it is + computationally more expensive. +- Bug fixes and improvements + 0.31.0 ------ - Added support for an alternative preview window layout that is activated diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/README.md new/fzf-0.32.0/README.md --- old/fzf-0.31.0/README.md 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/README.md 2022-08-02 14:56:14.000000000 +0200 @@ -557,7 +557,7 @@ ```sh FZF_DEFAULT_COMMAND='ps -ef' \ - fzf --bind 'ctrl-r:reload($FZF_DEFAULT_COMMAND)' \ + fzf --bind 'ctrl-r:reload(eval "$FZF_DEFAULT_COMMAND")' \ --header 'Press CTRL-R to reload' --header-lines=1 \ --height=50% --layout=reverse ``` @@ -566,7 +566,7 @@ ```sh FZF_DEFAULT_COMMAND='find . -type f' \ - fzf --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload($FZF_DEFAULT_COMMAND)' \ + fzf --bind 'ctrl-d:reload(find . -type d),ctrl-f:reload(eval "$FZF_DEFAULT_COMMAND")' \ --height=50% --layout=reverse ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/install new/fzf-0.32.0/install --- old/fzf-0.31.0/install 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/install 2022-08-02 14:56:14.000000000 +0200 @@ -2,7 +2,7 @@ set -u -version=0.31.0 +version=0.32.0 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/install.ps1 new/fzf-0.32.0/install.ps1 --- old/fzf-0.31.0/install.ps1 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/install.ps1 2022-08-02 14:56:14.000000000 +0200 @@ -1,4 +1,4 @@ -$version="0.31.0" +$version="0.32.0" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/main.go new/fzf-0.32.0/main.go --- old/fzf-0.31.0/main.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/main.go 2022-08-02 14:56:14.000000000 +0200 @@ -5,7 +5,7 @@ "github.com/junegunn/fzf/src/protector" ) -var version string = "0.31" +var version string = "0.32" var revision string = "devel" func main() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/man/man1/fzf-tmux.1 new/fzf-0.32.0/man/man1/fzf-tmux.1 --- old/fzf-0.31.0/man/man1/fzf-tmux.1 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/man/man1/fzf-tmux.1 2022-08-02 14:56:14.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf-tmux 1 "Jul 2022" "fzf 0.31.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Aug 2022" "fzf 0.32.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.31.0/man/man1/fzf.1 new/fzf-0.32.0/man/man1/fzf.1 --- old/fzf-0.31.0/man/man1/fzf.1 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/man/man1/fzf.1 2022-08-02 14:56:14.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Jul 2022" "fzf 0.31.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Aug 2022" "fzf 0.32.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -95,6 +95,8 @@ .br .BR length " Prefers line with shorter length" .br +.BR chunk " Prefers line with shorter matched chunk (delimited by whitespaces)" +.br .BR begin " Prefers line with matched substring closer to the beginning" .br .BR end " Prefers line with matched substring closer to the end" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/plugin/fzf.vim new/fzf-0.32.0/plugin/fzf.vim --- old/fzf-0.31.0/plugin/fzf.vim 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/plugin/fzf.vim 2022-08-02 14:56:14.000000000 +0200 @@ -164,7 +164,7 @@ if has_key(s:versions, a:bin) return s:versions[a:bin] end - let command = fzf#shellescape(a:bin) . ' --version --no-height' + let command = (&shell =~ 'powershell' ? '&' : '') . shellescape(a:bin) . ' --version --no-height' let output = systemlist(command) if v:shell_error || empty(output) return '' @@ -342,7 +342,8 @@ endfunction function! s:get_color(attr, ...) - let gui = !s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors + " Force 24 bit colors: g:fzf_force_termguicolors (temporary workaround for https://github.com/junegunn/fzf.vim/issues/1152) + let gui = get(g:, 'fzf_force_termguicolors', 0) || (!s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors) let fam = gui ? 'gui' : 'cterm' let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$' for group in a:000 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/shell/completion.bash new/fzf-0.32.0/shell/completion.bash --- old/fzf-0.31.0/shell/completion.bash 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/shell/completion.bash 2022-08-02 14:56:14.000000000 +0200 @@ -161,7 +161,11 @@ __fzf_generic_path_completion() { local cur base dir leftover matches trigger cmd - cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}" + cmd="${COMP_WORDS[0]}" + if [[ $cmd == \\* ]]; then + cmd="${cmd:1}" + fi + cmd="${cmd//[^A-Za-z0-9_=]/_}" COMPREPLY=() trigger=${FZF_COMPLETION_TRIGGER-'**'} cur="${COMP_WORDS[COMP_CWORD]}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/shell/key-bindings.zsh new/fzf-0.32.0/shell/key-bindings.zsh --- old/fzf-0.31.0/shell/key-bindings.zsh 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/shell/key-bindings.zsh 2022-08-02 14:56:14.000000000 +0200 @@ -97,7 +97,7 @@ fzf-history-widget() { local selected num setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null - selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^\s*[0-9]+\**\s+/, "", cmd); if (!seen[cmd]++) print $0 }' | + selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) ) local ret=$? if [ -n "$selected" ]; then diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/algo/algo.go new/fzf-0.32.0/src/algo/algo.go --- old/fzf-0.31.0/src/algo/algo.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/algo/algo.go 2022-08-02 14:56:14.000000000 +0200 @@ -89,6 +89,9 @@ var DEBUG bool +const delimiterChars = "/,:;|" +const whiteChars = " \t\n\v\f\r\x85\xA0" + func indexAt(index int, max int, forward bool) int { if forward { return index @@ -117,6 +120,12 @@ // in web2 dictionary and my file system. bonusBoundary = scoreMatch / 2 + // Extra bonus for word boundary after whitespace character or beginning of the string + bonusBoundaryWhite = bonusBoundary + 2 + + // Extra bonus for word boundary after slash, colon, semi-colon, and comma + bonusBoundaryDelimiter = bonusBoundary + 1 + // Although bonus point for non-word characters is non-contextual, we need it // for computing bonus points for consecutive chunks starting with a non-word // character. @@ -143,7 +152,9 @@ type charClass int const ( - charNonWord charClass = iota + charWhite charClass = iota + charNonWord + charDelimiter charLower charUpper charLetter @@ -181,6 +192,10 @@ return charUpper } else if char >= '0' && char <= '9' { return charNumber + } else if strings.IndexRune(whiteChars, char) >= 0 { + return charWhite + } else if strings.IndexRune(delimiterChars, char) >= 0 { + return charDelimiter } return charNonWord } @@ -194,6 +209,10 @@ return charNumber } else if unicode.IsLetter(char) { return charLetter + } else if unicode.IsSpace(char) { + return charWhite + } else if strings.IndexRune(delimiterChars, char) >= 0 { + return charDelimiter } return charNonWord } @@ -206,22 +225,33 @@ } func bonusFor(prevClass charClass, class charClass) int16 { - if prevClass == charNonWord && class != charNonWord { - // Word boundary - return bonusBoundary - } else if prevClass == charLower && class == charUpper || + if class > charNonWord { + if prevClass == charWhite { + // Word boundary after whitespace + return bonusBoundaryWhite + } else if prevClass == charDelimiter { + // Word boundary after a delimiter character + return bonusBoundaryDelimiter + } else if prevClass == charNonWord { + // Word boundary + return bonusBoundary + } + } + if prevClass == charLower && class == charUpper || prevClass != charNumber && class == charNumber { // camelCase letter123 return bonusCamel123 } else if class == charNonWord { return bonusNonWord + } else if class == charWhite { + return bonusBoundaryWhite } return 0 } func bonusAt(input *util.Chars, idx int) int16 { if idx == 0 { - return bonusBoundary + return bonusBoundaryWhite } return bonusFor(charClassOf(input.Get(idx-1)), charClassOf(input.Get(idx))) } @@ -377,7 +407,7 @@ // Phase 2. Calculate bonus for each point maxScore, maxScorePos := int16(0), 0 pidx, lastIdx := 0, 0 - pchar0, pchar, prevH0, prevClass, inGap := pattern[0], pattern[0], int16(0), charNonWord, false + pchar0, pchar, prevH0, prevClass, inGap := pattern[0], pattern[0], int16(0), charWhite, false Tsub := T[idx:] H0sub, C0sub, Bsub := H0[idx:][:len(Tsub)], C0[idx:][:len(Tsub)], B[idx:][:len(Tsub)] for off, char := range Tsub { @@ -417,7 +447,7 @@ C0sub[off] = 1 if M == 1 && (forward && score > maxScore || !forward && score >= maxScore) { maxScore, maxScorePos = score, idx+off - if forward && bonus == bonusBoundary { + if forward && bonus >= bonusBoundary { break } } @@ -486,11 +516,14 @@ s1 = Hdiag[off] + scoreMatch b := Bsub[off] consecutive = Cdiag[off] + 1 - // Break consecutive chunk - if b == bonusBoundary { - consecutive = 1 - } else if consecutive > 1 { - b = util.Max16(b, util.Max16(bonusConsecutive, B[col-int(consecutive)+1])) + if consecutive > 1 { + fb := B[col-int(consecutive)+1] + // Break consecutive chunk + if b >= bonusBoundary && b > fb { + consecutive = 1 + } else { + b = util.Max16(b, util.Max16(bonusConsecutive, fb)) + } } if s1+b < s2 { s1 += Bsub[off] @@ -555,7 +588,7 @@ func calculateScore(caseSensitive bool, normalize bool, text *util.Chars, pattern []rune, sidx int, eidx int, withPos bool) (int, *[]int) { pidx, score, inGap, consecutive, firstBonus := 0, 0, false, 0, int16(0) pos := posArray(withPos, len(pattern)) - prevClass := charNonWord + prevClass := charWhite if sidx > 0 { prevClass = charClassOf(text.Get(sidx - 1)) } @@ -583,7 +616,7 @@ firstBonus = bonus } else { // Break consecutive chunk - if bonus == bonusBoundary { + if bonus >= bonusBoundary && bonus > firstBonus { firstBonus = bonus } bonus = util.Max16(util.Max16(bonus, firstBonus), bonusConsecutive) @@ -741,7 +774,7 @@ if bonus > bestBonus { bestPos, bestBonus = index, bonus } - if bonus == bonusBoundary { + if bonus >= bonusBoundary { break } index -= pidx - 1 @@ -877,8 +910,8 @@ match = runesStr == string(pattern) } if match { - return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+bonusBoundary)*lenPattern + - (bonusFirstCharMultiplier-1)*bonusBoundary}, nil + return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+bonusBoundaryWhite)*lenPattern + + (bonusFirstCharMultiplier-1)*bonusBoundaryWhite}, nil } return Result{-1, -1, 0}, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/algo/algo_test.go new/fzf-0.32.0/src/algo/algo_test.go --- old/fzf-0.31.0/src/algo/algo_test.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/algo/algo_test.go 2022-08-02 14:56:14.000000000 +0200 @@ -45,29 +45,29 @@ assertMatch(t, fn, false, forward, "fooBarbaz1", "oBZ", 2, 9, scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3) assertMatch(t, fn, false, forward, "foo bar baz", "fbb", 0, 9, - scoreMatch*3+bonusBoundary*bonusFirstCharMultiplier+ - bonusBoundary*2+2*scoreGapStart+4*scoreGapExtension) + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+ + bonusBoundaryWhite*2+2*scoreGapStart+4*scoreGapExtension) assertMatch(t, fn, false, forward, "/AutomatorDocument.icns", "rdoc", 9, 13, scoreMatch*4+bonusCamel123+bonusConsecutive*2) assertMatch(t, fn, false, forward, "/man1/zshcompctl.1", "zshc", 6, 10, - scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*3) + scoreMatch*4+bonusBoundaryDelimiter*bonusFirstCharMultiplier+bonusBoundaryDelimiter*3) assertMatch(t, fn, false, forward, "/.oh-my-zsh/cache", "zshc", 8, 13, - scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*3+scoreGapStart) + scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*2+scoreGapStart+bonusBoundaryDelimiter) assertMatch(t, fn, false, forward, "ab0123 456", "12356", 3, 10, scoreMatch*5+bonusConsecutive*3+scoreGapStart+scoreGapExtension) assertMatch(t, fn, false, forward, "abc123 456", "12356", 3, 10, scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+bonusConsecutive+scoreGapStart+scoreGapExtension) assertMatch(t, fn, false, forward, "foo/bar/baz", "fbb", 0, 9, - scoreMatch*3+bonusBoundary*bonusFirstCharMultiplier+ - bonusBoundary*2+2*scoreGapStart+4*scoreGapExtension) + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+ + bonusBoundaryDelimiter*2+2*scoreGapStart+4*scoreGapExtension) assertMatch(t, fn, false, forward, "fooBarBaz", "fbb", 0, 7, - scoreMatch*3+bonusBoundary*bonusFirstCharMultiplier+ + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+ bonusCamel123*2+2*scoreGapStart+2*scoreGapExtension) assertMatch(t, fn, false, forward, "foo barbaz", "fbb", 0, 8, - scoreMatch*3+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary+ + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite+ scoreGapStart*2+scoreGapExtension*3) assertMatch(t, fn, false, forward, "fooBar Baz", "foob", 0, 4, - scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*3) + scoreMatch*4+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite*3) assertMatch(t, fn, false, forward, "xFoo-Bar Baz", "foo-b", 1, 6, scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+ bonusNonWord+bonusBoundary) @@ -75,14 +75,14 @@ assertMatch(t, fn, true, forward, "fooBarbaz", "oBz", 2, 9, scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3) assertMatch(t, fn, true, forward, "Foo/Bar/Baz", "FBB", 0, 9, - scoreMatch*3+bonusBoundary*(bonusFirstCharMultiplier+2)+ + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryDelimiter*2+ scoreGapStart*2+scoreGapExtension*4) assertMatch(t, fn, true, forward, "FooBarBaz", "FBB", 0, 7, - scoreMatch*3+bonusBoundary*bonusFirstCharMultiplier+bonusCamel123*2+ + scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusCamel123*2+ scoreGapStart*2+scoreGapExtension*2) assertMatch(t, fn, true, forward, "FooBar Baz", "FooB", 0, 4, - scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*2+ - util.Max(bonusCamel123, bonusBoundary)) + scoreMatch*4+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite*2+ + util.Max(bonusCamel123, bonusBoundaryWhite)) // Consecutive bonus updated assertMatch(t, fn, true, forward, "foo-bar", "o-ba", 2, 6, @@ -98,10 +98,10 @@ func TestFuzzyMatchBackward(t *testing.T) { assertMatch(t, FuzzyMatchV1, false, true, "foobar fb", "fb", 0, 4, - scoreMatch*2+bonusBoundary*bonusFirstCharMultiplier+ + scoreMatch*2+bonusBoundaryWhite*bonusFirstCharMultiplier+ scoreGapStart+scoreGapExtension) assertMatch(t, FuzzyMatchV1, false, false, "foobar fb", "fb", 7, 9, - scoreMatch*2+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary) + scoreMatch*2+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite) } func TestExactMatchNaive(t *testing.T) { @@ -114,9 +114,9 @@ assertMatch(t, ExactMatchNaive, false, dir, "/AutomatorDocument.icns", "rdoc", 9, 13, scoreMatch*4+bonusCamel123+bonusConsecutive*2) assertMatch(t, ExactMatchNaive, false, dir, "/man1/zshcompctl.1", "zshc", 6, 10, - scoreMatch*4+bonusBoundary*(bonusFirstCharMultiplier+3)) + scoreMatch*4+bonusBoundaryDelimiter*(bonusFirstCharMultiplier+3)) assertMatch(t, ExactMatchNaive, false, dir, "/.oh-my-zsh/cache", "zsh/c", 8, 13, - scoreMatch*5+bonusBoundary*(bonusFirstCharMultiplier+4)) + scoreMatch*5+bonusBoundary*(bonusFirstCharMultiplier+3)+bonusBoundaryDelimiter) } } @@ -128,7 +128,7 @@ } func TestPrefixMatch(t *testing.T) { - score := (scoreMatch+bonusBoundary)*3 + bonusBoundary*(bonusFirstCharMultiplier-1) + score := scoreMatch*3 + bonusBoundaryWhite*bonusFirstCharMultiplier + bonusBoundaryWhite*2 for _, dir := range []bool{true, false} { assertMatch(t, PrefixMatch, true, dir, "fooBarbaz", "Foo", -1, -1, 0) @@ -156,9 +156,10 @@ // Strip trailing white space from the string assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz", 6, 9, scoreMatch*3+bonusConsecutive*2) + // Only when the pattern doesn't end with a space assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz ", 6, 10, - scoreMatch*4+bonusConsecutive*2+bonusNonWord) + scoreMatch*4+bonusConsecutive*2+bonusBoundaryWhite) } } @@ -182,9 +183,9 @@ input, pattern, sidx, eidx, score) } } - test("S?? Dan??o Samba", "So", 0, 2, 56, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, ExactMatchNaive) - test("S?? Dan??o Samba", "sodc", 0, 7, 89, FuzzyMatchV1, FuzzyMatchV2) - test("Dan??o", "danco", 0, 5, 128, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, SuffixMatch, ExactMatchNaive, EqualMatch) + test("S?? Dan??o Samba", "So", 0, 2, 62, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, ExactMatchNaive) + test("S?? Dan??o Samba", "sodc", 0, 7, 97, FuzzyMatchV1, FuzzyMatchV2) + test("Dan??o", "danco", 0, 5, 140, FuzzyMatchV1, FuzzyMatchV2, PrefixMatch, SuffixMatch, ExactMatchNaive, EqualMatch) } func TestLongString(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/options.go new/fzf-0.32.0/src/options.go --- old/fzf-0.31.0/src/options.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/options.go 2022-08-02 14:56:14.000000000 +0200 @@ -35,7 +35,7 @@ --tac Reverse the order of the input --disabled Do not perform search --tiebreak=CRI[,..] Comma-separated list of sort criteria to apply - when the scores are tied [length|begin|end|index] + when the scores are tied [length|chunk|begin|end|index] (default: length) Interface @@ -125,6 +125,7 @@ const ( byScore criterion = iota + byChunk byLength byBegin byEnd @@ -611,6 +612,7 @@ func parseTiebreak(str string) []criterion { criteria := []criterion{byScore} hasIndex := false + hasChunk := false hasLength := false hasBegin := false hasEnd := false @@ -627,6 +629,9 @@ switch str { case "index": check(&hasIndex, "index") + case "chunk": + check(&hasChunk, "chunk") + criteria = append(criteria, byChunk) case "length": check(&hasLength, "length") criteria = append(criteria, byLength) @@ -640,6 +645,9 @@ errorExit("invalid sort criterion: " + str) } } + if len(criteria) > 4 { + errorExit("at most 3 tiebreaks are allowed: " + str) + } return criteria } @@ -1742,12 +1750,20 @@ } } +func expectsArbitraryString(opt string) bool { + switch opt { + case "-q", "--query", "-f", "--filter", "--header", "--prompt": + return true + } + return false +} + // ParseOptions parses command-line options func ParseOptions() *Options { opts := defaultOptions() - for _, arg := range os.Args[1:] { - if arg == "--version" { + for idx, arg := range os.Args[1:] { + if arg == "--version" && (idx == 0 || idx > 0 && !expectsArbitraryString(os.Args[idx])) { opts.Version = true return opts } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/result.go new/fzf-0.32.0/src/result.go --- old/fzf-0.31.0/src/result.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/result.go 2022-08-02 14:56:14.000000000 +0200 @@ -49,6 +49,21 @@ case byScore: // Higher is better val = math.MaxUint16 - util.AsUint16(score) + case byChunk: + b := minBegin + e := maxEnd + l := item.text.Length() + for ; b >= 1; b-- { + if unicode.IsSpace(item.text.Get(b - 1)) { + break + } + } + for ; e < l; e++ { + if unicode.IsSpace(item.text.Get(e)) { + break + } + } + val = util.AsUint16(e - b) case byLength: val = item.TrimLength() case byBegin, byEnd: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/result_test.go new/fzf-0.32.0/src/result_test.go --- old/fzf-0.31.0/src/result_test.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/result_test.go 2022-08-02 14:56:14.000000000 +0200 @@ -54,9 +54,9 @@ // FIXME global sortCriteria = []criterion{byScore, byLength} - strs := [][]rune{[]rune("foo"), []rune("foobar"), []rune("bar"), []rune("baz")} + str := []rune("foo") item1 := buildResult( - withIndex(&Item{text: util.RunesToChars(strs[0])}, 1), []Offset{}, 2) + withIndex(&Item{text: util.RunesToChars(str)}, 1), []Offset{}, 2) if item1.points[3] != math.MaxUint16-2 || // Bonus item1.points[2] != 3 || // Length item1.points[1] != 0 || // Unused @@ -65,7 +65,7 @@ t.Error(item1) } // Only differ in index - item2 := buildResult(&Item{text: util.RunesToChars(strs[0])}, []Offset{}, 2) + item2 := buildResult(&Item{text: util.RunesToChars(str)}, []Offset{}, 2) items := []Result{item1, item2} sort.Sort(ByRelevance(items)) @@ -98,6 +98,23 @@ } } +func TestChunkTiebreak(t *testing.T) { + // FIXME global + sortCriteria = []criterion{byScore, byChunk} + + score := 100 + test := func(input string, offset Offset, chunk string) { + item := buildResult(withIndex(&Item{text: util.RunesToChars([]rune(input))}, 1), []Offset{offset}, score) + if !(item.points[3] == math.MaxUint16-uint16(score) && item.points[2] == uint16(len(chunk))) { + t.Error(item.points) + } + } + test("hello foobar goodbye", Offset{8, 9}, "foobar") + test("hello foobar goodbye", Offset{7, 18}, "foobar goodbye") + test("hello foobar goodbye", Offset{0, 1}, "hello") + test("hello foobar goodbye", Offset{5, 7}, "hello foobar") // TBD +} + func TestColorOffset(t *testing.T) { // ------------ 20 ---- -- ---- // ++++++++ ++++++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/src/tui/light.go new/fzf-0.32.0/src/tui/light.go --- old/fzf-0.31.0/src/tui/light.go 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/src/tui/light.go 2022-08-02 14:56:14.000000000 +0200 @@ -540,7 +540,7 @@ t := atoi(elems[0], -1) x := atoi(elems[1], -1) - 1 - y := atoi(elems[2], -1) - 1 + y := atoi(elems[2], -1) - 1 - r.yoffset if t < 0 || x < 0 || y < 0 { return Event{Invalid, 0, nil} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.31.0/test/test_go.rb new/fzf-0.32.0/test/test_go.rb --- old/fzf-0.31.0/test/test_go.rb 2022-07-21 15:46:34.000000000 +0200 +++ new/fzf-0.32.0/test/test_go.rb 2022-08-02 14:56:14.000000000 +0200 @@ -754,6 +754,20 @@ assert_equal output, `#{FZF} -fh -n2 -d: < #{tempname}`.lines(chomp: true) end + def test_tiebreak_chunk + writelines(tempname, [ + '1 foobarbaz baz', + '2 foobar baz', + '3 foo barbaz' + ]) + + assert_equal [ + '3 foo barbaz', + '2 foobar baz', + '1 foobarbaz baz' + ], `#{FZF} -fo --tiebreak=chunk < #{tempname}`.lines(chomp: true) + end + def test_invalid_cache tmux.send_keys "(echo d; echo D; echo x) | #{fzf('-q d')}", :Enter tmux.until { |lines| assert_equal ' 2/3', lines[-2] }