From 910a1de4c56e8651ce5e6fecbcfd08f51d45a875 Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Thu, 26 Dec 2019 22:30:09 -0500 Subject: [PATCH] Fix some parser bugs around mixing [ and ( --- server/query.go | 22 +++++++++++++++------- server/query_test.go | 22 ++++++++++++++++++++-- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/server/query.go b/server/query.go index 8a52129b6..333ddffc9 100644 --- a/server/query.go +++ b/server/query.go @@ -12,7 +12,7 @@ import ( pb "github.com/livegrep/livegrep/src/proto/go_proto" ) -var pieceRE = regexp.MustCompile(`\(|(?:^([a-zA-Z0-9-_]+):|\\.)| `) +var pieceRE = regexp.MustCompile(`\[|\(|(?:^([a-zA-Z0-9-_]+):|\\.)| `) var knownTags = map[string]bool{ "file": true, @@ -79,16 +79,24 @@ func ParseQuery(query string, globalRegex bool) (pb.Query, error) { term = "" inRegex = globalRegex } - } else if match == "(" { + } else if match == "(" || match == "[" { if !(inRegex || justGotSpace) { - term += "(" + term += match } else { - // A parenthesis. Nothing is special until the - // end of a balanced set of parenthesis + // A parenthesis or a bracket. Consume + // until the end of a balanced set. p := 1 i := 0 esc := false var w bytes.Buffer + var open, close rune + switch match { + case "(": + open, close = '(', ')' + case "[": + open, close = '[', ']' + } + for i < len(q) { // We decode runes ourselves instead // of using range because exiting the @@ -101,9 +109,9 @@ func ParseQuery(query string, globalRegex bool) (pb.Query, error) { esc = false case r == '\\': esc = true - case r == '(': + case r == open: p++ - case r == ')': + case r == close: p-- } w.WriteRune(r) diff --git a/server/query_test.go b/server/query_test.go index 8cba455c9..960556080 100644 --- a/server/query_test.go +++ b/server/query_test.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "reflect" "testing" @@ -153,6 +154,21 @@ func TestParseQuery(t *testing.T) { pb.Query{Line: `a\(b`, File: "c", FoldCase: false}, true, }, + { + `[(] file:\.c`, + pb.Query{Line: `[(]`, File: "\\.c", FoldCase: true}, + true, + }, + { + `[ ] file:\.c`, + pb.Query{Line: `[ ]`, File: "\\.c", FoldCase: true}, + true, + }, + { + `[ \]] file:\.c`, + pb.Query{Line: `[ \]]`, File: "\\.c", FoldCase: true}, + true, + }, // literal parse mode { @@ -200,8 +216,10 @@ func TestParseQuery(t *testing.T) { for _, tc := range cases { parsed, err := ParseQuery(tc.in, tc.regex) if !reflect.DeepEqual(tc.out, parsed) { - t.Errorf("error parsing %q: expected %#v got %#v", - tc.in, tc.out, parsed) + got, _ := json.MarshalIndent(parsed, "", " ") + want, _ := json.MarshalIndent(tc.out, "", " ") + t.Errorf("error parsing %q: expected:\n%s\ngot:\n%s", + tc.in, want, got) } if err != nil { t.Errorf("parse(%v) error=%v", tc.in, err)