back up project

This commit is contained in:
hl-valdemar
2026-09-18 00:21:11 +02:00
commit ffe8b986ce
10 changed files with 1322 additions and 0 deletions
+292
View File
@@ -0,0 +1,292 @@
package main
import (
"fmt"
"os"
"path/filepath"
"slices"
"sort"
"strconv"
"strings"
"github.com/BurntSushi/toml"
)
type themePair struct {
Name string `toml:"name"`
Dark string `toml:"dark"`
Light string `toml:"light"`
}
type storedCatalog struct {
Pairs []themePair `toml:"pairs"`
Themes []string `toml:"themes"`
}
type currentPair struct {
Light string `toml:"light"`
Dark string `toml:"dark"`
}
type catalog struct {
FavoritePairs []themePair
FavoriteThemes []string
OtherPairs []themePair
OtherThemes []string
}
type state struct {
Current currentPair
Catalog catalog
}
type storedState struct {
Current currentPair `toml:"current"`
Favorites storedCatalog `toml:"favorites"`
Others storedCatalog `toml:"others"`
}
func defaultStatePath() string {
if path := os.Getenv("TINT_STATE_FILE"); path != "" {
return path
}
config := os.Getenv("XDG_CONFIG_HOME")
if config == "" {
config = filepath.Join(homeDir(), ".config")
}
return filepath.Join(config, "tinted-theming", "tinty", "state.toml")
}
func loadState(path string) (state, error) {
var stored storedState
metadata, err := toml.DecodeFile(path, &stored)
if err != nil {
return state{}, err
}
if unknown := metadata.Undecoded(); len(unknown) != 0 {
return state{}, fmt.Errorf("unknown state keys: %s", unknownKeys(unknown))
}
value := state{
Current: stored.Current,
Catalog: catalog{
FavoritePairs: stored.Favorites.Pairs,
FavoriteThemes: stored.Favorites.Themes,
OtherPairs: stored.Others.Pairs,
OtherThemes: stored.Others.Themes,
},
}
value.Catalog.normalize()
return value, nil
}
func saveState(path string, value state) error {
return writeAtomic(path, []byte(formatState(value)), 0o644)
}
func formatState(value state) string {
value.Catalog.normalize()
var output strings.Builder
fmt.Fprintf(&output, "[current]\nlight = %s\ndark = %s\n\n",
strconv.Quote(value.Current.Light), strconv.Quote(value.Current.Dark))
writePairs := func(name string, pairs []themePair) {
for _, pair := range pairs {
fmt.Fprintf(&output, "[[%s]]\nname = %s\ndark = %s\nlight = %s\n\n",
name, strconv.Quote(pair.Name), strconv.Quote(pair.Dark), strconv.Quote(pair.Light))
}
}
writeThemes := func(name string, themes []string) {
fmt.Fprintf(&output, "[%s]\nthemes = [\n", name)
for _, theme := range themes {
fmt.Fprintf(&output, "%s,\n", strconv.Quote(theme))
}
output.WriteString("]\n\n")
}
writePairs("favorites.pairs", value.Catalog.FavoritePairs)
writeThemes("favorites", value.Catalog.FavoriteThemes)
writePairs("others.pairs", value.Catalog.OtherPairs)
writeThemes("others", value.Catalog.OtherThemes)
return strings.TrimRight(output.String(), "\n") + "\n"
}
func unknownKeys(keys []toml.Key) string {
values := make([]string, len(keys))
for i, key := range keys {
values[i] = key.String()
}
return strings.Join(values, ", ")
}
func (c *catalog) normalize() {
c.FavoritePairs = uniquePairs(c.FavoritePairs)
favoritePairNames := make(map[string]bool, len(c.FavoritePairs))
for _, pair := range c.FavoritePairs {
favoritePairNames[pair.Name] = true
}
otherPairs := uniquePairs(c.OtherPairs)
c.OtherPairs = c.OtherPairs[:0]
for _, pair := range otherPairs {
if !favoritePairNames[pair.Name] {
c.OtherPairs = append(c.OtherPairs, pair)
}
}
c.FavoriteThemes = uniqueStrings(c.FavoriteThemes)
blocked := make(map[string]bool)
for _, theme := range c.FavoriteThemes {
blocked[theme] = true
}
for _, pair := range append(slices.Clone(c.FavoritePairs), c.OtherPairs...) {
blocked[pair.Dark] = true
blocked[pair.Light] = true
}
otherThemes := uniqueStrings(c.OtherThemes)
c.OtherThemes = c.OtherThemes[:0]
for _, theme := range otherThemes {
if !blocked[theme] {
c.OtherThemes = append(c.OtherThemes, theme)
}
}
}
func uniquePairs(pairs []themePair) []themePair {
byName := make(map[string]themePair, len(pairs))
for _, pair := range pairs {
byName[pair.Name] = pair
}
result := make([]themePair, 0, len(byName))
for _, pair := range byName {
result = append(result, pair)
}
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
return result
}
func uniqueStrings(values []string) []string {
seen := make(map[string]bool, len(values))
result := make([]string, 0, len(values))
for _, value := range values {
if value != "" && !seen[value] {
seen[value] = true
result = append(result, value)
}
}
sort.Strings(result)
return result
}
func (c *catalog) findPair(name string) (themePair, bool, bool) {
for _, pair := range c.FavoritePairs {
if pair.Name == name {
return pair, true, true
}
}
for _, pair := range c.OtherPairs {
if pair.Name == name {
return pair, false, true
}
}
return themePair{}, false, false
}
func (c *catalog) configurePair(pair themePair) {
_, favorite, exists := c.findPair(pair.Name)
if exists {
for _, old := range append(slices.Clone(c.FavoritePairs), c.OtherPairs...) {
if old.Name == pair.Name {
c.OtherThemes = append(c.OtherThemes, old.Dark, old.Light)
}
}
}
c.FavoritePairs = removePair(c.FavoritePairs, pair.Name)
c.OtherPairs = removePair(c.OtherPairs, pair.Name)
if favorite {
c.FavoritePairs = append(c.FavoritePairs, pair)
} else {
c.OtherPairs = append(c.OtherPairs, pair)
}
c.normalize()
}
func (c *catalog) favorite(item string) bool {
pair, _, found := c.findPair(item)
if found {
c.OtherPairs = removePair(c.OtherPairs, item)
c.FavoritePairs = append(c.FavoritePairs, pair)
c.normalize()
return true
}
c.OtherThemes = removeString(c.OtherThemes, item)
c.FavoriteThemes = append(c.FavoriteThemes, item)
c.normalize()
return false
}
func (c *catalog) unfavorite(item string) bool {
pair, _, found := c.findPair(item)
if found {
c.FavoritePairs = removePair(c.FavoritePairs, item)
c.OtherPairs = append(c.OtherPairs, pair)
c.normalize()
return true
}
c.FavoriteThemes = removeString(c.FavoriteThemes, item)
c.OtherThemes = append(c.OtherThemes, item)
c.normalize()
return false
}
func (c *catalog) record(pair currentPair) {
c.OtherThemes = append(c.OtherThemes, pair.Light, pair.Dark)
c.normalize()
}
func removePair(pairs []themePair, name string) []themePair {
result := pairs[:0]
for _, pair := range pairs {
if pair.Name != name {
result = append(result, pair)
}
}
return result
}
func removeString(values []string, target string) []string {
result := values[:0]
for _, value := range values {
if value != target {
result = append(result, value)
}
}
return result
}
func writeAtomic(path string, data []byte, mode os.FileMode) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}
file, err := os.CreateTemp(filepath.Dir(path), ".tint-*")
if err != nil {
return err
}
tmp := file.Name()
defer os.Remove(tmp)
if _, err := file.Write(data); err != nil {
file.Close()
return err
}
if err := file.Chmod(mode); err != nil {
file.Close()
return err
}
if err := file.Close(); err != nil {
return err
}
return os.Rename(tmp, path)
}
func homeDir() string {
if home := os.Getenv("HOME"); home != "" {
return home
}
home, _ := os.UserHomeDir()
return home
}