Load style from json

This commit is contained in:
Toby Padilla
2019-11-09 14:07:01 -06:00
parent 86bed674ac
commit 007bc18b9a
+162 -67
View File
@@ -1,8 +1,11 @@
package gold package gold
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"os"
"strconv" "strconv"
"strings" "strings"
@@ -26,134 +29,171 @@ const (
Blink Blink
) )
type TermRenderer struct { type ElementStyle struct {
style map[bf.NodeType]map[RuleKey]string Color string `json:"color"`
BackgroundColor string `json:"background_color"`
Underline bool `json:"underline"`
Bold bool `json:"bold"`
Italic bool `json:"italic"`
CrossedOut bool `json:"crossed_out"`
Faint bool `json:"faint"`
Conceal bool `json:"conceal"`
Overlined bool `json:"overlined"`
Inverse bool `json:"inverse"`
Blink bool `json:"blink"`
} }
func BaseString(node *bf.Node) string { type Element struct {
BaseString string
}
type TermRenderer struct {
style map[bf.NodeType]*ElementStyle
}
func NewElement(node *bf.Node) Element {
switch node.Type { switch node.Type {
case bf.Document: case bf.Document:
return "" return Element{""}
case bf.BlockQuote: case bf.BlockQuote:
return fmt.Sprintf("```\n%s\n```", string(node.Literal)) return Element{fmt.Sprintf("```\n%s\n```", string(node.Literal))}
case bf.List: case bf.List:
return "" return Element{""}
case bf.Item: case bf.Item:
return fmt.Sprintf("* %s", string(node.Literal)) return Element{fmt.Sprintf("* %s", string(node.Literal))}
case bf.Paragraph: case bf.Paragraph:
if node.Prev != nil && node.Prev.Type != bf.Link { if node.Prev != nil && node.Prev.Type != bf.Link {
return "\n" return Element{"\n"}
} else { } else {
return "" return Element{""}
} }
case bf.Heading: case bf.Heading:
return fmt.Sprintf("%s ", strings.Repeat("#", node.HeadingData.Level)) return Element{fmt.Sprintf("%s ", strings.Repeat("#", node.HeadingData.Level))}
case bf.HorizontalRule: case bf.HorizontalRule:
return "---\n" return Element{"---\n"}
case bf.Emph: case bf.Emph:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Strong: case bf.Strong:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Del: case bf.Del:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Link: case bf.Link:
return fmt.Sprintf("[%s](%s)\n", string(node.LastChild.Literal), string(node.LinkData.Destination)) return Element{fmt.Sprintf("[%s](%s)\n", string(node.LastChild.Literal), string(node.LinkData.Destination))}
case bf.Image: case bf.Image:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Text: case bf.Text:
if node.Parent != nil && node.Parent.Type != bf.Link { if node.Parent != nil && node.Parent.Type != bf.Link {
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
} else { } else {
return "" return Element{""}
} }
case bf.HTMLBlock: case bf.HTMLBlock:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.CodeBlock: case bf.CodeBlock:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Softbreak: case bf.Softbreak:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Hardbreak: case bf.Hardbreak:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Code: case bf.Code:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.HTMLSpan: case bf.HTMLSpan:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Table: case bf.Table:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableCell: case bf.TableCell:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableHead: case bf.TableHead:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableBody: case bf.TableBody:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableRow: case bf.TableRow:
return fmt.Sprintf("%s\n", string(node.Literal)) return Element{fmt.Sprintf("%s\n", string(node.Literal))}
default: default:
return "" return Element{""}
} }
} }
func NewTermRenderer(stylePath string) (*TermRenderer, error) {
if stylePath == "" {
return NewTermRendererFromBytes([]byte("{}"))
}
f, err := os.Open(stylePath)
if err != nil {
return nil, err
}
defer f.Close()
b, _ := ioutil.ReadAll(f)
return NewTermRendererFromBytes(b)
}
func NewTermRendererFromBytes(b []byte) (*TermRenderer, error) {
e := make(map[string]*ElementStyle, 0)
err := json.Unmarshal(b, &e)
if err != nil {
return nil, err
}
tr := &TermRenderer{}
tr.style = make(map[bf.NodeType]*ElementStyle)
for k, v := range e {
t, err := keyToType(k)
if err != nil {
fmt.Println(err)
continue
}
tr.style[t] = v
}
return tr, nil
}
func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus { func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus {
if !entering { if !entering {
return bf.GoToNext return bf.GoToNext
} }
text := BaseString(node) el := NewElement(node)
if text == "" { if el.BaseString == "" {
return bf.GoToNext return bf.GoToNext
} }
rules := tr.style[node.Type] rules := tr.style[node.Type]
if len(rules) == 0 { if rules == nil {
fmt.Fprintf(w, "%s", text) fmt.Fprintf(w, "%s", el.BaseString)
return bf.GoToNext return bf.GoToNext
} }
out := aurora.Reset(text) out := aurora.Reset(el.BaseString)
if r, ok := rules[Color]; ok { if rules.Color != "" {
i, err := strconv.Atoi(r) i, err := strconv.Atoi(rules.Color)
if err == nil && i >= 0 && i <= 255 { if err == nil && i >= 0 && i <= 255 {
out = out.Index(uint8(i)) out = out.Index(uint8(i))
} }
} }
if r, ok := rules[BackgroundColor]; ok { if rules.BackgroundColor != "" {
i, err := strconv.Atoi(r) i, err := strconv.Atoi(rules.BackgroundColor)
if err == nil && i >= 0 && i <= 255 { if err == nil && i >= 0 && i <= 255 {
out = out.Index(uint8(i)) out = out.Index(uint8(i))
} }
} }
if r, ok := rules[Underline]; ok { if rules.Underline {
if r == "true" { out = out.Underline()
out = out.Underline()
}
} }
if r, ok := rules[Bold]; ok { if rules.Bold {
if r == "true" { out = out.Bold()
out = out.Bold()
}
} }
if r, ok := rules[Italic]; ok { if rules.Italic {
if r == "true" { out = out.Italic()
out = out.Italic()
}
} }
if r, ok := rules[CrossedOut]; ok { if rules.CrossedOut {
if r == "true" { out = out.CrossedOut()
out = out.CrossedOut()
}
} }
if r, ok := rules[Overlined]; ok { if rules.Overlined {
if r == "true" { out = out.Overlined()
out = out.Overlined()
}
} }
if r, ok := rules[Inverse]; ok { if rules.Inverse {
if r == "true" { out = out.Reverse()
out = out.Reverse()
}
} }
if r, ok := rules[Blink]; ok { if rules.Blink {
if r == "true" { out = out.Blink()
out = out.Blink()
}
} }
w.Write([]byte(aurora.Sprintf("%s", out))) w.Write([]byte(aurora.Sprintf("%s", out)))
return bf.GoToNext return bf.GoToNext
@@ -164,3 +204,58 @@ func (tr *TermRenderer) RenderHeader(w io.Writer, ast *bf.Node) {
func (tr *TermRenderer) RenderFooter(w io.Writer, ast *bf.Node) { func (tr *TermRenderer) RenderFooter(w io.Writer, ast *bf.Node) {
} }
func keyToType(key string) (bf.NodeType, error) {
switch key {
case "document":
return bf.Document, nil
case "block_quote":
return bf.BlockQuote, nil
case "list":
return bf.List, nil
case "item":
return bf.Item, nil
case "paragraph":
return bf.Paragraph, nil
case "heading":
return bf.Heading, nil
case "hr":
return bf.HorizontalRule, nil
case "emph":
return bf.Emph, nil
case "strong":
return bf.Strong, nil
case "del":
return bf.Del, nil
case "link":
return bf.Link, nil
case "image":
return bf.Image, nil
case "text":
return bf.Text, nil
case "html_block":
return bf.HTMLBlock, nil
case "code_block":
return bf.CodeBlock, nil
case "softbreak":
return bf.Softbreak, nil
case "hardbreak":
return bf.Hardbreak, nil
case "code":
return bf.Code, nil
case "html_span":
return bf.HTMLSpan, nil
case "table":
return bf.Table, nil
case "table_cel":
return bf.TableCell, nil
case "table_head":
return bf.TableHead, nil
case "table_body":
return bf.TableBody, nil
case "table_row":
return bf.TableRow, nil
default:
return 0, fmt.Errorf("Invalid element type: %s", key)
}
}