2016-02-19 05:52:05 +08:00
|
|
|
package eval
|
|
|
|
|
|
|
|
import (
|
2016-02-23 09:45:35 +08:00
|
|
|
"errors"
|
2016-02-19 05:52:05 +08:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/elves/elvish/glob"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GlobPattern is en ephemeral Value generated when evaluating tilde and
|
|
|
|
// wildcards.
|
|
|
|
type GlobPattern glob.Pattern
|
|
|
|
|
2016-02-23 09:45:35 +08:00
|
|
|
var (
|
|
|
|
_ Value = GlobPattern{}
|
|
|
|
_ Indexer = GlobPattern{}
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrMustFollowWildcard = errors.New("must follow wildcard")
|
|
|
|
ErrModifierMustBeString = errors.New("modifier must be string")
|
|
|
|
)
|
|
|
|
|
2016-02-19 05:52:05 +08:00
|
|
|
func (GlobPattern) Kind() string {
|
|
|
|
return "glob-pattern"
|
|
|
|
}
|
|
|
|
|
2016-02-20 03:11:31 +08:00
|
|
|
func (gp GlobPattern) Repr(int) string {
|
2016-02-19 05:52:05 +08:00
|
|
|
return fmt.Sprintf("<GlobPattern%v>", gp)
|
|
|
|
}
|
|
|
|
|
2016-02-23 09:45:35 +08:00
|
|
|
func (gp GlobPattern) Index(modifiers []Value) []Value {
|
|
|
|
for _, value := range modifiers {
|
|
|
|
modifier, ok := value.(String)
|
|
|
|
if !ok {
|
|
|
|
throw(ErrModifierMustBeString)
|
|
|
|
}
|
|
|
|
switch string(modifier) {
|
|
|
|
case "a", "all":
|
|
|
|
if len(gp.Segments) == 0 {
|
|
|
|
throw(ErrBadGlobPattern)
|
|
|
|
}
|
2017-02-03 03:15:42 +08:00
|
|
|
if !glob.IsWild(gp.Segments[len(gp.Segments)-1]) {
|
2016-02-23 09:45:35 +08:00
|
|
|
throw(ErrMustFollowWildcard)
|
|
|
|
}
|
2017-02-03 03:15:42 +08:00
|
|
|
gp.Segments[len(gp.Segments)-1] = glob.Wild{
|
|
|
|
gp.Segments[len(gp.Segments)-1].(glob.Wild).Type, true,
|
|
|
|
}
|
2016-02-23 09:45:35 +08:00
|
|
|
default:
|
2016-03-08 09:23:49 +08:00
|
|
|
throw(fmt.Errorf("unknown modifier %s", modifier.Repr(NoPretty)))
|
2016-02-23 09:45:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return []Value{gp}
|
|
|
|
}
|
|
|
|
|
2016-02-19 05:52:05 +08:00
|
|
|
func (gp *GlobPattern) append(segs ...glob.Segment) {
|
|
|
|
gp.Segments = append(gp.Segments, segs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func wildcardToSegment(s string) glob.Segment {
|
|
|
|
switch s {
|
|
|
|
case "*":
|
2017-02-03 03:15:42 +08:00
|
|
|
return glob.Wild{glob.Star, false}
|
2016-02-19 05:52:05 +08:00
|
|
|
case "**":
|
2017-02-03 03:15:42 +08:00
|
|
|
return glob.Wild{glob.StarStar, false}
|
2016-02-19 05:52:05 +08:00
|
|
|
case "?":
|
2017-02-03 03:15:42 +08:00
|
|
|
return glob.Wild{glob.Question, false}
|
2016-02-19 05:52:05 +08:00
|
|
|
default:
|
|
|
|
throw(fmt.Errorf("bad wildcard: %q", s))
|
|
|
|
panic("unreachable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func stringToSegments(s string) []glob.Segment {
|
|
|
|
segs := []glob.Segment{}
|
|
|
|
for i := 0; i < len(s); {
|
|
|
|
j := i
|
|
|
|
for ; j < len(s) && s[j] != '/'; j++ {
|
|
|
|
}
|
|
|
|
if j > i {
|
2017-02-03 03:15:42 +08:00
|
|
|
segs = append(segs, glob.Literal{s[i:j]})
|
2016-02-19 05:52:05 +08:00
|
|
|
}
|
|
|
|
if j < len(s) {
|
|
|
|
for ; j < len(s) && s[j] == '/'; j++ {
|
|
|
|
}
|
2017-02-03 03:15:42 +08:00
|
|
|
segs = append(segs, glob.Slash{})
|
2016-02-19 05:52:05 +08:00
|
|
|
i = j
|
|
|
|
} else {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return segs
|
|
|
|
}
|
|
|
|
|
2016-06-29 05:08:15 +08:00
|
|
|
func doGlob(gp GlobPattern, abort <-chan struct{}) []Value {
|
|
|
|
names := []string{}
|
|
|
|
if !glob.Pattern(gp).Glob(func(name string) bool {
|
|
|
|
select {
|
|
|
|
case <-abort:
|
|
|
|
Logger.Println("glob aborted")
|
|
|
|
return false
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
names = append(names, name)
|
|
|
|
return true
|
|
|
|
}) {
|
|
|
|
throw(ErrInterrupted)
|
|
|
|
}
|
2016-02-19 05:52:05 +08:00
|
|
|
vs := make([]Value, len(names))
|
|
|
|
for i, name := range names {
|
|
|
|
vs[i] = String(name)
|
|
|
|
}
|
|
|
|
return vs
|
|
|
|
}
|