erm/app/fontinfo/match.go

104 lines
2.0 KiB
Go
Raw Normal View History

2023-01-16 06:03:38 +00:00
package fontinfo
import (
"fmt"
"io/fs"
"os"
"os/user"
"path/filepath"
"strings"
)
// Font represents a font file on disk
type Font struct {
Family string
Style string
Path string
}
var validExtensions = map[string]FontParser{
".ttf": &TruetypeParser{},
".otf": &TruetypeParser{},
//".bdf": &TruetypeParser{},
//".pcf": &TruetypeParser{},
}
var fontDirs = []string{
"~/.fonts",
"~/.local/share/fonts",
"/usr/local/share/fonts",
"/usr/share/fonts",
filepath.Join(os.Getenv("XDG_DATA_HOME"), "fonts"),
}
func init() {
dataDirs := strings.Split(os.Getenv("XDG_DATA_DIRS"), string(os.PathListSeparator))
for _, dir := range dataDirs {
if dir == "" {
continue
}
fontDirs = append(fontDirs, filepath.Join(dir, "fonts"))
}
}
// Match finds all fonts installed on the system which match the provided matchers
func Match(matchers ...Matcher) ([]Font, error) {
var fonts []Font
meta := make(map[string]*FontMetadata)
var home string
if usr, _ := user.Current(); usr != nil {
home = usr.HomeDir
}
for _, dir := range fontDirs {
if home != "" && strings.HasPrefix(dir, "~/") {
dir = filepath.Join(home, dir[2:])
}
if info, err := os.Stat(dir); os.IsNotExist(err) {
continue
} else if !info.IsDir() {
continue
}
err := filepath.WalkDir(dir, func(path string, info fs.DirEntry, err error) error {
if _, ok := meta[path]; ok {
return nil
}
ext := filepath.Ext(path)
if parser, ok := validExtensions[strings.ToLower(ext)]; ok {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
metadata, err := parser.Parse(f)
if err != nil {
fmt.Printf("could not parse %s: %s\n", path, err)
return nil
}
for _, match := range matchers {
if match(metadata) {
meta[path] = metadata
break
}
}
return nil
}
return nil
})
if err != nil {
return nil, err
}
}
for path, metadata := range meta {
fonts = append(fonts, Font{
Family: metadata.FontFamily,
Style: metadata.FontStyle,
Path: path,
})
}
return fonts, nil
}