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 If you enable multi-select mode with `-m` option, you can select multiple items
with TAB or Shift-TAB key. with TAB or Shift-TAB key.
### Extended mode ### Extended mode (WIP)
With `-x` or `--extended` option, fzf will start in "extended mode". 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` In extended mode, you can specify multiple patterns delimited by spaces, such as: `^music .mp3$ sbtrkt !rmx`
| Token | Description | Match type | | Token | Description | Match type |
| -------- | ----------------------------- | -------------------- | | ----------- | -------------------------------- | -------------------- |
| `^music` | Items that start with `music` | prefix-exact-match | | `^music` | Items that start with `music` | prefix-exact-match |
| `.mp3$` | Items that end with `.mp3` | suffix-exact-match | | `.mp3$` | Items that end with `.mp3` | suffix-exact-match |
| `sbtrkt` | Items that match `sbtrkt` | fuzzy-match | | `sbtrkt` | Items that match `sbtrkt` | fuzzy-match |
| `!rmx` | Items that do not match `rmx` | invert-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 Usage as Vim plugin
------------------- -------------------

23
fzf
View File

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

View File

@ -194,6 +194,14 @@ class TestFZF < MiniTest::Unit::TestCase
# ! + f # ! + f
assert_equal [["juicy", [[4, 5]]]], match.call('y !l', '') 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 end
assert !matcher.caches.empty? assert !matcher.caches.empty?
end end