mirror of
https://github.com/rwinkhart/glamour-temp-MUTN.git
synced 2026-09-06 00:47:15 -04:00
Move ANSIRenderer into a separate package
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -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.styles.CodeBlock
|
rules := ctx.options.Styles.CodeBlock
|
||||||
if rules.Indent != nil {
|
if rules.Indent != nil {
|
||||||
indent = *rules.Indent
|
indent = *rules.Indent
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"html"
|
"html"
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
type RenderContext struct {
|
type RenderContext struct {
|
||||||
options Options
|
options Options
|
||||||
styles StyleConfig
|
|
||||||
|
|
||||||
blockStack *BlockStack
|
blockStack *BlockStack
|
||||||
table *TableElement
|
table *TableElement
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -25,7 +25,7 @@ type Element struct {
|
|||||||
Finisher ElementFinisher
|
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
|
ctx := tr.context
|
||||||
// fmt.Print(strings.Repeat(" ", ctx.blockStack.Len()), node.Type(), node.Kind())
|
// fmt.Print(strings.Repeat(" ", ctx.blockStack.Len()), node.Type(), node.Kind())
|
||||||
// defer fmt.Println()
|
// defer fmt.Println()
|
||||||
@@ -35,7 +35,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
|
|||||||
case ast.KindDocument:
|
case ast.KindDocument:
|
||||||
e := &BlockElement{
|
e := &BlockElement{
|
||||||
Block: &bytes.Buffer{},
|
Block: &bytes.Buffer{},
|
||||||
Style: ctx.styles.Document,
|
Style: ctx.options.Styles.Document,
|
||||||
Margin: true,
|
Margin: true,
|
||||||
}
|
}
|
||||||
return Element{
|
return Element{
|
||||||
@@ -70,7 +70,7 @@ 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.styles.BlockQuote, true),
|
Style: cascadeStyle(ctx.blockStack.Current().Style, ctx.options.Styles.BlockQuote, true),
|
||||||
Margin: true,
|
Margin: true,
|
||||||
Newline: true,
|
Newline: true,
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
|
|||||||
|
|
||||||
// Lists
|
// Lists
|
||||||
case ast.KindList:
|
case ast.KindList:
|
||||||
s := ctx.styles.List.StyleBlock
|
s := ctx.options.Styles.List.StyleBlock
|
||||||
if s.Indent == nil {
|
if s.Indent == nil {
|
||||||
var i uint
|
var i uint
|
||||||
s.Indent = &i
|
s.Indent = &i
|
||||||
@@ -90,7 +90,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
|
|||||||
n := node.Parent()
|
n := node.Parent()
|
||||||
for n != nil {
|
for n != nil {
|
||||||
if n.Kind() == ast.KindList {
|
if n.Kind() == ast.KindList {
|
||||||
i := ctx.styles.List.LevelIndent
|
i := ctx.options.Styles.List.LevelIndent
|
||||||
s.Indent = &i
|
s.Indent = &i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -156,16 +156,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.styles.Text,
|
Style: ctx.options.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.styles.Emph
|
style := ctx.options.Styles.Emph
|
||||||
if n.Level > 1 {
|
if n.Level > 1 {
|
||||||
style = ctx.styles.Strong
|
style = ctx.options.Styles.Strong
|
||||||
}
|
}
|
||||||
|
|
||||||
return Element{
|
return Element{
|
||||||
@@ -178,7 +178,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.styles.Strikethrough
|
style := ctx.options.Styles.Strikethrough
|
||||||
|
|
||||||
return Element{
|
return Element{
|
||||||
Renderer: &BaseElement{
|
Renderer: &BaseElement{
|
||||||
@@ -192,7 +192,7 @@ func (tr *TermRenderer) NewElement(node ast.Node, source []byte) Element {
|
|||||||
Entering: "",
|
Entering: "",
|
||||||
Exiting: "",
|
Exiting: "",
|
||||||
Renderer: &BaseElement{
|
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)
|
// n := node.(*ast.CodeSpan)
|
||||||
e := &BlockElement{
|
e := &BlockElement{
|
||||||
Block: &bytes.Buffer{},
|
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{
|
return Element{
|
||||||
Renderer: e,
|
Renderer: e,
|
||||||
@@ -318,7 +318,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.styles.HTMLBlock.StylePrimitive,
|
Style: ctx.options.Styles.HTMLBlock.StylePrimitive,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
case ast.KindRawHTML:
|
case ast.KindRawHTML:
|
||||||
@@ -326,7 +326,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.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:
|
case astext.KindDefinitionList:
|
||||||
e := &BlockElement{
|
e := &BlockElement{
|
||||||
Block: &bytes.Buffer{},
|
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,
|
Margin: true,
|
||||||
Newline: true,
|
Newline: true,
|
||||||
}
|
}
|
||||||
@@ -347,14 +347,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.styles.DefinitionTerm,
|
Style: ctx.options.Styles.DefinitionTerm,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
case astext.KindDefinitionDescription:
|
case astext.KindDefinitionDescription:
|
||||||
return Element{
|
return Element{
|
||||||
Renderer: &BaseElement{
|
Renderer: &BaseElement{
|
||||||
Style: ctx.styles.DefinitionDescription,
|
Style: ctx.options.Styles.DefinitionDescription,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -14,21 +14,21 @@ 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.styles.Heading
|
rules := ctx.options.Styles.Heading
|
||||||
|
|
||||||
switch e.Level {
|
switch e.Level {
|
||||||
case 1:
|
case 1:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H1)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H1)
|
||||||
case 2:
|
case 2:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H2)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H2)
|
||||||
case 3:
|
case 3:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H3)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H3)
|
||||||
case 4:
|
case 4:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H4)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H4)
|
||||||
case 5:
|
case 5:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H5)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H5)
|
||||||
case 6:
|
case 6:
|
||||||
rules = cascadeStyles(false, rules, ctx.styles.H6)
|
rules = cascadeStyles(false, rules, ctx.options.Styles.H6)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !e.First {
|
if !e.First {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -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.styles.ImageText,
|
Style: ctx.options.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.styles.Image,
|
Style: ctx.options.Styles.Image,
|
||||||
}
|
}
|
||||||
err := el.Render(w, ctx)
|
err := el.Render(w, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -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.styles.LinkText,
|
Style: ctx.options.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.styles.Link
|
style := ctx.options.Styles.Link
|
||||||
if !textRendered {
|
if !textRendered {
|
||||||
pre = ""
|
pre = ""
|
||||||
style.BlockPrefix = ""
|
style.BlockPrefix = ""
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -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.styles.Enumeration,
|
Style: ctx.options.Styles.Enumeration,
|
||||||
Prefix: strconv.FormatInt(int64(e.Enumeration), 10),
|
Prefix: strconv.FormatInt(int64(e.Enumeration), 10),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
el = &BaseElement{
|
el = &BaseElement{
|
||||||
Style: ctx.styles.Item,
|
Style: ctx.options.Styles.Item,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -13,7 +13,7 @@ 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
|
||||||
rules := ctx.styles.Paragraph
|
rules := ctx.options.Styles.Paragraph
|
||||||
|
|
||||||
_, _ = w.Write([]byte("\n"))
|
_, _ = w.Write([]byte("\n"))
|
||||||
be := BlockElement{
|
be := BlockElement{
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -1,14 +1,7 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/lucasb-eyer/go-colorful"
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
"github.com/rakyll/statik/fs"
|
|
||||||
|
|
||||||
_ "github.com/charmbracelet/gold/statik"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type StylePrimitive struct {
|
type StylePrimitive struct {
|
||||||
@@ -95,27 +88,6 @@ type StyleConfig struct {
|
|||||||
HTMLSpan StyleBlock `json:"html_span"`
|
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 {
|
func cascadeStyles(onlyColors bool, s ...StyleBlock) StyleBlock {
|
||||||
var r StyleBlock
|
var r StyleBlock
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -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.styles.Table
|
rules := ctx.options.Styles.Table
|
||||||
if rules.Indent != nil {
|
if rules.Indent != nil {
|
||||||
indent = *rules.Indent
|
indent = *rules.Indent
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ 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.styles.Table
|
rules := ctx.options.Styles.Table
|
||||||
renderText(ctx.table.indentWriter, ctx.blockStack.Current().Style.StylePrimitive, rules.BlockSuffix)
|
renderText(ctx.table.indentWriter, ctx.blockStack.Current().Style.StylePrimitive, rules.BlockSuffix)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@@ -11,14 +11,14 @@ type TaskElement struct {
|
|||||||
func (e *TaskElement) Render(w io.Writer, ctx RenderContext) error {
|
func (e *TaskElement) Render(w io.Writer, ctx RenderContext) error {
|
||||||
var el *BaseElement
|
var el *BaseElement
|
||||||
|
|
||||||
pre := ctx.styles.Task.Unticked
|
pre := ctx.options.Styles.Task.Unticked
|
||||||
if e.Checked {
|
if e.Checked {
|
||||||
pre = ctx.styles.Task.Ticked
|
pre = ctx.options.Styles.Task.Ticked
|
||||||
}
|
}
|
||||||
|
|
||||||
el = &BaseElement{
|
el = &BaseElement{
|
||||||
Prefix: pre,
|
Prefix: pre,
|
||||||
Style: ctx.styles.Task.StylePrimitive,
|
Style: ctx.options.Styles.Task.StylePrimitive,
|
||||||
}
|
}
|
||||||
|
|
||||||
return el.Render(w, ctx)
|
return el.Render(w, ctx)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package gold
|
package ansi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -4,26 +4,22 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"io/ioutil"
|
||||||
"net/url"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/rakyll/statik/fs"
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
"github.com/yuin/goldmark/ast"
|
|
||||||
"github.com/yuin/goldmark/extension"
|
"github.com/yuin/goldmark/extension"
|
||||||
astext "github.com/yuin/goldmark/extension/ast"
|
|
||||||
"github.com/yuin/goldmark/parser"
|
"github.com/yuin/goldmark/parser"
|
||||||
"github.com/yuin/goldmark/renderer"
|
"github.com/yuin/goldmark/renderer"
|
||||||
"github.com/yuin/goldmark/util"
|
"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 {
|
type TermRenderer struct {
|
||||||
context RenderContext
|
Options ansi.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render initializes a new TermRenderer and renders a markdown with a specific
|
// 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
|
// RenderBytes initializes a new TermRenderer and renders a markdown with a
|
||||||
// specific style.
|
// specific style.
|
||||||
func RenderBytes(in []byte, stylePath string) ([]byte, error) {
|
func RenderBytes(in []byte, stylePath string) ([]byte, error) {
|
||||||
r, err := NewTermRenderer(stylePath, Options{
|
r, err := NewTermRenderer(stylePath, ansi.Options{
|
||||||
WordWrap: 80,
|
WordWrap: 80,
|
||||||
})
|
})
|
||||||
if err != nil {
|
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.
|
// 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 == "" {
|
if stylePath == "" {
|
||||||
return NewTermRendererFromBytes([]byte("{}"), options)
|
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
|
// NewTermRendererFromBytes returns a new TermRenderer with style and options
|
||||||
// set.
|
// set.
|
||||||
func NewTermRendererFromBytes(b []byte, options Options) (*TermRenderer, error) {
|
func NewTermRendererFromBytes(b []byte, options ansi.Options) (*TermRenderer, error) {
|
||||||
tr := &TermRenderer{
|
err := json.Unmarshal(b, &options.Styles)
|
||||||
context: NewRenderContext(options),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal(b, &tr.context.styles)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return tr, nil
|
return &TermRenderer{
|
||||||
|
Options: options,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render returns the markdown rendered into a string.
|
// Render returns the markdown rendered into a string.
|
||||||
@@ -89,139 +83,34 @@ func (tr *TermRenderer) RenderBytes(in []byte) ([]byte, error) {
|
|||||||
parser.WithAutoHeadingID(),
|
parser.WithAutoHeadingID(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ar := ansi.NewRenderer(tr.Options)
|
||||||
md.SetRenderer(
|
md.SetRenderer(
|
||||||
renderer.NewRenderer(
|
renderer.NewRenderer(
|
||||||
renderer.WithNodeRenderers(util.Prioritized(tr, 1000))))
|
renderer.WithNodeRenderers(util.Prioritized(ar, 1000))))
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err := md.Convert(in, &buf)
|
err := md.Convert(in, &buf)
|
||||||
return buf.Bytes(), err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterFuncs implements NodeRenderer.RegisterFuncs.
|
func loadStyle(f string) ([]byte, error) {
|
||||||
func (r *TermRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
var r io.ReadCloser
|
||||||
// blocks
|
var err error
|
||||||
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
|
r, err = os.Open(f)
|
||||||
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 {
|
if err != nil {
|
||||||
return ast.WalkStop, err
|
statikFS, err := fs.New()
|
||||||
}
|
|
||||||
}
|
|
||||||
} 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 {
|
if err != nil {
|
||||||
return ast.WalkStop, err
|
return nil, err
|
||||||
}
|
|
||||||
}
|
|
||||||
_, _ = bs.Current().Block.Write([]byte(e.Exiting))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ast.WalkContinue, nil
|
r, err = statikFS.Open("/" + f + ".json")
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
log.Fatal(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
if u.IsAbs() {
|
|
||||||
return rel
|
|
||||||
}
|
}
|
||||||
u.Path = strings.TrimPrefix(u.Path, "/")
|
|
||||||
|
|
||||||
base, err := url.Parse(baseURL)
|
defer r.Close()
|
||||||
if err != nil {
|
return ioutil.ReadAll(r)
|
||||||
return rel
|
|
||||||
}
|
|
||||||
return base.ResolveReference(u).String()
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user