diff --git a/ansiwriter.go b/ansi/ansiwriter.go similarity index 98% rename from ansiwriter.go rename to ansi/ansiwriter.go index badad5f..3bed749 100644 --- a/ansiwriter.go +++ b/ansi/ansiwriter.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" diff --git a/baseelement.go b/ansi/baseelement.go similarity index 99% rename from baseelement.go rename to ansi/baseelement.go index 4ea8fc6..ad1ed25 100644 --- a/baseelement.go +++ b/ansi/baseelement.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" diff --git a/blockelement.go b/ansi/blockelement.go similarity index 98% rename from blockelement.go rename to ansi/blockelement.go index 49b87e7..b089452 100644 --- a/blockelement.go +++ b/ansi/blockelement.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" diff --git a/blockstack.go b/ansi/blockstack.go similarity index 98% rename from blockstack.go rename to ansi/blockstack.go index 231d967..3663988 100644 --- a/blockstack.go +++ b/ansi/blockstack.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" diff --git a/codeblock.go b/ansi/codeblock.go similarity index 94% rename from codeblock.go rename to ansi/codeblock.go index 76054be..a97f25e 100644 --- a/codeblock.go +++ b/ansi/codeblock.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -16,7 +16,7 @@ func (e *CodeBlockElement) Render(w io.Writer, ctx RenderContext) error { var indent uint var margin uint - rules := ctx.styles.CodeBlock + rules := ctx.options.Styles.CodeBlock if rules.Indent != nil { indent = *rules.Indent } diff --git a/context.go b/ansi/context.go similarity index 94% rename from context.go rename to ansi/context.go index e1b4ba6..3610a6e 100644 --- a/context.go +++ b/ansi/context.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "html" @@ -9,7 +9,6 @@ import ( type RenderContext struct { options Options - styles StyleConfig blockStack *BlockStack table *TableElement diff --git a/elements.go b/ansi/elements.go similarity index 88% rename from elements.go rename to ansi/elements.go index 9b187fe..cf6d2b3 100644 --- a/elements.go +++ b/ansi/elements.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" @@ -25,7 +25,7 @@ type Element struct { Finisher ElementFinisher } -func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { +func (tr *ANSIRenderer) NewElement(node ast.Node, source []byte) Element { ctx := tr.context // fmt.Print(strings.Repeat(" ", ctx.blockStack.Len()), node.Type(), node.Kind()) // defer fmt.Println() @@ -35,7 +35,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { case ast.KindDocument: e := &BlockElement{ Block: &bytes.Buffer{}, - Style: ctx.styles.Document, + Style: ctx.options.Styles.Document, Margin: true, } return Element{ @@ -70,7 +70,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { case ast.KindBlockquote: e := &BlockElement{ Block: &bytes.Buffer{}, - Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.BlockQuote, true), + Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.BlockQuote, true), Margin: true, Newline: true, } @@ -82,7 +82,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { // Lists case ast.KindList: - s := ctx.styles.List.StyleBlock + s := ctx.options.Styles.List.StyleBlock if s.Indent == nil { var i uint s.Indent = &i @@ -90,7 +90,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { n := node.Parent() for n != nil { if n.Kind() == ast.KindList { - i := ctx.styles.List.LevelIndent + i := ctx.options.Styles.List.LevelIndent s.Indent = &i break } @@ -156,16 +156,16 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { return Element{ Renderer: &BaseElement{ Token: ctx.SanitizeHTML(s, false), - Style: ctx.styles.Text, + Style: ctx.options.Styles.Text, }, } case ast.KindEmphasis: n := node.(*ast.Emphasis) s := string(n.Text(source)) - style := ctx.styles.Emph + style := ctx.options.Styles.Emph if n.Level > 1 { - style = ctx.styles.Strong + style = ctx.options.Styles.Strong } return Element{ @@ -178,7 +178,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { case astext.KindStrikethrough: n := node.(*astext.Strikethrough) s := string(n.Text(source)) - style := ctx.styles.Strikethrough + style := ctx.options.Styles.Strikethrough return Element{ Renderer: &BaseElement{ @@ -192,7 +192,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { Entering: "", Exiting: "", Renderer: &BaseElement{ - Style: ctx.styles.HorizontalRule, + Style: ctx.options.Styles.HorizontalRule, }, } @@ -271,7 +271,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { // n := node.(*ast.CodeSpan) e := &BlockElement{ Block: &bytes.Buffer{}, - Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.Code, true), + Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.Code, true), } return Element{ Renderer: e, @@ -318,7 +318,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { return Element{ Renderer: &BaseElement{ Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n", - Style: ctx.styles.HTMLBlock.StylePrimitive, + Style: ctx.options.Styles.HTMLBlock.StylePrimitive, }, } case ast.KindRawHTML: @@ -326,7 +326,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { return Element{ Renderer: &BaseElement{ Token: ctx.SanitizeHTML(string(n.Text(source)), true) + "\n", - Style: ctx.styles.HTMLSpan.StylePrimitive, + Style: ctx.options.Styles.HTMLSpan.StylePrimitive, }, } @@ -334,7 +334,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { case astext.KindDefinitionList: e := &BlockElement{ Block: &bytes.Buffer{}, - Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.styles.DefinitionList, true), + Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.DefinitionList, true), Margin: true, Newline: true, } @@ -347,14 +347,14 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element { case astext.KindDefinitionTerm: return Element{ Renderer: &BaseElement{ - Style: ctx.styles.DefinitionTerm, + Style: ctx.options.Styles.DefinitionTerm, }, } case astext.KindDefinitionDescription: return Element{ Renderer: &BaseElement{ - Style: ctx.styles.DefinitionDescription, + Style: ctx.options.Styles.DefinitionDescription, }, } diff --git a/heading.go b/ansi/heading.go similarity index 78% rename from heading.go rename to ansi/heading.go index 72f4afb..0b34428 100644 --- a/heading.go +++ b/ansi/heading.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" @@ -14,21 +14,21 @@ type HeadingElement struct { func (e *HeadingElement) Render(w io.Writer, ctx RenderContext) error { bs := ctx.blockStack - rules := ctx.styles.Heading + rules := ctx.options.Styles.Heading switch e.Level { case 1: - rules = cascadeStyles(false, rules, ctx.styles.H1) + rules = cascadeStyles(false, rules, ctx.options.Styles.H1) case 2: - rules = cascadeStyles(false, rules, ctx.styles.H2) + rules = cascadeStyles(false, rules, ctx.options.Styles.H2) case 3: - rules = cascadeStyles(false, rules, ctx.styles.H3) + rules = cascadeStyles(false, rules, ctx.options.Styles.H3) case 4: - rules = cascadeStyles(false, rules, ctx.styles.H4) + rules = cascadeStyles(false, rules, ctx.options.Styles.H4) case 5: - rules = cascadeStyles(false, rules, ctx.styles.H5) + rules = cascadeStyles(false, rules, ctx.options.Styles.H5) case 6: - rules = cascadeStyles(false, rules, ctx.styles.H6) + rules = cascadeStyles(false, rules, ctx.options.Styles.H6) } if !e.First { diff --git a/image.go b/ansi/image.go similarity index 85% rename from image.go rename to ansi/image.go index 08ff50e..a4bb665 100644 --- a/image.go +++ b/ansi/image.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -15,7 +15,7 @@ func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error { if len(e.Text) > 0 { el := &BaseElement{ Token: e.Text, - Style: ctx.styles.ImageText, + Style: ctx.options.Styles.ImageText, } err := el.Render(w, ctx) if err != nil { @@ -26,7 +26,7 @@ func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error { el := &BaseElement{ Token: resolveRelativeURL(e.BaseURL, e.URL), Prefix: " ", - Style: ctx.styles.Image, + Style: ctx.options.Styles.Image, } err := el.Render(w, ctx) if err != nil { diff --git a/indent.go b/ansi/indent.go similarity index 98% rename from indent.go rename to ansi/indent.go index 9f5f3d0..ec9dfd8 100644 --- a/indent.go +++ b/ansi/indent.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" diff --git a/link.go b/ansi/link.go similarity index 93% rename from link.go rename to ansi/link.go index ebe1230..02f3635 100644 --- a/link.go +++ b/ansi/link.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -19,7 +19,7 @@ func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error { el := &BaseElement{ Token: e.Text, - Style: ctx.styles.LinkText, + Style: ctx.options.Styles.LinkText, } err := el.Render(w, ctx) if err != nil { @@ -53,7 +53,7 @@ func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error { if len(e.URL) > 0 { pre := " " - style := ctx.styles.Link + style := ctx.options.Styles.Link if !textRendered { pre = "" style.BlockPrefix = "" diff --git a/listitem.go b/ansi/listitem.go similarity index 78% rename from listitem.go rename to ansi/listitem.go index 01a71b6..8ef8622 100644 --- a/listitem.go +++ b/ansi/listitem.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -13,12 +13,12 @@ func (e *ItemElement) Render(w io.Writer, ctx RenderContext) error { var el *BaseElement if e.Enumeration > 0 { el = &BaseElement{ - Style: ctx.styles.Enumeration, + Style: ctx.options.Styles.Enumeration, Prefix: strconv.FormatInt(int64(e.Enumeration), 10), } } else { el = &BaseElement{ - Style: ctx.styles.Item, + Style: ctx.options.Styles.Item, } } diff --git a/margin.go b/ansi/margin.go similarity index 98% rename from margin.go rename to ansi/margin.go index 06ba6b6..4fd83c6 100644 --- a/margin.go +++ b/ansi/margin.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" diff --git a/padding.go b/ansi/padding.go similarity index 98% rename from padding.go rename to ansi/padding.go index 89cc7ca..247317d 100644 --- a/padding.go +++ b/ansi/padding.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" diff --git a/paragraph.go b/ansi/paragraph.go similarity index 95% rename from paragraph.go rename to ansi/paragraph.go index 61b26c5..6b9c939 100644 --- a/paragraph.go +++ b/ansi/paragraph.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "bytes" @@ -13,7 +13,7 @@ type ParagraphElement struct { func (e *ParagraphElement) Render(w io.Writer, ctx RenderContext) error { bs := ctx.blockStack - rules := ctx.styles.Paragraph + rules := ctx.options.Styles.Paragraph _, _ = w.Write([]byte("\n")) be := BlockElement{ diff --git a/ansi/renderer.go b/ansi/renderer.go new file mode 100644 index 0000000..2d698ca --- /dev/null +++ b/ansi/renderer.go @@ -0,0 +1,158 @@ +package ansi + +import ( + "io" + "log" + "net/url" + "strings" + + "github.com/yuin/goldmark/ast" + astext "github.com/yuin/goldmark/extension/ast" + "github.com/yuin/goldmark/renderer" + "github.com/yuin/goldmark/util" +) + +type Options struct { + BaseURL string + WordWrap int + Styles StyleConfig +} + +type ANSIRenderer struct { + context RenderContext +} + +// NewANSIRenderer returns a new ANSIRenderer with style and options set. +func NewRenderer(options Options) *ANSIRenderer { + return &ANSIRenderer{ + context: NewRenderContext(options), + } +} + +// RegisterFuncs implements NodeRenderer.RegisterFuncs. +func (r *ANSIRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { + // blocks + reg.Register(ast.KindDocument, r.renderNode) + reg.Register(ast.KindHeading, r.renderNode) + reg.Register(ast.KindBlockquote, r.renderNode) + reg.Register(ast.KindCodeBlock, r.renderNode) + reg.Register(ast.KindFencedCodeBlock, r.renderNode) + reg.Register(ast.KindHTMLBlock, r.renderNode) + reg.Register(ast.KindList, r.renderNode) + reg.Register(ast.KindListItem, r.renderNode) + reg.Register(ast.KindParagraph, r.renderNode) + reg.Register(ast.KindTextBlock, r.renderNode) + reg.Register(ast.KindThematicBreak, r.renderNode) + + // inlines + reg.Register(ast.KindAutoLink, r.renderNode) + reg.Register(ast.KindCodeSpan, r.renderNode) + reg.Register(ast.KindEmphasis, r.renderNode) + reg.Register(ast.KindImage, r.renderNode) + reg.Register(ast.KindLink, r.renderNode) + reg.Register(ast.KindRawHTML, r.renderNode) + reg.Register(ast.KindText, r.renderNode) + reg.Register(ast.KindString, r.renderNode) + + // tables + reg.Register(astext.KindTable, r.renderNode) + reg.Register(astext.KindTableHeader, r.renderNode) + reg.Register(astext.KindTableRow, r.renderNode) + reg.Register(astext.KindTableCell, r.renderNode) + + // definitions + reg.Register(astext.KindDefinitionList, r.renderNode) + reg.Register(astext.KindDefinitionTerm, r.renderNode) + reg.Register(astext.KindDefinitionDescription, r.renderNode) + + // footnotes + reg.Register(astext.KindFootnote, r.renderNode) + reg.Register(astext.KindFootnoteList, r.renderNode) + reg.Register(astext.KindFootnoteLink, r.renderNode) + reg.Register(astext.KindFootnoteBackLink, r.renderNode) + + // checkboxes + reg.Register(astext.KindTaskCheckBox, r.renderNode) + + // strikethrough + reg.Register(astext.KindStrikethrough, r.renderNode) +} + +func (tr *ANSIRenderer) renderNode(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { + // _, _ = w.Write([]byte(node.Type.String())) + writeTo := io.Writer(w) + bs := tr.context.blockStack + + // children get rendered by their parent + if isChild(node) { + return ast.WalkContinue, nil + } + + e := tr.NewElement(node, source) + if entering { + // everything below the Document element gets rendered into a block buffer + if bs.Len() > 0 { + writeTo = io.Writer(bs.Current().Block) + } + + _, _ = writeTo.Write([]byte(e.Entering)) + if e.Renderer != nil { + err := e.Renderer.Render(writeTo, tr.context) + if err != nil { + return ast.WalkStop, err + } + } + } else { + // everything below the Document element gets rendered into a block buffer + if bs.Len() > 0 { + writeTo = io.Writer(bs.Parent().Block) + } + + // if we're finished rendering the entire document, + // flush to the real writer + if node.Type() == ast.TypeDocument { + writeTo = w + } + + if e.Finisher != nil { + err := e.Finisher.Finish(writeTo, tr.context) + if err != nil { + return ast.WalkStop, err + } + } + _, _ = bs.Current().Block.Write([]byte(e.Exiting)) + } + + return ast.WalkContinue, nil +} + +func isChild(node ast.Node) bool { + if node.Parent() == nil { + return false + } + + // These types are already rendered by their parent + switch node.Parent().Kind() { + case ast.KindLink, ast.KindImage, ast.KindEmphasis, astext.KindStrikethrough, ast.KindBlockquote, astext.KindTableCell: + return true + default: + return false + } +} + +func resolveRelativeURL(baseURL string, rel string) string { + u, err := url.Parse(rel) + if err != nil { + log.Fatal(err) + } + if u.IsAbs() { + return rel + } + u.Path = strings.TrimPrefix(u.Path, "/") + + base, err := url.Parse(baseURL) + if err != nil { + return rel + } + return base.ResolveReference(u).String() +} diff --git a/style.go b/ansi/style.go similarity index 92% rename from style.go rename to ansi/style.go index 42c5a7f..afba71f 100644 --- a/style.go +++ b/ansi/style.go @@ -1,14 +1,7 @@ -package gold +package ansi import ( - "io" - "io/ioutil" - "os" - "github.com/lucasb-eyer/go-colorful" - "github.com/rakyll/statik/fs" - - _ "github.com/charmbracelet/gold/statik" ) type StylePrimitive struct { @@ -95,27 +88,6 @@ type StyleConfig struct { HTMLSpan StyleBlock `json:"html_span"` } -func loadStyle(f string) ([]byte, error) { - var r io.ReadCloser - var err error - - r, err = os.Open(f) - if err != nil { - statikFS, err := fs.New() - if err != nil { - return nil, err - } - - r, err = statikFS.Open("/" + f + ".json") - if err != nil { - return nil, err - } - } - - defer r.Close() - return ioutil.ReadAll(r) -} - func cascadeStyles(onlyColors bool, s ...StyleBlock) StyleBlock { var r StyleBlock diff --git a/table.go b/ansi/table.go similarity index 95% rename from table.go rename to ansi/table.go index 5f86742..da5d06c 100644 --- a/table.go +++ b/ansi/table.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -29,7 +29,7 @@ func (e *TableElement) Render(w io.Writer, ctx RenderContext) error { var indent uint var margin uint - rules := ctx.styles.Table + rules := ctx.options.Styles.Table if rules.Indent != nil { indent = *rules.Indent } @@ -56,7 +56,7 @@ func (e *TableElement) Finish(w io.Writer, ctx RenderContext) error { ctx.table.writer.Render() ctx.table.writer = nil - rules := ctx.styles.Table + rules := ctx.options.Styles.Table renderText(ctx.table.indentWriter, ctx.blockStack.Current().Style.StylePrimitive, rules.BlockSuffix) return nil } diff --git a/task.go b/ansi/task.go similarity index 62% rename from task.go rename to ansi/task.go index c26f919..327c3b2 100644 --- a/task.go +++ b/ansi/task.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "io" @@ -11,14 +11,14 @@ type TaskElement struct { func (e *TaskElement) Render(w io.Writer, ctx RenderContext) error { var el *BaseElement - pre := ctx.styles.Task.Unticked + pre := ctx.options.Styles.Task.Unticked if e.Checked { - pre = ctx.styles.Task.Ticked + pre = ctx.options.Styles.Task.Ticked } el = &BaseElement{ Prefix: pre, - Style: ctx.styles.Task.StylePrimitive, + Style: ctx.options.Styles.Task.StylePrimitive, } return el.Render(w, ctx) diff --git a/templatehelper.go b/ansi/templatehelper.go similarity index 99% rename from templatehelper.go rename to ansi/templatehelper.go index 636cff3..2b41820 100644 --- a/templatehelper.go +++ b/ansi/templatehelper.go @@ -1,4 +1,4 @@ -package gold +package ansi import ( "regexp" diff --git a/gold.go b/gold.go index ef736c9..469ba16 100644 --- a/gold.go +++ b/gold.go @@ -4,26 +4,22 @@ import ( "bytes" "encoding/json" "io" - "log" - "net/url" - "strings" + "io/ioutil" + "os" + "github.com/rakyll/statik/fs" "github.com/yuin/goldmark" - "github.com/yuin/goldmark/ast" "github.com/yuin/goldmark/extension" - astext "github.com/yuin/goldmark/extension/ast" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer" "github.com/yuin/goldmark/util" + + "github.com/charmbracelet/gold/ansi" + _ "github.com/charmbracelet/gold/statik" ) -type Options struct { - BaseURL string - WordWrap int -} - type TermRenderer struct { - context RenderContext + Options ansi.Options } // Render initializes a new TermRenderer and renders a markdown with a specific @@ -35,7 +31,7 @@ func Render(in string, stylePath string) ([]byte, error) { // RenderBytes initializes a new TermRenderer and renders a markdown with a // specific style. func RenderBytes(in []byte, stylePath string) ([]byte, error) { - r, err := NewTermRenderer(stylePath, Options{ + r, err := NewTermRenderer(stylePath, ansi.Options{ WordWrap: 80, }) if err != nil { @@ -45,7 +41,7 @@ func RenderBytes(in []byte, stylePath string) ([]byte, error) { } // NewTermRenderer returns a new TermRenderer with style and options set. -func NewTermRenderer(stylePath string, options Options) (*TermRenderer, error) { +func NewTermRenderer(stylePath string, options ansi.Options) (*TermRenderer, error) { if stylePath == "" { return NewTermRendererFromBytes([]byte("{}"), options) } @@ -59,17 +55,15 @@ func NewTermRenderer(stylePath string, options Options) (*TermRenderer, error) { // NewTermRendererFromBytes returns a new TermRenderer with style and options // set. -func NewTermRendererFromBytes(b []byte, options Options) (*TermRenderer, error) { - tr := &TermRenderer{ - context: NewRenderContext(options), - } - - err := json.Unmarshal(b, &tr.context.styles) +func NewTermRendererFromBytes(b []byte, options ansi.Options) (*TermRenderer, error) { + err := json.Unmarshal(b, &options.Styles) if err != nil { return nil, err } - return tr, nil + return &TermRenderer{ + Options: options, + }, nil } // Render returns the markdown rendered into a string. @@ -89,139 +83,34 @@ func (tr *TermRenderer) RenderBytes(in []byte) ([]byte, error) { parser.WithAutoHeadingID(), ), ) + + ar := ansi.NewRenderer(tr.Options) md.SetRenderer( renderer.NewRenderer( - renderer.WithNodeRenderers(util.Prioritized(tr, 1000)))) + renderer.WithNodeRenderers(util.Prioritized(ar, 1000)))) var buf bytes.Buffer err := md.Convert(in, &buf) return buf.Bytes(), err } -// RegisterFuncs implements NodeRenderer.RegisterFuncs. -func (r *TermRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { - // blocks - reg.Register(ast.KindDocument, r.renderNode) - reg.Register(ast.KindHeading, r.renderNode) - reg.Register(ast.KindBlockquote, r.renderNode) - reg.Register(ast.KindCodeBlock, r.renderNode) - reg.Register(ast.KindFencedCodeBlock, r.renderNode) - reg.Register(ast.KindHTMLBlock, r.renderNode) - reg.Register(ast.KindList, r.renderNode) - reg.Register(ast.KindListItem, r.renderNode) - reg.Register(ast.KindParagraph, r.renderNode) - reg.Register(ast.KindTextBlock, r.renderNode) - reg.Register(ast.KindThematicBreak, r.renderNode) +func loadStyle(f string) ([]byte, error) { + var r io.ReadCloser + var err error - // inlines - reg.Register(ast.KindAutoLink, r.renderNode) - reg.Register(ast.KindCodeSpan, r.renderNode) - reg.Register(ast.KindEmphasis, r.renderNode) - reg.Register(ast.KindImage, r.renderNode) - reg.Register(ast.KindLink, r.renderNode) - reg.Register(ast.KindRawHTML, r.renderNode) - reg.Register(ast.KindText, r.renderNode) - reg.Register(ast.KindString, r.renderNode) - - // tables - reg.Register(astext.KindTable, r.renderNode) - reg.Register(astext.KindTableHeader, r.renderNode) - reg.Register(astext.KindTableRow, r.renderNode) - reg.Register(astext.KindTableCell, r.renderNode) - - // definitions - reg.Register(astext.KindDefinitionList, r.renderNode) - reg.Register(astext.KindDefinitionTerm, r.renderNode) - reg.Register(astext.KindDefinitionDescription, r.renderNode) - - // footnotes - reg.Register(astext.KindFootnote, r.renderNode) - reg.Register(astext.KindFootnoteList, r.renderNode) - reg.Register(astext.KindFootnoteLink, r.renderNode) - reg.Register(astext.KindFootnoteBackLink, r.renderNode) - - // checkboxes - reg.Register(astext.KindTaskCheckBox, r.renderNode) - - // strikethrough - reg.Register(astext.KindStrikethrough, r.renderNode) -} - -func (tr *TermRenderer) renderNode(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { - // _, _ = w.Write([]byte(node.Type.String())) - writeTo := io.Writer(w) - bs := tr.context.blockStack - - // children get rendered by their parent - if isChild(node) { - return ast.WalkContinue, nil - } - - e := tr.NewElement(node, source) - if entering { - // everything below the Document element gets rendered into a block buffer - if bs.Len() > 0 { - writeTo = io.Writer(bs.Current().Block) - } - - _, _ = writeTo.Write([]byte(e.Entering)) - if e.Renderer != nil { - err := e.Renderer.Render(writeTo, tr.context) - if err != nil { - return ast.WalkStop, err - } - } - } else { - // everything below the Document element gets rendered into a block buffer - if bs.Len() > 0 { - writeTo = io.Writer(bs.Parent().Block) - } - - // if we're finished rendering the entire document, - // flush to the real writer - if node.Type() == ast.TypeDocument { - writeTo = w - } - - if e.Finisher != nil { - err := e.Finisher.Finish(writeTo, tr.context) - if err != nil { - return ast.WalkStop, err - } - } - _, _ = bs.Current().Block.Write([]byte(e.Exiting)) - } - - return ast.WalkContinue, nil -} - -func isChild(node ast.Node) bool { - if node.Parent() == nil { - return false - } - - // These types are already rendered by their parent - switch node.Parent().Kind() { - case ast.KindLink, ast.KindImage, ast.KindEmphasis, astext.KindStrikethrough, ast.KindBlockquote, astext.KindTableCell: - return true - default: - return false - } -} - -func resolveRelativeURL(baseURL string, rel string) string { - u, err := url.Parse(rel) + r, err = os.Open(f) if err != nil { - log.Fatal(err) - } - if u.IsAbs() { - return rel - } - u.Path = strings.TrimPrefix(u.Path, "/") + statikFS, err := fs.New() + if err != nil { + return nil, err + } - base, err := url.Parse(baseURL) - if err != nil { - return rel + r, err = statikFS.Open("/" + f + ".json") + if err != nil { + return nil, err + } } - return base.ResolveReference(u).String() + + defer r.Close() + return ioutil.ReadAll(r) }