Support include when loading themes from dirs
This commit is contained in:
parent
0b09d18b36
commit
7ce64fcde0
@ -29,7 +29,9 @@ type ConfigLine struct {
|
||||
}
|
||||
|
||||
type ConfigParser struct {
|
||||
LineHandler func(key, val string) error
|
||||
LineHandler func(key, val string) error
|
||||
CommentsHandler func(line string) error
|
||||
SourceHandler func(text, path string)
|
||||
|
||||
bad_lines []ConfigLine
|
||||
seen_includes map[string]bool
|
||||
@ -73,7 +75,16 @@ func (self *ConfigParser) parse(scanner Scanner, name, base_path_for_includes st
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimLeft(scanner.Text(), " ")
|
||||
lnum++
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
if line[0] == '#' {
|
||||
if self.CommentsHandler != nil {
|
||||
err := self.CommentsHandler(line)
|
||||
if err != nil {
|
||||
self.bad_lines = append(self.bad_lines, ConfigLine{Src_file: name, Line: line, Line_number: lnum, Err: err})
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
key, val, _ := strings.Cut(line, " ")
|
||||
@ -149,6 +160,9 @@ func (self *ConfigParser) ParseFiles(paths ...string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if self.SourceHandler != nil {
|
||||
self.SourceHandler(utils.UnsafeBytesToString(raw), path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -4,12 +4,12 @@ package themes
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"kitty/tools/config"
|
||||
"kitty/tools/utils"
|
||||
"kitty/tools/utils/style"
|
||||
"net/http"
|
||||
@ -136,52 +136,45 @@ type ThemeMetadata struct {
|
||||
Author string `json:"author"`
|
||||
}
|
||||
|
||||
func parse_theme_metadata(raw string) *ThemeMetadata {
|
||||
scanner := bufio.NewScanner(strings.NewReader(raw))
|
||||
func parse_theme_metadata(path string) (*ThemeMetadata, string, error) {
|
||||
var in_metadata, in_blurb, finished_metadata bool
|
||||
ans := ThemeMetadata{}
|
||||
settings := utils.NewSet[string]()
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" {
|
||||
continue
|
||||
read_is_dark := func(key, val string) (err error) {
|
||||
settings.Add(key)
|
||||
if key == "background" {
|
||||
val = strings.TrimSpace(val)
|
||||
if val != "" {
|
||||
bg, err := style.ParseColor(val)
|
||||
if err == nil {
|
||||
ans.Is_dark = utils.Max(bg.Red, bg.Green, bg.Green) < 115
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
read_metadata := func(line string) (err error) {
|
||||
is_block := strings.HasPrefix(line, "## ")
|
||||
if in_metadata && !is_block {
|
||||
finished_metadata = true
|
||||
}
|
||||
if finished_metadata {
|
||||
if line[0] != '#' {
|
||||
key, val, found := strings.Cut(line, " ")
|
||||
if found {
|
||||
settings.Add(key)
|
||||
if key == "background" {
|
||||
val = strings.TrimSpace(val)
|
||||
if val != "" {
|
||||
bg, err := style.ParseColor(val)
|
||||
if err == nil {
|
||||
ans.Is_dark = utils.Max(bg.Red, bg.Green, bg.Green) < 115
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
return
|
||||
}
|
||||
if !in_metadata && is_block {
|
||||
in_metadata = true
|
||||
}
|
||||
if !in_metadata {
|
||||
continue
|
||||
return
|
||||
}
|
||||
line = line[3:]
|
||||
if in_blurb {
|
||||
ans.Blurb += " " + line
|
||||
continue
|
||||
return
|
||||
}
|
||||
key, val, found := strings.Cut(line, ":")
|
||||
if !found {
|
||||
continue
|
||||
return
|
||||
}
|
||||
key = strings.TrimSpace(strings.ToLower(key))
|
||||
val = strings.TrimSpace(val)
|
||||
@ -198,9 +191,16 @@ func parse_theme_metadata(raw string) *ThemeMetadata {
|
||||
case "license":
|
||||
ans.License = val
|
||||
}
|
||||
return
|
||||
}
|
||||
source := ""
|
||||
cp := config.ConfigParser{LineHandler: read_is_dark, CommentsHandler: read_metadata, SourceHandler: func(code, path string) { source = code }}
|
||||
err := cp.ParseFiles(path)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
ans.Num_settings = settings.Len()
|
||||
return &ans
|
||||
return &ans, source, nil
|
||||
}
|
||||
|
||||
type Theme struct {
|
||||
@ -217,7 +217,7 @@ type Themes struct {
|
||||
}
|
||||
|
||||
var camel_case_pat = (&utils.Once[*regexp.Regexp]{Run: func() *regexp.Regexp {
|
||||
return regexp.MustCompile(`[a-z][A-Z]`)
|
||||
return regexp.MustCompile(`([a-z])([A-Z])`)
|
||||
}}).Get
|
||||
|
||||
func theme_name_from_file_name(fname string) string {
|
||||
@ -237,12 +237,10 @@ func (self *Themes) add_from_dir(dirpath string) error {
|
||||
}
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() && strings.HasSuffix(e.Name(), ".conf") {
|
||||
confb, err := os.ReadFile(e.Name())
|
||||
m, conf, err := parse_theme_metadata(filepath.Join(dirpath, e.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
conf := utils.UnsafeBytesToString(confb)
|
||||
m := parse_theme_metadata(conf)
|
||||
if m.Name == "" {
|
||||
m.Name = theme_name_from_file_name(e.Name())
|
||||
}
|
||||
|
||||
46
tools/themes/collection_test.go
Normal file
46
tools/themes/collection_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||
|
||||
package themes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func TestThemeCollections(t *testing.T) {
|
||||
for fname, expected := range map[string]string{
|
||||
"moose": "Moose",
|
||||
"mooseCat": "Moose Cat",
|
||||
"a_bC": "A B C",
|
||||
} {
|
||||
actual := theme_name_from_file_name(fname)
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("Unexpected theme name for %s:\n%s", fname, diff)
|
||||
}
|
||||
}
|
||||
|
||||
tdir := t.TempDir()
|
||||
|
||||
pt := func(expected ThemeMetadata, lines ...string) {
|
||||
os.WriteFile(filepath.Join(tdir, "temp.conf"), []byte(strings.Join(lines, "\n")), 0o600)
|
||||
actual, _, err := parse_theme_metadata(filepath.Join(tdir, "temp.conf"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if diff := cmp.Diff(&expected, actual); diff != "" {
|
||||
t.Fatalf("Failed to parse:\n%s\n\n%s", strings.Join(lines, "\n"), diff)
|
||||
}
|
||||
}
|
||||
pt(ThemeMetadata{Name: "XYZ", Blurb: "a b", Author: "A", Is_dark: true, Num_settings: 2},
|
||||
"# some crap", " ", "## ", "## author: A", "## name: XYZ", "## blurb: a", "## b", "", "color red", "background black", "include inc.conf")
|
||||
os.WriteFile(filepath.Join(tdir, "inc.conf"), []byte("background white"), 0o600)
|
||||
pt(ThemeMetadata{Name: "XYZ", Blurb: "a b", Author: "A", Num_settings: 2},
|
||||
"# some crap", " ", "## ", "## author: A", "## name: XYZ", "## blurb: a", "## b", "", "color red", "background black", "include inc.conf")
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user