From 665477d6902d12bee34f5391085848a4316527b3 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 7 Dec 2019 15:40:42 +0100 Subject: [PATCH] Move stateful objects to RenderContext struct --- baseelement.go | 12 +++++++----- codeblock.go | 6 ++++-- document.go | 19 ++++++++++++------- elements.go | 24 +++++++++++++----------- gold.go | 21 ++++++++++++--------- heading.go | 26 +++++++++++++++----------- image.go | 6 ++++-- link.go | 7 ++++--- list.go | 24 ++++++++++++++---------- listitem.go | 7 ++++--- paragraph.go | 37 ++++++++++++++++++++++--------------- table.go | 29 ++++++++++++++++++----------- 12 files changed, 129 insertions(+), 89 deletions(-) diff --git a/baseelement.go b/baseelement.go index 4be1b11..ae99b33 100644 --- a/baseelement.go +++ b/baseelement.go @@ -138,15 +138,17 @@ func renderText(w io.Writer, rules ElementStyle, s string) { } func (e *BaseElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - renderText(w, tr.blockStack.Current().Style, e.Prefix) + bs := tr.context.blockStack + + renderText(w, bs.Current().Style, e.Prefix) defer func() { - renderText(w, tr.blockStack.Current().Style, e.Suffix) + renderText(w, bs.Current().Style, e.Suffix) }() - rules := tr.blockStack.With(e.Style) - renderText(w, tr.blockStack.Current().Style, rules.Prefix) + rules := bs.With(e.Style) + renderText(w, bs.Current().Style, rules.Prefix) defer func() { - renderText(w, tr.blockStack.Current().Style, rules.Suffix) + renderText(w, bs.Current().Style, rules.Suffix) }() s := e.Token diff --git a/codeblock.go b/codeblock.go index 9bb250f..d22cada 100644 --- a/codeblock.go +++ b/codeblock.go @@ -13,9 +13,11 @@ type CodeBlockElement struct { } func (e *CodeBlockElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + var indent uint var margin uint - rules := tr.style[CodeBlock] + rules := ctx.style[CodeBlock] if rules.Indent != nil { indent = *rules.Indent } @@ -27,7 +29,7 @@ func (e *CodeBlockElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) iw := &IndentWriter{ Indent: indent + margin, IndentFunc: func(wr io.Writer) { - renderText(w, tr.blockStack.Parent().Style, " ") + renderText(w, ctx.blockStack.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: w, diff --git a/document.go b/document.go index 15d93a3..2a99a26 100644 --- a/document.go +++ b/document.go @@ -11,21 +11,26 @@ type DocumentElement struct { } func (e *DocumentElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - rules := tr.style[Document] + ctx := tr.context + rules := ctx.style[Document] + be := BlockElement{ Block: &bytes.Buffer{}, Style: rules, } - tr.blockStack.Push(be) + ctx.blockStack.Push(be) - renderText(tr.blockStack.Current().Block, rules, rules.Prefix) + renderText(ctx.blockStack.Current().Block, rules, rules.Prefix) return nil } func (e *DocumentElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + bs := ctx.blockStack + rules := ctx.style[Document] + var indent uint var margin uint - rules := tr.style[Document] if rules.Indent != nil { indent = *rules.Indent } @@ -49,14 +54,14 @@ func (e *DocumentElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) e Forward: pw, }, } - _, err := iw.Write(tr.blockStack.Current().Block.Bytes()) + _, err := iw.Write(bs.Current().Block.Bytes()) if err != nil { return err } renderText(iw, rules, suffix) - tr.blockStack.Current().Block.Reset() - tr.blockStack.Pop() + bs.Current().Block.Reset() + bs.Pop() return nil } diff --git a/elements.go b/elements.go index d82083d..ff8c217 100644 --- a/elements.go +++ b/elements.go @@ -24,6 +24,8 @@ type Element struct { } func (tr *TermRenderer) NewElement(node *bf.Node) Element { + ctx := tr.context + switch node.Type { case bf.Document: de := &DocumentElement{} @@ -37,7 +39,7 @@ func (tr *TermRenderer) NewElement(node *bf.Node) Element { Exiting: "\n", Renderer: &BaseElement{ Token: string(node.Literal), - Style: tr.style[BlockQuote], + Style: ctx.style[BlockQuote], }, } case bf.List: @@ -67,28 +69,28 @@ func (tr *TermRenderer) NewElement(node *bf.Node) Element { Exiting: "\n", Renderer: &BaseElement{ Token: "---", - Style: tr.style[HorizontalRule], + Style: ctx.style[HorizontalRule], }, } case bf.Emph: return Element{ Renderer: &BaseElement{ Token: string(node.FirstChild.Literal), - Style: tr.style[Emph], + Style: ctx.style[Emph], }, } case bf.Strong: return Element{ Renderer: &BaseElement{ Token: string(node.FirstChild.Literal), - Style: tr.style[Strong], + Style: ctx.style[Strong], }, } case bf.Del: return Element{ Renderer: &BaseElement{ Token: string(node.Literal), - Style: tr.style[Del], + Style: ctx.style[Del], }, } case bf.Link: @@ -103,14 +105,14 @@ func (tr *TermRenderer) NewElement(node *bf.Node) Element { return Element{ Renderer: &BaseElement{ Token: html.UnescapeString(stripper.Sanitize(string(node.Literal))), - Style: tr.style[Text], + Style: ctx.style[Text], }, } case bf.HTMLBlock: return Element{ Renderer: &BaseElement{ Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n", - Style: tr.style[HTMLBlock], + Style: ctx.style[HTMLBlock], }, } case bf.CodeBlock: @@ -126,7 +128,7 @@ func (tr *TermRenderer) NewElement(node *bf.Node) Element { Exiting: "\n", Renderer: &BaseElement{ Token: string(node.Literal), - Style: tr.style[Softbreak], + Style: ctx.style[Softbreak], }, } case bf.Hardbreak: @@ -134,21 +136,21 @@ func (tr *TermRenderer) NewElement(node *bf.Node) Element { Exiting: "\n", Renderer: &BaseElement{ Token: string(node.Literal), - Style: tr.style[Hardbreak], + Style: ctx.style[Hardbreak], }, } case bf.Code: return Element{ Renderer: &BaseElement{ Token: string(node.Literal), - Style: tr.style[Code], + Style: ctx.style[Code], }, } case bf.HTMLSpan: return Element{ Renderer: &BaseElement{ Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n", - Style: tr.style[HTMLSpan], + Style: ctx.style[HTMLSpan], }, } case bf.Table: diff --git a/gold.go b/gold.go index 530ae05..28696f2 100644 --- a/gold.go +++ b/gold.go @@ -19,9 +19,7 @@ type TermRenderer struct { BaseURL string WordWrap int - style map[StyleType]ElementStyle - blockStack BlockStack - table TableElement + context RenderContext } func Render(in string, stylePath string) ([]byte, error) { @@ -60,7 +58,11 @@ func NewTermRendererFromBytes(b []byte) (*TermRenderer, error) { } tr := &TermRenderer{ - style: make(map[StyleType]ElementStyle), + context: RenderContext{ + style: make(map[StyleType]ElementStyle), + blockStack: &BlockStack{}, + table: &TableElement{}, + }, } for k, v := range e { t, err := keyToType(k) @@ -68,7 +70,7 @@ func NewTermRendererFromBytes(b []byte) (*TermRenderer, error) { fmt.Println(err) continue } - tr.style[t] = v + tr.context.style[t] = v } return tr, nil } @@ -84,6 +86,7 @@ func (tr *TermRenderer) RenderBytes(in []byte) []byte { func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus { // _, _ = w.Write([]byte(node.Type.String())) writeTo := w + bs := tr.context.blockStack if isChild(node) { return bf.GoToNext @@ -91,8 +94,8 @@ func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf e := tr.NewElement(node) if entering { - if len(tr.blockStack) > 0 { - writeTo = io.Writer(tr.blockStack.Current().Block) + if len(*bs) > 0 { + writeTo = io.Writer(bs.Current().Block) } _, _ = writeTo.Write([]byte(e.Entering)) @@ -104,8 +107,8 @@ func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf } } } else { - if len(tr.blockStack) > 0 { - writeTo = io.Writer(tr.blockStack.Parent().Block) + if len(*bs) > 0 { + writeTo = io.Writer(bs.Parent().Block) } // if we're finished rendering the entire document, diff --git a/heading.go b/heading.go index 62aea50..3331064 100644 --- a/heading.go +++ b/heading.go @@ -11,25 +11,27 @@ type HeadingElement struct { } func (e *HeadingElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - var indent uint - var margin uint - rules := tr.style[Heading] + ctx := tr.context + bs := ctx.blockStack + rules := ctx.style[Heading] switch node.HeadingData.Level { case 1: - rules = cascadeStyles(false, rules, tr.style[H1]) + rules = cascadeStyles(false, rules, ctx.style[H1]) case 2: - rules = cascadeStyles(false, rules, tr.style[H2]) + rules = cascadeStyles(false, rules, ctx.style[H2]) case 3: - rules = cascadeStyles(false, rules, tr.style[H3]) + rules = cascadeStyles(false, rules, ctx.style[H3]) case 4: - rules = cascadeStyles(false, rules, tr.style[H4]) + rules = cascadeStyles(false, rules, ctx.style[H4]) case 5: - rules = cascadeStyles(false, rules, tr.style[H5]) + rules = cascadeStyles(false, rules, ctx.style[H5]) case 6: - rules = cascadeStyles(false, rules, tr.style[H6]) + rules = cascadeStyles(false, rules, ctx.style[H6]) } + var indent uint + var margin uint if rules.Indent != nil { indent = *rules.Indent } @@ -40,14 +42,16 @@ func (e *HeadingElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) er iw := &IndentWriter{ Indent: indent + margin, IndentFunc: func(wr io.Writer) { - renderText(w, tr.blockStack.Parent().Style, " ") + renderText(w, bs.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: w, }, } - flow := reflow.NewReflow(tr.WordWrap - int(indent) - int(margin*2) - int(tr.blockStack.Indent()) - int(tr.blockStack.Margin())*2) + flow := reflow.NewReflow(tr.WordWrap - + int(indent) - int(margin*2) - + int(bs.Indent()) - int(bs.Margin())*2) var pre string if node.Prev != nil { diff --git a/image.go b/image.go index 1bddd88..e14b9fc 100644 --- a/image.go +++ b/image.go @@ -10,10 +10,12 @@ type ImageElement struct { } func (e *ImageElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + if len(node.LastChild.Literal) > 0 { el := &BaseElement{ Token: string(node.LastChild.Literal), - Style: tr.style[ImageText], + Style: ctx.style[ImageText], } err := el.Render(w, node.LastChild, tr) if err != nil { @@ -24,7 +26,7 @@ func (e *ImageElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) erro el := &BaseElement{ Token: resolveRelativeURL(tr.BaseURL, string(node.LinkData.Destination)), Prefix: " ", - Style: tr.style[Image], + Style: ctx.style[Image], } err := el.Render(w, node, tr) if err != nil { diff --git a/link.go b/link.go index c92011f..53857db 100644 --- a/link.go +++ b/link.go @@ -10,8 +10,9 @@ type LinkElement struct { } func (e *LinkElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - var textRendered bool + ctx := tr.context + var textRendered bool if node.LastChild != nil { if node.LastChild.Type == bf.Image { el := tr.NewElement(node.LastChild) @@ -25,7 +26,7 @@ func (e *LinkElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error textRendered = true el := &BaseElement{ Token: string(node.LastChild.Literal), - Style: tr.style[LinkText], + Style: ctx.style[LinkText], } err := el.Render(w, node.LastChild, tr) if err != nil { @@ -36,7 +37,7 @@ func (e *LinkElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error if len(node.LinkData.Destination) > 0 { pre := " " - style := tr.style[Link] + style := ctx.style[Link] if !textRendered { pre = "" style.Prefix = "" diff --git a/list.go b/list.go index 7ada809..98717e9 100644 --- a/list.go +++ b/list.go @@ -12,24 +12,27 @@ type ListElement struct { } func (e *ListElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - rules := tr.style[List] + ctx := tr.context + rules := ctx.style[List] if node.Parent.Type != bf.Item { _, _ = w.Write([]byte("\n")) } be := BlockElement{ Block: &bytes.Buffer{}, - Style: cascadeStyle(tr.blockStack.Current().Style, rules, true), + Style: cascadeStyle(ctx.blockStack.Current().Style, rules, true), } - tr.blockStack.Push(be) + ctx.blockStack.Push(be) return nil } func (e *ListElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + bs := ctx.blockStack var indent uint var margin uint - rules := tr.blockStack.Current().Style + rules := bs.Current().Style if rules.Indent != nil { indent = *rules.Indent } @@ -37,10 +40,10 @@ func (e *ListElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error margin = *rules.Margin } suffix := rules.Suffix - renderText(tr.blockStack.Current().Block, rules, suffix) + renderText(bs.Current().Block, rules, suffix) pw := &PaddingWriter{ - Padding: uint(tr.WordWrap - int(tr.blockStack.Indent()) - int(tr.blockStack.Margin()*2)), + Padding: uint(tr.WordWrap - int(bs.Indent()) - int(bs.Margin()*2)), PadFunc: func(wr io.Writer) { renderText(w, rules, " ") }, @@ -51,19 +54,20 @@ func (e *ListElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error iw := &IndentWriter{ Indent: indent + margin, IndentFunc: func(wr io.Writer) { - renderText(w, tr.blockStack.Parent().Style, " ") + renderText(w, bs.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: pw, }, } - _, err := iw.Write(reflow.Bytes(tr.blockStack.Current().Block.Bytes(), tr.WordWrap-int(tr.blockStack.Indent())-int(tr.blockStack.Margin())*2)) + _, err := iw.Write(reflow.Bytes(bs.Current().Block.Bytes(), + tr.WordWrap-int(bs.Indent())-int(bs.Margin())*2)) if err != nil { return err } - tr.blockStack.Current().Block.Reset() - tr.blockStack.Pop() + bs.Current().Block.Reset() + bs.Pop() return nil } diff --git a/listitem.go b/listitem.go index fe0fa59..de853a4 100644 --- a/listitem.go +++ b/listitem.go @@ -11,8 +11,9 @@ type ItemElement struct { } func (e *ItemElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - var el *BaseElement + ctx := tr.context + var el *BaseElement if node.ListData.ListFlags&bf.ListTypeOrdered > 0 { var l int64 n := node @@ -23,13 +24,13 @@ func (e *ItemElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error el = &BaseElement{ Token: string(node.Literal), - Style: tr.style[Enumeration], + Style: ctx.style[Enumeration], Prefix: strconv.FormatInt(l+1, 10), } } else { el = &BaseElement{ Token: string(node.Literal), - Style: tr.style[Item], + Style: ctx.style[Item], } } diff --git a/paragraph.go b/paragraph.go index fe614c4..d336079 100644 --- a/paragraph.go +++ b/paragraph.go @@ -13,32 +13,38 @@ type ParagraphElement struct { } func (e *ParagraphElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + bs := ctx.blockStack + var rules ElementStyle if node.Parent != nil && node.Parent.Type == bf.Item { // list item - rules = tr.style[List] + rules = ctx.style[List] } else { - rules = tr.style[Paragraph] + rules = ctx.style[Paragraph] _, _ = w.Write([]byte("\n")) be := BlockElement{ Block: &bytes.Buffer{}, - Style: cascadeStyle(tr.blockStack.Current().Style, rules, true), + Style: cascadeStyle(bs.Current().Style, rules, true), } - tr.blockStack.Push(be) + bs.Push(be) } - renderText(w, tr.blockStack.Current().Style, rules.Prefix) + renderText(w, bs.Current().Style, rules.Prefix) return nil } func (e *ParagraphElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + bs := ctx.blockStack + rules := bs.Current().Style + var indent uint var margin uint keepNewlines := false - rules := tr.blockStack.Current().Style if node.Parent != nil && node.Parent.Type == bf.Item { // remove indent & margin for list items - rules = tr.blockStack.Current().Style + rules = bs.Current().Style keepNewlines = true } @@ -49,10 +55,11 @@ func (e *ParagraphElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) margin = *rules.Margin } suffix := rules.Suffix - renderText(tr.blockStack.Current().Block, rules, suffix) + + renderText(bs.Current().Block, rules, suffix) pw := &PaddingWriter{ - Padding: uint(tr.WordWrap - int(tr.blockStack.Indent()) - int(tr.blockStack.Margin()*2)), + Padding: uint(tr.WordWrap - int(bs.Indent()) - int(bs.Margin()*2)), PadFunc: func(wr io.Writer) { renderText(w, rules, " ") }, @@ -63,17 +70,17 @@ func (e *ParagraphElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) iw := &IndentWriter{ Indent: indent + margin, IndentFunc: func(wr io.Writer) { - renderText(w, tr.blockStack.Parent().Style, " ") + renderText(w, bs.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: pw, }, } - if len(strings.TrimSpace(tr.blockStack.Current().Block.String())) > 0 { - flow := reflow.NewReflow(tr.WordWrap - int(tr.blockStack.Indent()) - int(tr.blockStack.Margin())*2) + if len(strings.TrimSpace(bs.Current().Block.String())) > 0 { + flow := reflow.NewReflow(tr.WordWrap - int(bs.Indent()) - int(bs.Margin())*2) flow.KeepNewlines = keepNewlines - _, _ = flow.Write(tr.blockStack.Current().Block.Bytes()) + _, _ = flow.Write(bs.Current().Block.Bytes()) flow.Close() _, err := iw.Write(flow.Bytes()) @@ -83,10 +90,10 @@ func (e *ParagraphElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) _, _ = pw.Write([]byte("\n")) } - tr.blockStack.Current().Block.Reset() + bs.Current().Block.Reset() if node.Parent != nil && node.Parent.Type == bf.Item { } else { - tr.blockStack.Pop() + bs.Pop() } return nil } diff --git a/table.go b/table.go index b77c916..06139c3 100644 --- a/table.go +++ b/table.go @@ -23,9 +23,11 @@ type TableCellElement struct { } func (e *TableElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + var indent uint var margin uint - rules := tr.style[Table] + rules := ctx.style[Table] if rules.Indent != nil { indent = *rules.Indent } @@ -36,36 +38,41 @@ func (e *TableElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) erro iw := &IndentWriter{ Indent: indent + margin, IndentFunc: func(wr io.Writer) { - renderText(w, tr.blockStack.Parent().Style, " ") + renderText(w, ctx.blockStack.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: w, }, } - tr.table.writer = tablewriter.NewWriter(iw) + ctx.table.writer = tablewriter.NewWriter(iw) return nil } func (e *TableElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { - tr.table.writer.Render() - tr.table.writer = nil + ctx := tr.context + ctx.table.writer.Render() + ctx.table.writer = nil return nil } func (e *TableRowElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { - tr.table.writer.Append(tr.table.cell) - tr.table.cell = []string{} + ctx := tr.context + ctx.table.writer.Append(ctx.table.cell) + ctx.table.cell = []string{} return nil } func (e *TableHeadElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) error { - tr.table.writer.SetHeader(tr.table.header) - tr.table.header = []string{} + ctx := tr.context + ctx.table.writer.SetHeader(ctx.table.header) + ctx.table.header = []string{} return nil } func (e *TableCellElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { + ctx := tr.context + s := "" n := node.FirstChild for n != nil { @@ -75,9 +82,9 @@ func (e *TableCellElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) } if node.Parent.Parent.Type == bf.TableHead { - tr.table.header = append(tr.table.header, s) + ctx.table.header = append(ctx.table.header, s) } else { - tr.table.cell = append(tr.table.cell, s) + ctx.table.cell = append(ctx.table.cell, s) } return nil