From e4a49dbb2a50b0319a4ec5f09dd78eccddd19e3c Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sat, 16 Nov 2013 00:58:46 +0900 Subject: [PATCH] Add exact-match and invert-exact-match match types --- README.md | 16 +++++++++------- fzf | 23 ++++++++++++++++++----- test/test_fzf.rb | 8 ++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e840eae..b33bebe 100644 --- a/README.md +++ b/README.md @@ -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 ------------------- diff --git a/fzf b/fzf index 14c2a12..e097541 100755 --- a/fzf +++ b/fzf @@ -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]]]] diff --git a/test/test_fzf.rb b/test/test_fzf.rb index 681db5f..69cfa2f 100644 --- a/test/test_fzf.rb +++ b/test/test_fzf.rb @@ -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