1
0
mirror of https://github.com/alecthomas/chroma.git synced 2025-02-21 19:06:18 +02:00
chroma/style.go
2017-09-18 14:19:59 +10:00

188 lines
4.0 KiB
Go

package chroma
import (
"sort"
"strings"
)
// A StyleEntry in the Style map.
type StyleEntry struct {
// Hex colours.
Colour Colour
Background Colour
Border Colour
Bold bool
Italic bool
Underline bool
}
func (s *StyleEntry) String() string {
out := []string{}
if s.Bold {
out = append(out, "bold")
}
if s.Italic {
out = append(out, "italic")
}
if s.Underline {
out = append(out, "underline")
}
if s.Colour.IsSet() {
out = append(out, s.Colour.String())
}
if s.Background.IsSet() {
out = append(out, "bg:"+s.Background.String())
}
if s.Border.IsSet() {
out = append(out, "border:"+s.Border.String())
}
return strings.Join(out, " ")
}
func (s *StyleEntry) IsZero() bool {
return s.Colour == 0 && s.Background == 0 && s.Border == 0 && !s.Bold && !s.Italic && !s.Underline
}
func (s *StyleEntry) Sub(e *StyleEntry) *StyleEntry {
out := &StyleEntry{}
if e.Colour != s.Colour {
out.Colour = s.Colour
}
if e.Background != s.Background {
out.Background = s.Background
}
if e.Bold != s.Bold {
out.Bold = s.Bold
}
if e.Italic != s.Italic {
out.Italic = s.Italic
}
if e.Underline != s.Underline {
out.Underline = s.Underline
}
if e.Border != s.Border {
out.Border = s.Border
}
return out
}
// StyleEntries mapping TokenType to colour definition.
type StyleEntries map[TokenType]string
// NewStyle creates a new style definition.
func NewStyle(name string, entries StyleEntries) *Style {
s := &Style{
Name: name,
Entries: map[TokenType]*StyleEntry{},
}
s.Add(Background, "")
s.AddAll(entries)
return s
}
// A Style definition.
//
// See http://pygments.org/docs/styles/ for details. Semantics are intended to be identical.
type Style struct {
Name string
Entries map[TokenType]*StyleEntry
}
// Get a style entry. Will try sub-category or category if an exact match is not found, and
// finally return the entry mapped to `InheritStyle`.
func (s *Style) Get(ttype TokenType) *StyleEntry {
out := s.Entries[ttype]
if out == nil {
out = s.Entries[ttype.SubCategory()]
if out == nil {
out = s.Entries[ttype.Category()]
if out == nil {
out = s.Entries[Background]
}
}
}
return out
}
func (s *Style) AddAll(entries StyleEntries) *Style {
tis := []int{}
for tt := range entries {
tis = append(tis, int(tt))
}
sort.Ints(tis)
for _, ti := range tis {
tt := TokenType(ti)
entry := entries[tt]
s.Add(tt, entry)
}
return s
}
// Add a StyleEntry to the Style map.
//
// See http://pygments.org/docs/styles/#style-rules for details.
func (s *Style) Add(ttype TokenType, entry string) *Style { // nolint: gocyclo
dupl := s.Entries[ttype.SubCategory()]
if dupl == nil {
dupl = s.Entries[ttype.Category()]
if dupl == nil {
dupl = s.Entries[Background]
if dupl == nil {
dupl = &StyleEntry{}
}
}
}
parent := &StyleEntry{}
// Duplicate ancestor node.
*parent = *dupl
s.Entries[ttype] = ParseStyleEntry(parent, entry)
return s
}
// ParseStyleEntry parses a Pygments style entry.
func ParseStyleEntry(parent *StyleEntry, entry string) *StyleEntry { // nolint: gocyclo
out := &StyleEntry{}
parts := strings.Fields(entry)
// Check if parent style should be inherited...
if parent != nil {
inherit := true
for _, part := range parts {
if part == "noinherit" {
inherit = false
break
}
}
if inherit {
*out = *parent
}
}
for _, part := range parts {
switch {
case part == "italic":
out.Italic = true
case part == "noitalic":
out.Italic = false
case part == "bold":
out.Bold = true
case part == "nobold":
out.Bold = false
case part == "underline":
out.Underline = true
case part == "nounderline":
out.Underline = false
case part == "bg:":
out.Background = 0
case strings.HasPrefix(part, "bg:#"):
out.Background = ParseColour(part[3:])
case strings.HasPrefix(part, "border:#"):
out.Border = ParseColour(part[7:])
case strings.HasPrefix(part, "#"):
out.Colour = ParseColour(part)
default:
panic("unsupported style entry " + part)
}
}
return out
}