mirror of
https://github.com/rwinkhart/glamour-temp-MUTN.git
synced 2026-08-31 14:16:44 -04:00
390 lines
7.3 KiB
Go
390 lines
7.3 KiB
Go
package gold
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/logrusorgru/aurora"
|
|
bf "gopkg.in/russross/blackfriday.v2"
|
|
)
|
|
|
|
type ElementStyle struct {
|
|
Color string `json:"color"`
|
|
BackgroundColor string `json:"background_color"`
|
|
Underline bool `json:"underline"`
|
|
Bold bool `json:"bold"`
|
|
Italic bool `json:"italic"`
|
|
CrossedOut bool `json:"crossed_out"`
|
|
Faint bool `json:"faint"`
|
|
Conceal bool `json:"conceal"`
|
|
Overlined bool `json:"overlined"`
|
|
Inverse bool `json:"inverse"`
|
|
Blink bool `json:"blink"`
|
|
}
|
|
|
|
type Element struct {
|
|
Token string
|
|
Pre string
|
|
Post string
|
|
}
|
|
|
|
type TermRenderer struct {
|
|
style map[bf.NodeType]*ElementStyle
|
|
}
|
|
|
|
func Render(in string, stylePath string) ([]byte, error) {
|
|
return RenderBytes([]byte(in), stylePath)
|
|
}
|
|
|
|
func RenderBytes(in []byte, stylePath string) ([]byte, error) {
|
|
r, err := NewTermRenderer(stylePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bf.Run(in, bf.WithRenderer(r)), nil
|
|
}
|
|
|
|
func NewTermRenderer(stylePath string) (*TermRenderer, error) {
|
|
if stylePath == "" {
|
|
return NewTermRendererFromBytes([]byte("{}"))
|
|
}
|
|
f, err := os.Open(stylePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
b, _ := ioutil.ReadAll(f)
|
|
return NewTermRendererFromBytes(b)
|
|
}
|
|
|
|
func NewTermRendererFromBytes(b []byte) (*TermRenderer, error) {
|
|
e := make(map[string]*ElementStyle, 0)
|
|
err := json.Unmarshal(b, &e)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tr := &TermRenderer{}
|
|
tr.style = make(map[bf.NodeType]*ElementStyle)
|
|
|
|
for k, v := range e {
|
|
t, err := keyToType(k)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
continue
|
|
}
|
|
tr.style[t] = v
|
|
}
|
|
return tr, nil
|
|
}
|
|
|
|
func NewElement(node *bf.Node) Element {
|
|
switch node.Type {
|
|
case bf.Document:
|
|
return Element{
|
|
Token: "",
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.BlockQuote:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.List:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "",
|
|
}
|
|
case bf.Item:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "• ",
|
|
Post: "",
|
|
}
|
|
case bf.Paragraph:
|
|
pre := "\n"
|
|
if node.Prev == nil || (node.Parent != nil && node.Parent.Type == bf.Item) {
|
|
pre = ""
|
|
}
|
|
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: pre,
|
|
Post: "\n",
|
|
}
|
|
case bf.Heading:
|
|
var pre string
|
|
if node.Prev != nil {
|
|
pre = "\n"
|
|
}
|
|
|
|
return Element{
|
|
Token: fmt.Sprintf("%s %s", strings.Repeat("#", node.HeadingData.Level), node.FirstChild.Literal),
|
|
Pre: pre,
|
|
Post: "\n",
|
|
}
|
|
case bf.HorizontalRule:
|
|
return Element{
|
|
Token: "---",
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.Emph:
|
|
return Element{
|
|
Token: string(node.FirstChild.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Strong:
|
|
return Element{
|
|
Token: string(node.FirstChild.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Del:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Link:
|
|
return Element{
|
|
Token: fmt.Sprintf("[%s](%s)", string(node.LastChild.Literal), string(node.LinkData.Destination)),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Image:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Text:
|
|
if node.Parent != nil && node.Parent.Type != bf.Link {
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
}
|
|
return Element{
|
|
Token: "",
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.HTMLBlock:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.CodeBlock:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.Softbreak:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "\n",
|
|
}
|
|
case bf.Hardbreak:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.Code:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.HTMLSpan:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.Table:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
case bf.TableCell:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.TableHead:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.TableBody:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
case bf.TableRow:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "\n",
|
|
Post: "\n",
|
|
}
|
|
default:
|
|
return Element{
|
|
Token: string(node.Literal),
|
|
Pre: "",
|
|
Post: "",
|
|
}
|
|
}
|
|
}
|
|
|
|
func (tr *TermRenderer) RenderNode(w io.Writer, node *bf.Node, entering bool) bf.WalkStatus {
|
|
// fmt.Fprintf(w, "%s %t", node.Type, entering)
|
|
el := NewElement(node)
|
|
if entering && el.Pre != "" {
|
|
fmt.Fprintf(w, "%s", el.Pre)
|
|
}
|
|
if !entering && el.Post != "" {
|
|
fmt.Fprintf(w, "%s", el.Post)
|
|
}
|
|
if isChild(node) {
|
|
return bf.GoToNext
|
|
}
|
|
if !entering {
|
|
return bf.GoToNext
|
|
}
|
|
if el.Token == "" {
|
|
return bf.GoToNext
|
|
}
|
|
rules := tr.style[node.Type]
|
|
if rules == nil {
|
|
fmt.Fprintf(w, "%s", el.Token)
|
|
return bf.GoToNext
|
|
}
|
|
out := aurora.Reset(el.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 bf.GoToNext
|
|
}
|
|
|
|
func (tr *TermRenderer) RenderHeader(w io.Writer, ast *bf.Node) {
|
|
}
|
|
|
|
func (tr *TermRenderer) RenderFooter(w io.Writer, ast *bf.Node) {
|
|
}
|
|
|
|
func isChild(node *bf.Node) bool {
|
|
if node.Parent == nil {
|
|
return false
|
|
}
|
|
switch node.Parent.Type {
|
|
case bf.Heading, bf.Link, bf.Emph, bf.Strong:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func keyToType(key string) (bf.NodeType, error) {
|
|
switch key {
|
|
case "document":
|
|
return bf.Document, nil
|
|
case "block_quote":
|
|
return bf.BlockQuote, nil
|
|
case "list":
|
|
return bf.List, nil
|
|
case "item":
|
|
return bf.Item, nil
|
|
case "paragraph":
|
|
return bf.Paragraph, nil
|
|
case "heading":
|
|
return bf.Heading, nil
|
|
case "hr":
|
|
return bf.HorizontalRule, nil
|
|
case "emph":
|
|
return bf.Emph, nil
|
|
case "strong":
|
|
return bf.Strong, nil
|
|
case "del":
|
|
return bf.Del, nil
|
|
case "link":
|
|
return bf.Link, nil
|
|
case "image":
|
|
return bf.Image, nil
|
|
case "text":
|
|
return bf.Text, nil
|
|
case "html_block":
|
|
return bf.HTMLBlock, nil
|
|
case "code_block":
|
|
return bf.CodeBlock, nil
|
|
case "softbreak":
|
|
return bf.Softbreak, nil
|
|
case "hardbreak":
|
|
return bf.Hardbreak, nil
|
|
case "code":
|
|
return bf.Code, nil
|
|
case "html_span":
|
|
return bf.HTMLSpan, nil
|
|
case "table":
|
|
return bf.Table, nil
|
|
case "table_cel":
|
|
return bf.TableCell, nil
|
|
case "table_head":
|
|
return bf.TableHead, nil
|
|
case "table_body":
|
|
return bf.TableBody, nil
|
|
case "table_row":
|
|
return bf.TableRow, nil
|
|
default:
|
|
return 0, fmt.Errorf("Invalid element type: %s", key)
|
|
}
|
|
}
|