summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2013-12-20 15:30:48 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2013-12-20 15:30:48 +0900
commit159dd7f06926441f6476ab86bd673281b67f5fe4 (patch)
tree5fccdce34352679044f33b9c096572bbc4e880c4
parentb30f21e07416e20a41e00ef5e55b8e22ef006eb4 (diff)
Implement smart-case match (#12)
-rw-r--r--README.md1
-rwxr-xr-xfzf20
-rw-r--r--test/test_fzf.rb50
3 files changed, 61 insertions, 10 deletions
diff --git a/README.md b/README.md
index 0b96bcdf..b5f00b38 100644
--- a/README.md
+++ b/README.md
@@ -57,6 +57,7 @@ usage: fzf [options]
-q, --query=STR Initial query
-s, --sort=MAX Maximum number of matched items to sort. Default: 1000
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
+ -i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
+c, --no-color Disable colors
```
diff --git a/fzf b/fzf
index ee395ffa..a6a43347 100755
--- a/fzf
+++ b/fzf
@@ -67,7 +67,7 @@ class FZF
end
def initialize argv, source = $stdin
- @rxflag = Regexp::IGNORECASE
+ @rxflag = nil
@sort = ENV.fetch('FZF_DEFAULT_SORT', 1000).to_i
@color = true
@multi = false
@@ -79,6 +79,7 @@ class FZF
when '-h', '--help' then usage 0
when '-m', '--multi' then @multi = true
when '-x', '--extended' then @xmode = true
+ when '-i' then @rxflag = Regexp::IGNORECASE
when '+i' then @rxflag = 0
when '+s', '--no-sort' then @sort = nil
when '+c', '--no-color' then @color = false
@@ -136,6 +137,7 @@ class FZF
-q, --query=STR Initial query
-s, --sort=MAX Maximum number of matched items to sort. Default: 1000
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
+ -i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
+c, --no-color Disable colors]
exit x
@@ -770,14 +772,18 @@ class FZF
q.empty?
end
+ def rxflag_for q
+ @rxflag || (q =~ /[A-Z]/ ? 0 : Regexp::IGNORECASE)
+ end
+
def fuzzy_regex q
@regexp[q] ||= begin
- q = q.downcase if @rxflag != 0
+ q = q.downcase if @rxflag == Regexp::IGNORECASE
Regexp.new(query_chars(q).inject('') { |sum, e|
e = Regexp.escape e
sum << (e.length > 1 ? "(?:#{e}).*?" : # FIXME: not equivalent
"#{e}[^#{e}]*?")
- }, @rxflag)
+ }, rxflag_for(q))
end
end
@@ -830,16 +836,16 @@ class FZF
when ''
nil
when /^\^(.*)\$$/
- Regexp.new('^' << sanitize(Regexp.escape($1)) << '$', rxflag)
+ Regexp.new('^' << sanitize(Regexp.escape($1)) << '$', rxflag_for(w))
when /^'/
w.length > 1 ?
- Regexp.new(sanitize(Regexp.escape(w[1..-1])), rxflag) : nil
+ Regexp.new(sanitize(Regexp.escape(w[1..-1])), rxflag_for(w)) : nil
when /^\^/
w.length > 1 ?
- Regexp.new('^' << sanitize(Regexp.escape(w[1..-1])), rxflag) : nil
+ Regexp.new('^' << sanitize(Regexp.escape(w[1..-1])), rxflag_for(w)) : nil
when /\$$/
w.length > 1 ?
- Regexp.new(sanitize(Regexp.escape(w[0..-2])) << '$', rxflag) : nil
+ Regexp.new(sanitize(Regexp.escape(w[0..-2])) << '$', rxflag_for(w)) : nil
else
fuzzy_regex w
end, invert ]
diff --git a/test/test_fzf.rb b/test/test_fzf.rb
index 98818d75..8133c22c 100644
--- a/test/test_fzf.rb
+++ b/test/test_fzf.rb
@@ -9,10 +9,10 @@ load 'fzf'
class TestFZF < MiniTest::Unit::TestCase
def test_default_options
fzf = FZF.new []
- assert_equal 1000, fzf.sort
+ assert_equal 1000, fzf.sort
assert_equal false, fzf.multi
- assert_equal true, fzf.color
- assert_equal Regexp::IGNORECASE, fzf.rxflag
+ assert_equal true, fzf.color
+ assert_equal nil, fzf.rxflag
begin
ENV['FZF_DEFAULT_SORT'] = '1500'
@@ -152,15 +152,59 @@ class TestFZF < MiniTest::Unit::TestCase
# TODO : partial_cache
end
+ def test_fuzzy_matcher_rxflag
+ assert_equal nil, FZF::FuzzyMatcher.new(nil).rxflag
+ assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag
+ assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag
+
+ assert_equal 1, FZF::FuzzyMatcher.new(nil).rxflag_for('abc')
+ assert_equal 0, FZF::FuzzyMatcher.new(nil).rxflag_for('Abc')
+ assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag_for('abc')
+ assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag_for('Abc')
+ assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag_for('abc')
+ assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag_for('Abc')
+ end
+
def test_fuzzy_matcher_case_sensitive
+ # Smart-case match (Uppercase found)
+ assert_equal [['Fruit', [[0, 5]]]],
+ FZF::FuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
+
+ # Smart-case match (Uppercase not-found)
+ assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
+ FZF::FuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], 'fruit', '', '').sort
+
+ # Case-sensitive match (-i)
assert_equal [['Fruit', [[0, 5]]]],
FZF::FuzzyMatcher.new(0).match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
+ # Case-insensitive match (+i)
assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
FZF::FuzzyMatcher.new(Regexp::IGNORECASE).
match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
end
+ def test_extended_fuzzy_matcher_case_sensitive
+ %w['Fruit Fruit$].each do |q|
+ # Smart-case match (Uppercase found)
+ assert_equal [['Fruit', [[0, 5]]]],
+ FZF::ExtendedFuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], q, '', '').sort
+
+ # Smart-case match (Uppercase not-found)
+ assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
+ FZF::ExtendedFuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], q.downcase, '', '').sort
+
+ # Case-sensitive match (-i)
+ assert_equal [['Fruit', [[0, 5]]]],
+ FZF::ExtendedFuzzyMatcher.new(0).match(%w[Fruit Grapefruit], q, '', '').sort
+
+ # Case-insensitive match (+i)
+ assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
+ FZF::ExtendedFuzzyMatcher.new(Regexp::IGNORECASE).
+ match(%w[Fruit Grapefruit], q, '', '').sort
+ end
+ end
+
def test_extended_fuzzy_matcher
matcher = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE
list = %w[