From 4688db5f6f2cf1b8260cd7c4c6bf5b174b7de97a Mon Sep 17 00:00:00 2001 From: Pierre Neidhardt Date: Sat, 10 Sep 2016 15:54:43 +0530 Subject: [PATCH 1/7] Remove the LaTeX renderer stub and point to Ambrevar's implementation --- README.md | 15 +-- latex.go | 336 ---------------------------------------------------- markdown.go | 6 +- 3 files changed, 7 insertions(+), 350 deletions(-) delete mode 100644 latex.go diff --git a/README.md b/README.md index 7b97970..b025f1c 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ punctuation substitutions, etc.), and it is safe for all utf-8 (unicode) input. HTML output is currently supported, along with Smartypants -extensions. An experimental LaTeX output engine is also included. +extensions. It started as a translation from C of [Sundown][3]. @@ -69,7 +69,7 @@ html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) ### Custom options If you want to customize the set of options, first get a renderer -(currently either the HTML or LaTeX output engines), then use it to +(currently only the HTML output engine), then use it to call the more general `Markdown` function. For examples, see the implementations of `MarkdownBasic` and `MarkdownCommon` in `markdown.go`. @@ -233,15 +233,8 @@ are a few of note: * [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, but for markdown. -* LaTeX output: renders output as LaTeX. This is currently part of the - main Blackfriday repository, but may be split into its own project - in the future. If you are interested in owning and maintaining the - LaTeX output component, please be in touch. - - It renders some basic documents, but is only experimental at this - point. In particular, it does not do any inline escaping, so input - that happens to look like LaTeX code will be passed through without - modification. +* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex): + renders output as LaTeX. Todo diff --git a/latex.go b/latex.go deleted file mode 100644 index 900abf0..0000000 --- a/latex.go +++ /dev/null @@ -1,336 +0,0 @@ -// -// Blackfriday Markdown Processor -// Available at http://github.com/russross/blackfriday -// -// Copyright © 2011 Russ Ross . -// Distributed under the Simplified BSD License. -// See README.md for details. -// - -// -// -// LaTeX rendering backend -// -// - -package blackfriday - -import ( - "bytes" - "io" -) - -// Latex is a type that implements the Renderer interface for LaTeX output. -// -// Do not create this directly, instead use the NewLatexRenderer function. -type Latex struct { - w bytes.Buffer -} - -// NewLatexRenderer creates and configures a Latex object, which -// satisfies the Renderer interface. -// -// flags is a set of LATEX_* options ORed together (currently no such options -// are defined). -func NewLatexRenderer(flags int) *Latex { - var writer bytes.Buffer - return &Latex{ - w: writer, - } -} - -// render code chunks using verbatim, or listings if we have a language -func (r *Latex) BlockCode(text []byte, lang string) { - if lang == "" { - r.w.WriteString("\n\\begin{verbatim}\n") - } else { - r.w.WriteString("\n\\begin{lstlisting}[language=") - r.w.WriteString(lang) - r.w.WriteString("]\n") - } - r.w.Write(text) - if lang == "" { - r.w.WriteString("\n\\end{verbatim}\n") - } else { - r.w.WriteString("\n\\end{lstlisting}\n") - } -} - -func (r *Latex) TitleBlock(text []byte) { - -} - -func (r *Latex) BlockQuote(text []byte) { - r.w.WriteString("\n\\begin{quotation}\n") - r.w.Write(text) - r.w.WriteString("\n\\end{quotation}\n") -} - -func (r *Latex) BlockHtml(text []byte) { - // a pretty lame thing to do... - r.w.WriteString("\n\\begin{verbatim}\n") - r.w.Write(text) - r.w.WriteString("\n\\end{verbatim}\n") -} - -func (r *Latex) BeginHeader(level int, id string) { - switch level { - case 1: - r.w.WriteString("\n\\section{") - case 2: - r.w.WriteString("\n\\subsection{") - case 3: - r.w.WriteString("\n\\subsubsection{") - case 4: - r.w.WriteString("\n\\paragraph{") - case 5: - r.w.WriteString("\n\\subparagraph{") - case 6: - r.w.WriteString("\n\\textbf{") - } -} - -func (r *Latex) EndHeader(level int, id string, header []byte) { - r.w.WriteString("}\n") -} - -func (r *Latex) HRule() { - r.w.WriteString("\n\\HRule\n") -} - -func (r *Latex) BeginList(flags ListType) { - if flags&ListTypeOrdered != 0 { - r.w.WriteString("\n\\begin{enumerate}\n") - } else { - r.w.WriteString("\n\\begin{itemize}\n") - } -} - -func (r *Latex) EndList(flags ListType) { - if flags&ListTypeOrdered != 0 { - r.w.WriteString("\n\\end{enumerate}\n") - } else { - r.w.WriteString("\n\\end{itemize}\n") - } -} - -func (r *Latex) ListItem(text []byte, flags ListType) { - r.w.WriteString("\n\\item ") - r.w.Write(text) -} - -func (r *Latex) BeginParagraph() { - r.w.WriteString("\n") -} - -func (r *Latex) EndParagraph() { - r.w.WriteString("\n") -} - -func (r *Latex) Table(header []byte, body []byte, columnData []CellAlignFlags) { - r.w.WriteString("\n\\begin{tabular}{") - for _, elt := range columnData { - switch elt { - case TableAlignmentLeft: - r.w.WriteByte('l') - case TableAlignmentRight: - r.w.WriteByte('r') - default: - r.w.WriteByte('c') - } - } - r.w.WriteString("}\n") - r.w.Write(header) - r.w.WriteString(" \\\\\n\\hline\n") - r.w.Write(body) - r.w.WriteString("\n\\end{tabular}\n") -} - -func (r *Latex) TableRow(text []byte) { - r.w.WriteString(" \\\\\n") - r.w.Write(text) -} - -func (r *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align CellAlignFlags) { - if out.Len() > 0 { - out.WriteString(" & ") - } - out.Write(text) -} - -func (r *Latex) TableCell(out *bytes.Buffer, text []byte, align CellAlignFlags) { - if out.Len() > 0 { - out.WriteString(" & ") - } - out.Write(text) -} - -// TODO: this -func (r *Latex) BeginFootnotes() { -} - -// TODO: this -func (r *Latex) EndFootnotes() { -} - -func (r *Latex) FootnoteItem(name, text []byte, flags ListType) { - -} - -func (r *Latex) AutoLink(link []byte, kind autolinkType) { - r.w.WriteString("\\href{") - if kind == emailAutolink { - r.w.WriteString("mailto:") - } - r.w.Write(link) - r.w.WriteString("}{") - r.w.Write(link) - r.w.WriteString("}") -} - -func (r *Latex) CodeSpan(text []byte) { - r.w.WriteString("\\texttt{") - r.escapeSpecialChars(text) - r.w.WriteString("}") -} - -func (r *Latex) DoubleEmphasis(text []byte) { - r.w.WriteString("\\textbf{") - r.w.Write(text) - r.w.WriteString("}") -} - -func (r *Latex) Emphasis(text []byte) { - r.w.WriteString("\\textit{") - r.w.Write(text) - r.w.WriteString("}") -} - -func (r *Latex) Image(link []byte, title []byte, alt []byte) { - if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) { - // treat it like a link - r.w.WriteString("\\href{") - r.w.Write(link) - r.w.WriteString("}{") - r.w.Write(alt) - r.w.WriteString("}") - } else { - r.w.WriteString("\\includegraphics{") - r.w.Write(link) - r.w.WriteString("}") - } -} - -func (r *Latex) LineBreak() { - r.w.WriteString(" \\\\\n") -} - -func (r *Latex) Link(link []byte, title []byte, content []byte) { - r.w.WriteString("\\href{") - r.w.Write(link) - r.w.WriteString("}{") - r.w.Write(content) - r.w.WriteString("}") -} - -func (r *Latex) RawHtmlTag(tag []byte) { -} - -func (r *Latex) TripleEmphasis(text []byte) { - r.w.WriteString("\\textbf{\\textit{") - r.w.Write(text) - r.w.WriteString("}}") -} - -func (r *Latex) StrikeThrough(text []byte) { - r.w.WriteString("\\sout{") - r.w.Write(text) - r.w.WriteString("}") -} - -// TODO: this -func (r *Latex) FootnoteRef(ref []byte, id int) { -} - -func needsBackslash(c byte) bool { - for _, r := range []byte("_{}%$&\\~#") { - if c == r { - return true - } - } - return false -} - -func (r *Latex) escapeSpecialChars(text []byte) { - for i := 0; i < len(text); i++ { - // directly copy normal characters - org := i - - for i < len(text) && !needsBackslash(text[i]) { - i++ - } - if i > org { - r.w.Write(text[org:i]) - } - - // escape a character - if i >= len(text) { - break - } - r.w.WriteByte('\\') - r.w.WriteByte(text[i]) - } -} - -func (r *Latex) Entity(entity []byte) { - // TODO: convert this into a unicode character or something - r.w.Write(entity) -} - -func (r *Latex) NormalText(text []byte) { - r.escapeSpecialChars(text) -} - -// header and footer -func (r *Latex) DocumentHeader() { - r.w.WriteString("\\documentclass{article}\n") - r.w.WriteString("\n") - r.w.WriteString("\\usepackage{graphicx}\n") - r.w.WriteString("\\usepackage{listings}\n") - r.w.WriteString("\\usepackage[margin=1in]{geometry}\n") - r.w.WriteString("\\usepackage[utf8]{inputenc}\n") - r.w.WriteString("\\usepackage{verbatim}\n") - r.w.WriteString("\\usepackage[normalem]{ulem}\n") - r.w.WriteString("\\usepackage{hyperref}\n") - r.w.WriteString("\n") - r.w.WriteString("\\hypersetup{colorlinks,%\n") - r.w.WriteString(" citecolor=black,%\n") - r.w.WriteString(" filecolor=black,%\n") - r.w.WriteString(" linkcolor=black,%\n") - r.w.WriteString(" urlcolor=black,%\n") - r.w.WriteString(" pdfstartview=FitH,%\n") - r.w.WriteString(" breaklinks=true,%\n") - r.w.WriteString(" pdfauthor={Blackfriday Markdown Processor v") - r.w.WriteString(Version) - r.w.WriteString("}}\n") - r.w.WriteString("\n") - r.w.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n") - r.w.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n") - r.w.WriteString("\\parindent=0pt\n") - r.w.WriteString("\n") - r.w.WriteString("\\begin{document}\n") -} - -func (r *Latex) DocumentFooter() { - r.w.WriteString("\n\\end{document}\n") -} - -func (r *Latex) Render(ast *Node) []byte { - // TODO - return nil -} - -func (r *Latex) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus { - // TODO - return GoToNext -} diff --git a/markdown.go b/markdown.go index 7fa0e20..41080a3 100644 --- a/markdown.go +++ b/markdown.go @@ -153,7 +153,8 @@ var blockTags = map[string]struct{}{ // If the callback returns false, the rendering function should reset the // output buffer as though it had never been called. // -// Currently HTML and Latex implementations are provided +// Only an HTML implementation is provided in this repository, +// see the README for external implementations. type Renderer interface { Render(ast *Node) []byte RenderNode(w io.Writer, node *Node, entering bool) WalkStatus @@ -327,8 +328,7 @@ func MarkdownCommon(input []byte) []byte { // The supplied Renderer is used to format the output, and extensions dictates // which non-standard extensions are enabled. // -// To use the supplied HTML or LaTeX renderers, see NewHTMLRenderer and -// NewLatexRenderer, respectively. +// To use the supplied HTML renderer, see NewHTMLRenderer. func Markdown(input []byte, renderer Renderer, options Options) []byte { if renderer == nil { return nil From 8a11177489fa4fe8edb5a69f34888bda5b2139a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vytautas=20=C5=A0altenis?= Date: Sat, 17 Sep 2016 19:31:29 +0300 Subject: [PATCH 2/7] Add direct link to a footnote from it's referer Some renderers might not care to have an explicit list of footnotes at the end of the document, instead they're interested in the content of the footnote at the location of a referer. Make their lives easier by providing such a link --- inline.go | 5 +++++ markdown.go | 18 +++++++++++------- node.go | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/inline.go b/inline.go index f5e8c20..6b1fdc2 100644 --- a/inline.go +++ b/inline.go @@ -297,6 +297,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) { txtE := i i++ + var footnoteNode *Node // skip any amount of whitespace or newline // (this is much more lax than original markdown syntax) @@ -476,6 +477,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) { } } + footnoteNode = NewNode(Item) if t == linkInlineFootnote { // create a new reference noteID = len(p.notes) + 1 @@ -497,6 +499,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) { hasBlock: false, link: fragment, title: id, + footnote: footnoteNode, } p.notes = append(p.notes, ref) @@ -512,6 +515,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) { if t == linkDeferredFootnote { lr.noteID = len(p.notes) + 1 + lr.footnote = footnoteNode p.notes = append(p.notes, lr) } @@ -570,6 +574,7 @@ func link(p *parser, data []byte, offset int) (int, *Node) { linkNode.Destination = link linkNode.Title = title linkNode.NoteID = noteID + linkNode.Footnote = footnoteNode if t == linkInlineFootnote { i++ } diff --git a/markdown.go b/markdown.go index 7fa0e20..6cc23b5 100644 --- a/markdown.go +++ b/markdown.go @@ -213,14 +213,16 @@ func (p *parser) finalize(block *Node) { } func (p *parser) addChild(node NodeType, offset uint32) *Node { - for !p.tip.canContain(node) { + return p.addExistingChild(NewNode(node), offset) +} + +func (p *parser) addExistingChild(node *Node, offset uint32) *Node { + for !p.tip.canContain(node.Type) { p.finalize(p.tip) } - newNode := NewNode(node) - newNode.content = []byte{} - p.tip.AppendChild(newNode) - p.tip = newNode - return newNode + p.tip.AppendChild(node) + p.tip = node + return node } func (p *parser) closeUnmatchedBlocks() { @@ -419,7 +421,8 @@ func (p *parser) parseRefsToAST() { // the fixed initial set. for i := 0; i < len(p.notes); i++ { ref := p.notes[i] - block := p.addBlock(Item, nil) + p.addExistingChild(ref.footnote, 0) + block := ref.footnote block.ListFlags = flags | ListTypeOrdered block.RefLink = ref.link if ref.hasBlock { @@ -570,6 +573,7 @@ type reference struct { 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 } diff --git a/node.go b/node.go index 983ec10..9454873 100644 --- a/node.go +++ b/node.go @@ -84,6 +84,7 @@ type LinkData struct { Destination []byte // Destination is what goes into a href Title []byte // Title is the tooltip thing that goes in a title attribute NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote + Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil. } // CodeBlockData contains fields relevant to a CodeBlock node type. From 1aa82c40393e5adf88ec027830a526dbcf350cf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vytautas=20=C5=A0altenis?= Date: Sat, 17 Sep 2016 19:36:55 +0300 Subject: [PATCH 3/7] Make golint happy: fix method receiver golint insists on uniform receiver names. --- node.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node.go b/node.go index 9454873..3360e5b 100644 --- a/node.go +++ b/node.go @@ -278,8 +278,8 @@ type NodeVisitor func(node *Node, entering bool) WalkStatus // Walk is a convenience method that instantiates a walker and starts a // traversal of subtree rooted at n. -func (root *Node) Walk(visitor NodeVisitor) { - w := newNodeWalker(root) +func (n *Node) Walk(visitor NodeVisitor) { + w := newNodeWalker(n) for w.current != nil { status := visitor(w.current, w.entering) switch status { From 14a0c487b886d6ec301a6ae53e15e489e91cde8d Mon Sep 17 00:00:00 2001 From: Pierre Neidhardt Date: Wed, 5 Oct 2016 09:43:05 +0530 Subject: [PATCH 4/7] Fix walk with non-container root nodes When passed a non-container root node, the former algorithm would go on walking down the rest of the tree beyond the root. The former walk fix was supposed to do that but somehow the code disappeared in the process. --- node.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node.go b/node.go index 3360e5b..8f10698 100644 --- a/node.go +++ b/node.go @@ -309,7 +309,7 @@ func newNodeWalker(root *Node) *nodeWalker { } func (nw *nodeWalker) next() { - if !nw.entering && nw.current == nw.root { + if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root { nw.current = nil return } From 627dc87cadeec7f786e528f4f9ff89b88dbb1e9d Mon Sep 17 00:00:00 2001 From: Pierre Neidhardt Date: Sun, 9 Oct 2016 08:43:40 +0530 Subject: [PATCH 5/7] Add missing type to TableAlignment* constants --- markdown.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markdown.go b/markdown.go index c539932..25a24c2 100644 --- a/markdown.go +++ b/markdown.go @@ -86,7 +86,7 @@ type CellAlignFlags int // Only a single one of these values will be used; they are not ORed together. // These are mostly of interest if you are writing a new output format. const ( - TableAlignmentLeft = 1 << iota + TableAlignmentLeft CellAlignFlags = 1 << iota TableAlignmentRight TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight) ) From b61f73e4f990f6e45cda852ad41c226a7b3ea97b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vytautas=20=C5=A0altenis?= Date: Thu, 24 Nov 2016 20:37:33 +0200 Subject: [PATCH 6/7] Ditch SkipStyle flag It's been broken since early 2014, which clearly demonstrates that nobody uses it. Fixes #252. --- html.go | 8 -------- inline_test.go | 9 --------- 2 files changed, 17 deletions(-) diff --git a/html.go b/html.go index 54f2bea..5a0c5eb 100644 --- a/html.go +++ b/html.go @@ -31,7 +31,6 @@ type HTMLFlags int const ( HTMLFlagsNone HTMLFlags = 0 SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks - SkipStyle // Skip embedded bar", - "

