diff --git a/html.go b/html.go
index 59d1e32..e499cb3 100644
--- a/html.go
+++ b/html.go
@@ -333,7 +333,7 @@ func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags in
if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
doubleSpace(out)
}
- out.WriteString(`
`)
out.Write(text)
diff --git a/inline.go b/inline.go
index 56d38bd..ca7c6b1 100644
--- a/inline.go
+++ b/inline.go
@@ -15,6 +15,7 @@ package blackfriday
import (
"bytes"
+ "strconv"
)
// Functions to parse text within a block
@@ -174,8 +175,7 @@ const (
linkNormal linkType = iota
linkImg
linkDeferredFootnote
-
-// linkInlineFootnote
+ linkInlineFootnote
)
// '[': parse a link or an image or a footnote
@@ -193,7 +193,9 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
if offset > 0 && data[offset-1] == '!' {
t = linkImg
} else if p.flags&EXTENSION_FOOTNOTES != 0 {
- if len(data)-1 > offset && data[offset+1] == '^' {
+ if offset > 0 && data[offset-1] == '^' {
+ t = linkInlineFootnote
+ } else if len(data)-1 > offset && data[offset+1] == '^' {
t = linkDeferredFootnote
}
}
@@ -387,7 +389,7 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
title = lr.title
i++
- // shortcut reference style link or footnote
+ // shortcut reference style link or reference or inline footnote
default:
var id []byte
@@ -407,24 +409,58 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
id = b.Bytes()
} else {
if t == linkDeferredFootnote {
- id = data[2:txtE]
+ id = data[2:txtE] // get rid of the ^
} else {
id = data[1:txtE]
}
}
- // find the reference with matching id
key := string(bytes.ToLower(id))
- lr, ok := p.refs[key]
- if !ok {
- return 0
- }
+ if t == linkInlineFootnote {
+ // create a new reference
+ noteId = len(p.notes) + 1
- // keep link and title from reference
- link = lr.link
- // if inline footnote, title == footnote contents
- title = lr.title
- noteId = lr.noteId
+ var fragment []byte
+ if len(id) > 0 {
+ if len(id) < 16 {
+ fragment = make([]byte, len(id))
+ } else {
+ fragment = make([]byte, 16)
+ }
+ copy(fragment, slugify(id))
+ } else {
+ fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteId))...)
+ }
+
+ ref := &reference{
+ noteId: noteId,
+ hasBlock: false,
+ link: fragment,
+ title: id,
+ }
+
+ p.notes = append(p.notes, ref)
+
+ link = ref.link
+ title = ref.title
+ } else {
+ // find the reference with matching id
+ lr, ok := p.refs[key]
+ if !ok {
+ return 0
+ }
+
+ if t == linkDeferredFootnote {
+ lr.noteId = len(p.notes) + 1
+ p.notes = append(p.notes, lr)
+ }
+
+ // keep link and title from reference
+ link = lr.link
+ // if inline footnote, title == footnote contents
+ title = lr.title
+ noteId = lr.noteId
+ }
// rewind the whitespace
i = txtE + 1
@@ -470,6 +506,15 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
p.r.Image(out, uLink, title, content.Bytes())
+ case linkInlineFootnote:
+ outSize := out.Len()
+ outBytes := out.Bytes()
+ if outSize > 0 && outBytes[outSize-1] == '^' {
+ out.Truncate(outSize - 1)
+ }
+
+ p.r.FootnoteRef(out, link, noteId)
+
case linkDeferredFootnote:
p.r.FootnoteRef(out, link, noteId)
diff --git a/inline_test.go b/inline_test.go
index d2f0bab..3a307b8 100644
--- a/inline_test.go
+++ b/inline_test.go
@@ -513,7 +513,7 @@ func TestFootnotes(t *testing.T) {
-- This is the note
+
- This is the note
@@ -539,7 +539,7 @@ No longer in the footnote
-Paragraph 1
+Paragraph 1
Paragraph 2
@@ -577,9 +577,39 @@ what happens here
-- this is note c
+
- this is note c
-- this is note d
+
- this is note d
+
+
+
+`,
+
+ "testing inline^[this is the note] notes.\n",
+ `testing inline notes.
+
+`,
+
+ "testing multiple[^1] types^[inline note] of notes[^2]\n\n[^2]: the second deferred note\n[^1]: the first deferred note\n\n\twhich happens to be a block\n",
+ `testing multiple types of notes
+
diff --git a/markdown.go b/markdown.go
index 7d17433..6967bec 100644
--- a/markdown.go
+++ b/markdown.go
@@ -436,7 +436,9 @@ func isReference(p *parser, data []byte, tabSize int) int {
i++
if p.flags&EXTENSION_FOOTNOTES != 0 {
if data[i] == '^' {
- noteId = len(p.notes) + 1
+ // we can set it to anything here because the proper noteIds will
+ // be assigned later during the second pass. It just has to be != 0
+ noteId = 1
i++
}
}
@@ -479,7 +481,7 @@ func isReference(p *parser, data []byte, tabSize int) int {
hasBlock bool
)
- if p.flags&EXTENSION_FOOTNOTES != 0 && noteId > 0 {
+ if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
lineEnd = linkEnd
} else {
@@ -501,7 +503,6 @@ func isReference(p *parser, data []byte, tabSize int) int {
ref.link = data[idOffset:idEnd]
// if footnote, it's not really a title, it's the contained text
ref.title = raw
- p.notes = append(p.notes, ref)
} else {
ref.link = data[linkOffset:linkEnd]
ref.title = data[titleOffset:titleEnd]