Skip to content

Commit

Permalink
pattern: support Mode in all APIs
Browse files Browse the repository at this point in the history
And document the type.

This is perhaps the last remaining API change that was planned for v3.
  • Loading branch information
mvdan committed Dec 16, 2019
1 parent 7819eef commit 91c3a29
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
8 changes: 5 additions & 3 deletions expand/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ func Document(cfg *Config, word *syntax.Word) (string, error) {
return cfg.fieldJoin(field), nil
}

const patMode = pattern.Filenames | pattern.Braces

// Pattern expands a single shell word as a pattern, using syntax.QuotePattern
// on any non-quoted parts of the input word. The result can be used on
// syntax.TranslatePattern directly.
Expand All @@ -174,7 +176,7 @@ func Pattern(cfg *Config, word *syntax.Word) (string, error) {
buf := cfg.strBuilder()
for _, part := range field {
if part.quote > quoteNone {
buf.WriteString(pattern.QuoteMeta(part.val))
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
} else {
buf.WriteString(part.val)
}
Expand Down Expand Up @@ -345,11 +347,11 @@ func (cfg *Config) escapedGlobField(parts []fieldPart) (escaped string, glob boo
buf := cfg.strBuilder()
for _, part := range parts {
if part.quote > quoteNone {
buf.WriteString(pattern.QuoteMeta(part.val))
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
continue
}
buf.WriteString(part.val)
if pattern.HasMeta(part.val) {
if pattern.HasMeta(part.val, patMode) {
glob = true
}
}
Expand Down
5 changes: 3 additions & 2 deletions pattern/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ func ExampleRegexp() {

func ExampleQuoteMeta() {
pat := "foo?bar*"
const mode = 0
fmt.Println(pat)

quoted := pattern.QuoteMeta(pat)
quoted := pattern.QuoteMeta(pat, mode)
fmt.Println(quoted)

expr, err := pattern.Regexp(quoted, 0)
expr, err := pattern.Regexp(quoted, mode)
if err != nil {
return
}
Expand Down
21 changes: 17 additions & 4 deletions pattern/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
"strings"
)

// TODO: support Mode in the other APIs too

// Mode can be used to supply a number of options to the package's functions.
// Not all functions change their behavior with all of the options below.
type Mode uint

const (
Expand Down Expand Up @@ -254,13 +254,17 @@ func charClass(s string) (string, error) {
// This can be useful to avoid extra work, like TranslatePattern. Note that this
// function cannot be used to avoid QuotePattern, as backslashes are quoted by
// that function but ignored here.
func HasMeta(pat string) bool {
func HasMeta(pat string, mode Mode) bool {
for i := 0; i < len(pat); i++ {
switch pat[i] {
case '\\':
i++
case '*', '?', '[':
return true
case '{':
if mode&Braces != 0 {
return true
}
}
}
return false
Expand All @@ -270,11 +274,16 @@ func HasMeta(pat string) bool {
// given text. The returned string is a pattern that matches the literal text.
//
// For example, QuoteMeta(`foo*bar?`) returns `foo\*bar\?`.
func QuoteMeta(pat string) string {
func QuoteMeta(pat string, mode Mode) string {
any := false
loop:
for _, r := range pat {
switch r {
case '{':
if mode&Braces == 0 {
continue
}
fallthrough
case '*', '?', '[', '\\':
any = true
break loop
Expand All @@ -288,6 +297,10 @@ loop:
switch r {
case '*', '?', '[', '\\':
buf.WriteByte('\\')
case '{':
if mode&Braces != 0 {
buf.WriteByte('\\')
}
}
buf.WriteRune(r)
}
Expand Down
28 changes: 16 additions & 12 deletions pattern/pattern_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,31 @@ func TestRegexp(t *testing.T) {

var metaTests = []struct {
pat string
mode Mode
wantHas bool
wantQuote string
}{
{``, false, ``},
{`foo`, false, `foo`},
{`.`, false, `.`},
{`*`, true, `\*`},
{`foo?`, true, `foo\?`},
{`\[`, false, `\\\[`},
{``, 0, false, ``},
{`foo`, 0, false, `foo`},
{`.`, 0, false, `.`},
{`*`, 0, true, `\*`},
{`*`, Shortest | Filenames, true, `\*`},
{`foo?`, 0, true, `foo\?`},
{`\[`, 0, false, `\\\[`},
{`{`, 0, false, `{`},
{`{`, Braces, true, `\{`},
}

func TestMeta(t *testing.T) {
t.Parallel()
for _, tc := range metaTests {
if got := HasMeta(tc.pat); got != tc.wantHas {
t.Errorf("HasMeta(%q) got %t, wanted %t",
tc.pat, got, tc.wantHas)
if got := HasMeta(tc.pat, tc.mode); got != tc.wantHas {
t.Errorf("HasMeta(%q, %b) got %t, wanted %t",
tc.pat, tc.mode, got, tc.wantHas)
}
if got := QuoteMeta(tc.pat); got != tc.wantQuote {
t.Errorf("QuoteMeta(%q) got %q, wanted %q",
tc.pat, got, tc.wantQuote)
if got := QuoteMeta(tc.pat, tc.mode); got != tc.wantQuote {
t.Errorf("QuoteMeta(%q, %b) got %q, wanted %q",
tc.pat, tc.mode, got, tc.wantQuote)
}
}
}

0 comments on commit 91c3a29

Please sign in to comment.