Add exact-match and invert-exact-match match types

This commit is contained in:
Junegunn Choi 2013-11-16 00:58:46 +09:00
parent 76c7f4f9c0
commit e4a49dbb2a
3 changed files with 35 additions and 12 deletions

View File

@ -114,18 +114,20 @@ The following readline key bindings should also work as expected.
If you enable multi-select mode with `-m` option, you can select multiple items
with TAB or Shift-TAB key.
### Extended mode
### Extended mode (WIP)
With `-x` or `--extended` option, fzf will start in "extended mode".
In extended mode, you can specify multiple patterns delimited by spaces, such as: `^music .mp3$ sbtrkt !rmx`
| Token | Description | Match type |
| -------- | ----------------------------- | -------------------- |
| `^music` | Items that start with `music` | prefix-exact-match |
| `.mp3$` | Items that end with `.mp3` | suffix-exact-match |
| `sbtrkt` | Items that match `sbtrkt` | fuzzy-match |
| `!rmx` | Items that do not match `rmx` | invert-fuzzy-match |
| Token | Description | Match type |
| ----------- | -------------------------------- | -------------------- |
| `^music` | Items that start with `music` | prefix-exact-match |
| `.mp3$` | Items that end with `.mp3` | suffix-exact-match |
| `sbtrkt` | Items that match `sbtrkt` | fuzzy-match |
| `!rmx` | Items that do not match `rmx` | invert-fuzzy-match |
| `'wild` | Items that include `wild` | exact-match |
| `!'fire` | Items that do not include `fire` | invert-exact-match |
Usage as Vim plugin
-------------------

23
fzf
View File

@ -549,7 +549,7 @@ class FZF
end)
mcount = @matches.length
if @sort && mcount <= @sort && !q.empty?
if @sort && mcount <= @sort && !matcher.empty?(q)
@matches.set { |m| sort_by_rank m }
end
end#new_search
@ -697,6 +697,10 @@ class FZF
@rxflag = rxflag
end
def empty? q
q.empty?
end
def fuzzy_regex q
@regexp[q] ||= begin
q = q.downcase if @rxflag != 0
@ -739,10 +743,13 @@ class FZF
@regexps = {}
end
def match list, q, prefix, suffix
q = q.strip
def empty? q
parse(q).empty?
end
regexps = @regexps[q] ||= q.split(/\s+/).map { |w|
def parse q
q = q.strip
@regexps[q] ||= q.split(/\s+/).map { |w|
invert =
if w =~ /^!/
w = w[1..-1]
@ -753,6 +760,9 @@ class FZF
case w
when ''
nil
when /^'/
w.length > 1 ?
Regexp.new(Regexp.escape(w[1..-1]), rxflag) : nil
when /^\^/
w.length > 1 ?
Regexp.new('^' << Regexp.escape(w[1..-1]), rxflag) : nil
@ -763,10 +773,13 @@ class FZF
fuzzy_regex w
end, invert ]
}.select { |pair| pair.first }
end
def match list, q, prefix, suffix
regexps = parse q
# Look for prefix cache
cache = @caches[list.object_id]
prefix = prefix.strip.sub(/\$\S+$/, '').sub(/!\S+$/, '')
prefix = prefix.strip.sub(/\$\S*$/, '').sub(/(^|\s)!\S*$/, '')
prefix_cache = nil
(prefix.length - 1).downto(1) do |len|
break if prefix_cache = cache[Set[@regexps[prefix[0, len]]]]

View File

@ -194,6 +194,14 @@ class TestFZF < MiniTest::Unit::TestCase
# ! + f
assert_equal [["juicy", [[4, 5]]]], match.call('y !l', '')
# '
assert_equal %w[juiceful juiceless juicily],
match.call('il', '').map { |e| e.first }
assert_equal %w[juicily],
match.call("'il", '').map { |e| e.first }
assert_equal (list - %w[juicily]).sort,
match.call("!'il", '').map { |e| e.first }.sort
end
assert !matcher.caches.empty?
end