Skip to content

Commit

Permalink
Asciidoc fixes
Browse files Browse the repository at this point in the history
* Fix definition list dd parsing
* Handle callout lists
* Clean up parsing/rendering/templates, doc is now handled as a top-level
  section with subsections.
  • Loading branch information
nickh authored and schacon committed May 2, 2012
1 parent 68f5440 commit dead43c
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 70 deletions.
139 changes: 82 additions & 57 deletions lib/asciidoc.rb
Expand Up @@ -51,8 +51,9 @@ module Asciidoc
:verse => /^\[verse\]\s*$/,
:dlist => /^(.*)(::|;;)\s*$/,
:olist => /^\d+\.(.*)$/,
:ulist => /^\*(.*)$/,
:ulist => /^\s*\*(.*)$/,
:title => /^\.(.*)\s*$/,
:colist => /^\<\d+\>\s*(.*)/,
:oblock => /^\-\-\s*$/,
:anchor => /^\[\[([^\]]+)\]\]/,
:comment => /^\/\/\s/,
Expand Down Expand Up @@ -195,12 +196,12 @@ def content
end
when :oblock
blocks.map{|block| block.render}.join
when :olist, :ulist
when :olist, :ulist, :colist
@buffer.map do |li|
htmlify(li.content) + li.blocks.map{|block| block.render}.join
end
when :listing
@buffer.join('&x000A;')
@buffer.map{|l| l.gsub(/(<\d+>)/,'<b>\1</b>')}.join('&x000A;')
when :literal
@buffer.map{|l| htmlify(l)}.join('&x000A;')
else
Expand Down Expand Up @@ -422,15 +423,6 @@ class Document
# Public: Get the String document source.
attr_reader :source

# Public: Get the String title from the doc header.
attr_reader :title

# Public: Get the Array header section.
attr_reader :header

# Public: Get the Array of document sections.
attr_reader :sections

# Public: Get the Asciidoc::Renderer instance currently being used
# to render this Document.
attr_reader :renderer
Expand Down Expand Up @@ -489,14 +481,15 @@ def initialize(name, data, &block)

@source = @lines.join

@title = get_title
@header = next_section(@lines)

@sections = []
while @lines.any?
@sections << next_section(@lines)
@root = next_section(@lines)
if @root.blocks.first.is_a?(Section)
@header = @root.blocks.shift
else
@preamble = Section.new(self)
while @root.blocks.first.is_a?(Block)
@preamble << @root.blocks.shift
end
end
@sections.compact!
end

# Public: Render the Asciidoc document using Tilt-compatible templates in
Expand All @@ -513,42 +506,14 @@ def initialize(name, data, &block)
# => "<h1>Doc Title</h1>\n<div class=\"section\">\n <div class=\"paragraph\"><p>Foo</p></div>\n</div>\n"
def render(template_dir)
@renderer = Renderer.new(template_dir)

rendered_header = @renderer.render('header', header, :doc_title => title)

rendered_sections = sections.map{|section| section.render}.join

html = @renderer.render('document', self, :header => rendered_header, :sections => rendered_sections)

html = @renderer.render('document', @root, :header => @header, :preamble => @preamble)
@renderer = nil

@ic.iconv(html)
end

private

# Private: Return the String title from the document header.
#
# Examples
#
# source
# => "My Doc\n======\n\nGREETINGS\n---------\nThis is my doc."
#
# Asciidoc.new(source).get_title
# => "My Doc"
def get_title
header_loc = @lines.index{|s| s =~ /^=+\s*$/}

if !header_loc.nil?
title = @lines[header_loc - 1]
@lines.shift(header_loc + 1)

title.strip
else
nil
end
end

# Private: Return the next block from the section.
#
# * Skip over blank lines to find the start of the next content block.
Expand Down Expand Up @@ -680,8 +645,46 @@ def next_block(lines)
lines.unshift(this_line) unless this_line.nil?

block = Block.new(self, :ulist, items)
elsif this_line.match(REGEXP[:colist])
# colist is a series of blank-line-separated list items terminated by something that isn't an colist item
items = []
while !this_line.nil? && match = this_line.match(REGEXP[:colist])
item = ListItem.new
item_blocks = []
item_buffer = [match[1]]
while lines.any? && !lines.first.strip.empty? && !lines.first.match(REGEXP[:colist])
this_line = lines.shift
if this_line.match(REGEXP[:continue])
item_blocks << item_buffer.dup if item_buffer.any?
item_buffer.clear
else
item_buffer << this_line
end
end
item_blocks << item_buffer.dup if item_buffer.any?

item.content = item_blocks.shift.join

while item_block = item_blocks.shift
while item_block.any?
item.blocks << next_block(item_block)
end
end

items << item

while lines.any? && lines.first.strip.empty?
lines.shift
end

