package chromajson import ( "encoding/json" "fmt" "io" "strings" "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/styles" ) // Style is a chroma style type Style struct { Name string `json:"name"` Entries map[string]StyleEntry `json:"style"` } // StyleEntry is a mapping for a chroma style type StyleEntry struct { Color string `json:"color"` Background string `json:"background"` Border string `json:"border"` Accents []string `json:"accent"` } // String returns a chroma-representable style entry func (s StyleEntry) String() string { normalise := func(c string) string { return "#" + strings.TrimLeft(c, "#") } parts := make([]string, 0, 4) if len(s.Accents) > 0 { parts = append(parts, strings.Join(s.Accents, " ")) } if s.Background != "" { parts = append(parts, fmt.Sprintf("bg:%s", normalise(s.Background))) } if s.Border != "" { parts = append(parts, fmt.Sprintf("border:%s", normalise(s.Border))) } if s.Color != "" { parts = append(parts, normalise(s.Color)) } return strings.Join(parts, " ") } // Chroma converts a Style to a chroma.Style func (s *Style) Chroma() (*chroma.Style, error) { style := chroma.NewStyleBuilder(s.Name) for name, entry := range s.Entries { if token, ok := tokenToType[name]; ok { style.Add(token, entry.String()) } } return style.Build() } // Register registers the Style directly to chroma func (s *Style) Register() error { style, err := s.Chroma() if err != nil { return err } styles.Register(style) return nil } // LoadStyle loads a Style from an io.Reader func LoadStyle(r io.Reader) (*Style, error) { var s Style d := json.NewDecoder(r) d.DisallowUnknownFields() if err := d.Decode(&s); err != nil { return nil, err } return &s, nil }