Load style from json

This commit is contained in:
Toby Padilla 2019-11-09 14:07:01 -06:00
commit a89ebe80b5
3 changed files with 181 additions and 68 deletions

10
cmd/gold/dark.json Normal file
View file

@ -0,0 +1,10 @@
{
"link": {
"color": "123",
"underline": true
},
"heading": {
"bold": true,
"inverse": true
}
}

View file

@ -1,7 +1,9 @@
package main
import (
"flag"
"fmt"
"os"
"github.com/magicnumbers/gold"
bf "gopkg.in/russross/blackfriday.v2"
@ -22,7 +24,13 @@ This is a test yo.
`
func main() {
r := gold.TermRenderer{}
out := bf.Run([]byte(tmd), bf.WithRenderer(&r))
s := flag.String("s", "", "style json path")
flag.Parse()
r, err := gold.NewTermRenderer(*s)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
out := bf.Run([]byte(tmd), bf.WithRenderer(r))
fmt.Println(string(out))
}

229
gold.go
View file

@ -1,8 +1,11 @@
package gold
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"
"strings"
@ -26,134 +29,171 @@ const (
Blink
)
type TermRenderer struct {
style map[bf.NodeType]map[RuleKey]string
type ElementStyle struct {
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 {
case bf.Document:
return ""
return Element{""}
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:
return ""
return Element{""}
case bf.Item:
return fmt.Sprintf("* %s", string(node.Literal))
return Element{fmt.Sprintf("* %s", string(node.Literal))}
case bf.Paragraph:
if node.Prev != nil && node.Prev.Type != bf.Link {
return "\n"
return Element{"\n"}
} else {
return ""
return Element{""}
}
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:
return "---\n"
return Element{"---\n"}
case bf.Emph:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Strong:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Del:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
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:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Text:
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 {
return ""
return Element{""}
}
case bf.HTMLBlock:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.CodeBlock:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Softbreak:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Hardbreak:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Code:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.HTMLSpan:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.Table:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableCell:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableHead:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableBody:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
case bf.TableRow:
return fmt.Sprintf("%s\n", string(node.Literal))
return Element{fmt.Sprintf("%s\n", string(node.Literal))}
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 {
if !entering {
return bf.GoToNext
}
text := BaseString(node)
if text == "" {
el := NewElement(node)
if el.BaseString == "" {
return bf.GoToNext
}
rules := tr.style[node.Type]
if len(rules) == 0 {
fmt.Fprintf(w, "%s", text)
if rules == nil {
fmt.Fprintf(w, "%s", el.BaseString)
return bf.GoToNext
}
out := aurora.Reset(text)
if r, ok := rules[Color]; ok {
i, err := strconv.Atoi(r)
out := aurora.Reset(el.BaseString)
if rules.Color != "" {
i, err := strconv.Atoi(rules.Color)
if err == nil && i >= 0 && i <= 255 {
out = out.Index(uint8(i))
}
}
if r, ok := rules[BackgroundColor]; ok {
i, err := strconv.Atoi(r)
if rules.BackgroundColor != "" {
i, err := strconv.Atoi(rules.BackgroundColor)
if err == nil && i >= 0 && i <= 255 {
out = out.Index(uint8(i))
}
}
if r, ok := rules[Underline]; ok {
if r == "true" {
out = out.Underline()
}
if rules.Underline {
out = out.Underline()
}
if r, ok := rules[Bold]; ok {
if r == "true" {
out = out.Bold()
}
if rules.Bold {
out = out.Bold()
}
if r, ok := rules[Italic]; ok {
if r == "true" {
out = out.Italic()
}
if rules.Italic {
out = out.Italic()
}
if r, ok := rules[CrossedOut]; ok {
if r == "true" {
out = out.CrossedOut()
}
if rules.CrossedOut {
out = out.CrossedOut()
}
if r, ok := rules[Overlined]; ok {
if r == "true" {
out = out.Overlined()
}
if rules.Overlined {
out = out.Overlined()
}
if r, ok := rules[Inverse]; ok {
if r == "true" {
out = out.Reverse()
}
if rules.Inverse {
out = out.Reverse()
}
if r, ok := rules[Blink]; ok {
if r == "true" {
out = out.Blink()
}
if rules.Blink {
out = out.Blink()
}
w.Write([]byte(aurora.Sprintf("%s", out)))
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 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)
}
}