this_line = lines.shift
end
lines.unshift(this_line) unless this_line.nil?

block = Block.new(self, :colist, items)
elsif this_line.match(REGEXP[:dlist])
pairs = []
in_continuation = false

while !this_line.nil? && match = this_line.match(REGEXP[:dlist])
dt = ListItem.new(match[1])
Expand All @@ -691,15 +694,27 @@ def next_block(lines)
while lines.any? && !lines.first.strip.empty? && !lines.first.match(REGEXP[:dlist])
this_line = lines.shift
if this_line.match(REGEXP[:continue])
dd_blocks << dd_buffer.dup if dd_buffer.any?
if dd_buffer.any?
if in_continuation
dd_blocks << dd_buffer.dup
else
dd.content = dd_buffer.join
end
end
dd_buffer.clear
in_continuation = true
else
dd_buffer << this_line
end
end
dd_blocks << dd_buffer.dup if dd_buffer.detect{|line| !line.strip.empty?}

dd.content = dd_blocks.shift.join if dd_blocks.any?
if dd_buffer.detect{|line| !line.strip.empty?}
if in_continuation
dd_blocks << dd_buffer.dup
else
dd.content = dd_buffer.join
end
end

while dd_block = dd_blocks.shift
while dd_block.any?
Expand Down Expand Up @@ -763,9 +778,9 @@ def next_block(lines)
end
end

block.anchor = anchor
block.title = title
block.caption = caption
block.anchor ||= anchor
block.title ||= title
block.caption ||= caption

block
end
Expand All @@ -785,6 +800,10 @@ def section_level(line)
end
end

def is_section_heading?(line1, line2)
!line1.nil? && !line2.nil? && line1.match(REGEXP[:name]) && line2.match(REGEXP[:line]) && (line1.size - line2.size).abs <= 1
end

# Private: Return the next section from the document.
#
# Examples
Expand All @@ -808,8 +827,14 @@ def next_section(lines)
next_line = lines.first || ''
if match = this_line.match(REGEXP[:anchor])
section.anchor = match[1]
elsif (name = this_line.match(REGEXP[:name])) && (level = next_line.match(REGEXP[:line])) && (this_line.size - next_line.size).abs <= 1
section.name = name[1]
elsif is_section_heading?(this_line, next_line)
header = this_line.match(REGEXP[:name])
if anchor = header[1].match(/^(.*)\[\[([^\]]+)\]\]\s*$/)
section.name = anchor[1]
section.anchor = anchor[2]
else
section.name = header[1]
end
section.level = section_level(next_line)
lines.shift
end
Expand All @@ -823,7 +848,7 @@ def next_section(lines)
this_line = lines.shift
next_line = lines.first

if this_line.match(REGEXP[:name]) && !next_line.nil? && next_line.match(REGEXP[:line]) && !section.level.nil? && section_level(next_line) <= section.level
if is_section_heading?(this_line, next_line) && section_level(next_line) <= section.level
lines.unshift this_line
lines.unshift section_lines.pop if section_lines.any? && section_lines.last.match(REGEXP[:anchor])
break
Expand Down
17 changes: 15 additions & 2 deletions templates/document.html.erb
@@ -1,4 +1,17 @@
<div class='man-page'>
<%= header %>
<%= sections %>
<div id="header">
<h1><%= name %> Manual Page</h1>
<% if !header.nil? %>
<h2><%= header.name %></h2>
<div class="sectionbody"><%= header.content %></div>
<% elsif !preamble.nil? %>
<div class="preamble">
<div class="sectionbody">
<%= preamble.content %>
</div>
</div>
<% end %>
</div>

<%= content %>
</div>
5 changes: 0 additions & 5 deletions templates/header.html.erb

This file was deleted.

18 changes: 12 additions & 6 deletions templates/section.html.erb
@@ -1,8 +1,14 @@
<% if !anchor.nil? %>
<a name="#<%= anchor %>">
<a name="<%= anchor %>">
<% end %>
<h<%= level %> id="<%= section_id %>"><%= name %></h<%= level%>>
<% if !anchor.nil? %>
</a>
<% end %>
<div class="sectionbody"><%= content %></div>
<div class="sect<%= level %>">
<h<%= level + 1 %> id="<%= section_id %>"><%= name %></h<%= level + 1 %>>
<% if !anchor.nil? %>
</a>
<% end %>
<% if level == 1 %>
<div class="sectionbody"><%= content %></div>
<% else %>
<%= content %>
<% end %>
</div>
7 changes: 7 additions & 0 deletions templates/section_colist.html.erb
@@ -0,0 +1,7 @@
<div class="colist arabic">
<ol>
<% content.each do |li| %>
<li><p><%= li %></p></li>
<% end %>
</ol>
</div>

0 comments on commit dead43c

Please sign in to comment.