You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.0 KiB
157 lines
4.0 KiB
3 years ago
|
// This file is run by go generate, and generates nerdfont-provider-data.go.
|
||
|
// +build generation
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"bytes"
|
||
|
"io"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"os"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"text/template"
|
||
|
"time"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
var fileTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
|
||
|
// This file was generated by robots at
|
||
|
// {{ .Timestamp }}
|
||
|
// using data from
|
||
|
// {{ .URL }}
|
||
|
package main
|
||
|
|
||
|
var NerdFontGlyphs = []Glyph{
|
||
|
{{- range $key, $rune := .Glyphs }}
|
||
|
{
|
||
|
Key: {{ printf "%q" $key }},
|
||
|
Rune: 0x{{ printf "%x" $rune }},
|
||
|
},
|
||
|
{{- end }}
|
||
|
}
|
||
|
`))
|
||
|
|
||
|
const TokenStartString = ".nf-"
|
||
|
const ClassStartString = ":before {\n content: \"\\"
|
||
|
const ClassEndString = "\";\n}\n"
|
||
|
// SplitCSS scans the reader looking for data of the form
|
||
|
// .nf-(key):before {
|
||
|
// content: "\(hex)";
|
||
|
// }
|
||
|
// and returns (key):(hex) when it finds this data.
|
||
|
func SplitCSS(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||
|
if !bytes.HasPrefix(data, []byte(TokenStartString)) {
|
||
|
// This is not our goal. Skip this line.
|
||
|
nextNewline := bytes.IndexRune(data, '\n');
|
||
|
if nextNewline == -1 {
|
||
|
// Can't skip this line yet because we don't know where it ends!
|
||
|
return 0, nil, nil
|
||
|
} else {
|
||
|
offset := nextNewline + 1
|
||
|
// Skip this line in our own head and see if we get a result.
|
||
|
advance, token, err = SplitCSS(data[offset:], atEOF)
|
||
|
if advance > 0 || token != nil || err != nil {
|
||
|
// If we do, return it adjusted by the offset.
|
||
|
return advance + offset, token, err
|
||
|
} else {
|
||
|
// Otherwise, just tell the scanner to skip the line we found and keep going.
|
||
|
return offset, nil, nil
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
keyEnd := bytes.Index(data, []byte(ClassStartString))
|
||
|
if keyEnd == -1 {
|
||
|
// We don't know where the key ends!
|
||
|
return 0, nil, nil
|
||
|
}
|
||
|
key := data[len(TokenStartString):keyEnd]
|
||
|
contentEnd := bytes.Index(data, []byte(ClassEndString))
|
||
|
if contentEnd == -1 {
|
||
|
// We don't know where the content ends!
|
||
|
return 0, nil, nil
|
||
|
}
|
||
|
content := data[keyEnd + len(ClassStartString):contentEnd]
|
||
|
token = make([]byte, len(key) + len(content) + 1)
|
||
|
copy(token[:len(key)], key)
|
||
|
token[len(key)] = ':'
|
||
|
copy(token[len(key) + 1:], content)
|
||
|
return contentEnd + len(ClassEndString), token, nil
|
||
|
}
|
||
|
|
||
|
func SplitOnce(s string, sep string) (string, string) {
|
||
|
result := strings.SplitN(s, sep, 2)
|
||
|
if len(result) == 2 {
|
||
|
return result[0], result[1]
|
||
|
} else if len(result) == 1 {
|
||
|
return result[0], ""
|
||
|
} else {
|
||
|
panic("How did we get a different number of strings than 1 or 2 out of SplitN(2)?")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
const url = "https://raw.githubusercontent.com/ryanoasis/nerd-fonts/master/css/nerd-fonts-generated.css"
|
||
|
|
||
|
rsp, err := http.Get(url)
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed to get css file: %s", err)
|
||
|
}
|
||
|
defer func(b io.ReadCloser) {
|
||
|
err := b.Close()
|
||
|
if err != nil {
|
||
|
log.Printf("failed closing the css file: %s", err)
|
||
|
}
|
||
|
}(rsp.Body)
|
||
|
|
||
|
sc := bufio.NewScanner(rsp.Body)
|
||
|
sc.Split(SplitCSS)
|
||
|
|
||
|
glyphs := make(map[string]rune)
|
||
|
|
||
|
for sc.Scan() {
|
||
|
key, hex := SplitOnce(sc.Text(), ":")
|
||
|
val, err := strconv.ParseInt(hex, 16, 64)
|
||
|
if err != nil {
|
||
|
log.Printf("val %s for %s cannot be parsed as hex: %s", hex, key, err)
|
||
|
continue
|
||
|
}
|
||
|
if val > int64(unicode.MaxRune) {
|
||
|
log.Printf("val 0x%x for %s exceeds MaxRune", val, key)
|
||
|
continue
|
||
|
}
|
||
|
if old, ok := glyphs[key]; ok {
|
||
|
log.Printf("already stored %s as 0x%x but got 0x%x, replacing", key, old, val)
|
||
|
}
|
||
|
glyphs[key] = rune(val)
|
||
|
}
|
||
|
if sc.Err() != nil {
|
||
|
log.Fatalf("failed to scan: %s", sc.Err())
|
||
|
}
|
||
|
|
||
|
f, err := os.Create("nerdfont-provider-data.go")
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed to open the data file: %s", err)
|
||
|
}
|
||
|
defer func(f *os.File) {
|
||
|
err := f.Close()
|
||
|
if err != nil {
|
||
|
log.Printf("failed closing the data file: %s", err)
|
||
|
}
|
||
|
}(f)
|
||
|
|
||
|
err = fileTemplate.Execute(f, struct {
|
||
|
Timestamp time.Time
|
||
|
URL string
|
||
|
Glyphs map[string]rune
|
||
|
}{
|
||
|
Timestamp: time.Now(),
|
||
|
URL: url,
|
||
|
Glyphs: glyphs,
|
||
|
})
|
||
|
if err != nil {
|
||
|
log.Fatalf("failed writing template to the data file: %s", err)
|
||
|
}
|
||
|
}
|