123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package editorconfig
-
- import (
- "fmt"
- "regexp"
- "strconv"
- "strings"
- )
-
- var (
- // findLeftBrackets matches the opening left bracket {
- findLeftBrackets = regexp.MustCompile(`(^|[^\\])\{`)
- // findLeftBrackets matches the closing right bracket {
- findRightBrackets = regexp.MustCompile(`(^|[^\\])\}`)
- // findNumericRange matches a range of number, e.g. -2..5
- findNumericRange = regexp.MustCompile(`^([+-]?\d+)\.\.([+-]?\d+)$`)
- )
-
- // FnmatchCase tests whether the name matches the given pattern case included.
- func FnmatchCase(pattern, name string) (bool, error) {
- p, err := translate(pattern)
- if err != nil {
- return false, err
- }
-
- r, err := regexp.Compile(fmt.Sprintf("^%s$", p))
- if err != nil {
- return false, err
- }
-
- return r.MatchString(name), nil
- }
-
- func translate(pattern string) (string, error) {
- index := 0
- pat := []rune(pattern)
- length := len(pat)
-
- result := strings.Builder{}
-
- braceLevel := 0
- isEscaped := false
- inBrackets := false
-
- matchesBraces := len(findLeftBrackets.FindAllString(pattern, -1)) == len(findRightBrackets.FindAllString(pattern, -1))
-
- for index < length {
- r := pat[index]
- index++
-
- if r == '*' {
- p := index
- if p < length && pat[p] == '*' {
- result.WriteString(".*")
- index++
- } else {
- result.WriteString("[^/]*")
- }
- } else if r == '/' {
- p := index
- if p+2 < length && pat[p] == '*' && pat[p+1] == '*' && pat[p+2] == '/' {
- result.WriteString("(?:/|/.*/)")
- index += 3
- } else {
- result.WriteRune(r)
- }
- } else if r == '?' {
- result.WriteString("[^/]")
- } else if r == '[' {
- if inBrackets {
- result.WriteString("\\[")
- } else {
- hasSlash := false
- res := strings.Builder{}
-
- p := index
- for p < length {
- if pat[p] == ']' && pat[p-1] != '\\' {
- break
- }
- res.WriteRune(pat[p])
- if pat[p] == '/' && pat[p-1] != '\\' {
- hasSlash = true
- break
- }
- p++
- }
- if hasSlash {
- result.WriteString("\\[" + res.String())
- index = p + 1
- } else {
- inBrackets = true
- if index < length && pat[index] == '!' || pat[index] == '^' {
- index++
- result.WriteString("[^")
- } else {
- result.WriteRune('[')
- }
- }
- }
- } else if r == ']' {
- if inBrackets && pat[index-2] == '\\' {
- result.WriteString("\\]")
- } else {
- result.WriteRune(r)
- inBrackets = false
- }
- } else if r == '{' {
- hasComma := false
- p := index
- res := strings.Builder{}
-
- for p < length {
- if pat[p] == '}' && pat[p-1] != '\\' {
- break
- }
- res.WriteRune(pat[p])
- if pat[p] == ',' && pat[p-1] != '\\' {
- hasComma = true
- break
- }
- p++
- }
-
- if !hasComma && p < length {
- inner := res.String()
- sub := findNumericRange.FindStringSubmatch(inner)
- if len(sub) == 3 {
- from, _ := strconv.Atoi(sub[1])
- to, _ := strconv.Atoi(sub[2])
- result.WriteString("(?:")
- // XXX does not scale well
- for i := from; i < to; i++ {
- result.WriteString(strconv.Itoa(i))
- result.WriteRune('|')
- }
- result.WriteString(strconv.Itoa(to))
- result.WriteRune(')')
- } else {
- r, _ := translate(inner)
- result.WriteString(fmt.Sprintf("\\{%s\\}", r))
- }
- index = p + 1
- } else if matchesBraces {
- result.WriteString("(?:")
- braceLevel++
- } else {
- result.WriteString("\\{")
- }
- } else if r == '}' {
- if braceLevel > 0 {
- if isEscaped {
- result.WriteRune('}')
- isEscaped = false
- } else {
- result.WriteRune(')')
- braceLevel--
- }
- } else {
- result.WriteString("\\}")
- }
- } else if r == ',' {
- if braceLevel == 0 || isEscaped {
- result.WriteRune(r)
- } else {
- result.WriteRune('|')
- }
- } else if r != '\\' || isEscaped {
- result.WriteString(regexp.QuoteMeta(string(r)))
- isEscaped = false
- } else {
- isEscaped = true
- }
- }
-
- return result.String(), nil
- }
|