mirror of
https://github.com/rwinkhart/glamour-temp-MUTN.git
synced 2026-09-01 22:47:25 -04:00
Use a Renderer interface instead of rendering fragments
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type BaseElement struct {
|
||||
Token string
|
||||
Pre string
|
||||
Post string
|
||||
Style StyleType
|
||||
}
|
||||
|
||||
func (e *BaseElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
if e.Pre != "" {
|
||||
fmt.Fprintf(w, "%s", e.Pre)
|
||||
}
|
||||
defer func() {
|
||||
if e.Post != "" {
|
||||
fmt.Fprintf(w, "%s", e.Post)
|
||||
}
|
||||
}()
|
||||
|
||||
rules := tr.style[e.Style]
|
||||
if rules == nil {
|
||||
fmt.Fprintf(w, "%s", e.Token)
|
||||
return nil
|
||||
}
|
||||
|
||||
out := aurora.Reset(e.Token)
|
||||
if rules.Color != "" {
|
||||
i, err := strconv.Atoi(rules.Color)
|
||||
if err == nil && i >= 0 && i <= 255 {
|
||||
out = out.Index(uint8(i))
|
||||
}
|
||||
}
|
||||
if rules.BackgroundColor != "" {
|
||||
i, err := strconv.Atoi(rules.BackgroundColor)
|
||||
if err == nil && i >= 0 && i <= 255 {
|
||||
out = out.Index(uint8(i))
|
||||
}
|
||||
}
|
||||
if rules.Underline {
|
||||
out = out.Underline()
|
||||
}
|
||||
if rules.Bold {
|
||||
out = out.Bold()
|
||||
}
|
||||
if rules.Italic {
|
||||
out = out.Italic()
|
||||
}
|
||||
if rules.CrossedOut {
|
||||
out = out.CrossedOut()
|
||||
}
|
||||
if rules.Overlined {
|
||||
out = out.Overlined()
|
||||
}
|
||||
if rules.Inverse {
|
||||
out = out.Reverse()
|
||||
}
|
||||
if rules.Blink {
|
||||
out = out.Blink()
|
||||
}
|
||||
|
||||
w.Write([]byte(aurora.Sprintf("%s", out)))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/alecthomas/chroma/quick"
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type CodeBlockElement struct {
|
||||
Code string
|
||||
Language string
|
||||
}
|
||||
|
||||
func (e *CodeBlockElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
var theme string
|
||||
rules := tr.style[CodeBlock]
|
||||
if rules != nil {
|
||||
theme = rules.Theme
|
||||
}
|
||||
|
||||
if len(theme) > 0 {
|
||||
return quick.Highlight(w, e.Code, e.Language, "terminal16m", theme)
|
||||
}
|
||||
|
||||
// fallback rendering
|
||||
el := &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: CodeBlock,
|
||||
}
|
||||
return el.Render(w, node, tr)
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"html"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type ElementRenderer interface {
|
||||
Render(w io.Writer, node *bf.Node, tr *TermRenderer) error
|
||||
}
|
||||
|
||||
type Element struct {
|
||||
Pre string
|
||||
Post string
|
||||
Renderer ElementRenderer
|
||||
}
|
||||
|
||||
func (tr *TermRenderer) NewElement(node *bf.Node) Element {
|
||||
switch node.Type {
|
||||
case bf.Document:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Style: Document,
|
||||
},
|
||||
}
|
||||
case bf.BlockQuote:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: BlockQuote,
|
||||
},
|
||||
}
|
||||
case bf.List:
|
||||
return Element{
|
||||
Renderer: &ListElement{},
|
||||
}
|
||||
case bf.Item:
|
||||
return Element{
|
||||
Renderer: &ItemElement{},
|
||||
}
|
||||
case bf.Paragraph:
|
||||
return Element{
|
||||
Post: "\n",
|
||||
Renderer: &ParagraphElement{},
|
||||
}
|
||||
case bf.Heading:
|
||||
return Element{
|
||||
Post: "\n",
|
||||
Renderer: &HeadingElement{},
|
||||
}
|
||||
case bf.HorizontalRule:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Renderer: &BaseElement{
|
||||
Token: "---",
|
||||
Style: HorizontalRule,
|
||||
},
|
||||
}
|
||||
case bf.Emph:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.FirstChild.Literal),
|
||||
Style: Emph,
|
||||
},
|
||||
}
|
||||
case bf.Strong:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.FirstChild.Literal),
|
||||
Style: Strong,
|
||||
},
|
||||
}
|
||||
case bf.Del:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: Del,
|
||||
},
|
||||
}
|
||||
case bf.Link:
|
||||
return Element{
|
||||
Renderer: &LinkElement{},
|
||||
}
|
||||
case bf.Image:
|
||||
return Element{
|
||||
Renderer: &ImageElement{},
|
||||
}
|
||||
case bf.Text:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: html.UnescapeString(stripper.Sanitize(string(node.Literal))),
|
||||
Style: Text,
|
||||
},
|
||||
}
|
||||
case bf.HTMLBlock:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n",
|
||||
Style: HTMLBlock,
|
||||
},
|
||||
}
|
||||
case bf.CodeBlock:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Renderer: &CodeBlockElement{
|
||||
Code: string(node.Literal),
|
||||
Language: string(node.CodeBlockData.Info),
|
||||
},
|
||||
}
|
||||
case bf.Softbreak:
|
||||
return Element{
|
||||
Post: "\n",
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: Softbreak,
|
||||
},
|
||||
}
|
||||
case bf.Hardbreak:
|
||||
return Element{
|
||||
Post: "\n",
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: Hardbreak,
|
||||
},
|
||||
}
|
||||
case bf.Code:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
Style: Code,
|
||||
},
|
||||
}
|
||||
case bf.HTMLSpan:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n",
|
||||
Style: HTMLSpan,
|
||||
},
|
||||
}
|
||||
case bf.Table:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
}
|
||||
case bf.TableCell:
|
||||
return Element{}
|
||||
case bf.TableHead:
|
||||
return Element{}
|
||||
case bf.TableBody:
|
||||
return Element{}
|
||||
case bf.TableRow:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
}
|
||||
|
||||
default:
|
||||
return Element{
|
||||
Renderer: &BaseElement{
|
||||
Token: string(node.Literal),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,12 @@ package gold
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/chroma/quick"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
@@ -22,19 +17,6 @@ var (
|
||||
stripper = bluemonday.StrictPolicy()
|
||||
)
|
||||
|
||||
type Fragment struct {
|
||||
Token string
|
||||
Pre string
|
||||
Post string
|
||||
Style StyleType
|
||||
}
|
||||
|
||||
type Element struct {
|
||||
Pre string
|
||||
Post string
|
||||
Fragments []Fragment
|
||||
}
|
||||
|
||||
type TermRenderer struct {
|
||||
BaseURL string
|
||||
style map[StyleType]*ElementStyle
|
||||
@@ -89,313 +71,6 @@ func NewTermRendererFromBytes(b []byte) (*TermRenderer, error) {
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
func resolveRelativeURL(baseURL string, rel string) string {
|
||||
u, err := url.Parse(rel)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if u.IsAbs() {
|
||||
return rel
|
||||
}
|
||||
if u.Path[0] == '/' {
|
||||
u.Path = u.Path[1:]
|
||||
}
|
||||
|
||||
base, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return rel
|
||||
}
|
||||
return base.ResolveReference(u).String()
|
||||
}
|
||||
|
||||
func (tr *TermRenderer) NewElement(node *bf.Node) Element {
|
||||
switch node.Type {
|
||||
case bf.Document:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: "",
|
||||
Style: Document,
|
||||
}},
|
||||
}
|
||||
case bf.BlockQuote:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: BlockQuote,
|
||||
}},
|
||||
}
|
||||
case bf.List:
|
||||
pre := ""
|
||||
if node.Parent.Type != bf.Item {
|
||||
pre = "\n"
|
||||
}
|
||||
return Element{
|
||||
Pre: pre,
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: List,
|
||||
}},
|
||||
}
|
||||
case bf.Item:
|
||||
l := 0
|
||||
n := node
|
||||
for n.Parent != nil && (n.Parent.Type == bf.List || n.Parent.Type == bf.Item) {
|
||||
if n.Parent.Type == bf.List {
|
||||
l++
|
||||
}
|
||||
n = n.Parent
|
||||
}
|
||||
return Element{
|
||||
Pre: strings.Repeat(" ", l-1) + "• ",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Item,
|
||||
}},
|
||||
}
|
||||
case bf.Paragraph:
|
||||
pre := "\n"
|
||||
if node.Prev == nil || (node.Parent != nil && node.Parent.Type == bf.Item) {
|
||||
pre = ""
|
||||
}
|
||||
|
||||
return Element{
|
||||
Pre: pre,
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Paragraph,
|
||||
}},
|
||||
}
|
||||
case bf.Heading:
|
||||
var pre string
|
||||
if node.Prev != nil {
|
||||
pre = "\n"
|
||||
}
|
||||
|
||||
return Element{
|
||||
Pre: pre,
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: fmt.Sprintf("%s %s", strings.Repeat("#", node.HeadingData.Level), node.FirstChild.Literal),
|
||||
Style: Heading,
|
||||
}},
|
||||
}
|
||||
case bf.HorizontalRule:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: "---",
|
||||
Style: HorizontalRule,
|
||||
}},
|
||||
}
|
||||
case bf.Emph:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.FirstChild.Literal),
|
||||
Style: Emph,
|
||||
}},
|
||||
}
|
||||
case bf.Strong:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.FirstChild.Literal),
|
||||
Style: Strong,
|
||||
}},
|
||||
}
|
||||
case bf.Del:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Del,
|
||||
}},
|
||||
}
|
||||
|
||||
case bf.Link:
|
||||
f := []Fragment{}
|
||||
|
||||
if node.LastChild != nil {
|
||||
if node.LastChild.Type == bf.Image {
|
||||
el := tr.NewElement(node.LastChild)
|
||||
f = el.Fragments
|
||||
}
|
||||
if len(node.LastChild.Literal) > 0 {
|
||||
f = append(f, Fragment{
|
||||
Token: string(node.LastChild.Literal),
|
||||
Style: LinkText,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(node.LinkData.Destination) > 0 {
|
||||
f = append(f, Fragment{
|
||||
Token: resolveRelativeURL(tr.BaseURL, string(node.LinkData.Destination)),
|
||||
Pre: " (",
|
||||
Post: ")",
|
||||
Style: Link,
|
||||
})
|
||||
}
|
||||
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: f,
|
||||
}
|
||||
|
||||
case bf.Image:
|
||||
f := []Fragment{}
|
||||
if len(node.LastChild.Literal) > 0 {
|
||||
f = append(f, Fragment{
|
||||
Token: string(node.LastChild.Literal),
|
||||
Style: Image,
|
||||
})
|
||||
}
|
||||
if len(node.LinkData.Destination) > 0 {
|
||||
f = append(f, Fragment{
|
||||
Token: resolveRelativeURL(tr.BaseURL, string(node.LinkData.Destination)),
|
||||
Pre: " [Image: ",
|
||||
Post: "]",
|
||||
Style: Link,
|
||||
})
|
||||
}
|
||||
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: f,
|
||||
}
|
||||
|
||||
case bf.Text:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: html.UnescapeString(stripper.Sanitize(string(node.Literal))),
|
||||
Style: Text,
|
||||
}},
|
||||
}
|
||||
case bf.HTMLBlock:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n",
|
||||
Style: HTMLBlock,
|
||||
}},
|
||||
}
|
||||
case bf.CodeBlock:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: CodeBlock,
|
||||
}},
|
||||
}
|
||||
case bf.Softbreak:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Softbreak,
|
||||
}},
|
||||
}
|
||||
case bf.Hardbreak:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Hardbreak,
|
||||
}},
|
||||
}
|
||||
case bf.Code:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Code,
|
||||
}},
|
||||
}
|
||||
case bf.HTMLSpan:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: html.UnescapeString(strings.TrimSpace(stripper.Sanitize(string(node.Literal)))) + "\n",
|
||||
Style: HTMLSpan,
|
||||
}},
|
||||
}
|
||||
case bf.Table:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: Table,
|
||||
}},
|
||||
}
|
||||
case bf.TableCell:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: TableCell,
|
||||
}},
|
||||
}
|
||||
case bf.TableHead:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: TableHead,
|
||||
}},
|
||||
}
|
||||
case bf.TableBody:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: TableBody,
|
||||
}},
|
||||
}
|
||||
case bf.TableRow:
|
||||
return Element{
|
||||
Pre: "\n",
|
||||
Post: "\n",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
Style: TableRow,
|
||||
}},
|
||||
}
|
||||
|
||||
default:
|
||||
return Element{
|
||||
Pre: "",
|
||||
Post: "",
|
||||
Fragments: []Fragment{{
|
||||
Token: string(node.Literal),
|
||||
}},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tr *TermRenderer) Render(in string) string {
|
||||
return string(tr.RenderBytes([]byte(in)))
|
||||
}
|
||||
@@ -404,51 +79,6 @@ func (tr *TermRenderer) RenderBytes(in []byte) []byte {
|
||||
return bf.Run(in, bf.WithRenderer(tr))
|
||||
}
|
||||
|
||||
func (tr *TermRenderer) renderFragment(w io.Writer, f Fragment) {
|
||||
rules := tr.style[f.Style]
|
||||
if rules == nil {
|
||||
fmt.Fprintf(w, "%s", f.Token)
|
||||
return
|
||||
}
|
||||
|
||||
out := aurora.Reset(f.Token)
|
||||
if rules.Color != "" {
|
||||
i, err := strconv.Atoi(rules.Color)
|
||||
if err == nil && i >= 0 && i <= 255 {
|
||||
out = out.Index(uint8(i))
|
||||
}
|
||||
}
|
||||
if rules.BackgroundColor != "" {
|
||||
i, err := strconv.Atoi(rules.BackgroundColor)
|
||||
if err == nil && i >= 0 && i <= 255 {
|
||||
out = out.Index(uint8(i))
|
||||
}
|
||||
}
|
||||
if rules.Underline {
|
||||
out = out.Underline()
|
||||
}
|
||||
if rules.Bold {
|
||||
out = out.Bold()
|
||||
}
|
||||
if rules.Italic {
|
||||
out = out.Italic()
|
||||
}
|
||||
if rules.CrossedOut {
|
||||
out = out.CrossedOut()
|
||||
}
|
||||
if rules.Overlined {
|
||||
out = out.Overlined()
|
||||
}
|
||||
if rules.Inverse {
|
||||
out = out.Reverse()
|
||||
}
|
||||
if rules.Blink {
|
||||
out = out.Blink()
|
||||
}
|
||||
|
||||
w.Write([]byte(aurora.Sprintf("%s", out)))
|
||||
}
|
||||
|
||||
func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus {
|
||||
// fmt.Fprintf(w, "%s %t", node.Type, entering)
|
||||
e := tr.NewElement(node)
|
||||
@@ -465,33 +95,10 @@ func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf
|
||||
return bf.GoToNext
|
||||
}
|
||||
|
||||
for _, f := range e.Fragments {
|
||||
if node.Type == bf.CodeBlock {
|
||||
var theme string
|
||||
if rules, ok := tr.style[f.Style]; ok {
|
||||
if len(rules.Theme) > 0 {
|
||||
theme = rules.Theme
|
||||
}
|
||||
}
|
||||
if len(theme) > 0 {
|
||||
err := quick.Highlight(w, f.Token, string(node.CodeBlockData.Info), "terminal16m", theme)
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
// if chroma failed, render the fragment as text below
|
||||
}
|
||||
}
|
||||
|
||||
if f.Token == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if f.Pre != "" {
|
||||
fmt.Fprintf(w, "%s", f.Pre)
|
||||
}
|
||||
tr.renderFragment(w, f)
|
||||
if f.Post != "" {
|
||||
fmt.Fprintf(w, "%s", f.Post)
|
||||
if e.Renderer != nil {
|
||||
err := e.Renderer.Render(w, node, tr)
|
||||
if err == nil {
|
||||
return bf.GoToNext
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,3 +122,22 @@ func isChild(node *bf.Node) bool {
|
||||
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
|
||||
}
|
||||
if u.Path[0] == '/' {
|
||||
u.Path = u.Path[1:]
|
||||
}
|
||||
|
||||
base, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return rel
|
||||
}
|
||||
return base.ResolveReference(u).String()
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type HeadingElement struct {
|
||||
}
|
||||
|
||||
func (e *HeadingElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
var pre string
|
||||
if node.Prev != nil {
|
||||
pre = "\n"
|
||||
}
|
||||
|
||||
el := &BaseElement{
|
||||
Pre: pre,
|
||||
Token: fmt.Sprintf("%s %s", strings.Repeat("#", node.HeadingData.Level), node.FirstChild.Literal),
|
||||
Style: Heading,
|
||||
}
|
||||
return el.Render(w, node, tr)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type ImageElement struct {
|
||||
}
|
||||
|
||||
func (e *ImageElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
if len(node.LastChild.Literal) > 0 {
|
||||
el := &BaseElement{
|
||||
Token: string(node.LastChild.Literal),
|
||||
Style: Image,
|
||||
}
|
||||
el.Render(w, node.LastChild, tr)
|
||||
}
|
||||
if len(node.LinkData.Destination) > 0 {
|
||||
el := &BaseElement{
|
||||
Token: resolveRelativeURL(tr.BaseURL, string(node.LinkData.Destination)),
|
||||
Pre: " [Image: ",
|
||||
Post: "]",
|
||||
Style: Link,
|
||||
}
|
||||
el.Render(w, node, tr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type LinkElement struct {
|
||||
}
|
||||
|
||||
func (e *LinkElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
if node.LastChild != nil {
|
||||
if node.LastChild.Type == bf.Image {
|
||||
el := tr.NewElement(node.LastChild)
|
||||
el.Renderer.Render(w, node.LastChild, tr)
|
||||
}
|
||||
if len(node.LastChild.Literal) > 0 {
|
||||
el := &BaseElement{
|
||||
Token: string(node.LastChild.Literal),
|
||||
Style: LinkText,
|
||||
}
|
||||
el.Render(w, node.LastChild, tr)
|
||||
}
|
||||
}
|
||||
if len(node.LinkData.Destination) > 0 {
|
||||
el := &BaseElement{
|
||||
Token: resolveRelativeURL(tr.BaseURL, string(node.LinkData.Destination)),
|
||||
Pre: " (",
|
||||
Post: ")",
|
||||
Style: Link,
|
||||
}
|
||||
el.Render(w, node, tr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type ListElement struct {
|
||||
}
|
||||
|
||||
func (e *ListElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
pre := ""
|
||||
if node.Parent.Type != bf.Item {
|
||||
pre = "\n"
|
||||
}
|
||||
|
||||
el := &BaseElement{
|
||||
Pre: pre,
|
||||
Token: string(node.Literal),
|
||||
Style: List,
|
||||
}
|
||||
return el.Render(w, node, tr)
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type ItemElement struct {
|
||||
}
|
||||
|
||||
func (e *ItemElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
l := 0
|
||||
n := node
|
||||
for n.Parent != nil && (n.Parent.Type == bf.List || n.Parent.Type == bf.Item) {
|
||||
if n.Parent.Type == bf.List {
|
||||
l++
|
||||
}
|
||||
n = n.Parent
|
||||
}
|
||||
|
||||
el := &BaseElement{
|
||||
Pre: strings.Repeat(" ", l-1) + "• ",
|
||||
Token: string(node.Literal),
|
||||
Style: Item,
|
||||
}
|
||||
return el.Render(w, node, tr)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package gold
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
bf "gopkg.in/russross/blackfriday.v2"
|
||||
)
|
||||
|
||||
type ParagraphElement struct {
|
||||
}
|
||||
|
||||
func (e *ParagraphElement) Render(w io.Writer, node *bf.Node, tr *TermRenderer) error {
|
||||
pre := "\n"
|
||||
if node.Prev == nil || (node.Parent != nil && node.Parent.Type == bf.Item) {
|
||||
pre = ""
|
||||
}
|
||||
|
||||
el := &BaseElement{
|
||||
Pre: pre,
|
||||
Token: string(node.Literal),
|
||||
Style: Paragraph,
|
||||
}
|
||||
return el.Render(w, node, tr)
|
||||
}
|
||||
Reference in New Issue
Block a user