Skip to content
Permalink
Browse files

pattern: support Mode in all APIs

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 91c3a2981cadb79aa3803842e0c3a007f2be61ec
Showing with 41 additions and 21 deletions.
  1. +5 −3 expand/expand.go
  2. +3 −2 pattern/example_test.go
  3. +17 −4 pattern/pattern.go
  4. +16 −12 pattern/pattern_test.go
@@ -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.
@@ -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)
}
@@ -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
}
}
@@ -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
}
@@ -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 (
@@ -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
@@ -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
@@ -288,6 +297,10 @@ loop:
switch r {
case '*', '?', '[', '\\':
buf.WriteByte('\\')
case '{':
if mode&Braces != 0 {
buf.WriteByte('\\')
}
}
buf.WriteRune(r)
}
@@ -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.
You can’t perform that action at this time.