mirror of
https://github.com/yuin/goldmark
synced 2025-03-04 23:04:52 +00:00
Add String node
This commit is contained in:
parent
7b1dd7b221
commit
05645dd3c4
4 changed files with 209 additions and 158 deletions
|
|
@ -56,8 +56,26 @@ const (
|
||||||
textSoftLineBreak = 1 << iota
|
textSoftLineBreak = 1 << iota
|
||||||
textHardLineBreak
|
textHardLineBreak
|
||||||
textRaw
|
textRaw
|
||||||
|
textCode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func textFlagsString(flags uint8) string {
|
||||||
|
buf := []string{}
|
||||||
|
if flags&textSoftLineBreak != 0 {
|
||||||
|
buf = append(buf, "SoftLineBreak")
|
||||||
|
}
|
||||||
|
if flags&textHardLineBreak != 0 {
|
||||||
|
buf = append(buf, "HardLineBreak")
|
||||||
|
}
|
||||||
|
if flags&textRaw != 0 {
|
||||||
|
buf = append(buf, "Raw")
|
||||||
|
}
|
||||||
|
if flags&textCode != 0 {
|
||||||
|
buf = append(buf, "Code")
|
||||||
|
}
|
||||||
|
return strings.Join(buf, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
// Inline implements Inline.Inline.
|
// Inline implements Inline.Inline.
|
||||||
func (n *Text) Inline() {
|
func (n *Text) Inline() {
|
||||||
}
|
}
|
||||||
|
|
@ -130,7 +148,11 @@ func (n *Text) Text(source []byte) []byte {
|
||||||
|
|
||||||
// Dump implements Node.Dump.
|
// Dump implements Node.Dump.
|
||||||
func (n *Text) Dump(source []byte, level int) {
|
func (n *Text) Dump(source []byte, level int) {
|
||||||
fmt.Printf("%sText: \"%s\"\n", strings.Repeat(" ", level), strings.TrimRight(string(n.Text(source)), "\n"))
|
fs := textFlagsString(n.flags)
|
||||||
|
if len(fs) != 0 {
|
||||||
|
fs = "(" + fs + ")"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KindText is a NodeKind of the Text node.
|
// KindText is a NodeKind of the Text node.
|
||||||
|
|
@ -192,6 +214,77 @@ func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A String struct is a textual content that has a concrete value
|
||||||
|
type String struct {
|
||||||
|
BaseInline
|
||||||
|
|
||||||
|
Value []byte
|
||||||
|
flags uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inline implements Inline.Inline.
|
||||||
|
func (n *String) Inline() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRaw returns true if this text should be rendered without unescaping
|
||||||
|
// back slash escapes and resolving references.
|
||||||
|
func (n *String) IsRaw() bool {
|
||||||
|
return n.flags&textRaw != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRaw sets whether this text should be rendered as raw contents.
|
||||||
|
func (n *String) SetRaw(v bool) {
|
||||||
|
if v {
|
||||||
|
n.flags |= textRaw
|
||||||
|
} else {
|
||||||
|
n.flags = n.flags &^ textRaw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCode returns true if this text should be rendered without any
|
||||||
|
// modifications.
|
||||||
|
func (n *String) IsCode() bool {
|
||||||
|
return n.flags&textCode != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCode sets whether this text should be rendered without any modifications.
|
||||||
|
func (n *String) SetCode(v bool) {
|
||||||
|
if v {
|
||||||
|
n.flags |= textCode
|
||||||
|
} else {
|
||||||
|
n.flags = n.flags &^ textCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text implements Node.Text.
|
||||||
|
func (n *String) Text(source []byte) []byte {
|
||||||
|
return n.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump implements Node.Dump.
|
||||||
|
func (n *String) Dump(source []byte, level int) {
|
||||||
|
fs := textFlagsString(n.flags)
|
||||||
|
if len(fs) != 0 {
|
||||||
|
fs = "(" + fs + ")"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// KindString is a NodeKind of the String node.
|
||||||
|
var KindString = NewNodeKind("String")
|
||||||
|
|
||||||
|
// Kind implements Node.Kind.
|
||||||
|
func (n *String) Kind() NodeKind {
|
||||||
|
return KindString
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewString returns a new String node.
|
||||||
|
func NewString(v []byte) *String {
|
||||||
|
return &String{
|
||||||
|
Value: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A CodeSpan struct represents a code span of Markdown text.
|
// A CodeSpan struct represents a code span of Markdown text.
|
||||||
type CodeSpan struct {
|
type CodeSpan struct {
|
||||||
BaseInline
|
BaseInline
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
package ast
|
|
||||||
|
|
||||||
import (
|
|
||||||
gast "github.com/yuin/goldmark/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A TypographicText struct represents text that
|
|
||||||
// typographic text replaces certain punctuations.
|
|
||||||
type TypographicText struct {
|
|
||||||
gast.BaseInline
|
|
||||||
Value []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump implements Node.Dump.
|
|
||||||
func (n *TypographicText) Dump(source []byte, level int) {
|
|
||||||
gast.DumpHelper(n, source, level, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KindTypographicText is a NodeKind of the TypographicText node.
|
|
||||||
var KindTypographicText = gast.NewNodeKind("TypographicText")
|
|
||||||
|
|
||||||
// Kind implements Node.Kind.
|
|
||||||
func (n *TypographicText) Kind() gast.NodeKind {
|
|
||||||
return KindTypographicText
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTypographicText returns a new TypographicText node.
|
|
||||||
func NewTypographicText(value []byte) *TypographicText {
|
|
||||||
return &TypographicText{
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,10 +3,7 @@ package extension
|
||||||
import (
|
import (
|
||||||
"github.com/yuin/goldmark"
|
"github.com/yuin/goldmark"
|
||||||
gast "github.com/yuin/goldmark/ast"
|
gast "github.com/yuin/goldmark/ast"
|
||||||
"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/html"
|
|
||||||
"github.com/yuin/goldmark/text"
|
"github.com/yuin/goldmark/text"
|
||||||
"github.com/yuin/goldmark/util"
|
"github.com/yuin/goldmark/util"
|
||||||
)
|
)
|
||||||
|
|
@ -147,13 +144,15 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
|
||||||
if len(line) > 2 {
|
if len(line) > 2 {
|
||||||
if c == '-' {
|
if c == '-' {
|
||||||
if s.Substitutions[EmDash] != nil && line[1] == '-' && line[2] == '-' { // ---
|
if s.Substitutions[EmDash] != nil && line[1] == '-' && line[2] == '-' { // ---
|
||||||
node := ast.NewTypographicText(s.Substitutions[EmDash])
|
node := gast.NewString(s.Substitutions[EmDash])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(3)
|
block.Advance(3)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
} else if c == '.' {
|
} else if c == '.' {
|
||||||
if s.Substitutions[Ellipsis] != nil && line[1] == '.' && line[2] == '.' { // ...
|
if s.Substitutions[Ellipsis] != nil && line[1] == '.' && line[2] == '.' { // ...
|
||||||
node := ast.NewTypographicText(s.Substitutions[Ellipsis])
|
node := gast.NewString(s.Substitutions[Ellipsis])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(3)
|
block.Advance(3)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
@ -163,20 +162,23 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
|
||||||
if len(line) > 1 {
|
if len(line) > 1 {
|
||||||
if c == '<' {
|
if c == '<' {
|
||||||
if s.Substitutions[LeftAngleQuote] != nil && line[1] == '<' { // <<
|
if s.Substitutions[LeftAngleQuote] != nil && line[1] == '<' { // <<
|
||||||
node := ast.NewTypographicText(s.Substitutions[LeftAngleQuote])
|
node := gast.NewString(s.Substitutions[LeftAngleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(2)
|
block.Advance(2)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
} else if c == '>' {
|
} else if c == '>' {
|
||||||
if s.Substitutions[RightAngleQuote] != nil && line[1] == '>' { // >>
|
if s.Substitutions[RightAngleQuote] != nil && line[1] == '>' { // >>
|
||||||
node := ast.NewTypographicText(s.Substitutions[RightAngleQuote])
|
node := gast.NewString(s.Substitutions[RightAngleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(2)
|
block.Advance(2)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
} else if s.Substitutions[EnDash] != nil && c == '-' && line[1] == '-' { // --
|
} else if s.Substitutions[EnDash] != nil && c == '-' && line[1] == '-' { // --
|
||||||
node := ast.NewTypographicText(s.Substitutions[EnDash])
|
node := gast.NewString(s.Substitutions[EnDash])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(2)
|
block.Advance(2)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
@ -188,24 +190,28 @@ func (s *typographerParser) Parse(parent gast.Node, block text.Reader, pc parser
|
||||||
}
|
}
|
||||||
if c == '\'' {
|
if c == '\'' {
|
||||||
if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose {
|
if s.Substitutions[LeftSingleQuote] != nil && d.CanOpen && !d.CanClose {
|
||||||
node := ast.NewTypographicText(s.Substitutions[LeftSingleQuote])
|
node := gast.NewString(s.Substitutions[LeftSingleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(1)
|
block.Advance(1)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
if s.Substitutions[RightSingleQuote] != nil && d.CanClose && !d.CanOpen {
|
if s.Substitutions[RightSingleQuote] != nil && d.CanClose && !d.CanOpen {
|
||||||
node := ast.NewTypographicText(s.Substitutions[RightSingleQuote])
|
node := gast.NewString(s.Substitutions[RightSingleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(1)
|
block.Advance(1)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c == '"' {
|
if c == '"' {
|
||||||
if s.Substitutions[LeftDoubleQuote] != nil && d.CanOpen && !d.CanClose {
|
if s.Substitutions[LeftDoubleQuote] != nil && d.CanOpen && !d.CanClose {
|
||||||
node := ast.NewTypographicText(s.Substitutions[LeftDoubleQuote])
|
node := gast.NewString(s.Substitutions[LeftDoubleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(1)
|
block.Advance(1)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
if s.Substitutions[RightDoubleQuote] != nil && d.CanClose && !d.CanOpen {
|
if s.Substitutions[RightDoubleQuote] != nil && d.CanClose && !d.CanOpen {
|
||||||
node := ast.NewTypographicText(s.Substitutions[RightDoubleQuote])
|
node := gast.NewString(s.Substitutions[RightDoubleQuote])
|
||||||
|
node.SetCode(true)
|
||||||
block.Advance(1)
|
block.Advance(1)
|
||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
@ -218,35 +224,6 @@ func (s *typographerParser) CloseBlock(parent gast.Node, pc parser.Context) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypographerHTMLRenderer is a renderer.NodeRenderer implementation that
|
|
||||||
// renders Typographer nodes.
|
|
||||||
type TypographerHTMLRenderer struct {
|
|
||||||
html.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTypographerHTMLRenderer returns a new TypographerHTMLRenderer.
|
|
||||||
func NewTypographerHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
|
|
||||||
r := &TypographerHTMLRenderer{
|
|
||||||
Config: html.NewConfig(),
|
|
||||||
}
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt.SetHTMLOption(&r.Config)
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
|
|
||||||
func (r *TypographerHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
|
||||||
reg.Register(ast.KindTypographicText, r.renderTypographicText)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *TypographerHTMLRenderer) renderTypographicText(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) {
|
|
||||||
if entering {
|
|
||||||
w.Write(n.(*ast.TypographicText).Value)
|
|
||||||
}
|
|
||||||
return gast.WalkContinue, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type typographer struct {
|
type typographer struct {
|
||||||
options []TypographerOption
|
options []TypographerOption
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +242,4 @@ func (e *typographer) Extend(m goldmark.Markdown) {
|
||||||
m.Parser().AddOptions(parser.WithInlineParsers(
|
m.Parser().AddOptions(parser.WithInlineParsers(
|
||||||
util.Prioritized(NewTypographerParser(e.options...), 9999),
|
util.Prioritized(NewTypographerParser(e.options...), 9999),
|
||||||
))
|
))
|
||||||
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
|
||||||
util.Prioritized(NewTypographerHTMLRenderer(), 500),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@ func (r *Renderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
||||||
reg.Register(ast.KindLink, r.renderLink)
|
reg.Register(ast.KindLink, r.renderLink)
|
||||||
reg.Register(ast.KindRawHTML, r.renderRawHTML)
|
reg.Register(ast.KindRawHTML, r.renderRawHTML)
|
||||||
reg.Register(ast.KindText, r.renderText)
|
reg.Register(ast.KindText, r.renderText)
|
||||||
|
reg.Register(ast.KindString, r.renderString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) writeLines(w util.BufWriter, source []byte, n ast.Node) {
|
func (r *Renderer) writeLines(w util.BufWriter, source []byte, n ast.Node) {
|
||||||
|
|
@ -198,40 +199,38 @@ func (r *Renderer) renderDocument(w util.BufWriter, source []byte, node ast.Node
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var attrNameID = []byte("id")
|
|
||||||
|
|
||||||
func (r *Renderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
n := node.(*ast.Heading)
|
n := node.(*ast.Heading)
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<h")
|
_, _ = w.WriteString("<h")
|
||||||
w.WriteByte("0123456"[n.Level])
|
_ = w.WriteByte("0123456"[n.Level])
|
||||||
if n.Attributes() != nil {
|
if n.Attributes() != nil {
|
||||||
r.RenderAttributes(w, node)
|
r.RenderAttributes(w, node)
|
||||||
}
|
}
|
||||||
w.WriteByte('>')
|
_ = w.WriteByte('>')
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</h")
|
_, _ = w.WriteString("</h")
|
||||||
w.WriteByte("0123456"[n.Level])
|
_ = w.WriteByte("0123456"[n.Level])
|
||||||
w.WriteString(">\n")
|
_, _ = w.WriteString(">\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) renderBlockquote(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderBlockquote(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<blockquote>\n")
|
_, _ = w.WriteString("<blockquote>\n")
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</blockquote>\n")
|
_, _ = w.WriteString("</blockquote>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<pre><code>")
|
_, _ = w.WriteString("<pre><code>")
|
||||||
r.writeLines(w, source, n)
|
r.writeLines(w, source, n)
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</code></pre>\n")
|
_, _ = w.WriteString("</code></pre>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -239,17 +238,17 @@ func (r *Renderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node,
|
||||||
func (r *Renderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
n := node.(*ast.FencedCodeBlock)
|
n := node.(*ast.FencedCodeBlock)
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<pre><code")
|
_, _ = w.WriteString("<pre><code")
|
||||||
language := n.Language(source)
|
language := n.Language(source)
|
||||||
if language != nil {
|
if language != nil {
|
||||||
w.WriteString(" class=\"language-")
|
_, _ = w.WriteString(" class=\"language-")
|
||||||
r.Writer.Write(w, language)
|
r.Writer.Write(w, language)
|
||||||
w.WriteString("\"")
|
_, _ = w.WriteString("\"")
|
||||||
}
|
}
|
||||||
w.WriteByte('>')
|
_ = w.WriteByte('>')
|
||||||
r.writeLines(w, source, n)
|
r.writeLines(w, source, n)
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</code></pre>\n")
|
_, _ = w.WriteString("</code></pre>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -261,18 +260,18 @@ func (r *Renderer) renderHTMLBlock(w util.BufWriter, source []byte, node ast.Nod
|
||||||
l := n.Lines().Len()
|
l := n.Lines().Len()
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
line := n.Lines().At(i)
|
line := n.Lines().At(i)
|
||||||
w.Write(line.Value(source))
|
_, _ = w.Write(line.Value(source))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("<!-- raw HTML omitted -->\n")
|
_, _ = w.WriteString("<!-- raw HTML omitted -->\n")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if n.HasClosure() {
|
if n.HasClosure() {
|
||||||
if r.Unsafe {
|
if r.Unsafe {
|
||||||
closure := n.ClosureLine
|
closure := n.ClosureLine
|
||||||
w.Write(closure.Value(source))
|
_, _ = w.Write(closure.Value(source))
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("<!-- raw HTML omitted -->\n")
|
_, _ = w.WriteString("<!-- raw HTML omitted -->\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,41 +285,41 @@ func (r *Renderer) renderList(w util.BufWriter, source []byte, node ast.Node, en
|
||||||
tag = "ol"
|
tag = "ol"
|
||||||
}
|
}
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteByte('<')
|
_ = w.WriteByte('<')
|
||||||
w.WriteString(tag)
|
_, _ = w.WriteString(tag)
|
||||||
if n.IsOrdered() && n.Start != 1 {
|
if n.IsOrdered() && n.Start != 1 {
|
||||||
fmt.Fprintf(w, " start=\"%d\">\n", n.Start)
|
fmt.Fprintf(w, " start=\"%d\">\n", n.Start)
|
||||||
} else {
|
} else {
|
||||||
w.WriteString(">\n")
|
_, _ = w.WriteString(">\n")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</")
|
_, _ = w.WriteString("</")
|
||||||
w.WriteString(tag)
|
_, _ = w.WriteString(tag)
|
||||||
w.WriteString(">\n")
|
_, _ = w.WriteString(">\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) renderListItem(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderListItem(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<li>")
|
_, _ = w.WriteString("<li>")
|
||||||
fc := n.FirstChild()
|
fc := n.FirstChild()
|
||||||
if fc != nil {
|
if fc != nil {
|
||||||
if _, ok := fc.(*ast.TextBlock); !ok {
|
if _, ok := fc.(*ast.TextBlock); !ok {
|
||||||
w.WriteByte('\n')
|
_ = w.WriteByte('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</li>\n")
|
_, _ = w.WriteString("</li>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) renderParagraph(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderParagraph(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<p>")
|
_, _ = w.WriteString("<p>")
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</p>\n")
|
_, _ = w.WriteString("</p>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +327,7 @@ func (r *Renderer) renderParagraph(w util.BufWriter, source []byte, n ast.Node,
|
||||||
func (r *Renderer) renderTextBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderTextBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if !entering {
|
if !entering {
|
||||||
if _, ok := n.NextSibling().(ast.Node); ok && n.FirstChild() != nil {
|
if _, ok := n.NextSibling().(ast.Node); ok && n.FirstChild() != nil {
|
||||||
w.WriteByte('\n')
|
_ = w.WriteByte('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
|
|
@ -339,9 +338,9 @@ func (r *Renderer) renderThemanticBreak(w util.BufWriter, source []byte, n ast.N
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
if r.XHTML {
|
if r.XHTML {
|
||||||
w.WriteString("<hr />\n")
|
_, _ = w.WriteString("<hr />\n")
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("<hr>\n")
|
_, _ = w.WriteString("<hr>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -351,22 +350,22 @@ func (r *Renderer) renderAutoLink(w util.BufWriter, source []byte, node ast.Node
|
||||||
if !entering {
|
if !entering {
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
w.WriteString(`<a href="`)
|
_, _ = w.WriteString(`<a href="`)
|
||||||
url := n.URL(source)
|
url := n.URL(source)
|
||||||
label := n.Label(source)
|
label := n.Label(source)
|
||||||
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
|
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
|
||||||
w.WriteString("mailto:")
|
_, _ = w.WriteString("mailto:")
|
||||||
}
|
}
|
||||||
w.Write(util.EscapeHTML(util.URLEscape(url, false)))
|
_, _ = w.Write(util.EscapeHTML(util.URLEscape(url, false)))
|
||||||
w.WriteString(`">`)
|
_, _ = w.WriteString(`">`)
|
||||||
w.Write(util.EscapeHTML(label))
|
_, _ = w.Write(util.EscapeHTML(label))
|
||||||
w.WriteString(`</a>`)
|
_, _ = w.WriteString(`</a>`)
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<code>")
|
_, _ = w.WriteString("<code>")
|
||||||
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
|
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
|
||||||
segment := c.(*ast.Text).Segment
|
segment := c.(*ast.Text).Segment
|
||||||
value := segment.Value(source)
|
value := segment.Value(source)
|
||||||
|
|
@ -381,7 +380,7 @@ func (r *Renderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, e
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
w.WriteString("</code>")
|
_, _ = w.WriteString("</code>")
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,13 +391,13 @@ func (r *Renderer) renderEmphasis(w util.BufWriter, source []byte, node ast.Node
|
||||||
tag = "strong"
|
tag = "strong"
|
||||||
}
|
}
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteByte('<')
|
_ = w.WriteByte('<')
|
||||||
w.WriteString(tag)
|
_, _ = w.WriteString(tag)
|
||||||
w.WriteByte('>')
|
_ = w.WriteByte('>')
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</")
|
_, _ = w.WriteString("</")
|
||||||
w.WriteString(tag)
|
_, _ = w.WriteString(tag)
|
||||||
w.WriteByte('>')
|
_ = w.WriteByte('>')
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -406,19 +405,19 @@ func (r *Renderer) renderEmphasis(w util.BufWriter, source []byte, node ast.Node
|
||||||
func (r *Renderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *Renderer) renderLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
n := node.(*ast.Link)
|
n := node.(*ast.Link)
|
||||||
if entering {
|
if entering {
|
||||||
w.WriteString("<a href=\"")
|
_, _ = w.WriteString("<a href=\"")
|
||||||
if r.Unsafe || !IsDangerousURL(n.Destination) {
|
if r.Unsafe || !IsDangerousURL(n.Destination) {
|
||||||
w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
|
_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
|
||||||
}
|
}
|
||||||
w.WriteByte('"')
|
_ = w.WriteByte('"')
|
||||||
if n.Title != nil {
|
if n.Title != nil {
|
||||||
w.WriteString(` title="`)
|
_, _ = w.WriteString(` title="`)
|
||||||
r.Writer.Write(w, n.Title)
|
r.Writer.Write(w, n.Title)
|
||||||
w.WriteByte('"')
|
_ = w.WriteByte('"')
|
||||||
}
|
}
|
||||||
w.WriteByte('>')
|
_ = w.WriteByte('>')
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("</a>")
|
_, _ = w.WriteString("</a>")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
@ -427,22 +426,22 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
n := node.(*ast.Image)
|
n := node.(*ast.Image)
|
||||||
w.WriteString("<img src=\"")
|
_, _ = w.WriteString("<img src=\"")
|
||||||
if r.Unsafe || !IsDangerousURL(n.Destination) {
|
if r.Unsafe || !IsDangerousURL(n.Destination) {
|
||||||
w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
|
_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
|
||||||
}
|
}
|
||||||
w.WriteString(`" alt="`)
|
_, _ = w.WriteString(`" alt="`)
|
||||||
w.Write(n.Text(source))
|
_, _ = w.Write(n.Text(source))
|
||||||
w.WriteByte('"')
|
_ = w.WriteByte('"')
|
||||||
if n.Title != nil {
|
if n.Title != nil {
|
||||||
w.WriteString(` title="`)
|
_, _ = w.WriteString(` title="`)
|
||||||
r.Writer.Write(w, n.Title)
|
r.Writer.Write(w, n.Title)
|
||||||
w.WriteByte('"')
|
_ = w.WriteByte('"')
|
||||||
}
|
}
|
||||||
if r.XHTML {
|
if r.XHTML {
|
||||||
w.WriteString(" />")
|
_, _ = w.WriteString(" />")
|
||||||
} else {
|
} else {
|
||||||
w.WriteString(">")
|
_, _ = w.WriteString(">")
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
|
|
@ -456,11 +455,11 @@ func (r *Renderer) renderRawHTML(w util.BufWriter, source []byte, node ast.Node,
|
||||||
l := n.Segments.Len()
|
l := n.Segments.Len()
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
segment := n.Segments.At(i)
|
segment := n.Segments.At(i)
|
||||||
w.Write(segment.Value(source))
|
_, _ = w.Write(segment.Value(source))
|
||||||
}
|
}
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
w.WriteString("<!-- raw HTML omitted -->")
|
_, _ = w.WriteString("<!-- raw HTML omitted -->")
|
||||||
return ast.WalkSkipChildren, nil
|
return ast.WalkSkipChildren, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,12 +475,29 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
|
||||||
r.Writer.Write(w, segment.Value(source))
|
r.Writer.Write(w, segment.Value(source))
|
||||||
if n.HardLineBreak() || (n.SoftLineBreak() && r.HardWraps) {
|
if n.HardLineBreak() || (n.SoftLineBreak() && r.HardWraps) {
|
||||||
if r.XHTML {
|
if r.XHTML {
|
||||||
w.WriteString("<br />\n")
|
_, _ = w.WriteString("<br />\n")
|
||||||
} else {
|
} else {
|
||||||
w.WriteString("<br>\n")
|
_, _ = w.WriteString("<br>\n")
|
||||||
}
|
}
|
||||||
} else if n.SoftLineBreak() {
|
} else if n.SoftLineBreak() {
|
||||||
w.WriteByte('\n')
|
_ = w.WriteByte('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ast.WalkContinue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
|
if !entering {
|
||||||
|
return ast.WalkContinue, nil
|
||||||
|
}
|
||||||
|
n := node.(*ast.String)
|
||||||
|
if n.IsCode() {
|
||||||
|
_, _ = w.Write(n.Value)
|
||||||
|
} else {
|
||||||
|
if n.IsRaw() {
|
||||||
|
r.Writer.RawWrite(w, n.Value)
|
||||||
|
} else {
|
||||||
|
r.Writer.Write(w, n.Value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
|
|
@ -490,11 +506,11 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
|
||||||
// RenderAttributes renders given node's attributes.
|
// RenderAttributes renders given node's attributes.
|
||||||
func (r *Renderer) RenderAttributes(w util.BufWriter, node ast.Node) {
|
func (r *Renderer) RenderAttributes(w util.BufWriter, node ast.Node) {
|
||||||
for _, attr := range node.Attributes() {
|
for _, attr := range node.Attributes() {
|
||||||
w.WriteString(" ")
|
_, _ = w.WriteString(" ")
|
||||||
w.Write(attr.Name)
|
_, _ = w.Write(attr.Name)
|
||||||
w.WriteString(`="`)
|
_, _ = w.WriteString(`="`)
|
||||||
w.Write(util.EscapeHTML(attr.Value))
|
_, _ = w.Write(util.EscapeHTML(attr.Value))
|
||||||
w.WriteByte('"')
|
_ = w.WriteByte('"')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -516,11 +532,11 @@ func escapeRune(writer util.BufWriter, r rune) {
|
||||||
if r < 256 {
|
if r < 256 {
|
||||||
v := util.EscapeHTMLByte(byte(r))
|
v := util.EscapeHTMLByte(byte(r))
|
||||||
if v != nil {
|
if v != nil {
|
||||||
writer.Write(v)
|
_, _ = writer.Write(v)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.WriteRune(util.ToValidRune(r))
|
_, _ = writer.WriteRune(util.ToValidRune(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultWriter) RawWrite(writer util.BufWriter, source []byte) {
|
func (d *defaultWriter) RawWrite(writer util.BufWriter, source []byte) {
|
||||||
|
|
@ -529,21 +545,21 @@ func (d *defaultWriter) RawWrite(writer util.BufWriter, source []byte) {
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
v := util.EscapeHTMLByte(source[i])
|
v := util.EscapeHTMLByte(source[i])
|
||||||
if v != nil {
|
if v != nil {
|
||||||
writer.Write(source[i-n : i])
|
_, _ = writer.Write(source[i-n : i])
|
||||||
n = 0
|
n = 0
|
||||||
writer.Write(v)
|
_, _ = writer.Write(v)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
writer.Write(source[l-n:])
|
_, _ = writer.Write(source[l-n:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *defaultWriter) Write(writer util.BufWriter, source []byte) {
|
func (d *defaultWriter) Write(writer util.BufWriter, source []byte) {
|
||||||
escaped := false
|
escaped := false
|
||||||
ok := false
|
var ok bool
|
||||||
limit := len(source)
|
limit := len(source)
|
||||||
n := 0
|
n := 0
|
||||||
for i := 0; i < limit; i++ {
|
for i := 0; i < limit; i++ {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue