Source File
markdown.go
Belonging Package
github.com/russross/blackfriday/v2
package blackfriday
import (
)
const Version = "2.0"
type Extensions int
const (
NoExtensions Extensions = 0
NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words
Tables // Render tables
FencedCode // Render fenced code blocks
Autolink // Detect embedded URLs that are not explicitly marked
Strikethrough // Strikethrough text using ~~test~~
LaxHTMLBlocks // Loosen up HTML block parsing rules
SpaceHeadings // Be strict about prefix heading rules
HardLineBreak // Translate newlines into line breaks
TabSizeEight // Expand tabs to eight spaces instead of four
Footnotes // Pandoc-style footnotes
NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block
HeadingIDs // specify heading IDs with {#id}
Titleblock // Titleblock ala pandoc
AutoHeadingIDs // Create the heading ID from the text
BackslashLineBreak // Translate trailing backslashes into line breaks
DefinitionLists // Render definition lists
CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants |
SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
BackslashLineBreak | DefinitionLists
)
const (
ListTypeOrdered ListType = 1 << iota
ListTypeDefinition
ListTypeTerm
ListItemContainsBlock
ListItemBeginningOfList // TODO: figure out if this is of any use now
ListItemEndOfList
)
type CellAlignFlags int
const (
TableAlignmentLeft CellAlignFlags = 1 << iota
TableAlignmentRight
TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
)
const (
TabSizeDefault = 4
TabSizeDouble = 8
)
var blockTags = map[string]struct{}{
"blockquote": {},
"del": {},
"div": {},
"dl": {},
"fieldset": {},
"form": {},
"h1": {},
"h2": {},
"h3": {},
"h4": {},
"h5": {},
"h6": {},
"iframe": {},
"ins": {},
"math": {},
"noscript": {},
"ol": {},
"pre": {},
"p": {},
"script": {},
"style": {},
"table": {},
"ul": {},
"address": {},
"article": {},
"aside": {},
"canvas": {},
"figcaption": {},
"figure": {},
"footer": {},
"header": {},
"hgroup": {},
"main": {},
"nav": {},
"output": {},
"progress": {},
"section": {},
"video": {},
}
RenderNode(w io.Writer, node *Node, entering bool) WalkStatus
type Markdown struct {
renderer Renderer
referenceOverride ReferenceOverrideFunc
refs map[string]*reference
inlineCallback [256]inlineParser
extensions Extensions
nesting int
maxNesting int
insideLink bool
notes []*reference
doc *Node
tip *Node // = doc
oldTip *Node
lastMatchedContainer *Node // = doc
allClosed bool
}
func ( *Markdown) ( string) ( *reference, bool) {
if .referenceOverride != nil {
, := .referenceOverride()
if {
if == nil {
return nil, false
}
return &reference{
link: []byte(.Link),
title: []byte(.Title),
noteID: 0,
hasBlock: false,
text: []byte(.Text)}, true
}
, = .refs[strings.ToLower()]
return ,
}
func ( *Markdown) ( *Node) {
:= .Parent
.open = false
.tip =
}
func ( *Markdown) ( NodeType, uint32) *Node {
return .addExistingChild(NewNode(), )
}
func ( *Markdown) ( *Node, uint32) *Node {
for !.tip.canContain(.Type) {
.finalize(.tip)
}
.tip.AppendChild()
.tip =
return
}
func ( *Markdown) () {
if !.allClosed {
for .oldTip != .lastMatchedContainer {
:= .oldTip.Parent
.finalize(.oldTip)
.oldTip =
}
.allClosed = true
}
}
type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool)
.inlineCallback[' '] = maybeLineBreak
.inlineCallback['*'] = emphasis
.inlineCallback['_'] = emphasis
if .extensions&Strikethrough != 0 {
.inlineCallback['~'] = emphasis
}
.inlineCallback['`'] = codeSpan
.inlineCallback['\n'] = lineBreak
.inlineCallback['['] = link
.inlineCallback['<'] = leftAngle
.inlineCallback['\\'] = escape
.inlineCallback['&'] = entity
.inlineCallback['!'] = maybeImage
.inlineCallback['^'] = maybeInlineFootnote
if .extensions&Autolink != 0 {
.inlineCallback['h'] = maybeAutoLink
.inlineCallback['m'] = maybeAutoLink
.inlineCallback['f'] = maybeAutoLink
.inlineCallback['H'] = maybeAutoLink
.inlineCallback['M'] = maybeAutoLink
.inlineCallback['F'] = maybeAutoLink
}
if .extensions&Footnotes != 0 {
.notes = make([]*reference, 0)
}
return &
}
func ( Extensions) Option {
return func( *Markdown) {
.extensions =
}
}
func () Option {
return func( *Markdown) {
.extensions = NoExtensions
.renderer = NewHTMLRenderer(HTMLRendererParameters{
Flags: HTMLFlagsNone,
})
}
}
func ( ReferenceOverrideFunc) Option {
return func( *Markdown) {
.referenceOverride =
}
}
func ( []byte, ...Option) []byte {
:= NewHTMLRenderer(HTMLRendererParameters{
Flags: CommonHTMLFlags,
})
:= []Option{WithRenderer(), WithExtensions(CommonExtensions)}
= append(, ...)
:= New(...)
:= .Parse()
var bytes.Buffer
.renderer.RenderHeader(&, )
.Walk(func( *Node, bool) WalkStatus {
return .renderer.RenderNode(&, , )
})
.renderer.RenderFooter(&, )
return .Bytes()
}
.doc.Walk(func( *Node, bool) WalkStatus {
if .Type == Paragraph || .Type == Heading || .Type == TableCell {
.inline(, .content)
.content = nil
}
return GoToNext
})
.parseRefsToAST()
return .doc
}
func ( *Markdown) () {
if .extensions&Footnotes == 0 || len(.notes) == 0 {
return
}
.tip = .doc
:= .addBlock(List, nil)
.IsFootnotesList = true
.ListFlags = ListTypeOrdered
for := 0; < len(.notes); ++ {
:= .notes[]
.addExistingChild(.footnote, 0)
:= .footnote
.ListFlags = | ListTypeOrdered
.RefLink = .link
if .hasBlock {
|= ListItemContainsBlock
.block(.title)
} else {
.inline(, .title)
}
&^= ListItemBeginningOfList | ListItemContainsBlock
}
:= .Parent
finalizeList()
.tip =
.Walk(func( *Node, bool) WalkStatus {
if .Type == Paragraph || .Type == Heading {
.inline(, .content)
.content = nil
}
return GoToNext
})
}
type reference struct {
link []byte
title []byte
noteID int // 0 if not a footnote ref
hasBlock bool
footnote *Node // a link to the Item node within a list of footnotes
text []byte // only gets populated by refOverride feature with Reference.Text
}
func ( *reference) () string {
return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}",
.link, .title, .text, .noteID, .hasBlock)
}
if len() < 4 {
return 0
}
:= 0
for < 3 && [] == ' ' {
++
}
:= 0
if [] != '[' {
return 0
}
++
if .extensions&Footnotes != 0 {
if == 0 && == {
return 0
++
if >= len() || [] != ':' {
return 0
}
++
for < len() && ([] == ' ' || [] == '\t') {
++
}
if < len() && ([] == '\n' || [] == '\r') {
++
if < len() && [] == '\n' && [-1] == '\r' {
++
}
}
for < len() && ([] == ' ' || [] == '\t') {
++
}
if >= len() {
return 0
}
var (
, int
, int
int
[]byte
bool
)
if .extensions&Footnotes != 0 && != 0 {
, , , = scanFootnote(, , , )
=
} else {
, , , , = scanLinkRef(, , )
}
if == 0 {
return 0
}
if [] == '<' {
++
}
=
for < len() && [] != ' ' && [] != '\t' && [] != '\n' && [] != '\r' {
++
}
=
if [] == '<' && [-1] == '>' {
++
--
}
if > 0 {
= + 1
for < len() && ([] == ' ' || [] == '\t') {
++
}
}
if +1 < len() && ([] == '\'' || [] == '"' || [] == '(') {
++
=
--
for > && ([] == ' ' || [] == '\t') {
--
}
if > && ([] == '\'' || [] == '"' || [] == ')') {
=
=
}
}
return
}
for < len() && [] == ' ' {
++
}
=
=
for < len() && [-1] != '\n' {
++
}
.Write([:])
=
for < len() && [-1] != '\n' {
++
}
break
}
func ( byte) bool {
return ishorizontalspace() || isverticalspace()
}
func ( []byte) []byte {
if len() == 0 {
return
}
:= make([]byte, 0, len())
:= false
for , := range {
if isalnum() {
= false
= append(, )
} else if {
continue
} else {
= append(, '-')
= true
}
}
var , int
var byte
for , = range {
if != '-' {
break
}
}
for = len() - 1; > 0; -- {
if [] != '-' {
break
}
}
return [ : +1]
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |