Skip to content

Commit

Permalink
Implement the footnote extension
Browse files Browse the repository at this point in the history
  • Loading branch information
drbrain committed Oct 31, 2011
1 parent 486ced2 commit e3d05f1
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 45 deletions.
120 changes: 75 additions & 45 deletions pegdown.kpeg
Expand Up @@ -56,7 +56,12 @@
@formatter = RDoc::Markup::ToJoinedParagraph.new
@extensions = extensions

@references = nil
@references = nil
@unlinked_references = nil

@footnotes = nil
@notes = nil
@unlinked_notes = nil
end

def extension? name
Expand All @@ -81,27 +86,56 @@
# document a placeholder is created that will be filled later.

def link_to content, label = content
raise 'enable notes extension' if content.start_with? '^' and label == content
if ref = @references[label] then
"{#{content}}[#{ref}]"
else
ref = @unlinked[label] || ""
@unlinked[label] = ref
ref = @unlinked_references[label] || ""
@unlinked_references[label] = ref
["{#{content}}[", ref, "]"]
end
end

##
# Finds a footnote reference for +label+ and creates a new link to it with
# +content+ as the link text. If +label+ has not be encountered in the
# document a placeholder is created that will be filled later.

def note_for label
if ref = @notes[label] then
"{*#{label}}[#{ref}]"
else
ref = @unlinked_notes[label] || ""
@unlinked_notes[label] = ref
["{*#{label}}[", ref, "]"]
end
end

alias peg_parse parse

def parse markdown
setup_parser markdown, @debug

@references = {}
@unlinked = {}
if notes? then
@footnotes = []
@notes = {}
@unlinked_notes = {}
end

@references = {}
@unlinked_references = {}

peg_parse

doc = result

if notes? then
unless @footnotes.empty? then
doc << RDoc::Markup::Rule.new(1)
doc.push(*@footnotes)
end
end

doc.accept @formatter

doc
Expand All @@ -112,11 +146,26 @@
# link references.

def reference label, link
if ref = @unlinked.delete(label) then
if ref = @unlinked_references.delete(label) then
ref.replace link
end

@references[label] = ref
@references[label] = link
end

##
# Stores +label+ as a note and fills in previously unknown note references.

def note label
foottext = "rdoc-label:foottext-#{label}:footmark-#{label}"

if ref = @unlinked_notes.delete(label) then
ref.replace foottext
end

@notes[label] = foottext

"{^1}[rdoc-label:footmark-#{label}:foottext-#{label}] "
end
}

Expand Down Expand Up @@ -745,49 +794,30 @@ ExtendedSpecialChar = &{ notes? } ( "^" )

NoteReference = &{ notes? }
RawNoteReference:ref
{ raise 'element *match;
if (find_note(&match, ref->contents.str)) {
$$ = mk_element(NOTE);
assert(match->children != NULL);
$$->children = match->children;
$$->contents.str = 0;
} else {
char *s;
s = malloc(strlen(ref->contents.str) + 4);
sprintf(s, "[^%s]", ref->contents.str);
$$ = mk_str(s);
free(s);
}'
}
{ note_for ref }

RawNoteReference = "[^" < ( !Newline !"]" . )+ > "]"
{ raise " $$ = mk_str(yytext); " }
RawNoteReference = "[^" < ( !Newline !"]" . )+ > "]" { text }

Note = &{ notes? }
NonindentSpace ref:rawNoteReference ":" Sp
NonindentSpace RawNoteReference:ref ":" Sp
StartList:a
( RawNoteBlock { raise " a = cons($$, a); " } )
( RawNoteBlock:l )
( &Indent RawNoteBlock { raise " a = cons($$, a); " } )*
{ raise '$$ = mk_list(NOTE, a);
$$->contents.str = strdup(ref->contents.str); '
{ a.unshift note ref
@footnotes << RDoc::Markup::Paragraph.new(*a)
nil
}

InlineNote = &{ notes? }
"^["
StartList:a
( !"]" Inline { raise " a = cons($$, a); " } )+
"]"
{ raise '$$ = mk_list(NOTE, a);
$$->contents.str = 0; '}

Notes = StartList:a
( b:note { raise " a = cons(b, a); " } | SkipBlock )*
{ raise " notes = reverse(a); " }

RawNoteBlock = StartList:a
( !BlankLine OptionallyIndentedLine { raise " a = cons($$, a); " } )+
( < BlankLine* > { raise " a = cons(mk_str(yytext), a); " } )
{ raise '$$ = mk_str_from_list(a, true);
$$->key = RAW; '
}
InlineNote = &{ notes? }
"^["
StartList:a
( !"]" Inline { raise " a = cons($$, a); " } )+
"]"
{ raise '$$ = mk_list(NOTE, a);
$$->contents.str = 0; '}

RawNoteBlock = StartList:a
( !BlankLine OptionallyIndentedLine:l { a << l } )+
( < BlankLine* > { a << text } )
{ a }

23 changes: 23 additions & 0 deletions test/test_pegdown.rb
Expand Up @@ -317,6 +317,29 @@ def test_parse_list_number_continue
assert_equal expected, doc
end

def test_parse_note
@parser.notes = true

doc = parse <<-MD
Some text.[^1]
[^1]: With a footnote
MD

expected = doc(
para("Some text.{*1}[rdoc-label:foottext-1:footmark-1]"),
@RM::Rule.new(1),
para("{^1}[rdoc-label:footmark-1:foottext-1] With a footnote\n"))

assert_equal expected, doc
end

def test_parse_note_no_notes
assert_raises RuntimeError do
parse "Some text.[^1]"
end
end

def test_parse_paragraph
doc = parse "it worked\n"

Expand Down

0 comments on commit e3d05f1

Please sign in to comment.