Merge d709d401cf
into 4c9bf95126
commit
628760900b
6
html.go
6
html.go
|
@ -465,6 +465,8 @@ var (
|
|||
h5CloseTag = []byte("</h5>")
|
||||
h6Tag = []byte("<h6")
|
||||
h6CloseTag = []byte("</h6>")
|
||||
mathTag = []byte("<math>")
|
||||
mathCloseTag = []byte("</math>")
|
||||
|
||||
footnotesDivBytes = []byte("\n<div class=\"footnotes\">\n\n")
|
||||
footnotesCloseDivBytes = []byte("\n</div>\n")
|
||||
|
@ -827,6 +829,10 @@ func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkSt
|
|||
r.out(w, trCloseTag)
|
||||
r.cr(w)
|
||||
}
|
||||
case Math:
|
||||
r.out(w, mathTag)
|
||||
escapeAllHTML(w, node.Literal)
|
||||
r.out(w, mathCloseTag)
|
||||
default:
|
||||
panic("Unknown node type " + node.Type.String())
|
||||
}
|
||||
|
|
26
inline.go
26
inline.go
|
@ -735,7 +735,9 @@ func linkEndsWithEntity(data []byte, linkEnd int) bool {
|
|||
}
|
||||
|
||||
// hasPrefixCaseInsensitive is a custom implementation of
|
||||
// strings.HasPrefix(strings.ToLower(s), prefix)
|
||||
//
|
||||
// strings.HasPrefix(strings.ToLower(s), prefix)
|
||||
//
|
||||
// we rolled our own because ToLower pulls in a huge machinery of lowercasing
|
||||
// anything from Unicode and that's very slow. Since this func will only be
|
||||
// used on ASCII protocol prefixes, we can take shortcuts.
|
||||
|
@ -1226,3 +1228,25 @@ func text(s []byte) *Node {
|
|||
func normalizeURI(s []byte) []byte {
|
||||
return s // TODO: implement
|
||||
}
|
||||
|
||||
func math(p *Markdown, data []byte, offset int) (int, *Node) {
|
||||
if offset > 0 && data[offset-1] == '\\' {
|
||||
return 0, nil // Dollar sign has been escaped.
|
||||
}
|
||||
data = data[offset:]
|
||||
isInline := len(data) > 2 && data[1] != '$'
|
||||
if isInline {
|
||||
data = data[1:]
|
||||
nl := bytes.IndexByte(data, '\n')
|
||||
dolla := bytes.IndexByte(data, '$')
|
||||
if dolla < 0 || (nl >= 0 && nl < dolla) {
|
||||
return 0, nil // No end to math node or newline before dollar.
|
||||
}
|
||||
math := NewNode(Math)
|
||||
math.Literal = data[:dolla]
|
||||
return dolla + 2, math
|
||||
}
|
||||
// Block math unsupported.
|
||||
// isBlock := len(data) > 4 && data[1] == '$' && data[2] != '$'
|
||||
return 0, nil
|
||||
}
|
||||
|
|
|
@ -1214,3 +1214,15 @@ func BenchmarkSmartDoubleQuotes(b *testing.B) {
|
|||
runMarkdown("this should be normal \"quoted\" text.\n", params)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMath(t *testing.T) {
|
||||
doTestsParam(t, []string{
|
||||
"In class we saw $a$ is a length.",
|
||||
"<p>In class we saw <math>a</math> is a length.</p>\n",
|
||||
|
||||
"What we see is that following $a+b <three> four$. Right?",
|
||||
"<p>What we see is that following <math>a+b <three> four</math>. Right?</p>\n",
|
||||
}, TestParams{
|
||||
extensions: DollarMath,
|
||||
})
|
||||
}
|
||||
|
|
48
markdown.go
48
markdown.go
|
@ -47,6 +47,7 @@ const (
|
|||
AutoHeadingIDs // Create the heading ID from the text
|
||||
BackslashLineBreak // Translate trailing backslashes into line breaks
|
||||
DefinitionLists // Render definition lists
|
||||
DollarMath // Parse inline and block math inside '$' as Math nodes.
|
||||
|
||||
CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants |
|
||||
SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes
|
||||
|
@ -308,6 +309,9 @@ func New(opts ...Option) *Markdown {
|
|||
if p.extensions&Footnotes != 0 {
|
||||
p.notes = make([]*reference, 0)
|
||||
}
|
||||
if p.extensions&DollarMath != 0 {
|
||||
p.inlineCallback['$'] = math
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
|
@ -345,8 +349,8 @@ func WithNoExtensions() Option {
|
|||
// In Markdown, the link reference syntax can be made to resolve a link to
|
||||
// a reference instead of an inline URL, in one of the following ways:
|
||||
//
|
||||
// * [link text][refid]
|
||||
// * [refid][]
|
||||
// - [link text][refid]
|
||||
// - [refid][]
|
||||
//
|
||||
// Usually, the refid is defined at the bottom of the Markdown document. If
|
||||
// this override function is provided, the refid is passed to the override
|
||||
|
@ -363,7 +367,9 @@ func WithRefOverride(o ReferenceOverrideFunc) Option {
|
|||
// block of markdown-encoded text.
|
||||
//
|
||||
// The simplest invocation of Run takes one argument, input:
|
||||
// output := Run(input)
|
||||
//
|
||||
// output := Run(input)
|
||||
//
|
||||
// This will parse the input with CommonExtensions enabled and render it with
|
||||
// the default HTMLRenderer (with CommonHTMLFlags).
|
||||
//
|
||||
|
@ -371,13 +377,15 @@ func WithRefOverride(o ReferenceOverrideFunc) Option {
|
|||
// type does not contain exported fields, you can not use it directly. Instead,
|
||||
// use the With* functions. For example, this will call the most basic
|
||||
// functionality, with no extensions:
|
||||
// output := Run(input, WithNoExtensions())
|
||||
//
|
||||
// output := Run(input, WithNoExtensions())
|
||||
//
|
||||
// You can use any number of With* arguments, even contradicting ones. They
|
||||
// will be applied in order of appearance and the latter will override the
|
||||
// former:
|
||||
// output := Run(input, WithNoExtensions(), WithExtensions(exts),
|
||||
// WithRenderer(yourRenderer))
|
||||
//
|
||||
// output := Run(input, WithNoExtensions(), WithExtensions(exts),
|
||||
// WithRenderer(yourRenderer))
|
||||
func Run(input []byte, opts ...Option) []byte {
|
||||
r := NewHTMLRenderer(HTMLRendererParameters{
|
||||
Flags: CommonHTMLFlags,
|
||||
|
@ -491,35 +499,35 @@ func (p *Markdown) parseRefsToAST() {
|
|||
//
|
||||
// Consider this markdown with reference-style links:
|
||||
//
|
||||
// [link][ref]
|
||||
// [link][ref]
|
||||
//
|
||||
// [ref]: /url/ "tooltip title"
|
||||
// [ref]: /url/ "tooltip title"
|
||||
//
|
||||
// It will be ultimately converted to this HTML:
|
||||
//
|
||||
// <p><a href=\"/url/\" title=\"title\">link</a></p>
|
||||
// <p><a href=\"/url/\" title=\"title\">link</a></p>
|
||||
//
|
||||
// And a reference structure will be populated as follows:
|
||||
//
|
||||
// p.refs["ref"] = &reference{
|
||||
// link: "/url/",
|
||||
// title: "tooltip title",
|
||||
// }
|
||||
// p.refs["ref"] = &reference{
|
||||
// link: "/url/",
|
||||
// title: "tooltip title",
|
||||
// }
|
||||
//
|
||||
// Alternatively, reference can contain information about a footnote. Consider
|
||||
// this markdown:
|
||||
//
|
||||
// Text needing a footnote.[^a]
|
||||
// Text needing a footnote.[^a]
|
||||
//
|
||||
// [^a]: This is the note
|
||||
// [^a]: This is the note
|
||||
//
|
||||
// A reference structure will be populated as follows:
|
||||
//
|
||||
// p.refs["a"] = &reference{
|
||||
// link: "a",
|
||||
// title: "This is the note",
|
||||
// noteID: <some positive int>,
|
||||
// }
|
||||
// p.refs["a"] = &reference{
|
||||
// link: "a",
|
||||
// title: "This is the note",
|
||||
// noteID: <some positive int>,
|
||||
// }
|
||||
//
|
||||
// TODO: As you can see, it begs for splitting into two dedicated structures
|
||||
// for refs and for footnotes.
|
||||
|
|
Loading…
Reference in New Issue