gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/client9/misspell/ignore/glob.go (about)

     1  package ignore
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/gobwas/glob"
     8  )
     9  
    10  // Matcher defines an interface for filematchers
    11  //
    12  type Matcher interface {
    13  	Match(string) bool
    14  	True() bool
    15  	MarshalText() ([]byte, error)
    16  }
    17  
    18  // MultiMatch has matching on a list of matchers
    19  type MultiMatch struct {
    20  	matchers []Matcher
    21  }
    22  
    23  // NewMultiMatch creates a new MultiMatch instance
    24  func NewMultiMatch(matchers []Matcher) *MultiMatch {
    25  	return &MultiMatch{matchers: matchers}
    26  }
    27  
    28  // Match satifies the Matcher iterface
    29  func (mm *MultiMatch) Match(arg string) bool {
    30  	// Normal: OR
    31  	// false, false -> false
    32  	// false, true  -> true
    33  	// true, false -> true
    34  	// true, true -> true
    35  
    36  	// Invert:
    37  	// false, false -> false
    38  	// false, true -> false
    39  	// true, false -> true
    40  	// true, true -> false
    41  	use := false
    42  	for _, m := range mm.matchers {
    43  		if m.Match(arg) {
    44  			use = m.True()
    45  		}
    46  	}
    47  	return use
    48  
    49  }
    50  
    51  // True returns true
    52  func (mm *MultiMatch) True() bool { return true }
    53  
    54  // MarshalText satifies the ?? interface
    55  func (mm *MultiMatch) MarshalText() ([]byte, error) {
    56  	return []byte("multi"), nil
    57  }
    58  
    59  // GlobMatch handle glob matching
    60  type GlobMatch struct {
    61  	orig    string
    62  	matcher glob.Glob
    63  	normal  bool
    64  }
    65  
    66  // NewGlobMatch creates a new GlobMatch instance or error
    67  func NewGlobMatch(arg []byte) (*GlobMatch, error) {
    68  	truth := true
    69  	if len(arg) > 0 && arg[0] == '!' {
    70  		truth = false
    71  		arg = arg[1:]
    72  	}
    73  	if bytes.IndexByte(arg, '/') == -1 {
    74  		return NewBaseGlobMatch(string(arg), truth)
    75  	}
    76  	return NewPathGlobMatch(string(arg), truth)
    77  }
    78  
    79  // NewBaseGlobMatch compiles a new matcher.
    80  // Arg true should be set to false if the output is inverted.
    81  func NewBaseGlobMatch(arg string, truth bool) (*GlobMatch, error) {
    82  	g, err := glob.Compile(arg)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	return &GlobMatch{orig: arg, matcher: g, normal: truth}, nil
    87  }
    88  
    89  // NewPathGlobMatch compiles a new matcher.
    90  // Arg true should be set to false if the output is inverted.
    91  func NewPathGlobMatch(arg string, truth bool) (*GlobMatch, error) {
    92  	// if starts with "/" then glob only applies to top level
    93  	if len(arg) > 0 && arg[0] == '/' {
    94  		arg = arg[1:]
    95  	}
    96  
    97  	// create path-aware glob
    98  	g, err := glob.Compile(arg, '/')
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	return &GlobMatch{orig: arg, matcher: g, normal: truth}, nil
   103  }
   104  
   105  // True returns true if this should be evaluated normally ("true is true")
   106  //  and false if the result should be inverted ("false is true")
   107  //
   108  func (g *GlobMatch) True() bool { return g.normal }
   109  
   110  // MarshalText is really a debug function
   111  func (g *GlobMatch) MarshalText() ([]byte, error) {
   112  	return []byte(fmt.Sprintf("\"%s: %v %s\"", "GlobMatch", g.normal, g.orig)), nil
   113  }
   114  
   115  // Match satisfies the Matcher interface
   116  func (g *GlobMatch) Match(file string) bool {
   117  	return g.matcher.Match(file)
   118  }