diff --git a/inline.go b/inline.go index c1f7475..4483b8f 100644 --- a/inline.go +++ b/inline.go @@ -488,6 +488,7 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int { } p.notes = append(p.notes, ref) + p.notesRecord[string(ref.link)] = struct{}{} link = ref.link title = ref.title @@ -498,9 +499,10 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int { return 0 } - if t == linkDeferredFootnote { + if t == linkDeferredFootnote && !p.isFootnote(lr) { lr.noteId = len(p.notes) + 1 p.notes = append(p.notes, lr) + p.notesRecord[string(lr.link)] = struct{}{} } // keep link and title from reference diff --git a/inline_test.go b/inline_test.go index bcaba09..4061cfb 100644 --- a/inline_test.go +++ b/inline_test.go @@ -1023,6 +1023,28 @@ what happens here +`, + `testing footnotes.[^a] + +test footnotes the second.[^b] + +[^a]: This is the first note[^a]. +[^b]: this is the second note.[^a] +`, + `

testing footnotes.1

+ +

test footnotes the second.2

+
+ +
+ +
    +
  1. This is the first note1. +
  2. +
  3. this is the second note.1 +
  4. +
+
`, } @@ -1076,6 +1098,34 @@ func TestNestedFootnotes(t *testing.T) { +`, + `This uses footnote A.[^A] + +This uses footnote C.[^C] + +[^A]: + A note. use itself.[^A] +[^B]: + B note, uses A to test duplicate.[^A] +[^C]: + C note, uses B.[^B] +`, + `

This uses footnote A.1

+ +

This uses footnote C.2

+
+ +
+ +
    +
  1. A note. use itself.1 +
  2. +
  3. C note, uses B.3 +
  4. +
  5. B note, uses A to test duplicate.1 +
  6. +
+
`, } doTestsInlineParam(t, tests, Options{Extensions: EXTENSION_FOOTNOTES}, 0, diff --git a/markdown.go b/markdown.go index 6d842d3..1722a73 100644 --- a/markdown.go +++ b/markdown.go @@ -218,7 +218,8 @@ type parser struct { // Footnotes need to be ordered as well as available to quickly check for // presence. If a ref is also a footnote, it's stored both in refs and here // in notes. Slice is nil if footnotes not enabled. - notes []*reference + notes []*reference + notesRecord map[string]struct{} } func (p *parser) getRef(refid string) (ref *reference, found bool) { @@ -241,6 +242,11 @@ func (p *parser) getRef(refid string) (ref *reference, found bool) { return ref, found } +func (p *parser) isFootnote(ref *reference) bool { + _, ok := p.notesRecord[string(ref.link)] + return ok +} + // // // Public interface @@ -376,6 +382,7 @@ func MarkdownOptions(input []byte, renderer Renderer, opts Options) []byte { if extensions&EXTENSION_FOOTNOTES != 0 { p.notes = make([]*reference, 0) + p.notesRecord = make(map[string]struct{}) } first := firstPass(p, input)