Decode style JSON into a typed struct

This commit is contained in:
Christian Muehlhaeuser
2019-12-13 03:04:48 +01:00
parent 219f21c4e7
commit 35342a2061
17 changed files with 184 additions and 249 deletions
+6 -6
View File
@@ -17,7 +17,7 @@ type BaseElement struct {
Token string Token string
Prefix string Prefix string
Suffix string Suffix string
Style ElementStyle Style StylePrimitive
} }
func color(c *string) (uint8, error) { func color(c *string) (uint8, error) {
@@ -79,7 +79,7 @@ func formatToken(format string, token string) (string, error) {
return b.String(), err return b.String(), err
} }
func renderText(w io.Writer, rules ElementStyle, s string) { func renderText(w io.Writer, rules StylePrimitive, s string) {
if len(s) == 0 { if len(s) == 0 {
return return
} }
@@ -139,15 +139,15 @@ func renderText(w io.Writer, rules ElementStyle, s string) {
func (e *BaseElement) Render(w io.Writer, ctx RenderContext) error { func (e *BaseElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
renderText(w, bs.Current().Style, e.Prefix) renderText(w, bs.Current().Style.StylePrimitive, e.Prefix)
defer func() { defer func() {
renderText(w, bs.Current().Style, e.Suffix) renderText(w, bs.Current().Style.StylePrimitive, e.Suffix)
}() }()
rules := bs.With(e.Style) rules := bs.With(e.Style)
renderText(w, bs.Current().Style, rules.Prefix) renderText(w, bs.Current().Style.StylePrimitive, rules.Prefix)
defer func() { defer func() {
renderText(w, bs.Current().Style, rules.Suffix) renderText(w, bs.Current().Style.StylePrimitive, rules.Suffix)
}() }()
s := e.Token s := e.Token
+13 -6
View File
@@ -9,16 +9,17 @@ import (
type BlockElement struct { type BlockElement struct {
Block *bytes.Buffer Block *bytes.Buffer
Style ElementStyle Style StyleBlock
Margin bool Margin bool
Newline bool
} }
func (e *BlockElement) Render(w io.Writer, ctx RenderContext) error { func (e *BlockElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
bs.Push(*e) bs.Push(*e)
renderText(w, bs.Parent().Style, e.Style.Prefix) renderText(w, bs.Parent().Style.StylePrimitive, e.Style.Prefix)
renderText(w, bs.Current().Style, e.Style.StyledPrefix) renderText(w, bs.Current().Style.StylePrimitive, e.Style.StyledPrefix)
return nil return nil
} }
@@ -32,7 +33,13 @@ func (e *BlockElement) Finish(w io.Writer, ctx RenderContext) error {
if err != nil { if err != nil {
return err return err
} }
mw.Write([]byte("\n"))
if e.Newline {
_, err = mw.Write([]byte("\n"))
if err != nil {
return err
}
}
} else { } else {
_, err := bs.Parent().Block.Write(bs.Current().Block.Bytes()) _, err := bs.Parent().Block.Write(bs.Current().Block.Bytes())
if err != nil { if err != nil {
@@ -40,8 +47,8 @@ func (e *BlockElement) Finish(w io.Writer, ctx RenderContext) error {
} }
} }
renderText(w, bs.Current().Style, e.Style.StyledSuffix) renderText(w, bs.Current().Style.StylePrimitive, e.Style.StyledSuffix)
renderText(w, bs.Parent().Style, e.Style.Suffix) renderText(w, bs.Parent().Style.StylePrimitive, e.Style.Suffix)
bs.Current().Block.Reset() bs.Current().Block.Reset()
bs.Pop() bs.Pop()
+4 -2
View File
@@ -77,6 +77,8 @@ func (s BlockStack) Current() BlockElement {
return s[len(s)-1] return s[len(s)-1]
} }
func (s BlockStack) With(child ElementStyle) ElementStyle { func (s BlockStack) With(child StylePrimitive) StylePrimitive {
return cascadeStyle(s.Current().Style, child, true) sb := StyleBlock{}
sb.StylePrimitive = child
return cascadeStyle(s.Current().Style, sb, true).StylePrimitive
} }
+3 -3
View File
@@ -11,14 +11,14 @@ type CheckedItemElement struct {
func (e *CheckedItemElement) Render(w io.Writer, ctx RenderContext) error { func (e *CheckedItemElement) Render(w io.Writer, ctx RenderContext) error {
var el *BaseElement var el *BaseElement
pre := "✗ " pre := ctx.styles.Task.Unticked
if e.Checked { if e.Checked {
pre = "✓ " pre = ctx.styles.Task.Ticked
} }
el = &BaseElement{ el = &BaseElement{
Prefix: pre, Prefix: pre,
Style: ctx.style[CheckedItem], Style: ctx.styles.Task.StylePrimitive,
} }
return el.Render(w, ctx) return el.Render(w, ctx)
+5 -5
View File
@@ -16,7 +16,7 @@ func (e *CodeBlockElement) Render(w io.Writer, ctx RenderContext) error {
var indent uint var indent uint
var margin uint var margin uint
rules := ctx.style[CodeBlock] rules := ctx.styles.CodeBlock
if rules.Indent != nil { if rules.Indent != nil {
indent = *rules.Indent indent = *rules.Indent
} }
@@ -28,7 +28,7 @@ func (e *CodeBlockElement) Render(w io.Writer, ctx RenderContext) error {
iw := &IndentWriter{ iw := &IndentWriter{
Indent: indent + margin, Indent: indent + margin,
IndentFunc: func(wr io.Writer) { IndentFunc: func(wr io.Writer) {
renderText(w, bs.Current().Style, " ") renderText(w, bs.Current().Style.StylePrimitive, " ")
}, },
Forward: &AnsiWriter{ Forward: &AnsiWriter{
Forward: w, Forward: w,
@@ -36,16 +36,16 @@ func (e *CodeBlockElement) Render(w io.Writer, ctx RenderContext) error {
} }
if len(theme) > 0 { if len(theme) > 0 {
renderText(iw, bs.Current().Style, rules.Prefix) renderText(iw, bs.Current().Style.StylePrimitive, rules.Prefix)
err := quick.Highlight(iw, e.Code, e.Language, "terminal16m", theme) err := quick.Highlight(iw, e.Code, e.Language, "terminal16m", theme)
renderText(iw, bs.Current().Style, rules.Suffix) renderText(iw, bs.Current().Style.StylePrimitive, rules.Suffix)
return err return err
} }
// fallback rendering // fallback rendering
el := &BaseElement{ el := &BaseElement{
Token: e.Code, Token: e.Code,
Style: rules, Style: rules.StylePrimitive,
} }
return el.Render(iw, ctx) return el.Render(iw, ctx)
+1 -2
View File
@@ -9,7 +9,7 @@ import (
type RenderContext struct { type RenderContext struct {
options Options options Options
style map[StyleType]ElementStyle styles StyleConfig
blockStack *BlockStack blockStack *BlockStack
table *TableElement table *TableElement
@@ -20,7 +20,6 @@ type RenderContext struct {
func NewRenderContext(options Options) RenderContext { func NewRenderContext(options Options) RenderContext {
return RenderContext{ return RenderContext{
options: options, options: options,
style: make(map[StyleType]ElementStyle),
blockStack: &BlockStack{}, blockStack: &BlockStack{},
table: &TableElement{}, table: &TableElement{},
stripper: bluemonday.StrictPolicy(), stripper: bluemonday.StrictPolicy(),
+4 -4
View File
@@ -9,7 +9,7 @@ type DocumentElement struct {
} }
func (e *DocumentElement) Render(w io.Writer, ctx RenderContext) error { func (e *DocumentElement) Render(w io.Writer, ctx RenderContext) error {
rules := ctx.style[Document] rules := ctx.styles.Document
be := BlockElement{ be := BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
@@ -17,20 +17,20 @@ func (e *DocumentElement) Render(w io.Writer, ctx RenderContext) error {
} }
ctx.blockStack.Push(be) ctx.blockStack.Push(be)
renderText(ctx.blockStack.Current().Block, rules, rules.Prefix) renderText(ctx.blockStack.Current().Block, rules.StylePrimitive, rules.Prefix)
return nil return nil
} }
func (e *DocumentElement) Finish(w io.Writer, ctx RenderContext) error { func (e *DocumentElement) Finish(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
rules := ctx.style[Document] rules := ctx.styles.Document
mw := NewMarginWriter(ctx, w, rules) mw := NewMarginWriter(ctx, w, rules)
_, err := mw.Write(bs.Current().Block.Bytes()) _, err := mw.Write(bs.Current().Block.Bytes())
if err != nil { if err != nil {
return err return err
} }
renderText(mw, rules, rules.Suffix) renderText(mw, rules.StylePrimitive, rules.Suffix)
bs.Current().Block.Reset() bs.Current().Block.Reset()
bs.Pop() bs.Pop()
+31 -13
View File
@@ -61,8 +61,9 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
case ast.KindBlockquote: case ast.KindBlockquote:
e := &BlockElement{ e := &BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.style[BlockQuote], true), Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.BlockQuote, true),
Margin: true, Margin: true,
Newline: true,
} }
return Element{ return Element{
Entering: "\n", Entering: "\n",
@@ -72,10 +73,26 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
// Lists // Lists
case ast.KindList: case ast.KindList:
s := ctx.styles.List.StyleBlock
if s.Indent == nil {
var i uint
s.Indent = &i
}
n := node.Parent()
for n != nil {
if n.Kind() == ast.KindList {
i := ctx.styles.List.LevelIndent
s.Indent = &i
break
}
n = n.Parent()
}
e := &BlockElement{ e := &BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.style[List], true), Style: cascadeStyle(ctx.blockStack.Current().Style, s, true),
Margin: true, Margin: true,
Newline: true,
} }
return Element{ return Element{
Entering: "\n", Entering: "\n",
@@ -130,16 +147,16 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
Token: ctx.SanitizeHTML(s, false), Token: ctx.SanitizeHTML(s, false),
Style: ctx.style[Text], Style: ctx.styles.Text,
}, },
} }
case ast.KindEmphasis: case ast.KindEmphasis:
n := node.(*ast.Emphasis) n := node.(*ast.Emphasis)
s := string(n.Text(source)) s := string(n.Text(source))
style := ctx.style[Emph] style := ctx.styles.Emph
if n.Level > 1 { if n.Level > 1 {
style = ctx.style[Strong] style = ctx.styles.Strong
} }
return Element{ return Element{
@@ -152,7 +169,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
case astext.KindStrikethrough: case astext.KindStrikethrough:
n := node.(*astext.Strikethrough) n := node.(*astext.Strikethrough)
s := string(n.Text(source)) s := string(n.Text(source))
style := ctx.style[Strikethrough] style := ctx.styles.Strikethrough
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
@@ -166,7 +183,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
Entering: "", Entering: "",
Exiting: "", Exiting: "",
Renderer: &BaseElement{ Renderer: &BaseElement{
Style: ctx.style[HorizontalRule], Style: ctx.styles.HorizontalRule,
}, },
} }
@@ -240,7 +257,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
// n := node.(*ast.CodeSpan) // n := node.(*ast.CodeSpan)
e := &BlockElement{ e := &BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.style[Code], true), Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.Code, true),
} }
return Element{ return Element{
Renderer: e, Renderer: e,
@@ -287,7 +304,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n", Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n",
Style: ctx.style[HTMLBlock], Style: ctx.styles.HTMLBlock.StylePrimitive,
}, },
} }
case ast.KindRawHTML: case ast.KindRawHTML:
@@ -295,7 +312,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n", Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n",
Style: ctx.style[HTMLSpan], Style: ctx.styles.HTMLSpan.StylePrimitive,
}, },
} }
@@ -303,8 +320,9 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
case astext.KindDefinitionList: case astext.KindDefinitionList:
e := &BlockElement{ e := &BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.style[DefinitionList], true), Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.DefinitionList, true),
Margin: true, Margin: true,
Newline: true,
} }
return Element{ return Element{
Entering: "\n", Entering: "\n",
@@ -315,14 +333,14 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
case astext.KindDefinitionTerm: case astext.KindDefinitionTerm:
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
Style: ctx.style[DefinitionTerm], Style: ctx.styles.DefinitionTerm,
}, },
} }
case astext.KindDefinitionDescription: case astext.KindDefinitionDescription:
return Element{ return Element{
Renderer: &BaseElement{ Renderer: &BaseElement{
Style: ctx.style[DefinitionDescription], Style: ctx.styles.DefinitionDescription,
}, },
} }
+2 -13
View File
@@ -3,7 +3,6 @@ package gold
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"log" "log"
"net/url" "net/url"
@@ -61,23 +60,13 @@ func NewTermRenderer(stylePath string, options Options) (*TermRenderer, error) {
// NewTermRendererFromBytes returns a new TermRenderer with style and options // NewTermRendererFromBytes returns a new TermRenderer with style and options
// set. // set.
func NewTermRendererFromBytes(b []byte, options Options) (*TermRenderer, error) { func NewTermRendererFromBytes(b []byte, options Options) (*TermRenderer, error) {
e := make(map[string]ElementStyle)
err := json.Unmarshal(b, &e)
if err != nil {
return nil, err
}
tr := &TermRenderer{ tr := &TermRenderer{
context: NewRenderContext(options), context: NewRenderContext(options),
} }
for k, v := range e { err := json.Unmarshal(b, &tr.context.styles)
t, err := keyToType(k)
if err != nil { if err != nil {
fmt.Println(err) return nil, err
continue
}
tr.context.style[t] = v
} }
return tr, nil return tr, nil
+13 -13
View File
@@ -14,25 +14,25 @@ type HeadingElement struct {
func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error { func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
rules := ctx.style[Heading] rules := ctx.styles.Heading
switch e.Level { switch e.Level {
case 1: case 1:
rules = cascadeStyles(false, rules, ctx.style[H1]) rules = cascadeStyles(false, rules, ctx.styles.H1)
case 2: case 2:
rules = cascadeStyles(false, rules, ctx.style[H2]) rules = cascadeStyles(false, rules, ctx.styles.H2)
case 3: case 3:
rules = cascadeStyles(false, rules, ctx.style[H3]) rules = cascadeStyles(false, rules, ctx.styles.H3)
case 4: case 4:
rules = cascadeStyles(false, rules, ctx.style[H4]) rules = cascadeStyles(false, rules, ctx.styles.H4)
case 5: case 5:
rules = cascadeStyles(false, rules, ctx.style[H5]) rules = cascadeStyles(false, rules, ctx.styles.H5)
case 6: case 6:
rules = cascadeStyles(false, rules, ctx.style[H6]) rules = cascadeStyles(false, rules, ctx.styles.H6)
} }
if !e.First { if !e.First {
renderText(w, bs.Current().Style, "\n") renderText(w, bs.Current().Style.StylePrimitive, "\n")
} }
be := BlockElement{ be := BlockElement{
@@ -41,8 +41,8 @@ func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error {
} }
bs.Push(be) bs.Push(be)
renderText(w, bs.Parent().Style, rules.Prefix) renderText(w, bs.Parent().Style.StylePrimitive, rules.Prefix)
renderText(w, bs.Current().Style, rules.StyledPrefix) renderText(w, bs.Current().Style.StylePrimitive, rules.StyledPrefix)
return nil return nil
} }
@@ -62,7 +62,7 @@ func (e *HeadingElement) Finish(w io.Writer, ctx RenderContext) error {
iw := &IndentWriter{ iw := &IndentWriter{
Indent: indent + margin, Indent: indent + margin,
IndentFunc: func(wr io.Writer) { IndentFunc: func(wr io.Writer) {
renderText(w, bs.Parent().Style, " ") renderText(w, bs.Parent().Style.StylePrimitive, " ")
}, },
Forward: &AnsiWriter{ Forward: &AnsiWriter{
Forward: w, Forward: w,
@@ -81,8 +81,8 @@ func (e *HeadingElement) Finish(w io.Writer, ctx RenderContext) error {
return err return err
} }
renderText(w, bs.Current().Style, rules.StyledSuffix) renderText(w, bs.Current().Style.StylePrimitive, rules.StyledSuffix)
renderText(w, bs.Parent().Style, rules.Suffix) renderText(w, bs.Parent().Style.StylePrimitive, rules.Suffix)
bs.Current().Block.Reset() bs.Current().Block.Reset()
bs.Pop() bs.Pop()
+2 -2
View File
@@ -15,7 +15,7 @@ func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error {
if len(e.Text) > 0 { if len(e.Text) > 0 {
el := &BaseElement{ el := &BaseElement{
Token: e.Text, Token: e.Text,
Style: ctx.style[ImageText], Style: ctx.styles.ImageText,
} }
err := el.Render(w, ctx) err := el.Render(w, ctx)
if err != nil { if err != nil {
@@ -26,7 +26,7 @@ func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error {
el := &BaseElement{ el := &BaseElement{
Token: resolveRelativeURL(e.BaseURL, e.URL), Token: resolveRelativeURL(e.BaseURL, e.URL),
Prefix: " ", Prefix: " ",
Style: ctx.style[Image], Style: ctx.styles.Image,
} }
err := el.Render(w, ctx) err := el.Render(w, ctx)
if err != nil { if err != nil {
+2 -2
View File
@@ -19,7 +19,7 @@ func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error {
el := &BaseElement{ el := &BaseElement{
Token: e.Text, Token: e.Text,
Style: ctx.style[LinkText], Style: ctx.styles.LinkText,
} }
err := el.Render(w, ctx) err := el.Render(w, ctx)
if err != nil { if err != nil {
@@ -53,7 +53,7 @@ func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error {
if len(e.URL) > 0 { if len(e.URL) > 0 {
pre := " " pre := " "
style := ctx.style[Link] style := ctx.styles.Link
if !textRendered { if !textRendered {
pre = "" pre = ""
style.Prefix = "" style.Prefix = ""
+2 -2
View File
@@ -13,12 +13,12 @@ func (e *ItemElement) Render(w io.Writer, ctx RenderContext) error {
var el *BaseElement var el *BaseElement
if e.Enumeration > 0 { if e.Enumeration > 0 {
el = &BaseElement{ el = &BaseElement{
Style: ctx.style[Enumeration], Style: ctx.styles.Enumeration,
Prefix: strconv.FormatInt(int64(e.Enumeration), 10), Prefix: strconv.FormatInt(int64(e.Enumeration), 10),
} }
} else { } else {
el = &BaseElement{ el = &BaseElement{
Style: ctx.style[Item], Style: ctx.styles.Item,
} }
} }
+3 -3
View File
@@ -10,7 +10,7 @@ type MarginWriter struct {
iw *IndentWriter iw *IndentWriter
} }
func NewMarginWriter(ctx RenderContext, w io.Writer, rules ElementStyle) *MarginWriter { func NewMarginWriter(ctx RenderContext, w io.Writer, rules StyleBlock) *MarginWriter {
bs := ctx.blockStack bs := ctx.blockStack
var indent uint var indent uint
@@ -25,7 +25,7 @@ func NewMarginWriter(ctx RenderContext, w io.Writer, rules ElementStyle) *Margin
pw := &PaddingWriter{ pw := &PaddingWriter{
Padding: bs.Width(ctx), Padding: bs.Width(ctx),
PadFunc: func(wr io.Writer) { PadFunc: func(wr io.Writer) {
renderText(w, rules, " ") renderText(w, rules.StylePrimitive, " ")
}, },
Forward: &AnsiWriter{ Forward: &AnsiWriter{
Forward: w, Forward: w,
@@ -34,7 +34,7 @@ func NewMarginWriter(ctx RenderContext, w io.Writer, rules ElementStyle) *Margin
iw := &IndentWriter{ iw := &IndentWriter{
Indent: indent + margin, Indent: indent + margin,
IndentFunc: func(wr io.Writer) { IndentFunc: func(wr io.Writer) {
renderText(w, bs.Parent().Style, " ") renderText(w, bs.Parent().Style.StylePrimitive, " ")
}, },
Forward: &AnsiWriter{ Forward: &AnsiWriter{
Forward: pw, Forward: pw,
+6 -9
View File
@@ -13,9 +13,8 @@ type ParagraphElement struct {
func (e *ParagraphElement) Render(w io.Writer, ctx RenderContext) error { func (e *ParagraphElement) Render(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
var rules ElementStyle rules := ctx.styles.Paragraph
rules = ctx.style[Paragraph]
_, _ = w.Write([]byte("\n")) _, _ = w.Write([]byte("\n"))
be := BlockElement{ be := BlockElement{
Block: &bytes.Buffer{}, Block: &bytes.Buffer{},
@@ -23,8 +22,8 @@ func (e *ParagraphElement) Render(w io.Writer, ctx RenderContext) error {
} }
bs.Push(be) bs.Push(be)
renderText(w, bs.Parent().Style, rules.Prefix) renderText(w, bs.Parent().Style.StylePrimitive, rules.Prefix)
renderText(w, bs.Current().Style, rules.StyledPrefix) renderText(w, bs.Current().Style.StylePrimitive, rules.StyledPrefix)
return nil return nil
} }
@@ -32,12 +31,10 @@ func (e *ParagraphElement) Finish(w io.Writer, ctx RenderContext) error {
bs := ctx.blockStack bs := ctx.blockStack
rules := bs.Current().Style rules := bs.Current().Style
keepNewlines := false
mw := NewMarginWriter(ctx, w, rules) mw := NewMarginWriter(ctx, w, rules)
if len(strings.TrimSpace(bs.Current().Block.String())) > 0 { if len(strings.TrimSpace(bs.Current().Block.String())) > 0 {
flow := reflow.NewReflow(int(bs.Width(ctx))) flow := reflow.NewReflow(int(bs.Width(ctx)))
flow.KeepNewlines = keepNewlines flow.KeepNewlines = false
_, _ = flow.Write(bs.Current().Block.Bytes()) _, _ = flow.Write(bs.Current().Block.Bytes())
flow.Close() flow.Close()
@@ -48,8 +45,8 @@ func (e *ParagraphElement) Finish(w io.Writer, ctx RenderContext) error {
_, _ = mw.Write([]byte("\n")) _, _ = mw.Write([]byte("\n"))
} }
renderText(w, bs.Current().Style, rules.StyledSuffix) renderText(w, bs.Current().Style.StylePrimitive, rules.StyledSuffix)
renderText(w, bs.Parent().Style, rules.Suffix) renderText(w, bs.Parent().Style.StylePrimitive, rules.Suffix)
bs.Current().Block.Reset() bs.Current().Block.Reset()
bs.Pop() bs.Pop()
+71 -148
View File
@@ -1,7 +1,6 @@
package gold package gold
import ( import (
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
@@ -12,67 +11,11 @@ import (
_ "github.com/charmbracelet/gold/statik" _ "github.com/charmbracelet/gold/statik"
) )
type StyleType int type StylePrimitive struct {
Prefix string `json:"prefix"`
const ( Suffix string `json:"suffix"`
Document StyleType = iota StyledPrefix string `json:"styled_prefix"`
StyledSuffix string `json:"styled_suffix"`
// Block elements
Heading
Paragraph
BlockQuote
List
// Text elements
Text
Strikethrough
Emph
Strong
HorizontalRule
// ListItem styles
Item
CheckedItem
Enumeration
// Links
Link
LinkText
// Images
Image
ImageText
// Code styles
CodeBlock
Code
// Table styles
Table
TableCell
TableHead
TableBody
TableRow
// Definition Lists
DefinitionList
DefinitionTerm
DefinitionDescription
// HTML styles
HTMLBlock
HTMLSpan
// Style definitions for individual heading levels
H1
H2
H3
H4
H5
H6
)
type ElementStyle struct {
Color *string `json:"color"` Color *string `json:"color"`
BackgroundColor *string `json:"background_color"` BackgroundColor *string `json:"background_color"`
Underline *bool `json:"underline"` Underline *bool `json:"underline"`
@@ -84,14 +27,72 @@ type ElementStyle struct {
Overlined *bool `json:"overlined"` Overlined *bool `json:"overlined"`
Inverse *bool `json:"inverse"` Inverse *bool `json:"inverse"`
Blink *bool `json:"blink"` Blink *bool `json:"blink"`
Format string `json:"format"`
}
type StyleTask struct {
StyleBlock
Ticked string `json:"ticked"`
Unticked string `json:"unticked"`
}
type StyleBlock struct {
StylePrimitive
Indent *uint `json:"indent"` Indent *uint `json:"indent"`
Margin *uint `json:"margin"` Margin *uint `json:"margin"`
}
type StyleCodeBlock struct {
StyleBlock
Theme string `json:"theme"` Theme string `json:"theme"`
Prefix string `json:"prefix"` }
Suffix string `json:"suffix"`
StyledPrefix string `json:"styled_prefix"` type StyleList struct {
StyledSuffix string `json:"styled_suffix"` StyleBlock
Format string `json:"format"` LevelIndent uint `json:"level_indent"`
}
type StyleConfig struct {
Document StyleBlock `json:"document"`
BlockQuote StyleBlock `json:"block_quote"`
Paragraph StyleBlock `json:"paragraph"`
List StyleList `json:"list"`
Heading StyleBlock `json:"heading"`
H1 StyleBlock `json:"h1"`
H2 StyleBlock `json:"h2"`
H3 StyleBlock `json:"h3"`
H4 StyleBlock `json:"h4"`
H5 StyleBlock `json:"h5"`
H6 StyleBlock `json:"h6"`
Text StylePrimitive `json:"text"`
Strikethrough StylePrimitive `json:"strike_through"`
Emph StylePrimitive `json:"emph"`
Strong StylePrimitive `json:"strong"`
HorizontalRule StylePrimitive `json:"hr"`
Item StylePrimitive `json:"item"`
Enumeration StylePrimitive `json:"enumeration"`
Task StyleTask `json:"task"`
Link StylePrimitive `json:"link"`
LinkText StylePrimitive `json:"link_text"`
Image StylePrimitive `json:"image"`
ImageText StylePrimitive `json:"image_text"`
Code StyleBlock `json:"code"`
CodeBlock StyleCodeBlock `json:"code_block"`
Table StyleBlock `json:"table"`
DefinitionList StyleBlock `json:"definition_list"`
DefinitionTerm StylePrimitive `json:"definition_term"`
DefinitionDescription StylePrimitive `json:"definition_description"`
HTMLBlock StyleBlock `json:"html_block"`
HTMLSpan StyleBlock `json:"html_span"`
} }
func loadStyle(f string) ([]byte, error) { func loadStyle(f string) ([]byte, error) {
@@ -115,8 +116,8 @@ func loadStyle(f string) ([]byte, error) {
return ioutil.ReadAll(r) return ioutil.ReadAll(r)
} }
func cascadeStyles(onlyColors bool, s ...ElementStyle) ElementStyle { func cascadeStyles(onlyColors bool, s ...StyleBlock) StyleBlock {
var r ElementStyle var r StyleBlock
for _, v := range s { for _, v := range s {
r = cascadeStyle(r, v, onlyColors) r = cascadeStyle(r, v, onlyColors)
@@ -124,7 +125,7 @@ func cascadeStyles(onlyColors bool, s ...ElementStyle) ElementStyle {
return r return r
} }
func cascadeStyle(parent ElementStyle, child ElementStyle, onlyColors bool) ElementStyle { func cascadeStyle(parent StyleBlock, child StyleBlock, onlyColors bool) StyleBlock {
s := child s := child
s.Color = parent.Color s.Color = parent.Color
@@ -248,81 +249,3 @@ func hexToANSIColor(h string) (int, error) {
} }
return 232 + grayIdx, nil return 232 + grayIdx, nil
} }
func keyToType(key string) (StyleType, error) {
switch key {
case "document":
return Document, nil
case "block_quote":
return BlockQuote, nil
case "list":
return List, nil
case "item":
return Item, nil
case "checked_item":
return CheckedItem, nil
case "enumeration":
return Enumeration, nil
case "paragraph":
return Paragraph, nil
case "heading":
return Heading, nil
case "h1":
return H1, nil
case "h2":
return H2, nil
case "h3":
return H3, nil
case "h4":
return H4, nil
case "h5":
return H5, nil
case "h6":
return H6, nil
case "hr":
return HorizontalRule, nil
case "strikethrough":
return Strikethrough, nil
case "emph":
return Emph, nil
case "strong":
return Strong, nil
case "link":
return Link, nil
case "link_text":
return LinkText, nil
case "image":
return Image, nil
case "image_text":
return ImageText, nil
case "text":
return Text, nil
case "html_block":
return HTMLBlock, nil
case "code_block":
return CodeBlock, nil
case "code":
return Code, nil
case "html_span":
return HTMLSpan, nil
case "table":
return Table, nil
case "table_cel":
return TableCell, nil
case "table_head":
return TableHead, nil
case "table_body":
return TableBody, nil
case "table_row":
return TableRow, nil
case "definition_list":
return DefinitionList, nil
case "definition_term":
return DefinitionTerm, nil
case "definition_description":
return DefinitionDescription, nil
default:
return 0, fmt.Errorf("invalid style element type: %s", key)
}
}
+5 -5
View File
@@ -29,7 +29,7 @@ func (e *TableElement) Render(w io.Writer, ctx RenderContext) error {
var indent uint var indent uint
var margin uint var margin uint
rules := ctx.style[Table] rules := ctx.styles.Table
if rules.Indent != nil { if rules.Indent != nil {
indent = *rules.Indent indent = *rules.Indent
} }
@@ -40,14 +40,14 @@ func (e *TableElement) Render(w io.Writer, ctx RenderContext) error {
ctx.table.indentWriter = &IndentWriter{ ctx.table.indentWriter = &IndentWriter{
Indent: indent + margin, Indent: indent + margin,
IndentFunc: func(wr io.Writer) { IndentFunc: func(wr io.Writer) {
renderText(w, bs.Current().Style, " ") renderText(w, bs.Current().Style.StylePrimitive, " ")
}, },
Forward: &AnsiWriter{ Forward: &AnsiWriter{
Forward: w, Forward: w,
}, },
} }
renderText(ctx.table.indentWriter, bs.Current().Style, rules.Prefix) renderText(ctx.table.indentWriter, bs.Current().Style.StylePrimitive, rules.Prefix)
ctx.table.writer = tablewriter.NewWriter(ctx.table.indentWriter) ctx.table.writer = tablewriter.NewWriter(ctx.table.indentWriter)
return nil return nil
} }
@@ -56,8 +56,8 @@ func (e *TableElement) Finish(w io.Writer, ctx RenderContext) error {
ctx.table.writer.Render() ctx.table.writer.Render()
ctx.table.writer = nil ctx.table.writer = nil
rules := ctx.style[Table] rules := ctx.styles.Table
renderText(ctx.table.indentWriter, ctx.blockStack.Current().Style, rules.Suffix) renderText(ctx.table.indentWriter, ctx.blockStack.Current().Style.StylePrimitive, rules.Suffix)
return nil return nil
} }