internal/shaderlister: enable to specify multiple patterns

Updates #3157
This commit is contained in:
Hajime Hoshi 2025-02-08 23:47:15 +09:00
parent 76bba89589
commit 5db5346272
2 changed files with 54 additions and 31 deletions

View File

@ -188,7 +188,7 @@ const (
var ( var (
reShaderSourceDirective = regexp.MustCompile(`(?m)^\s*//` + regexp.QuoteMeta(shaderSourceDirective) + `$`) reShaderSourceDirective = regexp.MustCompile(`(?m)^\s*//` + regexp.QuoteMeta(shaderSourceDirective) + `$`)
reShaderFileDirective = regexp.MustCompile(`(?m)^\s*//` + regexp.QuoteMeta(shaderFileDirective) + ` (.+)$`) reShaderFileDirective = regexp.MustCompile(`(?m)^\s*//` + regexp.QuoteMeta(shaderFileDirective) + ` `)
) )
func hasShaderSourceDirectiveInComment(commentGroup *ast.CommentGroup) bool { func hasShaderSourceDirectiveInComment(commentGroup *ast.CommentGroup) bool {
@ -200,6 +200,10 @@ func hasShaderSourceDirectiveInComment(commentGroup *ast.CommentGroup) bool {
return false return false
} }
func isAsciiSpace(r rune) bool {
return r == ' ' || r == '\t' || r == '\v' || r == '\n' || r == '\r'
}
func appendShaderSources(shaders []Shader, pkg *packages.Package) ([]Shader, error) { func appendShaderSources(shaders []Shader, pkg *packages.Package) ([]Shader, error) {
topLevelDecls := map[ast.Decl]struct{}{} topLevelDecls := map[ast.Decl]struct{}{}
for _, file := range pkg.Syntax { for _, file := range pkg.Syntax {
@ -213,46 +217,63 @@ func appendShaderSources(shaders []Shader, pkg *packages.Package) ([]Shader, err
} }
// Resolve ebitengine:shaderfile directives. // Resolve ebitengine:shaderfile directives.
visitedPatterns := map[string]struct{}{}
visitedPaths := map[string]struct{}{}
for _, f := range pkg.Syntax { for _, f := range pkg.Syntax {
for _, c := range f.Comments { for _, c := range f.Comments {
for _, l := range c.List { for _, l := range c.List {
m := reShaderFileDirective.FindStringSubmatch(l.Text) m := reShaderFileDirective.FindString(l.Text)
if len(m) == 0 { if m == "" {
continue continue
} }
pattern := filepath.Join(pkg.Dir, filepath.FromSlash(m[1])) patterns := strings.TrimPrefix(l.Text, m)
stat, err := os.Stat(pattern) for _, pattern := range strings.FieldsFunc(patterns, isAsciiSpace) {
if err == nil && stat.IsDir() { pattern := filepath.Join(pkg.Dir, filepath.FromSlash(pattern))
// If the pattern is a directory, read all files in the directory recursively. if _, ok := visitedPatterns[pattern]; ok {
if err := filepath.WalkDir(pattern, func(path string, d os.DirEntry, err error) error { continue
if err != nil { }
return err visitedPatterns[pattern] = struct{}{}
} stat, err := os.Stat(pattern)
if d.IsDir() { if err == nil && stat.IsDir() {
// If the pattern is a directory, read all files in the directory recursively.
if err := filepath.WalkDir(pattern, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
if _, ok := visitedPaths[path]; ok {
return nil
}
visitedPaths[path] = struct{}{}
shaders, err = appendShaderFromFile(shaders, pkg.PkgPath, path)
if err != nil {
return err
}
return nil return nil
}); err != nil {
return nil, err
} }
shaders, err = appendShaderFromFile(shaders, pkg.PkgPath, path) continue
if err != nil { }
return err if err != nil && !errors.Is(err, os.ErrNotExist) {
}
return nil
}); err != nil {
return nil, err return nil, err
} }
continue paths, err := filepath.Glob(pattern)
}
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
}
paths, err := filepath.Glob(pattern)
if err != nil {
return nil, err
}
for _, path := range paths {
shaders, err = appendShaderFromFile(shaders, pkg.PkgPath, path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, path := range paths {
if _, ok := visitedPaths[path]; ok {
continue
}
visitedPaths[path] = struct{}{}
shaders, err = appendShaderFromFile(shaders, pkg.PkgPath, path)
if err != nil {
return nil, err
}
}
} }
} }
} }

View File

@ -69,7 +69,9 @@ const (
_, _ = "ignored", "ignored again" // multiple consts are ignored to avoid confusion. _, _ = "ignored", "ignored again" // multiple consts are ignored to avoid confusion.
) )
//ebitengine:shaderfile *_kage.go //ebitengine:shaderfile *_kage.go resource nonexistent.go
//ebitengine:shaderfile resource
// Duplicated files are ignored.
//ebitengine:shaderfile *_kage.go *_kage.go *_kage.go
//ebitengine:shaderfile nonexistent.go //ebitengine:shaderfile nonexistent.go