foo

\n\n

color: #f00 bar

\n", - }, TestParams{ - HTMLFlags: SkipStyle, - }) -} - func TestUseXHTML(t *testing.T) { doTestsParam(t, []string{ "---", From 9c4ef640b9d298803f93982f7abbfcde074b3b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vytautas=20=C5=A0altenis?= Date: Thu, 24 Nov 2016 21:48:48 +0200 Subject: [PATCH 7/7] Move TOC and OmitContents to HTML flags The root problem this commit fixes is the duplication of Extensions field in HTMLRendererParameters. The duplication crept in there only to support these two flags, so moving the flags solves the problem. They're only used in renderer anyway. Fixes #277. --- block_test.go | 12 +++++++++--- helpers_test.go | 4 +--- html.go | 9 +++++---- markdown.go | 8 ++------ 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/block_test.go b/block_test.go index 46feb40..909f4a8 100644 --- a/block_test.go +++ b/block_test.go @@ -1601,7 +1601,9 @@ func TestTOC(t *testing.T) { "#", "", } - doTestsBlock(t, tests, TOC) + doTestsParam(t, tests, TestParams{ + HTMLFlags: UseXHTML | TOC, + }) } func TestOmitContents(t *testing.T) { @@ -1625,9 +1627,13 @@ func TestOmitContents(t *testing.T) { "#\n\nfoo", "", } - doTestsBlock(t, tests, TOC|OmitContents) + doTestsParam(t, tests, TestParams{ + HTMLFlags: UseXHTML | TOC | OmitContents, + }) // Now run again: make sure OmitContents implies TOC - doTestsBlock(t, tests, OmitContents) + doTestsParam(t, tests, TestParams{ + HTMLFlags: UseXHTML | OmitContents, + }) } func TestCompletePage(t *testing.T) { diff --git a/helpers_test.go b/helpers_test.go index 99ac806..ecefe2f 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -44,7 +44,6 @@ func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, s func runMarkdown(input string, params TestParams) string { params.HTMLRendererParameters.Flags = params.HTMLFlags - params.HTMLRendererParameters.Extensions = params.Options.Extensions renderer := NewHTMLRenderer(params.HTMLRendererParameters) return string(Markdown([]byte(input), renderer, params.Options)) } @@ -54,8 +53,7 @@ func doTests(t *testing.T, tests []string) { doTestsParam(t, tests, TestParams{ Options: DefaultOptions, HTMLRendererParameters: HTMLRendererParameters{ - Flags: CommonHTMLFlags, - Extensions: CommonExtensions, + Flags: CommonHTMLFlags, }, }) } diff --git a/html.go b/html.go index 54f2bea..a4f0753 100644 --- a/html.go +++ b/html.go @@ -46,6 +46,8 @@ const ( SmartypantsDashes // Enable smart dashes (with Smartypants) SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering + TOC // Generate a table of contents + OmitContents // Skip the main contents (for a standalone table of contents) TagName = "[A-Za-z][A-Za-z0-9-]*" AttributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*" @@ -90,8 +92,7 @@ type HTMLRendererParameters struct { CSS string // Optional CSS file URL (used if CompletePage is set) Icon string // Optional icon file URL (used if CompletePage is set) - Flags HTMLFlags // Flags allow customizing this renderer's behavior - Extensions Extensions // Extensions give Smartypants and HTML renderer access to Blackfriday's global extensions + Flags HTMLFlags // Flags allow customizing this renderer's behavior } // HTMLRenderer is a type that implements the Renderer interface for HTML output. @@ -829,9 +830,9 @@ func (r *HTMLRenderer) Render(ast *Node) []byte { //dump(ast) var buff bytes.Buffer r.writeDocumentHeader(&buff) - if r.Extensions&TOC != 0 || r.Extensions&OmitContents != 0 { + if r.Flags&TOC != 0 || r.Flags&OmitContents != 0 { r.writeTOC(&buff, ast) - if r.Extensions&OmitContents != 0 { + if r.Flags&OmitContents != 0 { return buff.Bytes() } } diff --git a/markdown.go b/markdown.go index 25a24c2..558b008 100644 --- a/markdown.go +++ b/markdown.go @@ -46,8 +46,6 @@ const ( AutoHeaderIDs // Create the header ID from the text BackslashLineBreak // Translate trailing backslashes into line breaks DefinitionLists // Render definition lists - TOC // Generate a table of contents - OmitContents // Skip the main contents (for a standalone table of contents) CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes @@ -290,8 +288,7 @@ type Options struct { func MarkdownBasic(input []byte) []byte { // set up the HTML renderer renderer := NewHTMLRenderer(HTMLRendererParameters{ - Flags: UseXHTML, - Extensions: CommonExtensions, + Flags: UseXHTML, }) // set up the parser @@ -319,8 +316,7 @@ func MarkdownBasic(input []byte) []byte { func MarkdownCommon(input []byte) []byte { // set up the HTML renderer renderer := NewHTMLRenderer(HTMLRendererParameters{ - Flags: CommonHTMLFlags, - Extensions: CommonExtensions, + Flags: CommonHTMLFlags, }) return Markdown(input, renderer, DefaultOptions) }