Implement --extended-exact option (#24)
This commit is contained in:
parent
b22fd6de6d
commit
2dbca00bfb
@ -50,6 +50,7 @@ usage: fzf [options]
|
|||||||
Options
|
Options
|
||||||
-m, --multi Enable multi-select
|
-m, --multi Enable multi-select
|
||||||
-x, --extended Extended-search mode
|
-x, --extended Extended-search mode
|
||||||
|
-e, --extended-exact Extended-search mode (exact match)
|
||||||
-q, --query=STR Initial query
|
-q, --query=STR Initial query
|
||||||
-f, --filter=STR Filter mode. Do not start interactive finder.
|
-f, --filter=STR Filter mode. Do not start interactive finder.
|
||||||
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
|
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
|
||||||
@ -120,6 +121,9 @@ such as: `^music .mp3$ sbtrkt !rmx`
|
|||||||
| `'wild` | Items that include `wild` | exact-match (quoted) |
|
| `'wild` | Items that include `wild` | exact-match (quoted) |
|
||||||
| `!'fire` | Items that do not include `fire` | inverse-exact-match |
|
| `!'fire` | Items that do not include `fire` | inverse-exact-match |
|
||||||
|
|
||||||
|
If you don't need fuzzy matching and do not wish to "quote" every word, start
|
||||||
|
fzf with `-e` or `--extended-exact` option.
|
||||||
|
|
||||||
Useful examples
|
Useful examples
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
42
fzf
42
fzf
@ -7,7 +7,7 @@
|
|||||||
# / __/ / /_/ __/
|
# / __/ / /_/ __/
|
||||||
# /_/ /___/_/ Fuzzy finder for your shell
|
# /_/ /___/_/ Fuzzy finder for your shell
|
||||||
#
|
#
|
||||||
# Version: 0.7.3 (February 20, 2014)
|
# Version: 0.7.3 (March 4, 2014)
|
||||||
#
|
#
|
||||||
# Author: Junegunn Choi
|
# Author: Junegunn Choi
|
||||||
# URL: https://github.com/junegunn/fzf
|
# URL: https://github.com/junegunn/fzf
|
||||||
@ -78,7 +78,7 @@ class FZF
|
|||||||
@sort = ENV.fetch('FZF_DEFAULT_SORT', 1000).to_i
|
@sort = ENV.fetch('FZF_DEFAULT_SORT', 1000).to_i
|
||||||
@color = true
|
@color = true
|
||||||
@multi = false
|
@multi = false
|
||||||
@extended = false
|
@extended = nil
|
||||||
@mouse = true
|
@mouse = true
|
||||||
@filter = nil
|
@filter = nil
|
||||||
|
|
||||||
@ -95,8 +95,8 @@ class FZF
|
|||||||
when '-h', '--help' then usage 0
|
when '-h', '--help' then usage 0
|
||||||
when '-m', '--multi' then @multi = true
|
when '-m', '--multi' then @multi = true
|
||||||
when '+m', '--no-multi' then @multi = false
|
when '+m', '--no-multi' then @multi = false
|
||||||
when '-x', '--extended' then @extended = true
|
when '-x', '--extended' then @extended = :fuzzy
|
||||||
when '+x', '--no-extended' then @extended = false
|
when '+x', '--no-extended' then @extended = nil
|
||||||
when '-i' then @rxflag = Regexp::IGNORECASE
|
when '-i' then @rxflag = Regexp::IGNORECASE
|
||||||
when '+i' then @rxflag = 0
|
when '+i' then @rxflag = 0
|
||||||
when '-c', '--color' then @color = true
|
when '-c', '--color' then @color = true
|
||||||
@ -119,6 +119,8 @@ class FZF
|
|||||||
@sort = sort.to_i
|
@sort = sort.to_i
|
||||||
when /^-s([0-9]+)$/, /^--sort=([0-9]+)$/
|
when /^-s([0-9]+)$/, /^--sort=([0-9]+)$/
|
||||||
@sort = $1.to_i
|
@sort = $1.to_i
|
||||||
|
when '-e', '--extended-exact' then @extended = :exact
|
||||||
|
when '+e', '--no-extended-exact' then @extended = nil
|
||||||
else
|
else
|
||||||
usage 1, "illegal option: #{o}"
|
usage 1, "illegal option: #{o}"
|
||||||
end
|
end
|
||||||
@ -162,14 +164,21 @@ class FZF
|
|||||||
end
|
end
|
||||||
|
|
||||||
def filter_list list
|
def filter_list list
|
||||||
matcher = (@extended ? ExtendedFuzzyMatcher : FuzzyMatcher).new @rxflag
|
matches = get_matcher.match(list, @filter, '', '')
|
||||||
matches = matcher.match(list, @filter, '', '')
|
|
||||||
if @sort && matches.length <= @sort
|
if @sort && matches.length <= @sort
|
||||||
matches = sort_by_rank(matches)
|
matches = sort_by_rank(matches)
|
||||||
end
|
end
|
||||||
matches.each { |m| puts m.first }
|
matches.each { |m| puts m.first }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_matcher
|
||||||
|
if @extended
|
||||||
|
ExtendedFuzzyMatcher.new @rxflag, @extended
|
||||||
|
else
|
||||||
|
FuzzyMatcher.new @rxflag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def version
|
def version
|
||||||
File.open(__FILE__, 'r') do |f|
|
File.open(__FILE__, 'r') do |f|
|
||||||
f.each_line do |line|
|
f.each_line do |line|
|
||||||
@ -188,6 +197,7 @@ class FZF
|
|||||||
Options
|
Options
|
||||||
-m, --multi Enable multi-select
|
-m, --multi Enable multi-select
|
||||||
-x, --extended Extended-search mode
|
-x, --extended Extended-search mode
|
||||||
|
-e, --extended-exact Extended-search mode (exact match)
|
||||||
-q, --query=STR Initial query
|
-q, --query=STR Initial query
|
||||||
-f, --filter=STR Filter mode. Do not start interactive finder.
|
-f, --filter=STR Filter mode. Do not start interactive finder.
|
||||||
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
|
-s, --sort=MAX Maximum number of matched items to sort (default: 1000)
|
||||||
@ -582,7 +592,7 @@ class FZF
|
|||||||
end
|
end
|
||||||
|
|
||||||
def start_search
|
def start_search
|
||||||
matcher = (@extended ? ExtendedFuzzyMatcher : FuzzyMatcher).new @rxflag
|
matcher = get_matcher
|
||||||
searcher = Thread.new {
|
searcher = Thread.new {
|
||||||
lists = []
|
lists = []
|
||||||
events = {}
|
events = {}
|
||||||
@ -952,9 +962,10 @@ class FZF
|
|||||||
end
|
end
|
||||||
|
|
||||||
class ExtendedFuzzyMatcher < FuzzyMatcher
|
class ExtendedFuzzyMatcher < FuzzyMatcher
|
||||||
def initialize rxflag
|
def initialize rxflag, mode = :fuzzy
|
||||||
super
|
super rxflag
|
||||||
@regexps = {}
|
@regexps = {}
|
||||||
|
@mode = mode
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty? q
|
def empty? q
|
||||||
@ -977,8 +988,11 @@ class FZF
|
|||||||
when /^\^(.*)\$$/
|
when /^\^(.*)\$$/
|
||||||
Regexp.new('^' << sanitize(Regexp.escape($1)) << '$', rxflag_for(w))
|
Regexp.new('^' << sanitize(Regexp.escape($1)) << '$', rxflag_for(w))
|
||||||
when /^'/
|
when /^'/
|
||||||
w.length > 1 ?
|
if @mode == :fuzzy && w.length > 1
|
||||||
Regexp.new(sanitize(Regexp.escape(w[1..-1])), rxflag_for(w)) : nil
|
exact_regex w[1..-1]
|
||||||
|
elsif @mode == :exact
|
||||||
|
exact_regex w
|
||||||
|
end
|
||||||
when /^\^/
|
when /^\^/
|
||||||
w.length > 1 ?
|
w.length > 1 ?
|
||||||
Regexp.new('^' << sanitize(Regexp.escape(w[1..-1])), rxflag_for(w)) : nil
|
Regexp.new('^' << sanitize(Regexp.escape(w[1..-1])), rxflag_for(w)) : nil
|
||||||
@ -986,11 +1000,15 @@ class FZF
|
|||||||
w.length > 1 ?
|
w.length > 1 ?
|
||||||
Regexp.new(sanitize(Regexp.escape(w[0..-2])) << '$', rxflag_for(w)) : nil
|
Regexp.new(sanitize(Regexp.escape(w[0..-2])) << '$', rxflag_for(w)) : nil
|
||||||
else
|
else
|
||||||
fuzzy_regex w
|
@mode == :fuzzy ? fuzzy_regex(w) : exact_regex(w)
|
||||||
end, invert ]
|
end, invert ]
|
||||||
}.select { |pair| pair.first }
|
}.select { |pair| pair.first }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def exact_regex w
|
||||||
|
Regexp.new(sanitize(Regexp.escape(w)), rxflag_for(w))
|
||||||
|
end
|
||||||
|
|
||||||
def match list, q, prefix, suffix
|
def match list, q, prefix, suffix
|
||||||
regexps = parse q
|
regexps = parse q
|
||||||
# Look for prefix cache
|
# Look for prefix cache
|
||||||
|
@ -36,7 +36,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
fzf.query.get
|
fzf.query.get
|
||||||
assert_equal 'goodbye world',
|
assert_equal 'goodbye world',
|
||||||
fzf.filter
|
fzf.filter
|
||||||
assert_equal true, fzf.extended
|
assert_equal :fuzzy, fzf.extended
|
||||||
assert_equal true, fzf.multi
|
assert_equal true, fzf.multi
|
||||||
assert_equal false, fzf.color
|
assert_equal false, fzf.color
|
||||||
assert_equal false, fzf.mouse
|
assert_equal false, fzf.mouse
|
||||||
@ -45,7 +45,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
def test_option_parser
|
def test_option_parser
|
||||||
# Long opts
|
# Long opts
|
||||||
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
||||||
--filter=howdy --extended --no-mouse]
|
--filter=howdy --extended-exact --no-mouse]
|
||||||
assert_equal 2000, fzf.sort
|
assert_equal 2000, fzf.sort
|
||||||
assert_equal true, fzf.multi
|
assert_equal true, fzf.multi
|
||||||
assert_equal false, fzf.color
|
assert_equal false, fzf.color
|
||||||
@ -53,7 +53,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal 0, fzf.rxflag
|
assert_equal 0, fzf.rxflag
|
||||||
assert_equal 'hello', fzf.query.get
|
assert_equal 'hello', fzf.query.get
|
||||||
assert_equal 'howdy', fzf.filter
|
assert_equal 'howdy', fzf.filter
|
||||||
assert_equal true, fzf.extended
|
assert_equal :exact, fzf.extended
|
||||||
|
|
||||||
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello
|
||||||
--filter a --filter b
|
--filter a --filter b
|
||||||
@ -65,7 +65,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal 1, fzf.rxflag
|
assert_equal 1, fzf.rxflag
|
||||||
assert_equal 'b', fzf.filter
|
assert_equal 'b', fzf.filter
|
||||||
assert_equal 'hello', fzf.query.get
|
assert_equal 'hello', fzf.query.get
|
||||||
assert_equal false, fzf.extended
|
assert_equal nil, fzf.extended
|
||||||
|
|
||||||
# Short opts
|
# Short opts
|
||||||
fzf = FZF.new %w[-s 2000 +c -m +i -qhello -x -fhowdy]
|
fzf = FZF.new %w[-s 2000 +c -m +i -qhello -x -fhowdy]
|
||||||
@ -75,7 +75,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal 0, fzf.rxflag
|
assert_equal 0, fzf.rxflag
|
||||||
assert_equal 'hello', fzf.query.get
|
assert_equal 'hello', fzf.query.get
|
||||||
assert_equal 'howdy', fzf.filter
|
assert_equal 'howdy', fzf.filter
|
||||||
assert_equal true, fzf.extended
|
assert_equal :fuzzy, fzf.extended
|
||||||
|
|
||||||
# Left-to-right
|
# Left-to-right
|
||||||
fzf = FZF.new %w[-s 2000 +c -m +i -qhello -x -fgoodbye
|
fzf = FZF.new %w[-s 2000 +c -m +i -qhello -x -fgoodbye
|
||||||
@ -86,7 +86,7 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
assert_equal 1, fzf.rxflag
|
assert_equal 1, fzf.rxflag
|
||||||
assert_equal 'world', fzf.query.get
|
assert_equal 'world', fzf.query.get
|
||||||
assert_equal 'world', fzf.filter
|
assert_equal 'world', fzf.filter
|
||||||
assert_equal false, fzf.extended
|
assert_equal nil, fzf.extended
|
||||||
|
|
||||||
fzf = FZF.new %w[--query hello +s -s 2000 --query=world]
|
fzf = FZF.new %w[--query hello +s -s 2000 --query=world]
|
||||||
assert_equal 2000, fzf.sort
|
assert_equal 2000, fzf.sort
|
||||||
@ -378,6 +378,25 @@ class TestFZF < MiniTest::Unit::TestCase
|
|||||||
FZF.new([]).sort_by_rank(xmatcher.match(list, '01 __', '', '')))
|
FZF.new([]).sort_by_rank(xmatcher.match(list, '01 __', '', '')))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_extended_exact_mode
|
||||||
|
exact = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE, :exact
|
||||||
|
fuzzy = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE, :fuzzy
|
||||||
|
list = %w[
|
||||||
|
extended-exact-mode-not-fuzzy
|
||||||
|
extended'-fuzzy-mode
|
||||||
|
]
|
||||||
|
assert_equal 2, fuzzy.match(list, 'extended', '', '').length
|
||||||
|
assert_equal 2, fuzzy.match(list, 'mode extended', '', '').length
|
||||||
|
assert_equal 2, fuzzy.match(list, 'xtndd', '', '').length
|
||||||
|
assert_equal 2, fuzzy.match(list, "'-fuzzy", '', '').length
|
||||||
|
|
||||||
|
assert_equal 2, exact.match(list, 'extended', '', '').length
|
||||||
|
assert_equal 2, exact.match(list, 'mode extended', '', '').length
|
||||||
|
assert_equal 0, exact.match(list, 'xtndd', '', '').length
|
||||||
|
assert_equal 1, exact.match(list, "'-fuzzy", '', '').length
|
||||||
|
assert_equal 2, exact.match(list, "-fuzzy", '', '').length
|
||||||
|
end
|
||||||
|
|
||||||
if RUBY_PLATFORM =~ /darwin/
|
if RUBY_PLATFORM =~ /darwin/
|
||||||
NFD = '한글'
|
NFD = '한글'
|
||||||
def test_nfc
|
def test_nfc
|
||||||
|
Loading…
Reference in New Issue
Block a user