diff options
author | Junegunn Choi <junegunn.c@gmail.com> | 2015-11-03 22:49:32 +0900 |
---|---|---|
committer | Junegunn Choi <junegunn.c@gmail.com> | 2015-11-03 22:49:32 +0900 |
commit | 81a88693c12507bcc460bd1150af0f48f917670c (patch) | |
tree | c4fc4449ad6f82dc834c211ec8e5a855528701c9 /src | |
parent | 68541e66b7b4735fc720d5298ffb3d99b115025b (diff) |
Make --extended default
Close #400
Diffstat (limited to 'src')
-rw-r--r-- | src/core.go | 2 | ||||
-rw-r--r-- | src/options.go | 39 | ||||
-rw-r--r-- | src/options_test.go | 2 | ||||
-rw-r--r-- | src/pattern.go | 50 | ||||
-rw-r--r-- | src/pattern_test.go | 28 |
5 files changed, 62 insertions, 59 deletions
diff --git a/src/core.go b/src/core.go index 35d7cedb..becaed4b 100644 --- a/src/core.go +++ b/src/core.go @@ -143,7 +143,7 @@ func Run(opts *Options) { // Matcher patternBuilder := func(runes []rune) *Pattern { return BuildPattern( - opts.Mode, opts.Case, opts.Tiebreak != byEnd, + opts.Fuzzy, opts.Extended, opts.Case, opts.Tiebreak != byEnd, opts.Nth, opts.Delimiter, runes) } matcher := NewMatcher(patternBuilder, sort, opts.Tac, eventBox) diff --git a/src/options.go b/src/options.go index 16de221a..42b27f34 100644 --- a/src/options.go +++ b/src/options.go @@ -16,7 +16,8 @@ const usage = `usage: fzf [options] Search -x, --extended Extended-search mode - -e, --extended-exact Extended-search mode (exact match) + (enabled by default; +x or --no-extended to disable) + -e, --exact Enable Exact-match -i Case-insensitive match (default: smart-case match) +i Case-sensitive match -n, --nth=N[,..] Comma-separated list of field index expressions @@ -58,20 +59,10 @@ const usage = `usage: fzf [options] Environment variables FZF_DEFAULT_COMMAND Default command to use when input is tty - FZF_DEFAULT_OPTS Defaults options. (e.g. '-x -m') + FZF_DEFAULT_OPTS Defaults options. (e.g. '--reverse --inline-info') ` -// Mode denotes the current search mode -type Mode int - -// Search modes -const ( - ModeFuzzy Mode = iota - ModeExtended - ModeExtendedExact -) - // Case denotes case-sensitivity of search type Case int @@ -98,7 +89,8 @@ func defaultMargin() [4]string { // Options stores the values of command-line options type Options struct { - Mode Mode + Fuzzy bool + Extended bool Case Case Nth []Range WithNth []Range @@ -143,7 +135,8 @@ func defaultTheme() *curses.ColorTheme { func defaultOptions() *Options { return &Options{ - Mode: ModeFuzzy, + Fuzzy: true, + Extended: true, Case: CaseSmart, Nth: make([]Range, 0), WithNth: make([]Range, 0), @@ -684,11 +677,17 @@ func parseOptions(opts *Options, allArgs []string) { case "-h", "--help": help(exitOk) case "-x", "--extended": - opts.Mode = ModeExtended - case "-e", "--extended-exact": - opts.Mode = ModeExtendedExact - case "+x", "--no-extended", "+e", "--no-extended-exact": - opts.Mode = ModeFuzzy + opts.Extended = true + case "-e", "--exact": + opts.Fuzzy = false + case "--extended-exact": + // Note that we now don't have --no-extended-exact + opts.Fuzzy = false + opts.Extended = true + case "+x", "--no-extended": + opts.Extended = false + case "+e", "--no-exact": + opts.Fuzzy = true case "-q", "--query": opts.Query = nextString(allArgs, &i, "query string required") case "-f", "--filter": @@ -873,7 +872,7 @@ func parseOptions(opts *Options, allArgs []string) { // If we're not using extended search mode, --nth option becomes irrelevant // if it contains the whole range - if opts.Mode == ModeFuzzy || len(opts.Nth) == 1 { + if !opts.Extended || len(opts.Nth) == 1 { for _, r := range opts.Nth { if r.begin == rangeEllipsis && r.end == rangeEllipsis { opts.Nth = make([]Range, 0) diff --git a/src/options_test.go b/src/options_test.go index 1e9ede4e..ef86abec 100644 --- a/src/options_test.go +++ b/src/options_test.go @@ -100,7 +100,7 @@ func TestIrrelevantNth(t *testing.T) { t.Errorf("nth should be empty: %s", opts.Nth) } } - for _, words := range [][]string{[]string{"--nth", "..,3"}, []string{"--nth", "3,1.."}, []string{"--nth", "..-1,1"}} { + for _, words := range [][]string{[]string{"--nth", "..,3", "+x"}, []string{"--nth", "3,1..", "+x"}, []string{"--nth", "..-1,1", "+x"}} { { opts := defaultOptions() parseOptions(opts, words) diff --git a/src/pattern.go b/src/pattern.go index f5dd8a75..7c81ea02 100644 --- a/src/pattern.go +++ b/src/pattern.go @@ -38,7 +38,8 @@ type term struct { // Pattern represents search pattern type Pattern struct { - mode Mode + fuzzy bool + extended bool caseSensitive bool forward bool text []rune @@ -63,7 +64,7 @@ func init() { func clearPatternCache() { // We can uniquely identify the pattern for a given string since - // mode and caseMode do not change while the program is running + // search mode and caseMode do not change while the program is running _patternCache = make(map[string]*Pattern) } @@ -72,14 +73,13 @@ func clearChunkCache() { } // BuildPattern builds Pattern object from the given arguments -func BuildPattern(mode Mode, caseMode Case, forward bool, +func BuildPattern(fuzzy bool, extended bool, caseMode Case, forward bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern { var asString string - switch mode { - case ModeExtended, ModeExtendedExact: + if extended { asString = strings.Trim(string(runes), " ") - default: + } else { asString = string(runes) } @@ -91,15 +91,14 @@ func BuildPattern(mode Mode, caseMode Case, forward bool, caseSensitive, hasInvTerm := true, false terms := []term{} - switch mode { - case ModeExtended, ModeExtendedExact: - terms = parseTerms(mode, caseMode, asString) + if extended { + terms = parseTerms(fuzzy, caseMode, asString) for _, term := range terms { if term.inv { hasInvTerm = true } } - default: + } else { lowerString := strings.ToLower(asString) caseSensitive = caseMode == CaseRespect || caseMode == CaseSmart && lowerString != asString @@ -109,7 +108,8 @@ func BuildPattern(mode Mode, caseMode Case, forward bool, } ptr := &Pattern{ - mode: mode, + fuzzy: fuzzy, + extended: extended, caseSensitive: caseSensitive, forward: forward, text: []rune(asString), @@ -129,7 +129,7 @@ func BuildPattern(mode Mode, caseMode Case, forward bool, return ptr } -func parseTerms(mode Mode, caseMode Case, str string) []term { +func parseTerms(fuzzy bool, caseMode Case, str string) []term { tokens := _splitRegex.Split(str, -1) terms := []term{} for _, token := range tokens { @@ -141,7 +141,7 @@ func parseTerms(mode Mode, caseMode Case, str string) []term { text = lowerText } origText := []rune(text) - if mode == ModeExtendedExact { + if !fuzzy { typ = termExact } @@ -151,10 +151,11 @@ func parseTerms(mode Mode, caseMode Case, str string) []term { } if strings.HasPrefix(text, "'") { - if mode == ModeExtended { + // Flip exactness + if fuzzy { typ = termExact text = text[1:] - } else if mode == ModeExtendedExact { + } else { typ = termFuzzy text = text[1:] } @@ -185,7 +186,7 @@ func parseTerms(mode Mode, caseMode Case, str string) []term { // IsEmpty returns true if the pattern is effectively empty func (p *Pattern) IsEmpty() bool { - if p.mode == ModeFuzzy { + if !p.extended { return len(p.text) == 0 } return len(p.terms) == 0 @@ -198,7 +199,7 @@ func (p *Pattern) AsString() string { // CacheKey is used to build string to be used as the key of result cache func (p *Pattern) CacheKey() string { - if p.mode == ModeFuzzy { + if !p.extended { return p.AsString() } cacheableTerms := []string{} @@ -250,9 +251,9 @@ Loop: func (p *Pattern) matchChunk(chunk *Chunk) []*Item { matches := []*Item{} - if p.mode == ModeFuzzy { + if !p.extended { for _, item := range *chunk { - if sidx, eidx, tlen := p.fuzzyMatch(item); sidx >= 0 { + if sidx, eidx, tlen := p.basicMatch(item); sidx >= 0 { matches = append(matches, dupItem(item, []Offset{Offset{int32(sidx), int32(eidx), int32(tlen)}})) } @@ -269,8 +270,8 @@ func (p *Pattern) matchChunk(chunk *Chunk) []*Item { // MatchItem returns true if the Item is a match func (p *Pattern) MatchItem(item *Item) bool { - if p.mode == ModeFuzzy { - sidx, _, _ := p.fuzzyMatch(item) + if !p.extended { + sidx, _, _ := p.basicMatch(item) return sidx >= 0 } offsets := p.extendedMatch(item) @@ -289,9 +290,12 @@ func dupItem(item *Item, offsets []Offset) *Item { rank: Rank{0, 0, item.index}} } -func (p *Pattern) fuzzyMatch(item *Item) (int, int, int) { +func (p *Pattern) basicMatch(item *Item) (int, int, int) { input := p.prepareInput(item) - return p.iter(algo.FuzzyMatch, input, p.caseSensitive, p.forward, p.text) + if p.fuzzy { + return p.iter(algo.FuzzyMatch, input, p.caseSensitive, p.forward, p.text) + } + return p.iter(algo.ExactMatchNaive, input, p.caseSensitive, p.forward, p.text) } func (p *Pattern) extendedMatch(item *Item) []Offset { diff --git a/src/pattern_test.go b/src/pattern_test.go index d5086128..8b41a695 100644 --- a/src/pattern_test.go +++ b/src/pattern_test.go @@ -8,7 +8,7 @@ import ( ) func TestParseTermsExtended(t *testing.T) { - terms := parseTerms(ModeExtended, CaseSmart, + terms := parseTerms(true, CaseSmart, "aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$ ^iii$") if len(terms) != 9 || terms[0].typ != termFuzzy || terms[0].inv || @@ -33,7 +33,7 @@ func TestParseTermsExtended(t *testing.T) { } func TestParseTermsExtendedExact(t *testing.T) { - terms := parseTerms(ModeExtendedExact, CaseSmart, + terms := parseTerms(false, CaseSmart, "aaa 'bbb ^ccc ddd$ !eee !'fff !^ggg !hhh$") if len(terms) != 8 || terms[0].typ != termExact || terms[0].inv || len(terms[0].text) != 3 || @@ -49,7 +49,7 @@ func TestParseTermsExtendedExact(t *testing.T) { } func TestParseTermsEmpty(t *testing.T) { - terms := parseTerms(ModeExtended, CaseSmart, "' $ ^ !' !^ !$") + terms := parseTerms(true, CaseSmart, "' $ ^ !' !^ !$") if len(terms) != 0 { t.Errorf("%s", terms) } @@ -58,7 +58,7 @@ func TestParseTermsEmpty(t *testing.T) { func TestExact(t *testing.T) { defer clearPatternCache() clearPatternCache() - pattern := BuildPattern(ModeExtended, CaseSmart, true, + pattern := BuildPattern(true, true, CaseSmart, true, []Range{}, Delimiter{}, []rune("'abc")) sidx, eidx := algo.ExactMatchNaive( pattern.caseSensitive, pattern.forward, []rune("aabbcc abc"), pattern.terms[0].text) @@ -70,7 +70,7 @@ func TestExact(t *testing.T) { func TestEqual(t *testing.T) { defer clearPatternCache() clearPatternCache() - pattern := BuildPattern(ModeExtended, CaseSmart, true, []Range{}, Delimiter{}, []rune("^AbC$")) + pattern := BuildPattern(true, true, CaseSmart, true, []Range{}, Delimiter{}, []rune("^AbC$")) match := func(str string, sidxExpected int, eidxExpected int) { sidx, eidx := algo.EqualMatch( @@ -86,17 +86,17 @@ func TestEqual(t *testing.T) { func TestCaseSensitivity(t *testing.T) { defer clearPatternCache() clearPatternCache() - pat1 := BuildPattern(ModeFuzzy, CaseSmart, true, []Range{}, Delimiter{}, []rune("abc")) + pat1 := BuildPattern(true, false, CaseSmart, true, []Range{}, Delimiter{}, []rune("abc")) clearPatternCache() - pat2 := BuildPattern(ModeFuzzy, CaseSmart, true, []Range{}, Delimiter{}, []rune("Abc")) + pat2 := BuildPattern(true, false, CaseSmart, true, []Range{}, Delimiter{}, []rune("Abc")) clearPatternCache() - pat3 := BuildPattern(ModeFuzzy, CaseIgnore, true, []Range{}, Delimiter{}, []rune("abc")) + pat3 := BuildPattern(true, false, CaseIgnore, true, []Range{}, Delimiter{}, []rune("abc")) clearPatternCache() - pat4 := BuildPattern(ModeFuzzy, CaseIgnore, true, []Range{}, Delimiter{}, []rune("Abc")) + pat4 := BuildPattern(true, false, CaseIgnore, true, []Range{}, Delimiter{}, []rune("Abc")) clearPatternCache() - pat5 := BuildPattern(ModeFuzzy, CaseRespect, true, []Range{}, Delimiter{}, []rune("abc")) + pat5 := BuildPattern(true, false, CaseRespect, true, []Range{}, Delimiter{}, []rune("abc")) clearPatternCache() - pat6 := BuildPattern(ModeFuzzy, CaseRespect, true, []Range{}, Delimiter{}, []rune("Abc")) + pat6 := BuildPattern(true, false, CaseRespect, true, []Range{}, Delimiter{}, []rune("Abc")) if string(pat1.text) != "abc" || pat1.caseSensitive != false || string(pat2.text) != "Abc" || pat2.caseSensitive != true || @@ -109,19 +109,19 @@ func TestCaseSensitivity(t *testing.T) { } func TestOrigTextAndTransformed(t *testing.T) { - pattern := BuildPattern(ModeExtended, CaseSmart, true, []Range{}, Delimiter{}, []rune("jg")) + pattern := BuildPattern(true, true, CaseSmart, true, []Range{}, Delimiter{}, []rune("jg")) tokens := Tokenize([]rune("junegunn"), Delimiter{}) trans := Transform(tokens, []Range{Range{1, 1}}) origRunes := []rune("junegunn.choi") - for _, mode := range []Mode{ModeFuzzy, ModeExtended} { + for _, extended := range []bool{false, true} { chunk := Chunk{ &Item{ text: []rune("junegunn"), origText: &origRunes, transformed: trans}, } - pattern.mode = mode + pattern.extended = extended matches := pattern.matchChunk(&chunk) if string(matches[0].text) != "junegunn" || string(*matches[0].origText) != "junegunn.choi" || matches[0].offsets[0][0] != 0 || matches[0].offsets[0][1] != 5 || |