diff options
Diffstat (limited to 'vendor/github.com/gomarkdown')
15 files changed, 342 insertions, 366 deletions
diff --git a/vendor/github.com/gomarkdown/markdown/.gitpod.yml b/vendor/github.com/gomarkdown/markdown/.gitpod.yml deleted file mode 100644 index dde1f1d9..00000000 --- a/vendor/github.com/gomarkdown/markdown/.gitpod.yml +++ /dev/null @@ -1,9 +0,0 @@ -# This configuration file was automatically generated by Gitpod. -# Please adjust to your needs (see https://www.gitpod.io/docs/config-gitpod-file) -# and commit this file to your remote git repository to share the goodness with others. - -tasks: - - init: go get && go build ./... && go test ./... - command: go run - - diff --git a/vendor/github.com/gomarkdown/markdown/README.md b/vendor/github.com/gomarkdown/markdown/README.md index a85ce69c..a60b8ba5 100644 --- a/vendor/github.com/gomarkdown/markdown/README.md +++ b/vendor/github.com/gomarkdown/markdown/README.md @@ -6,7 +6,16 @@ Package `github.com/gomarkdown/markdown` is a Go library for parsing Markdown te It's very fast and supports common extensions. -Try code examples online: https://replit.com/@kjk1?path=folder/gomarkdown +Tutorial: https://blog.kowalczyk.info/article/cxn3/advanced-markdown-processing-in-go.html + +Code examples: +* https://onlinetool.io/goplayground/#txO7hJ-ibeU : basic markdown => HTML +* https://onlinetool.io/goplayground/#yFRIWRiu-KL : customize HTML renderer +* https://onlinetool.io/goplayground/#2yV5-HDKBUV : modify AST +* https://onlinetool.io/goplayground/#9fqKwRbuJ04 : customize parser +* https://onlinetool.io/goplayground/#Bk0zTvrzUDR : syntax highlight + +Those examples are also in [examples](./examples) directory. ## API Docs: @@ -15,101 +24,58 @@ Try code examples online: https://replit.com/@kjk1?path=folder/gomarkdown - https://pkg.go.dev/github.com/gomarkdown/markdown/parser : parser - https://pkg.go.dev/github.com/gomarkdown/markdown/html : html renderer -## Users - -Some tools using this package: https://pkg.go.dev/github.com/gomarkdown/markdown?tab=importedby - ## Usage To convert markdown text to HTML using reasonable defaults: ```go -md := []byte("## markdown document") -output := markdown.ToHTML(md, nil, nil) -``` - -Try it online: https://replit.com/@kjk1/gomarkdown-basic - -## Customizing markdown parser +package main -Markdown format is loosely specified and there are multiple extensions invented after original specification was created. - -The parser supports several [extensions](https://pkg.go.dev/github.com/gomarkdown/markdown/parser#Extensions). +import ( + "os" -Default parser uses most common `parser.CommonExtensions` but you can easily use parser with custom extension: + "github.com/gomarkdown/markdown" + "github.com/gomarkdown/markdown/ast" + "github.com/gomarkdown/markdown/html" + "github.com/gomarkdown/markdown/parser" -```go -import ( - "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/parser" + "fmt" ) -extensions := parser.CommonExtensions | parser.AutoHeadingIDs -parser := parser.NewWithExtensions(extensions) +var mds = `# header -md := []byte("markdown text") -html := markdown.ToHTML(md, parser, nil) -``` - -Try it online: https://replit.com/@kjk1/gomarkdown-customized-html-renderer +Sample text. -## Customizing HTML renderer +[link](http://example.com) +` -Similarly, HTML renderer can be configured with different [options](https://pkg.go.dev/github.com/gomarkdown/markdown/html#RendererOptions) +func mdToHTML(md []byte) []byte { + // create markdown parser with extensions + extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock + p := parser.NewWithExtensions(extensions) + doc := p.Parse(md) -Here's how to use a custom renderer: + // create HTML renderer with extensions + htmlFlags := html.CommonFlags | html.HrefTargetBlank + opts := html.RendererOptions{Flags: htmlFlags} + renderer := html.NewRenderer(opts) -```go -import ( - "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/html" -) + return markdown.Render(doc, renderer) +} -htmlFlags := html.CommonFlags | html.HrefTargetBlank -opts := html.RendererOptions{Flags: htmlFlags} -renderer := html.NewRenderer(opts) +func main() { + md := []byte(mds) + html := mdToHTML(md) -md := []byte("markdown text") -html := markdown.ToHTML(md, nil, renderer) + fmt.Printf("--- Markdown:\n%s\n\n--- HTML:\n%s\n", md, html) +} ``` -Try it online: https://replit.com/@kjk1/gomarkdown-customized-html-renderer - -HTML renderer also supports reusing most of the logic and overriding rendering of only specific nodes. - -You can provide [RenderNodeFunc](https://pkg.go.dev/github.com/gomarkdown/markdown/html#RenderNodeFunc) in [RendererOptions](https://pkg.go.dev/github.com/gomarkdown/markdown/html#RendererOptions). - -The function is called for each node in AST, you can implement custom rendering logic and tell HTML renderer to skip rendering this node. - -Here's the simplest example that drops all code blocks from the output: - -````go -import ( - "github.com/gomarkdown/markdown" - "github.com/gomarkdown/markdown/ast" - "github.com/gomarkdown/markdown/html" -) +Try it online: https://onlinetool.io/goplayground/#txO7hJ-ibeU -// return (ast.GoToNext, true) to tell html renderer to skip rendering this node -// (because you've rendered it) -func renderHookDropCodeBlock(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) { - // skip all nodes that are not CodeBlock nodes - if _, ok := node.(*ast.CodeBlock); !ok { - return ast.GoToNext, false - } - // custom rendering logic for ast.CodeBlock. By doing nothing it won't be - // present in the output - return ast.GoToNext, true -} +For more documentation read [this guide](https://blog.kowalczyk.info/article/cxn3/advanced-markdown-processing-in-go.html) -opts := html.RendererOptions{ - Flags: html.CommonFlags, - RenderNodeHook: renderHookDropCodeBlock, -} -renderer := html.NewRenderer(opts) -md := "test\n```\nthis code block will be dropped from output\n```\ntext" -html := markdown.ToHTML([]byte(md), nil, renderer) -```` +Comparing to other markdown parsers: https://babelmark.github.io/ ## Sanitize untrusted content @@ -129,12 +95,6 @@ maybeUnsafeHTML := markdown.ToHTML(md, nil, nil) html := bluemonday.UGCPolicy().SanitizeBytes(maybeUnsafeHTML) ``` -## Windows / Mac newlines - -The library only supports Unix newlines. If you have markdown text with possibly -Windows / Mac newlines, normalize newlines before calling this library using -`d = markdown.NormalizeNewlines(d)` - ## mdtohtml command-line tool https://github.com/gomarkdown/mdtohtml is a command-line markdown to html @@ -323,26 +283,15 @@ implements the following extensions: - **Mmark support**, see <https://mmark.miek.nl/post/syntax/> for all new syntax elements this adds. -## Todo +## Users -- port https://github.com/russross/blackfriday/issues/348 -- port [LaTeX output](https://github.com/Ambrevar/Blackfriday-LaTeX): - renders output as LaTeX. -- port https://github.com/shurcooL/github_flavored_markdown to markdown -- port [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, - but for markdown. -- More unit testing -- Improve unicode support. It does not understand all unicode - rules (about what constitutes a letter, a punctuation symbol, - etc.), so it may fail to detect word boundaries correctly in - some instances. It is safe on all utf-8 input. +Some tools using this package: https://pkg.go.dev/github.com/gomarkdown/markdown?tab=importedby ## History -markdown is a fork of v2 of https://github.com/russross/blackfriday that is: +markdown is a fork of v2 of https://github.com/russross/blackfriday. -- actively maintained (sadly in Feb 2018 blackfriday was inactive for 5 months with many bugs and pull requests accumulated) -- refactored API (split into ast/parser/html sub-packages) +I refactored the API (split into ast/parser/html sub-packages). Blackfriday itself was based on C implementation [sundown](https://github.com/vmg/sundown) which in turn was based on [libsoldout](http://fossil.instinctive.eu/libsoldout/home). diff --git a/vendor/github.com/gomarkdown/markdown/ast/node.go b/vendor/github.com/gomarkdown/markdown/ast/node.go index 1d558dd3..8f802db8 100644 --- a/vendor/github.com/gomarkdown/markdown/ast/node.go +++ b/vendor/github.com/gomarkdown/markdown/ast/node.go @@ -92,6 +92,12 @@ type Container struct { *Attribute // Block level attribute } +// return true if can contain children of a given node type +// used by custom nodes to over-ride logic in canNodeContain +type CanContain interface { + CanContain(Node) bool +} + // AsContainer returns itself as *Container func (c *Container) AsContainer() *Container { return c diff --git a/vendor/github.com/gomarkdown/markdown/ast/print.go b/vendor/github.com/gomarkdown/markdown/ast/print.go index b186ec07..a4e3d624 100644 --- a/vendor/github.com/gomarkdown/markdown/ast/print.go +++ b/vendor/github.com/gomarkdown/markdown/ast/print.go @@ -157,6 +157,8 @@ func printRecur(w io.Writer, node Node, prefix string, depth int) { content += "flags=" + flags + " " } printDefault(w, indent, typeName, content) + case *CodeBlock: + printDefault(w, indent, typeName + ":" + string(v.Info), content) default: printDefault(w, indent, typeName, content) } diff --git a/vendor/github.com/gomarkdown/markdown/codecov.yml b/vendor/github.com/gomarkdown/markdown/codecov.yml deleted file mode 100644 index f681ff11..00000000 --- a/vendor/github.com/gomarkdown/markdown/codecov.yml +++ /dev/null @@ -1,8 +0,0 @@ -coverage: - status: - project: - default: - # basic - target: 60% - threshold: 2% - base: auto diff --git a/vendor/github.com/gomarkdown/markdown/html/renderer.go b/vendor/github.com/gomarkdown/markdown/html/renderer.go index fc63c5fe..494e7540 100644 --- a/vendor/github.com/gomarkdown/markdown/html/renderer.go +++ b/vendor/github.com/gomarkdown/markdown/html/renderer.go @@ -88,13 +88,15 @@ type RendererOptions struct { // FootnoteReturnLinks flag is enabled. If blank, the string // <sup>[return]</sup> is used. FootnoteReturnLinkContents string - // CitationFormatString defines how a citation is rendered. If blnck, the string + // CitationFormatString defines how a citation is rendered. If blank, the string // <sup>[%s]</sup> is used. Where %s will be substituted with the citation target. CitationFormatString string // If set, add this text to the front of each Heading ID, to ensure uniqueness. HeadingIDPrefix string // If set, add this text to the back of each Heading ID, to ensure uniqueness. HeadingIDSuffix string + // can over-write <p> for paragraph tag + ParagraphTag string Title string // Document title (used if CompletePage is set) CSS string // Optional CSS file URL (used if CompletePage is set) @@ -120,7 +122,7 @@ type RendererOptions struct { // // Do not create this directly, instead use the NewRenderer function. type Renderer struct { - opts RendererOptions + Opts RendererOptions closeTag string // how to end singleton tags: either " />" or ">" @@ -168,7 +170,7 @@ func EscapeHTML(w io.Writer, d []byte) { } } -func escLink(w io.Writer, text []byte) { +func EscLink(w io.Writer, text []byte) { unesc := html.UnescapeString(string(text)) EscapeHTML(w, []byte(unesc)) } @@ -207,7 +209,7 @@ func NewRenderer(opts RendererOptions) *Renderer { } return &Renderer{ - opts: opts, + Opts: opts, closeTag: closeTag, headingIDs: make(map[string]int), @@ -250,12 +252,12 @@ func isRelativeLink(link []byte) (yes bool) { return false } -func (r *Renderer) addAbsPrefix(link []byte) []byte { - if len(link) == 0 { +func AddAbsPrefix(link []byte, prefix string) []byte { + if len(link) == 0 || len(prefix) == 0 { return link } - if r.opts.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { - newDest := r.opts.AbsolutePrefix + if isRelativeLink(link) && link[0] != '.' { + newDest := prefix if link[0] != '/' { newDest += "/" } @@ -294,7 +296,7 @@ func isMailto(link []byte) bool { } func needSkipLink(r *Renderer, dest []byte) bool { - flags := r.opts.Flags + flags := r.Opts.Flags if flags&SkipLinks != 0 { return true } @@ -317,7 +319,7 @@ func appendLanguageAttr(attrs []string, info []byte) []string { return append(attrs, s) } -func (r *Renderer) outTag(w io.Writer, name string, attrs []string) { +func (r *Renderer) OutTag(w io.Writer, name string, attrs []string) { s := name if len(attrs) > 0 { s += " " + strings.Join(attrs, " ") @@ -326,22 +328,22 @@ func (r *Renderer) outTag(w io.Writer, name string, attrs []string) { r.lastOutputLen = 1 } -func footnoteRef(prefix string, node *ast.Link) string { - urlFrag := prefix + string(slugify(node.Destination)) +func FootnoteRef(prefix string, node *ast.Link) string { + urlFrag := prefix + string(Slugify(node.Destination)) nStr := strconv.Itoa(node.NoteID) anchor := `<a href="#fn:` + urlFrag + `">` + nStr + `</a>` return `<sup class="footnote-ref" id="fnref:` + urlFrag + `">` + anchor + `</sup>` } -func footnoteItem(prefix string, slug []byte) string { +func FootnoteItem(prefix string, slug []byte) string { return `<li id="fn:` + prefix + string(slug) + `">` } -func footnoteReturnLink(prefix, returnLink string, slug []byte) string { +func FootnoteReturnLink(prefix, returnLink string, slug []byte) string { return ` <a class="footnote-return" href="#fnref:` + prefix + string(slug) + `">` + returnLink + `</a>` } -func listItemOpenCR(listItem *ast.ListItem) bool { +func ListItemOpenCR(listItem *ast.ListItem) bool { if ast.GetPrevNode(listItem) == nil { return false } @@ -349,13 +351,13 @@ func listItemOpenCR(listItem *ast.ListItem) bool { return !ld.Tight && ld.ListFlags&ast.ListTypeDefinition == 0 } -func skipParagraphTags(para *ast.Paragraph) bool { +func SkipParagraphTags(para *ast.Paragraph) bool { parent := para.Parent grandparent := parent.GetParent() - if grandparent == nil || !isList(grandparent) { + if grandparent == nil || !IsList(grandparent) { return false } - isParentTerm := isListItemTerm(parent) + isParentTerm := IsListItemTerm(parent) grandparentListData := grandparent.(*ast.List) tightOrTerm := grandparentListData.Tight || isParentTerm return tightOrTerm @@ -391,35 +393,35 @@ var ( closeHTags = []string{"</h1>", "</h2>", "</h3>", "</h4>", "</h5>"} ) -func headingOpenTagFromLevel(level int) string { +func HeadingOpenTagFromLevel(level int) string { if level < 1 || level > 5 { return "<h6" } return openHTags[level-1] } -func headingCloseTagFromLevel(level int) string { +func HeadingCloseTagFromLevel(level int) string { if level < 1 || level > 5 { return "</h6>" } return closeHTags[level-1] } -func (r *Renderer) outHRTag(w io.Writer, attrs []string) { +func (r *Renderer) OutHRTag(w io.Writer, attrs []string) { hr := TagWithAttributes("<hr", attrs) - r.OutOneOf(w, r.opts.Flags&UseXHTML == 0, hr, "<hr />") + r.OutOneOf(w, r.Opts.Flags&UseXHTML == 0, hr, "<hr />") } // Text writes ast.Text node func (r *Renderer) Text(w io.Writer, text *ast.Text) { - if r.opts.Flags&Smartypants != 0 { + if r.Opts.Flags&Smartypants != 0 { var tmp bytes.Buffer EscapeHTML(&tmp, text.Literal) r.sr.Process(w, tmp.Bytes()) } else { _, parentIsLink := text.Parent.(*ast.Link) if parentIsLink { - escLink(w, text.Literal) + EscLink(w, text.Literal) } else { EscapeHTML(w, text.Literal) } @@ -428,7 +430,7 @@ func (r *Renderer) Text(w io.Writer, text *ast.Text) { // HardBreak writes ast.Hardbreak node func (r *Renderer) HardBreak(w io.Writer, node *ast.Hardbreak) { - r.OutOneOf(w, r.opts.Flags&UseXHTML == 0, "<br>", "<br />") + r.OutOneOf(w, r.Opts.Flags&UseXHTML == 0, "<br>", "<br />") r.CR(w) } @@ -459,7 +461,7 @@ func (r *Renderer) OutOneOfCr(w io.Writer, outFirst bool, first string, second s // HTMLSpan writes ast.HTMLSpan node func (r *Renderer) HTMLSpan(w io.Writer, span *ast.HTMLSpan) { - if r.opts.Flags&SkipHTML == 0 { + if r.Opts.Flags&SkipHTML == 0 { r.Out(w, span.Literal) } } @@ -467,18 +469,18 @@ func (r *Renderer) HTMLSpan(w io.Writer, span *ast.HTMLSpan) { func (r *Renderer) linkEnter(w io.Writer, link *ast.Link) { attrs := link.AdditionalAttributes dest := link.Destination - dest = r.addAbsPrefix(dest) + dest = AddAbsPrefix(dest, r.Opts.AbsolutePrefix) var hrefBuf bytes.Buffer hrefBuf.WriteString("href=\"") - escLink(&hrefBuf, dest) + EscLink(&hrefBuf, dest) hrefBuf.WriteByte('"') attrs = append(attrs, hrefBuf.String()) if link.NoteID != 0 { - r.Outs(w, footnoteRef(r.opts.FootnoteAnchorPrefix, link)) + r.Outs(w, FootnoteRef(r.Opts.FootnoteAnchorPrefix, link)) return } - attrs = appendLinkAttrs(attrs, r.opts.Flags, dest) + attrs = appendLinkAttrs(attrs, r.Opts.Flags, dest) if len(link.Title) > 0 { var titleBuff bytes.Buffer titleBuff.WriteString("title=\"") @@ -486,7 +488,7 @@ func (r *Renderer) linkEnter(w io.Writer, link *ast.Link) { titleBuff.WriteByte('"') attrs = append(attrs, titleBuff.String()) } - r.outTag(w, "<a", attrs) + r.OutTag(w, "<a", attrs) } func (r *Renderer) linkExit(w io.Writer, link *ast.Link) { @@ -511,33 +513,34 @@ func (r *Renderer) Link(w io.Writer, link *ast.Link, entering bool) { } func (r *Renderer) imageEnter(w io.Writer, image *ast.Image) { - dest := image.Destination - dest = r.addAbsPrefix(dest) - if r.DisableTags == 0 { - //if options.safe && potentiallyUnsafe(dest) { - //out(w, `<img src="" alt="`) - //} else { - if r.opts.Flags&LazyLoadImages != 0 { - r.Outs(w, `<img loading="lazy" src="`) - } else { - r.Outs(w, `<img src="`) - } - escLink(w, dest) - r.Outs(w, `" alt="`) - //} - } r.DisableTags++ + if r.DisableTags > 1 { + return + } + src := image.Destination + src = AddAbsPrefix(src, r.Opts.AbsolutePrefix) + attrs := BlockAttrs(image) + if r.Opts.Flags&LazyLoadImages != 0 { + attrs = append(attrs, `loading="lazy"`) + } + + s := TagWithAttributes("<img", attrs) + s = s[:len(s)-1] // hackish: strip off ">" from end + r.Outs(w, s+` src="`) + EscLink(w, src) + r.Outs(w, `" alt="`) } func (r *Renderer) imageExit(w io.Writer, image *ast.Image) { r.DisableTags-- - if r.DisableTags == 0 { - if image.Title != nil { - r.Outs(w, `" title="`) - EscapeHTML(w, image.Title) - } - r.Outs(w, `" />`) + if r.DisableTags > 0 { + return + } + if image.Title != nil { + r.Outs(w, `" title="`) + EscapeHTML(w, image.Title) } + r.Outs(w, `" />`) } // Image writes ast.Image node @@ -571,20 +574,28 @@ func (r *Renderer) paragraphEnter(w io.Writer, para *ast.Paragraph) { } } - tag := TagWithAttributes("<p", BlockAttrs(para)) + ptag := "<p" + if r.Opts.ParagraphTag != "" { + ptag = "<" + r.Opts.ParagraphTag + } + tag := TagWithAttributes(ptag, BlockAttrs(para)) r.Outs(w, tag) } func (r *Renderer) paragraphExit(w io.Writer, para *ast.Paragraph) { - r.Outs(w, "</p>") - if !(isListItem(para.Parent) && ast.GetNextNode(para) == nil) { + ptag := "</p>" + if r.Opts.ParagraphTag != "" { + ptag = "</" + r.Opts.ParagraphTag + ">" + } + r.Outs(w, ptag) + if !(IsListItem(para.Parent) && ast.GetNextNode(para) == nil) { r.CR(w) } } // Paragraph writes ast.Paragraph node func (r *Renderer) Paragraph(w io.Writer, para *ast.Paragraph, entering bool) { - if skipParagraphTags(para) { + if SkipParagraphTags(para) { return } if entering { @@ -603,7 +614,7 @@ func (r *Renderer) Code(w io.Writer, node *ast.Code) { // HTMLBlock write ast.HTMLBlock node func (r *Renderer) HTMLBlock(w io.Writer, node *ast.HTMLBlock) { - if r.opts.Flags&SkipHTML != 0 { + if r.Opts.Flags&SkipHTML != 0 { return } r.CR(w) @@ -611,6 +622,25 @@ func (r *Renderer) HTMLBlock(w io.Writer, node *ast.HTMLBlock) { r.CR(w) } +func (r *Renderer) EnsureUniqueHeadingID(id string) string { + for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { + tmp := fmt.Sprintf("%s-%d", id, count+1) + + if _, tmpFound := r.headingIDs[tmp]; !tmpFound { + r.headingIDs[id] = count + 1 + id = tmp + } else { + id = id + "-1" + } + } + + if _, found := r.headingIDs[id]; !found { + r.headingIDs[id] = 0 + } + + return id +} + func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) { var attrs []string var class string @@ -629,44 +659,25 @@ func (r *Renderer) headingEnter(w io.Writer, nodeData *ast.Heading) { attrs = []string{`class="` + class + `"`} } - ensureUniqueHeadingID := func(id string) string { - for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { - tmp := fmt.Sprintf("%s-%d", id, count+1) - - if _, tmpFound := r.headingIDs[tmp]; !tmpFound { - r.headingIDs[id] = count + 1 - id = tmp - } else { - id = id + "-1" - } - } - - if _, found := r.headingIDs[id]; !found { - r.headingIDs[id] = 0 - } - - return id - } - if nodeData.HeadingID != "" { - id := ensureUniqueHeadingID(nodeData.HeadingID) - if r.opts.HeadingIDPrefix != "" { - id = r.opts.HeadingIDPrefix + id + id := r.EnsureUniqueHeadingID(nodeData.HeadingID) + if r.Opts.HeadingIDPrefix != "" { + id = r.Opts.HeadingIDPrefix + id } - if r.opts.HeadingIDSuffix != "" { - id = id + r.opts.HeadingIDSuffix + if r.Opts.HeadingIDSuffix != "" { + id = id + r.Opts.HeadingIDSuffix } attrID := `id="` + id + `"` attrs = append(attrs, attrID) } attrs = append(attrs, BlockAttrs(nodeData)...) r.CR(w) - r.outTag(w, headingOpenTagFromLevel(nodeData.Level), attrs) + r.OutTag(w, HeadingOpenTagFromLevel(nodeData.Level), attrs) } func (r *Renderer) headingExit(w io.Writer, heading *ast.Heading) { - r.Outs(w, headingCloseTagFromLevel(heading.Level)) - if !(isListItem(heading.Parent) && ast.GetNextNode(heading) == nil) { + r.Outs(w, HeadingCloseTagFromLevel(heading.Level)) + if !(IsListItem(heading.Parent) && ast.GetNextNode(heading) == nil) { r.CR(w) } } @@ -683,7 +694,7 @@ func (r *Renderer) Heading(w io.Writer, node *ast.Heading, entering bool) { // HorizontalRule writes ast.HorizontalRule node func (r *Renderer) HorizontalRule(w io.Writer, node *ast.HorizontalRule) { r.CR(w) - r.outHRTag(w, BlockAttrs(node)) + r.OutHRTag(w, BlockAttrs(node)) r.CR(w) } @@ -693,15 +704,15 @@ func (r *Renderer) listEnter(w io.Writer, nodeData *ast.List) { if nodeData.IsFootnotesList { r.Outs(w, "\n<div class=\"footnotes\">\n\n") - if r.opts.Flags&FootnoteNoHRTag == 0 { - r.outHRTag(w, nil) + if r.Opts.Flags&FootnoteNoHRTag == 0 { + r.OutHRTag(w, nil) r.CR(w) } } r.CR(w) - if isListItem(nodeData.Parent) { + if IsListItem(nodeData.Parent) { grand := nodeData.Parent.GetParent() - if isListTight(grand) { + if IsListTight(grand) { r.CR(w) } } @@ -717,7 +728,7 @@ func (r *Renderer) listEnter(w io.Writer, nodeData *ast.List) { openTag = "<dl" } attrs = append(attrs, BlockAttrs(nodeData)...) - r.outTag(w, openTag, attrs) + r.OutTag(w, openTag, attrs) r.CR(w) } @@ -760,12 +771,12 @@ func (r *Renderer) List(w io.Writer, list *ast.List, entering bool) { } func (r *Renderer) listItemEnter(w io.Writer, listItem *ast.ListItem) { - if listItemOpenCR(listItem) { + if ListItemOpenCR(listItem) { r.CR(w) } if listItem.RefLink != nil { - slug := slugify(listItem.RefLink) - r.Outs(w, footnoteItem(r.opts.FootnoteAnchorPrefix, slug)) + slug := Slugify(listItem.RefLink) + r.Outs(w, FootnoteItem(r.Opts.FootnoteAnchorPrefix, slug)) return } @@ -780,11 +791,11 @@ func (r *Renderer) listItemEnter(w io.Writer, listItem *ast.ListItem) { } func (r *Renderer) listItemExit(w io.Writer, listItem *ast.ListItem) { - if listItem.RefLink != nil && r.opts.Flags&FootnoteReturnLinks != 0 { - slug := slugify(listItem.RefLink) - prefix := r.opts.FootnoteAnchorPrefix - link := r.opts.FootnoteReturnLinkContents - s := footnoteReturnLink(prefix, link, slug) + if listItem.RefLink != nil && r.Opts.Flags&FootnoteReturnLinks != 0 { + slug := Slugify(listItem.RefLink) + prefix := r.Opts.FootnoteAnchorPrefix + link := r.Opts.FootnoteReturnLinkContents + s := FootnoteReturnLink(prefix, link, slug) r.Outs(w, s) } @@ -815,7 +826,7 @@ func (r *Renderer) EscapeHTMLCallouts(w io.Writer, d []byte) { ld := len(d) Parse: for i := 0; i < ld; i++ { - for _, comment := range r.opts.Comments { + for _, comment := range r.Opts.Comments { if !bytes.HasPrefix(d[i:], comment) { break } @@ -853,14 +864,14 @@ func (r *Renderer) CodeBlock(w io.Writer, codeBlock *ast.CodeBlock) { r.Outs(w, "<pre>") code := TagWithAttributes("<code", attrs) r.Outs(w, code) - if r.opts.Comments != nil { + if r.Opts.Comments != nil { r.EscapeHTMLCallouts(w, codeBlock.Literal) } else { EscapeHTML(w, codeBlock.Literal) } r.Outs(w, "</code>") r.Outs(w, "</pre>") - if !isListItem(codeBlock.Parent) { + if !IsListItem(codeBlock.Parent) { r.CR(w) } } @@ -910,7 +921,7 @@ func (r *Renderer) TableCell(w io.Writer, tableCell *ast.TableCell, entering boo if ast.GetPrevNode(tableCell) == nil { r.CR(w) } - r.outTag(w, openTag, attrs) + r.OutTag(w, openTag, attrs) } // TableBody writes ast.TableBody node @@ -959,8 +970,8 @@ func (r *Renderer) Citation(w io.Writer, node *ast.Citation) { case ast.CitationTypeSuppressed: attr[0] = `class="suppressed"` } - r.outTag(w, "<cite", attr) - r.Outs(w, fmt.Sprintf(`<a href="#%s">`+r.opts.CitationFormatString+`</a>`, c, c)) + r.OutTag(w, "<cite", attr) + r.Outs(w, fmt.Sprintf(`<a href="#%s">`+r.Opts.CitationFormatString+`</a>`, c, c)) r.Outs(w, "</cite>") } } @@ -968,7 +979,7 @@ func (r *Renderer) Citation(w io.Writer, node *ast.Citation) { // Callout writes ast.Callout node func (r *Renderer) Callout(w io.Writer, node *ast.Callout) { attr := []string{`class="callout"`} - r.outTag(w, "<span", attr) + r.OutTag(w, "<span", attr) r.Out(w, node.ID) r.Outs(w, "</span>") } @@ -977,14 +988,14 @@ func (r *Renderer) Callout(w io.Writer, node *ast.Callout) { func (r *Renderer) Index(w io.Writer, node *ast.Index) { // there is no in-text representation. attr := []string{`class="index"`, fmt.Sprintf(`id="%s"`, node.ID)} - r.outTag(w, "<span", attr) + r.OutTag(w, "<span", attr) r.Outs(w, "</span>") } // RenderNode renders a markdown node to HTML func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.WalkStatus { - if r.opts.RenderNodeHook != nil { - status, didHandle := r.opts.RenderNodeHook(w, node, entering) + if r.Opts.RenderNodeHook != nil { + status, didHandle := r.Opts.RenderNodeHook(w, node, entering) if didHandle { return status } @@ -1019,7 +1030,7 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal case *ast.Citation: r.Citation(w, node) case *ast.Image: - if r.opts.Flags&SkipImages != 0 { + if r.Opts.Flags&SkipImages != 0 { return ast.SkipChildren } r.Image(w, node, entering) @@ -1098,7 +1109,7 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal // RenderHeader writes HTML document preamble and TOC if requested. func (r *Renderer) RenderHeader(w io.Writer, ast ast.Node) { r.writeDocumentHeader(w) - if r.opts.Flags&TOC != 0 { + if r.Opts.Flags&TOC != 0 { r.writeTOC(w, ast) } } @@ -1109,18 +1120,18 @@ func (r *Renderer) RenderFooter(w io.Writer, _ ast.Node) { r.Outs(w, "</section>\n") } - if r.opts.Flags&CompletePage == 0 { + if r.Opts.Flags&CompletePage == 0 { return } io.WriteString(w, "\n</body>\n</html>\n") } func (r *Renderer) writeDocumentHeader(w io.Writer) { - if r.opts.Flags&CompletePage == 0 { + if r.Opts.Flags&CompletePage == 0 { return } ending := "" - if r.opts.Flags&UseXHTML != 0 { + if r.Opts.Flags&UseXHTML != 0 { io.WriteString(w, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ") io.WriteString(w, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n") io.WriteString(w, "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n") @@ -1131,35 +1142,35 @@ func (r *Renderer) writeDocumentHeader(w io.Writer) { } io.WriteString(w, "<head>\n") io.WriteString(w, " <title>") - if r.opts.Flags&Smartypants != 0 { - r.sr.Process(w, []byte(r.opts.Title)) + if r.Opts.Flags&Smartypants != 0 { + r.sr.Process(w, []byte(r.Opts.Title)) } else { - EscapeHTML(w, []byte(r.opts.Title)) + EscapeHTML(w, []byte(r.Opts.Title)) } io.WriteString(w, "</title>\n") - io.WriteString(w, r.opts.Generator) + io.WriteString(w, r.Opts.Generator) io.WriteString(w, "\"") io.WriteString(w, ending) io.WriteString(w, ">\n") io.WriteString(w, " <meta charset=\"utf-8\"") io.WriteString(w, ending) io.WriteString(w, ">\n") - if r.opts.CSS != "" { + if r.Opts.CSS != "" { io.WriteString(w, " <link rel=\"stylesheet\" type=\"text/css\" href=\"") - EscapeHTML(w, []byte(r.opts.CSS)) + EscapeHTML(w, []byte(r.Opts.CSS)) io.WriteString(w, "\"") io.WriteString(w, ending) io.WriteString(w, ">\n") } - if r.opts.Icon != "" { + if r.Opts.Icon != "" { io.WriteString(w, " <link rel=\"icon\" type=\"image/x-icon\" href=\"") - EscapeHTML(w, []byte(r.opts.Icon)) + EscapeHTML(w, []byte(r.Opts.Icon)) io.WriteString(w, "\"") io.WriteString(w, ending) io.WriteString(w, ">\n") } - if r.opts.Head != nil { - w.Write(r.opts.Head) + if r.Opts.Head != nil { + w.Write(r.Opts.Head) } io.WriteString(w, "</head>\n") io.WriteString(w, "<body>\n\n") @@ -1221,31 +1232,31 @@ func (r *Renderer) writeTOC(w io.Writer, doc ast.Node) { r.lastOutputLen = buf.Len() } -func isList(node ast.Node) bool { +func IsList(node ast.Node) bool { _, ok := node.(*ast.List) return ok } -func isListTight(node ast.Node) bool { +func IsListTight(node ast.Node) bool { if list, ok := node.(*ast.List); ok { return list.Tight } return false } -func isListItem(node ast.Node) bool { +func IsListItem(node ast.Node) bool { _, ok := node.(*ast.ListItem) return ok } -func isListItemTerm(node ast.Node) bool { +func IsListItemTerm(node ast.Node) bool { data, ok := node.(*ast.ListItem) return ok && data.ListFlags&ast.ListTypeTerm != 0 } // TODO: move to internal package // Create a url-safe slug for fragments -func slugify(in []byte) []byte { +func Slugify(in []byte) []byte { if len(in) == 0 { return in } diff --git a/vendor/github.com/gomarkdown/markdown/markdown.go b/vendor/github.com/gomarkdown/markdown/markdown.go index 537eb27b..2fb73c1e 100644 --- a/vendor/github.com/gomarkdown/markdown/markdown.go +++ b/vendor/github.com/gomarkdown/markdown/markdown.go @@ -84,28 +84,7 @@ func ToHTML(markdown []byte, p *parser.Parser, renderer Renderer) []byte { return Render(doc, renderer) } -// NormalizeNewlines converts Windows and Mac newlines to Unix newlines -// The parser only supports Unix newlines. If your mardown content +// NormalizeNewlines converts Windows and Mac newlines to Unix newlines. +// The parser only supports Unix newlines. If your markdown content // might contain Windows or Mac newlines, use this function to convert to Unix newlines -func NormalizeNewlines(d []byte) []byte { - wi := 0 - n := len(d) - for i := 0; i < n; i++ { - c := d[i] - // 13 is CR - if c != 13 { - d[wi] = c - wi++ - continue - } - // replace CR (mac / win) with LF (unix) - d[wi] = 10 - wi++ - if i < n-1 && d[i+1] == 10 { - // this was CRLF, so skip the LF - i++ - } - - } - return d[:wi] -} +var NormalizeNewlines = parser.NormalizeNewlines diff --git a/vendor/github.com/gomarkdown/markdown/parser/aside.go b/vendor/github.com/gomarkdown/markdown/parser/aside.go index 96e25fe0..9d02ed04 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/aside.go +++ b/vendor/github.com/gomarkdown/markdown/parser/aside.go @@ -25,13 +25,13 @@ func (p *Parser) asidePrefix(data []byte) int { // aside ends with at least one blank line // followed by something without a aside prefix func (p *Parser) terminateAside(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { + if IsEmpty(data[beg:]) <= 0 { return false } if end >= len(data) { return true } - return p.asidePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 + return p.asidePrefix(data[end:]) == 0 && IsEmpty(data[end:]) == 0 } // parse a aside fragment @@ -66,8 +66,8 @@ func (p *Parser) aside(data []byte) int { beg = end } - block := p.addBlock(&ast.Aside{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.Aside{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } diff --git a/vendor/github.com/gomarkdown/markdown/parser/block.go b/vendor/github.com/gomarkdown/markdown/parser/block.go index 490871c7..028ae758 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/block.go +++ b/vendor/github.com/gomarkdown/markdown/parser/block.go @@ -103,10 +103,10 @@ func sanitizeHeadingID(text string) string { return string(anchorName) } -// Parse block-level data. +// Parse Block-level data. // Note: this function and many that it calls assume that // the input buffer ends with a newline. -func (p *Parser) block(data []byte) { +func (p *Parser) Block(data []byte) { // this is called recursively: enforce a maximum depth if p.nesting >= p.maxNesting { return @@ -142,7 +142,7 @@ func (p *Parser) block(data []byte) { } } p.includeStack.Push(path) - p.block(included) + p.Block(included) p.includeStack.Pop() data = data[consumed:] continue @@ -156,10 +156,10 @@ func (p *Parser) block(data []byte) { data = data[consumed:] if node != nil { - p.addBlock(node) + p.AddBlock(node) if blockdata != nil { - p.block(blockdata) - p.finalize(node) + p.Block(blockdata) + p.Finalize(node) } } continue @@ -213,7 +213,7 @@ func (p *Parser) block(data []byte) { } // blank lines. note: returns the # of bytes to skip - if i := p.isEmpty(data); i > 0 { + if i := IsEmpty(data); i > 0 { data = data[i:] continue } @@ -255,11 +255,11 @@ func (p *Parser) block(data []byte) { // ****** // or // ______ - if p.isHRule(data) { + if isHRule(data) { i := skipUntilChar(data, 0, '\n') hr := ast.HorizontalRule{} hr.Literal = bytes.Trim(data[:i], " \n") - p.addBlock(&hr) + p.AddBlock(&hr) data = data[i:] continue } @@ -377,7 +377,7 @@ func (p *Parser) block(data []byte) { p.nesting-- } -func (p *Parser) addBlock(n ast.Node) ast.Node { +func (p *Parser) AddBlock(n ast.Node) ast.Node { p.closeUnmatchedBlocks() if p.attr != nil { @@ -448,7 +448,7 @@ func (p *Parser) prefixHeading(data []byte) int { p.allHeadingsWithAutoID = append(p.allHeadingsWithAutoID, block) } block.Content = data[i:end] - p.addBlock(block) + p.AddBlock(block) } return skip } @@ -521,7 +521,7 @@ func (p *Parser) prefixSpecialHeading(data []byte) int { } block.Literal = data[i:end] block.Content = data[i:end] - p.addBlock(block) + p.AddBlock(block) } return skip } @@ -572,7 +572,7 @@ func (p *Parser) titleBlock(data []byte, doRender bool) int { IsTitleblock: true, } block.Content = data - p.addBlock(block) + p.AddBlock(block) return consumed } @@ -617,14 +617,14 @@ func (p *Parser) html(data []byte, doRender bool) int { } // see if it is the only thing on the line - if skip := p.isEmpty(data[j:]); skip > 0 { + if skip := IsEmpty(data[j:]); skip > 0 { // see if it is followed by a blank line/eof j += skip if j >= len(data) { found = true i = j } else { - if skip := p.isEmpty(data[j:]); skip > 0 { + if skip := IsEmpty(data[j:]); skip > 0 { j += skip found = true i = j @@ -667,7 +667,7 @@ func (p *Parser) html(data []byte, doRender bool) int { // trim newlines end := backChar(data, i, '\n') htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBLock) + p.AddBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } @@ -683,13 +683,13 @@ func finalizeHTMLBlock(block *ast.HTMLBlock) { func (p *Parser) htmlComment(data []byte, doRender bool) int { i := p.inlineHTMLComment(data) // needs to end with a blank line - if j := p.isEmpty(data[i:]); j > 0 { + if j := IsEmpty(data[i:]); j > 0 { size := i + j if doRender { // trim trailing newlines end := backChar(data, size, '\n') htmlBLock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBLock) + p.AddBlock(htmlBLock) finalizeHTMLBlock(htmlBLock) } return size @@ -715,13 +715,13 @@ func (p *Parser) htmlHr(data []byte, doRender bool) int { } if i < len(data) && data[i] == '>' { i++ - if j := p.isEmpty(data[i:]); j > 0 { + if j := IsEmpty(data[i:]); j > 0 { size := i + j if doRender { // trim newlines end := backChar(data, size, '\n') htmlBlock := &ast.HTMLBlock{Leaf: ast.Leaf{Content: data[:end]}} - p.addBlock(htmlBlock) + p.AddBlock(htmlBlock) finalizeHTMLBlock(htmlBlock) } return size @@ -753,7 +753,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { // check that the rest of the line is blank skip := 0 - if skip = p.isEmpty(data[i:]); skip == 0 { + if skip = IsEmpty(data[i:]); skip == 0 { return 0 } i += skip @@ -766,7 +766,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { if p.extensions&LaxHTMLBlocks != 0 { return i } - if skip = p.isEmpty(data[i:]); skip == 0 { + if skip = IsEmpty(data[i:]); skip == 0 { // following line must be blank return 0 } @@ -774,7 +774,7 @@ func (p *Parser) htmlFindEnd(tag string, data []byte) int { return i + skip } -func (*Parser) isEmpty(data []byte) int { +func IsEmpty(data []byte) int { // it is okay to call isEmpty on an empty buffer if len(data) == 0 { return 0 @@ -790,7 +790,7 @@ func (*Parser) isEmpty(data []byte) int { return i } -func (*Parser) isHRule(data []byte) bool { +func isHRule(data []byte) bool { i := 0 // skip up to three spaces @@ -976,7 +976,7 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { codeBlock.Content = work.Bytes() // TODO: get rid of temp buffer if p.extensions&Mmark == 0 { - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) return beg } @@ -988,12 +988,12 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { figure.HeadingID = id p.Inline(caption, captionContent) - p.addBlock(figure) + p.AddBlock(figure) codeBlock.AsLeaf().Attribute = figure.AsContainer().Attribute p.addChild(codeBlock) finalizeCodeBlock(codeBlock) p.addChild(caption) - p.finalize(figure) + p.Finalize(figure) beg += consumed @@ -1001,7 +1001,7 @@ func (p *Parser) fencedCodeBlock(data []byte, doRender bool) int { } // Still here, normal block - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) } @@ -1055,13 +1055,13 @@ func (p *Parser) quotePrefix(data []byte) int { // blockquote ends with at least one blank line // followed by something without a blockquote prefix func (p *Parser) terminateBlockquote(data []byte, beg, end int) bool { - if p.isEmpty(data[beg:]) <= 0 { + if IsEmpty(data[beg:]) <= 0 { return false } if end >= len(data) { return true } - return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 + return p.quotePrefix(data[end:]) == 0 && IsEmpty(data[end:]) == 0 } // parse a blockquote fragment @@ -1096,9 +1096,9 @@ func (p *Parser) quote(data []byte) int { } if p.extensions&Mmark == 0 { - block := p.addBlock(&ast.BlockQuote{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.BlockQuote{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } @@ -1108,24 +1108,24 @@ func (p *Parser) quote(data []byte) int { figure.HeadingID = id p.Inline(caption, captionContent) - p.addBlock(figure) // this discard any attributes + p.AddBlock(figure) // this discard any attributes block := &ast.BlockQuote{} block.AsContainer().Attribute = figure.AsContainer().Attribute p.addChild(block) - p.block(raw.Bytes()) - p.finalize(block) + p.Block(raw.Bytes()) + p.Finalize(block) p.addChild(caption) - p.finalize(figure) + p.Finalize(figure) end += consumed return end } - block := p.addBlock(&ast.BlockQuote{}) - p.block(raw.Bytes()) - p.finalize(block) + block := p.AddBlock(&ast.BlockQuote{}) + p.Block(raw.Bytes()) + p.Finalize(block) return end } @@ -1152,7 +1152,7 @@ func (p *Parser) code(data []byte) int { i = skipUntilChar(data, i, '\n') i = skipCharN(data, i, '\n', 1) - blankline := p.isEmpty(data[beg:i]) > 0 + blankline := IsEmpty(data[beg:i]) > 0 if pre := p.codePrefix(data[beg:i]); pre > 0 { beg += pre } else if !blankline { @@ -1185,7 +1185,7 @@ func (p *Parser) code(data []byte) int { } // TODO: get rid of temp buffer codeBlock.Content = work.Bytes() - p.addBlock(codeBlock) + p.AddBlock(codeBlock) finalizeCodeBlock(codeBlock) return i @@ -1237,10 +1237,29 @@ func (p *Parser) dliPrefix(data []byte) int { if data[0] != ':' || !(data[1] == ' ' || data[1] == '\t') { return 0 } + // TODO: this is a no-op (data[0] is ':' so not ' '). + // Maybe the intent was to eat spaces before ':' ? + // either way, no change in tests i := skipChar(data, 0, ' ') return i + 2 } +// TODO: maybe it was meant to be like below +// either way, no change in tests +/* +func (p *Parser) dliPrefix(data []byte) int { + i := skipChar(data, 0, ' ') + if i+len(data) < 2 { + return 0 + } + // need a ':' followed by a space or a tab + if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') { + return 0 + } + return i + 2 +} +*/ + // parse ordered or unordered list block func (p *Parser) list(data []byte, flags ast.ListType, start int, delim byte) int { i := 0 @@ -1251,7 +1270,7 @@ func (p *Parser) list(data []byte, flags ast.ListType, start int, delim byte) in Start: start, Delimiter: delim, } - block := p.addBlock(list) + block := p.AddBlock(list) for i < len(data) { skip := p.listItem(data[i:], &flags) @@ -1398,7 +1417,7 @@ gatherlines: // if it is an empty line, guess that it is part of this item // and move on to the next line - if p.isEmpty(data[line:i]) > 0 { + if IsEmpty(data[line:i]) > 0 { containsBlankLine = true line = i continue @@ -1432,7 +1451,7 @@ gatherlines: // evaluate how this line fits in switch { // is this a nested list item? - case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || p.oliPrefix(chunk) > 0 || p.dliPrefix(chunk) > 0: + case (p.uliPrefix(chunk) > 0 && !isHRule(chunk)) || p.oliPrefix(chunk) > 0 || p.dliPrefix(chunk) > 0: // if indent is 4 or more spaces on unordered or ordered lists // we need to add leadingWhiteSpaces + 1 spaces in the beginning of the chunk @@ -1484,10 +1503,7 @@ gatherlines: case containsBlankLine && indent < 4: if *flags&ast.ListTypeDefinition != 0 && i < len(data)-1 { // is the next item still a part of this list? - next := i - for next < len(data) && data[next] != '\n' { - next++ - } + next := skipUntilChar(data, i, '\n') for next < len(data)-1 && data[next] == '\n' { next++ } @@ -1526,16 +1542,16 @@ gatherlines: BulletChar: bulletChar, Delimiter: delimiter, } - p.addBlock(listItem) + p.AddBlock(listItem) // render the contents of the list item if *flags&ast.ListItemContainsBlock != 0 && *flags&ast.ListTypeTerm == 0 { // intermediate render of block item, except for definition term if sublist > 0 { - p.block(rawBytes[:sublist]) - p.block(rawBytes[sublist:]) + p.Block(rawBytes[:sublist]) + p.Block(rawBytes[sublist:]) } else { - p.block(rawBytes) + p.Block(rawBytes) } } else { // intermediate render of inline item @@ -1547,7 +1563,7 @@ gatherlines: } p.addChild(para) if sublist > 0 { - p.block(rawBytes[sublist:]) + p.Block(rawBytes[sublist:]) } } return line @@ -1574,7 +1590,7 @@ func (p *Parser) renderParagraph(data []byte) { } para := &ast.Paragraph{} para.Content = data[beg:end] - p.addBlock(para) + p.AddBlock(para) } // blockMath handle block surround with $$ @@ -1596,7 +1612,7 @@ func (p *Parser) blockMath(data []byte) int { // render the display math mathBlock := &ast.MathBlock{} mathBlock.Literal = data[2:end] - p.addBlock(mathBlock) + p.AddBlock(mathBlock) return end + 2 } @@ -1626,7 +1642,7 @@ func (p *Parser) paragraph(data []byte) int { } // did we find a blank line marking the end of the paragraph? - if n := p.isEmpty(current); n > 0 { + if n := IsEmpty(current); n > 0 { // did this blank line followed by a definition list item? if p.extensions&DefinitionLists != 0 { if i < len(data)-1 && data[i+1] == ':' { @@ -1663,7 +1679,7 @@ func (p *Parser) paragraph(data []byte) int { } block.Content = data[prev:eol] - p.addBlock(block) + p.AddBlock(block) // find the end of the underline return skipUntilChar(data, i, '\n') @@ -1680,7 +1696,7 @@ func (p *Parser) paragraph(data []byte) int { } // if there's a prefixed heading or a horizontal rule after this, paragraph is over - if p.isPrefixHeading(current) || p.isPrefixSpecialHeading(current) || p.isHRule(current) { + if p.isPrefixHeading(current) || p.isPrefixSpecialHeading(current) || isHRule(current) { p.renderParagraph(data[:i]) return i } diff --git a/vendor/github.com/gomarkdown/markdown/parser/block_table.go b/vendor/github.com/gomarkdown/markdown/parser/block_table.go index 0bf4f4ad..fa8efdf2 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/block_table.go +++ b/vendor/github.com/gomarkdown/markdown/parser/block_table.go @@ -12,7 +12,7 @@ func isBackslashEscaped(data []byte, i int) bool { } func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool) { - p.addBlock(&ast.TableRow{}) + p.AddBlock(&ast.TableRow{}) col := 0 i := skipChar(data, 0, '|') @@ -61,7 +61,7 @@ func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool // an empty cell that we should ignore, it exists because of colspan colspans-- } else { - p.addBlock(block) + p.AddBlock(block) } if colspan > 0 { @@ -75,7 +75,7 @@ func (p *Parser) tableRow(data []byte, columns []ast.CellAlignFlags, header bool IsHeader: header, Align: columns[col], } - p.addBlock(block) + p.AddBlock(block) } // silently ignore rows with too many cells @@ -109,7 +109,7 @@ func (p *Parser) tableFooter(data []byte) bool { return false } - p.addBlock(&ast.TableFooter{}) + p.AddBlock(&ast.TableFooter{}) return true } @@ -217,7 +217,7 @@ func (p *Parser) tableHeader(data []byte, doRender bool) (size int, columns []as } // end of column test is messy switch { - case dashes < 3: + case dashes < 1: // not a valid column return @@ -253,9 +253,9 @@ func (p *Parser) tableHeader(data []byte, doRender bool) (size int, columns []as if doRender { table = &ast.Table{} - p.addBlock(table) + p.AddBlock(table) if header != nil { - p.addBlock(&ast.TableHeader{}) + p.AddBlock(&ast.TableHeader{}) p.tableRow(header, columns, true) } } @@ -277,7 +277,7 @@ func (p *Parser) table(data []byte) int { return 0 } - p.addBlock(&ast.TableBody{}) + p.AddBlock(&ast.TableBody{}) for i < len(data) { pipes, rowStart := 0, i @@ -319,7 +319,7 @@ func (p *Parser) table(data []byte) int { ast.AppendChild(figure, caption) p.addChild(figure) - p.finalize(figure) + p.Finalize(figure) i += consumed } diff --git a/vendor/github.com/gomarkdown/markdown/parser/caption.go b/vendor/github.com/gomarkdown/markdown/parser/caption.go index fe31711a..08794504 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/caption.go +++ b/vendor/github.com/gomarkdown/markdown/parser/caption.go @@ -11,7 +11,7 @@ func (p *Parser) caption(data, caption []byte) ([]byte, string, int) { } j := len(caption) data = data[j:] - end := p.linesUntilEmpty(data) + end := LinesUntilEmpty(data) data = data[:end] @@ -23,8 +23,8 @@ func (p *Parser) caption(data, caption []byte) ([]byte, string, int) { return data, "", end + j } -// linesUntilEmpty scans lines up to the first empty line. -func (p *Parser) linesUntilEmpty(data []byte) int { +// LinesUntilEmpty scans lines up to the first empty line. +func LinesUntilEmpty(data []byte) int { line, i := 0, 0 for line < len(data) { @@ -35,7 +35,7 @@ func (p *Parser) linesUntilEmpty(data []byte) int { i++ } - if p.isEmpty(data[line:i]) == 0 { + if IsEmpty(data[line:i]) == 0 { line = i continue } diff --git a/vendor/github.com/gomarkdown/markdown/parser/figures.go b/vendor/github.com/gomarkdown/markdown/parser/figures.go index 6615449c..0566c16e 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/figures.go +++ b/vendor/github.com/gomarkdown/markdown/parser/figures.go @@ -98,10 +98,10 @@ func (p *Parser) figureBlock(data []byte, doRender bool) int { } figure := &ast.CaptionFigure{} - p.addBlock(figure) - p.block(raw.Bytes()) + p.AddBlock(figure) + p.Block(raw.Bytes()) - defer p.finalize(figure) + defer p.Finalize(figure) if captionContent, id, consumed := p.caption(data[beg:], []byte("Figure: ")); consumed > 0 { caption := &ast.Caption{} @@ -113,7 +113,5 @@ func (p *Parser) figureBlock(data []byte, doRender bool) int { beg += consumed } - - p.finalize(figure) return beg } diff --git a/vendor/github.com/gomarkdown/markdown/parser/matter.go b/vendor/github.com/gomarkdown/markdown/parser/matter.go index 92686357..df284237 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/matter.go +++ b/vendor/github.com/gomarkdown/markdown/parser/matter.go @@ -29,8 +29,8 @@ func (p *Parser) documentMatter(data []byte) int { return 0 } node := &ast.DocumentMatter{Matter: matter} - p.addBlock(node) - p.finalize(node) + p.AddBlock(node) + p.Finalize(node) return consumed } diff --git a/vendor/github.com/gomarkdown/markdown/parser/parser.go b/vendor/github.com/gomarkdown/markdown/parser/parser.go index 07444cd8..91123e1b 100644 --- a/vendor/github.com/gomarkdown/markdown/parser/parser.go +++ b/vendor/github.com/gomarkdown/markdown/parser/parser.go @@ -42,7 +42,7 @@ const ( SuperSubscript // Super- and subscript support: 2^10^, H~2~O. EmptyLinesBreakList // 2 empty lines break out of list Includes // Support including other files. - Mmark // Support Mmark syntax, see https://mmark.nl/syntax + Mmark // Support Mmark syntax, see https://mmark.miek.nl/post/syntax/ CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | Autolink | Strikethrough | SpaceHeadings | HeadingIDs | @@ -206,13 +206,13 @@ func (p *Parser) isFootnote(ref *reference) bool { return ok } -func (p *Parser) finalize(block ast.Node) { +func (p *Parser) Finalize(block ast.Node) { p.tip = block.GetParent() } func (p *Parser) addChild(node ast.Node) ast.Node { for !canNodeContain(p.tip, node) { - p.finalize(p.tip) + p.Finalize(p.tip) } ast.AppendChild(p.tip, node) p.tip = node @@ -239,6 +239,18 @@ func canNodeContain(n ast.Node, v ast.Node) bool { _, ok := v.(*ast.TableCell) return ok } + // for nodes implemented outside of ast package, allow them + // to implement this logic via CanContain interface + if o, ok := n.(ast.CanContain); ok { + return o.CanContain(v) + } + // for container nodes outside of ast package default to true + // because false is a bad default + typ := fmt.Sprintf("%T", n) + customNode := !strings.HasPrefix(typ, "*ast.") + if customNode { + return n.AsLeaf() == nil + } return false } @@ -248,7 +260,7 @@ func (p *Parser) closeUnmatchedBlocks() { } for p.oldTip != p.lastMatchedContainer { parent := p.oldTip.GetParent() - p.finalize(p.oldTip) + p.Finalize(p.oldTip) p.oldTip = parent } p.allClosed = true @@ -273,10 +285,14 @@ type Reference struct { // You can then convert AST to html using html.Renderer, to some other format // using a custom renderer or transform the tree. func (p *Parser) Parse(input []byte) ast.Node { - p.block(input) + // the code only works with Unix CR newlines so to make life easy for + // callers normalize newlines + input = NormalizeNewlines(input) + + p.Block(input) // Walk the tree and finish up some of unfinished blocks for p.tip != nil { - p.finalize(p.tip) + p.Finalize(p.tip) } // Walk the tree again and process inline markdown in each block ast.WalkFunc(p.Doc, func(node ast.Node, entering bool) ast.WalkStatus { @@ -322,8 +338,8 @@ func (p *Parser) parseRefsToAST() { IsFootnotesList: true, ListFlags: ast.ListTypeOrdered, } - p.addBlock(&ast.Footnotes{}) - block := p.addBlock(list) + p.AddBlock(&ast.Footnotes{}) + block := p.AddBlock(list) flags := ast.ListItemBeginningOfList // Note: this loop is intentionally explicit, not range-form. This is // because the body of the loop will append nested footnotes to p.notes and @@ -338,7 +354,7 @@ func (p *Parser) parseRefsToAST() { listItem.RefLink = ref.link if ref.hasBlock { flags |= ast.ListItemContainsBlock - p.block(ref.title) + p.Block(ref.title) } else { p.Inline(block, ref.title) } @@ -660,7 +676,7 @@ gatherLines: // if it is an empty line, guess that it is part of this item // and move on to the next line - if p.isEmpty(data[blockEnd:i]) > 0 { + if IsEmpty(data[blockEnd:i]) > 0 { containsBlankLine = true blockEnd = i continue @@ -883,3 +899,26 @@ func isListItem(d ast.Node) bool { _, ok := d.(*ast.ListItem) return ok } + +func NormalizeNewlines(d []byte) []byte { + wi := 0 + n := len(d) + for i := 0; i < n; i++ { + c := d[i] + // 13 is CR + if c != 13 { + d[wi] = c + wi++ + continue + } + // replace CR (mac / win) with LF (unix) + d[wi] = 10 + wi++ + if i < n-1 && d[i+1] == 10 { + // this was CRLF, so skip the LF + i++ + } + + } + return d[:wi] +} diff --git a/vendor/github.com/gomarkdown/markdown/todo.md b/vendor/github.com/gomarkdown/markdown/todo.md deleted file mode 100644 index be8bb55c..00000000 --- a/vendor/github.com/gomarkdown/markdown/todo.md +++ /dev/null @@ -1,7 +0,0 @@ -# Things to do - -[ ] docs: add examples like https://godoc.org/github.com/dgrijalva/jwt-go (put in foo_example_test.go). Or see https://github.com/garyburd/redigo/blob/master/redis/zpop_example_test.go#L5 / https://godoc.org/github.com/garyburd/redigo/redis or https://godoc.org/github.com/go-redis/redis - -[ ] figure out expandTabs and parser.TabSizeEight. Are those used? - -[ ] SoftbreakData is not used |