From f092e4038fd1344bcd0a7c11f7ab7355734f7275 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Tue, 28 Jul 2020 13:06:57 +0900 Subject: [PATCH] Smart match of accented characters Fix #1618 --- CHANGELOG.md | 4 ++++ src/pattern.go | 12 +++++++++--- test/test_go.rb | 8 ++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d81536..5126d4cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,10 @@ CHANGELOG fzf --delimiter : --preview 'nl {1}' --preview-window +{2}-5 ``` - Added support for ANSI colors in `--prompt` string +- Smart match of accented characters + - An unaccented character in the query string will match both accented and + unaccented characters, while an accented character will only match + accented characters. This is similar to how "smart-case" match works. - Vim plugin - `tmux` layout option for using fzf-tmux ```vim diff --git a/src/pattern.go b/src/pattern.go index 4880d6e9..56dc830f 100644 --- a/src/pattern.go +++ b/src/pattern.go @@ -33,6 +33,7 @@ type term struct { inv bool text []rune caseSensitive bool + normalize bool } // String returns the string representation of a term. @@ -128,6 +129,8 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, } } else { lowerString := strings.ToLower(asString) + normalize = normalize && + lowerString == string(algo.NormalizeRunes([]rune(lowerString))) caseSensitive = caseMode == CaseRespect || caseMode == CaseSmart && lowerString != asString if !caseSensitive { @@ -173,6 +176,8 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet lowerText := strings.ToLower(text) caseSensitive := caseMode == CaseRespect || caseMode == CaseSmart && text != lowerText + normalizeTerm := normalize && + lowerText == string(algo.NormalizeRunes([]rune(lowerText))) if !caseSensitive { text = lowerText } @@ -222,14 +227,15 @@ func parseTerms(fuzzy bool, caseMode Case, normalize bool, str string) []termSet set = termSet{} } textRunes := []rune(text) - if normalize { + if normalizeTerm { textRunes = algo.NormalizeRunes(textRunes) } set = append(set, term{ typ: typ, inv: inv, text: textRunes, - caseSensitive: caseSensitive}) + caseSensitive: caseSensitive, + normalize: normalizeTerm}) switchSet = true } } @@ -360,7 +366,7 @@ func (p *Pattern) extendedMatch(item *Item, withPos bool, slab *util.Slab) ([]Of matched := false for _, term := range termSet { pfun := p.procFun[term.typ] - off, score, pos := p.iter(pfun, input, term.caseSensitive, p.normalize, p.forward, term.text, withPos, slab) + off, score, pos := p.iter(pfun, input, term.caseSensitive, term.normalize, p.forward, term.text, withPos, slab) if sidx := off[0]; sidx >= 0 { if term.inv { continue diff --git a/test/test_go.rb b/test/test_go.rb index 75e84ec4..2afb5b81 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1805,6 +1805,14 @@ class TestGoFZF < TestBase tmux.until { |lines| lines.item_count == 1 } tmux.until { |lines| assert_match %r{121.*121/1000}, lines[1] } end + + def test_normalized_match + echoes = '(echo a; echo á; echo A; echo Á;)' + assert_equal %w[a á A Á], `#{echoes} | #{FZF} -f a`.lines.map(&:chomp) + assert_equal %w[á Á], `#{echoes} | #{FZF} -f á`.lines.map(&:chomp) + assert_equal %w[A Á], `#{echoes} | #{FZF} -f A`.lines.map(&:chomp) + assert_equal %w[Á], `#{echoes} | #{FZF} -f Á`.lines.map(&:chomp) + end end module TestShell