diff --git a/baseelement.go b/baseelement.go index 4667fb7..2180fd0 100644 --- a/baseelement.go +++ b/baseelement.go @@ -63,12 +63,12 @@ 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.blockStyle.Current(), e.Prefix) + renderText(w, tr.blockStack.Current().Style, e.Prefix) defer func() { - renderText(w, tr.blockStyle.Current(), e.Suffix) + renderText(w, tr.blockStack.Current().Style, e.Suffix) }() - rules := tr.blockStyle.With(tr.style[e.Style]) + rules := tr.blockStack.With(tr.style[e.Style]) if rules != nil { renderText(w, rules, rules.Prefix) defer func() { diff --git a/codeblock.go b/codeblock.go index 14a9e18..e748ddf 100644 --- a/codeblock.go +++ b/codeblock.go @@ -26,7 +26,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.blockStyle.Parent(), " ") + renderText(w, tr.blockStack.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: w, diff --git a/document.go b/document.go index 28f270d..9c19cd9 100644 --- a/document.go +++ b/document.go @@ -1,6 +1,7 @@ package gold import ( + "bytes" "io" bf "gopkg.in/russross/blackfriday.v2" @@ -12,8 +13,12 @@ type DocumentElement struct { func (e *DocumentElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { rules := tr.style[Document] if rules != nil { - tr.blockStyle.Push(rules) - renderText(w, rules, rules.Prefix) + be := BlockElement{ + Block: &bytes.Buffer{}, + Style: rules, + } + tr.blockStack.Push(be) + renderText(tr.blockStack.Current().Block, rules, rules.Prefix) } return nil } @@ -43,14 +48,14 @@ func (e *DocumentElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) e Forward: pw, }, } - _, err := iw.Write(tr.document.Bytes()) + _, err := iw.Write(tr.blockStack.Current().Block.Bytes()) if err != nil { return err } renderText(iw, rules, suffix) - tr.document.Reset() - tr.blockStyle.Pop() + tr.blockStack.Current().Block.Reset() + tr.blockStack.Pop() return nil } diff --git a/gold.go b/gold.go index 94285b2..a9646b0 100644 --- a/gold.go +++ b/gold.go @@ -1,7 +1,6 @@ package gold import ( - "bytes" "encoding/json" "fmt" "io" @@ -23,9 +22,7 @@ type TermRenderer struct { WordWrap int style map[StyleType]*ElementStyle - document bytes.Buffer - paragraph *bytes.Buffer - blockStyle StyleStack + blockStack BlockStack table TableElement } @@ -87,7 +84,8 @@ func (tr *TermRenderer) RenderBytes(in []byte) []byte { } func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus { - writeTo := io.Writer(&tr.document) + //tr.document.Write([]byte(node.Type.String())) + writeTo := io.Writer(nil) if isChild(node) { return bf.GoToNext @@ -95,11 +93,9 @@ func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf e := tr.NewElement(node) if entering { - _, _ = tr.document.Write([]byte(e.Entering)) - - // each paragraph gets rendered into a separate buffer - if tr.paragraph != nil { - writeTo = tr.paragraph + if len(tr.blockStack) > 0 { + writeTo = io.Writer(tr.blockStack.Current().Block) + _, _ = writeTo.Write([]byte(e.Entering)) } if e.Renderer != nil { @@ -110,6 +106,10 @@ 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 we're finished rendering the entire document, // flush to the real writer if node.Type == bf.Document { @@ -124,7 +124,7 @@ func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf } } - _, _ = tr.document.Write([]byte(e.Exiting)) + _, _ = writeTo.Write([]byte(e.Exiting)) } return bf.GoToNext diff --git a/paragraph.go b/paragraph.go index 6581169..61e70d8 100644 --- a/paragraph.go +++ b/paragraph.go @@ -3,6 +3,7 @@ package gold import ( "bytes" "io" + "strings" "github.com/muesli/reflow" bf "gopkg.in/russross/blackfriday.v2" @@ -12,19 +13,22 @@ type ParagraphElement struct { } func (e *ParagraphElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error { - tr.paragraph = &bytes.Buffer{} - - rules := tr.style[Paragraph] - tr.blockStyle.Push(rules) - + var rules *ElementStyle if node.Parent != nil && node.Parent.Type == bf.Item { // list item + rules = tr.style[List] } else { + rules = tr.style[Paragraph] _, _ = w.Write([]byte("\n")) + be := BlockElement{ + Block: &bytes.Buffer{}, + Style: cascadeStyle(tr.blockStack.Current().Style, rules), + } + tr.blockStack.Push(be) } if rules != nil { - renderText(w, tr.blockStyle.Current(), rules.Prefix) + renderText(w, tr.blockStack.Current().Style, rules.Prefix) } return nil } @@ -33,22 +37,21 @@ func (e *ParagraphElement) Finish(w io.Writer, node *bf.Node, tr *TermRenderer) var indent uint var margin uint var suffix string - rules := tr.blockStyle.Current() + 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 + } + if rules != nil { indent = rules.Indent margin = rules.Margin suffix = rules.Suffix - - if node.Parent != nil && node.Parent.Type == bf.Item { - // remove indent & margin for list items - indent = 0 - margin = 0 - } } - renderText(tr.paragraph, rules, suffix) + renderText(tr.blockStack.Current().Block, rules, suffix) pw := &PaddingWriter{ - Padding: uint(tr.WordWrap - int(tr.blockStyle.Indent()) - int(tr.blockStyle.Margin()*2)), + Padding: uint(tr.WordWrap - int(tr.blockStack.Indent()) - int(tr.blockStack.Margin()*2)), PadFunc: func(wr io.Writer) { renderText(w, rules, " ") }, @@ -59,24 +62,25 @@ 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.blockStyle.Parent(), " ") + renderText(w, tr.blockStack.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: pw, }, } - _, err := iw.Write(reflow.ReflowBytes(tr.paragraph.Bytes(), tr.WordWrap-int(tr.blockStyle.Indent())-int(tr.blockStyle.Margin())*2)) - if err != nil { - return err + if len(strings.TrimSpace(tr.blockStack.Current().Block.String())) > 0 { + _, err := iw.Write(reflow.ReflowBytes(tr.blockStack.Current().Block.Bytes(), tr.WordWrap-int(tr.blockStack.Indent())-int(tr.blockStack.Margin())*2)) + if err != nil { + return err + } + _, _ = pw.Write([]byte("\n")) } - _, _ = pw.Write([]byte("\n")) - tr.paragraph.Reset() - tr.paragraph = nil - - if rules != nil { - tr.blockStyle.Pop() + tr.blockStack.Current().Block.Reset() + if node.Parent != nil && node.Parent.Type == bf.Item { + } else { + tr.blockStack.Pop() } return nil } diff --git a/style.go b/style.go index f43a618..c502001 100644 --- a/style.go +++ b/style.go @@ -1,6 +1,7 @@ package gold import ( + "bytes" "fmt" ) @@ -55,13 +56,18 @@ type ElementStyle struct { Suffix string `json:"suffix"` } -type StyleStack []*ElementStyle - -func (s *StyleStack) Push(style *ElementStyle) { - *s = append(*s, style) +type BlockElement struct { + Block *bytes.Buffer + Style *ElementStyle } -func (s *StyleStack) Pop() { +type BlockStack []BlockElement + +func (s *BlockStack) Push(e BlockElement) { + *s = append(*s, e) +} + +func (s *BlockStack) Pop() { stack := *s if len(stack) == 0 { return @@ -71,50 +77,52 @@ func (s *StyleStack) Pop() { *s = stack } -func (s StyleStack) Indent() uint { +func (s BlockStack) Indent() uint { var i uint for _, v := range s { - if v == nil { + if v.Style == nil { continue } - i += v.Indent + i += v.Style.Indent } return i } -func (s StyleStack) Margin() uint { +func (s BlockStack) Margin() uint { var i uint for _, v := range s { - if v == nil { + if v.Style == nil { continue } - i += v.Margin + i += v.Style.Margin } return i } -func (s StyleStack) Parent() *ElementStyle { +func (s BlockStack) Parent() BlockElement { if len(s) < 2 { return s.Current() } - return cascadeStyles(s[0:len(s)-2], s[len(s)-2]) + return s[len(s)-2] } -func (s StyleStack) Current() *ElementStyle { +func (s BlockStack) Current() BlockElement { if len(s) == 0 { - return nil + return BlockElement{ + Block: &bytes.Buffer{}, + } } - return cascadeStyles(s[0:len(s)-1], s[len(s)-1]) + return s[len(s)-1] } -func (s StyleStack) With(child *ElementStyle) *ElementStyle { - return cascadeStyles(s, child) +func (s BlockStack) With(child *ElementStyle) *ElementStyle { + return cascadeStyle(s.Current().Style, child) } func cascadeStyle(parent *ElementStyle, child *ElementStyle) *ElementStyle { @@ -142,18 +150,6 @@ func cascadeStyle(parent *ElementStyle, child *ElementStyle) *ElementStyle { return &s } -func cascadeStyles(parents StyleStack, child *ElementStyle) *ElementStyle { - if len(parents) == 0 { - return child - } - parent := parents[0] - for i := 1; i < len(parents); i++ { - parent = cascadeStyle(parent, parents[i]) - } - - return cascadeStyle(parent, child) -} - func keyToType(key string) (StyleType, error) { switch key { case "document": diff --git a/table.go b/table.go index e82d96a..a1166da 100644 --- a/table.go +++ b/table.go @@ -33,7 +33,7 @@ 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.blockStyle.Parent(), " ") + renderText(w, tr.blockStack.Parent().Style, " ") }, Forward: &AnsiWriter{ Forward: w,