104 lines
2.0 KiB
Go
104 lines
2.0 KiB
Go
|
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
|
||
|
}
|