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) {
      -
    1. This is the note +
    2. This is the note
    @@ -539,7 +539,7 @@ No longer in the footnote
      -
    1. Paragraph 1

      +
    2. Paragraph 1

      Paragraph 2

      @@ -577,9 +577,39 @@ what happens here
        -
      1. this is note c +
      2. this is note c
      3. -
      4. this is note d +
      5. this is note d +
      6. +
      + +`, + + "testing inline^[this is the note] notes.\n", + `

      testing inline1 notes.

      +
      + +
      + +
        +
      1. this is the note
      2. +
      +
      +`, + + "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 multiple1 types2 of notes3

      +
      + +
      + +
        +
      1. the first deferred note

        + +

        which happens to be a block

        +
      2. +
      3. inline note
      4. +
      5. the second deferred note
      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]