mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Renamespace lib/rdoc/markup from SM::SimpleMarkup to RDoc::Markup.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@15033 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
cbd4604c53
commit
fcb0b1f503
31 changed files with 2573 additions and 2863 deletions
|
@ -1,2 +0,0 @@
|
|||
simple_markup
|
||||
simple_markup.rb
|
|
@ -1,6 +1,7 @@
|
|||
require 'rdoc/markup/simple_markup/lines.rb'
|
||||
require 'rdoc/markup'
|
||||
require 'rdoc/markup/lines'
|
||||
|
||||
module SM
|
||||
class RDoc::Markup
|
||||
|
||||
##
|
||||
# A Fragment is a chunk of text, subclassed as a paragraph, a list
|
||||
|
@ -119,7 +120,7 @@ module SM
|
|||
|
||||
##
|
||||
# Collect groups of lines together. Each group will end up containing a flow
|
||||
# of text
|
||||
# of text.
|
||||
|
||||
class LineCollection
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
module SM
|
||||
require 'rdoc/markup'
|
||||
|
||||
class RDoc::Markup
|
||||
|
||||
##
|
||||
# We manage a set of attributes. Each attribute has a symbol name and a bit
|
||||
# value
|
||||
# value.
|
||||
|
||||
class Attribute
|
||||
SPECIAL = 1
|
||||
|
@ -39,7 +41,7 @@ module SM
|
|||
|
||||
##
|
||||
# An AttrChanger records a change in attributes. It contains a bitmap of the
|
||||
# attributes to turn on, and a bitmap of those to turn off
|
||||
# attributes to turn on, and a bitmap of those to turn off.
|
||||
|
||||
AttrChanger = Struct.new(:turn_on, :turn_off)
|
||||
|
||||
|
@ -50,7 +52,7 @@ module SM
|
|||
end
|
||||
|
||||
##
|
||||
# An array of attributes which parallels the characters in a string
|
||||
# An array of attributes which parallels the characters in a string.
|
||||
|
||||
class AttrSpan
|
||||
def initialize(length)
|
||||
|
@ -84,12 +86,12 @@ module SM
|
|||
end
|
||||
|
||||
def to_s
|
||||
"Special: type=#{type}, name=#{SM::Attribute.as_string type}, text=#{text.dump}"
|
||||
"Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}"
|
||||
end
|
||||
|
||||
def inspect
|
||||
"#<SM::Special:0x%x @type=%p, name=%p @text=%p>" % [
|
||||
object_id, @type, SM::Attribute.as_string(type), text.dump]
|
||||
"#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [
|
||||
object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump]
|
||||
end
|
||||
end
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
module SM
|
||||
class RDoc::Markup
|
||||
|
||||
##
|
||||
# We store the lines we're working on as objects of class Line. These
|
||||
|
@ -14,7 +14,7 @@ module SM
|
|||
RULE = :RULE
|
||||
PARAGRAPH = :PARAGRAPH
|
||||
VERBATIM = :VERBATIM
|
||||
|
||||
|
||||
# line type
|
||||
attr_accessor :type
|
||||
|
||||
|
@ -36,7 +36,6 @@ module SM
|
|||
|
||||
# true if this line has been deleted from the list of lines
|
||||
attr_accessor :deleted
|
||||
|
||||
|
||||
def initialize(text)
|
||||
@text = text.dup
|
||||
|
@ -69,7 +68,6 @@ module SM
|
|||
|
||||
##
|
||||
# Strip off the leading margin
|
||||
#
|
||||
|
||||
def strip_leading(size)
|
||||
if @text.size > size
|
||||
|
@ -85,7 +83,7 @@ module SM
|
|||
end
|
||||
|
||||
##
|
||||
# A container for all the lines
|
||||
# A container for all the lines.
|
||||
|
||||
class Lines
|
||||
|
71
lib/rdoc/markup/preprocess.rb
Normal file
71
lib/rdoc/markup/preprocess.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
require 'rdoc/markup'
|
||||
|
||||
##
|
||||
# Handle common directives that can occur in a block of text:
|
||||
#
|
||||
# : include : filename
|
||||
|
||||
class RDoc::Markup::PreProcess
|
||||
|
||||
def initialize(input_file_name, include_path)
|
||||
@input_file_name = input_file_name
|
||||
@include_path = include_path
|
||||
end
|
||||
|
||||
##
|
||||
# Look for common options in a chunk of text. Options that we don't handle
|
||||
# are passed back to our caller as |directive, param|
|
||||
|
||||
def handle(text)
|
||||
text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
|
||||
prefix = $1
|
||||
directive = $2.downcase
|
||||
param = $3
|
||||
|
||||
case directive
|
||||
when "include"
|
||||
filename = param.split[0]
|
||||
include_file(filename, prefix)
|
||||
|
||||
else
|
||||
yield(directive, param)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Include a file, indenting it correctly.
|
||||
|
||||
def include_file(name, indent)
|
||||
if full_name = find_include_file(name) then
|
||||
content = File.open(full_name) {|f| f.read}
|
||||
# strip leading '#'s, but only if all lines start with them
|
||||
if content =~ /^[^#]/
|
||||
content.gsub(/^/, indent)
|
||||
else
|
||||
content.gsub(/^#?/, indent)
|
||||
end
|
||||
else
|
||||
$stderr.puts "Couldn't find file to include: '#{name}'"
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Look for the given file in the directory containing the current file,
|
||||
# and then in each of the directories specified in the RDOC_INCLUDE path
|
||||
|
||||
def find_include_file(name)
|
||||
to_search = [ File.dirname(@input_file_name) ].concat @include_path
|
||||
to_search.each do |dir|
|
||||
full_name = File.join(dir, name)
|
||||
stat = File.stat(full_name) rescue next
|
||||
return full_name if stat.readable?
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,463 +0,0 @@
|
|||
require 'rdoc/markup/simple_markup/fragments'
|
||||
require 'rdoc/markup/simple_markup/lines.rb'
|
||||
|
||||
##
|
||||
# SimpleMarkup parses plain text documents and attempts to decompose
|
||||
# them into their constituent parts. Some of these parts are high-level:
|
||||
# paragraphs, chunks of verbatim text, list entries and the like. Other
|
||||
# parts happen at the character level: a piece of bold text, a word in
|
||||
# code font. This markup is similar in spirit to that used on WikiWiki
|
||||
# webs, where folks create web pages using a simple set of formatting
|
||||
# rules.
|
||||
#
|
||||
# SimpleMarkup itself does no output formatting: this is left to a
|
||||
# different set of classes.
|
||||
#
|
||||
# SimpleMarkup is extendable at runtime: you can add new markup
|
||||
# elements to be recognised in the documents that SimpleMarkup parses.
|
||||
#
|
||||
# SimpleMarkup is intended to be the basis for a family of tools which
|
||||
# share the common requirement that simple, plain-text should be
|
||||
# rendered in a variety of different output formats and media. It is
|
||||
# envisaged that SimpleMarkup could be the basis for formating RDoc
|
||||
# style comment blocks, Wiki entries, and online FAQs.
|
||||
#
|
||||
# = Basic Formatting
|
||||
#
|
||||
# * SimpleMarkup looks for a document's natural left margin. This is
|
||||
# used as the initial margin for the document.
|
||||
#
|
||||
# * Consecutive lines starting at this margin are considered to be a
|
||||
# paragraph.
|
||||
#
|
||||
# * If a paragraph starts with a "*", "-", or with "<digit>.", then it is
|
||||
# taken to be the start of a list. The margin in increased to be the
|
||||
# first non-space following the list start flag. Subsequent lines
|
||||
# should be indented to this new margin until the list ends. For
|
||||
# example:
|
||||
#
|
||||
# * this is a list with three paragraphs in
|
||||
# the first item. This is the first paragraph.
|
||||
#
|
||||
# And this is the second paragraph.
|
||||
#
|
||||
# 1. This is an indented, numbered list.
|
||||
# 2. This is the second item in that list
|
||||
#
|
||||
# This is the third conventional paragraph in the
|
||||
# first list item.
|
||||
#
|
||||
# * This is the second item in the original list
|
||||
#
|
||||
# * You can also construct labeled lists, sometimes called description
|
||||
# or definition lists. Do this by putting the label in square brackets
|
||||
# and indenting the list body:
|
||||
#
|
||||
# [cat] a small furry mammal
|
||||
# that seems to sleep a lot
|
||||
#
|
||||
# [ant] a little insect that is known
|
||||
# to enjoy picnics
|
||||
#
|
||||
# A minor variation on labeled lists uses two colons to separate the
|
||||
# label from the list body:
|
||||
#
|
||||
# cat:: a small furry mammal
|
||||
# that seems to sleep a lot
|
||||
#
|
||||
# ant:: a little insect that is known
|
||||
# to enjoy picnics
|
||||
#
|
||||
# This latter style guarantees that the list bodies' left margins are
|
||||
# aligned: think of them as a two column table.
|
||||
#
|
||||
# * Any line that starts to the right of the current margin is treated
|
||||
# as verbatim text. This is useful for code listings. The example of a
|
||||
# list above is also verbatim text.
|
||||
#
|
||||
# * A line starting with an equals sign (=) is treated as a
|
||||
# heading. Level one headings have one equals sign, level two headings
|
||||
# have two,and so on.
|
||||
#
|
||||
# * A line starting with three or more hyphens (at the current indent)
|
||||
# generates a horizontal rule. THe more hyphens, the thicker the rule
|
||||
# (within reason, and if supported by the output device)
|
||||
#
|
||||
# * You can use markup within text (except verbatim) to change the
|
||||
# appearance of parts of that text. Out of the box, SimpleMarkup
|
||||
# supports word-based and general markup.
|
||||
#
|
||||
# Word-based markup uses flag characters around individual words:
|
||||
#
|
||||
# [\*word*] displays word in a *bold* font
|
||||
# [\_word_] displays word in an _emphasized_ font
|
||||
# [\+word+] displays word in a +code+ font
|
||||
#
|
||||
# General markup affects text between a start delimiter and and end
|
||||
# delimiter. Not surprisingly, these delimiters look like HTML markup.
|
||||
#
|
||||
# [\<b>text...</b>] displays word in a *bold* font
|
||||
# [\<em>text...</em>] displays word in an _emphasized_ font
|
||||
# [\<i>text...</i>] displays word in an _emphasized_ font
|
||||
# [\<tt>text...</tt>] displays word in a +code+ font
|
||||
#
|
||||
# Unlike conventional Wiki markup, general markup can cross line
|
||||
# boundaries. You can turn off the interpretation of markup by
|
||||
# preceding the first character with a backslash, so \\\<b>bold
|
||||
# text</b> and \\\*bold* produce \<b>bold text</b> and \*bold
|
||||
# respectively.
|
||||
#
|
||||
# = Using SimpleMarkup
|
||||
#
|
||||
# For information on using SimpleMarkup programatically, see SM::SimpleMarkup.
|
||||
#--
|
||||
# Author:: Dave Thomas, dave@pragmaticprogrammer.com
|
||||
# Version:: 0.0
|
||||
# License:: Ruby license
|
||||
|
||||
module SM
|
||||
|
||||
# == Synopsis
|
||||
#
|
||||
# This code converts <tt>input_string</tt>, which is in the format
|
||||
# described in markup/simple_markup.rb, to HTML. The conversion
|
||||
# takes place in the +convert+ method, so you can use the same
|
||||
# SimpleMarkup object to convert multiple input strings.
|
||||
#
|
||||
# require 'rdoc/markup/simple_markup'
|
||||
# require 'rdoc/markup/simple_markup/to_html'
|
||||
#
|
||||
# p = SM::SimpleMarkup.new
|
||||
# h = SM::ToHtml.new
|
||||
#
|
||||
# puts p.convert(input_string, h)
|
||||
#
|
||||
# You can extend the SimpleMarkup parser to recognise new markup
|
||||
# sequences, and to add special processing for text that matches a
|
||||
# regular epxression. Here we make WikiWords significant to the parser,
|
||||
# and also make the sequences {word} and \<no>text...</no> signify
|
||||
# strike-through text. When then subclass the HTML output class to deal
|
||||
# with these:
|
||||
#
|
||||
# require 'rdoc/markup/simple_markup'
|
||||
# require 'rdoc/markup/simple_markup/to_html'
|
||||
#
|
||||
# class WikiHtml < SM::ToHtml
|
||||
# def handle_special_WIKIWORD(special)
|
||||
# "<font color=red>" + special.text + "</font>"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# p = SM::SimpleMarkup.new
|
||||
# p.add_word_pair("{", "}", :STRIKE)
|
||||
# p.add_html("no", :STRIKE)
|
||||
#
|
||||
# p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
|
||||
#
|
||||
# h = WikiHtml.new
|
||||
# h.add_tag(:STRIKE, "<strike>", "</strike>")
|
||||
#
|
||||
# puts "<body>" + p.convert(ARGF.read, h) + "</body>"
|
||||
|
||||
class SimpleMarkup
|
||||
|
||||
SPACE = ?\s
|
||||
|
||||
# List entries look like:
|
||||
# * text
|
||||
# 1. text
|
||||
# [label] text
|
||||
# label:: text
|
||||
#
|
||||
# Flag it as a list entry, and work out the indent for subsequent lines
|
||||
|
||||
SIMPLE_LIST_RE = /^(
|
||||
( \* (?# bullet)
|
||||
|- (?# bullet)
|
||||
|\d+\. (?# numbered )
|
||||
|[A-Za-z]\. (?# alphabetically numbered )
|
||||
)
|
||||
\s+
|
||||
)\S/x
|
||||
|
||||
LABEL_LIST_RE = /^(
|
||||
( \[.*?\] (?# labeled )
|
||||
|\S.*:: (?# note )
|
||||
)(?:\s+|$)
|
||||
)/x
|
||||
|
||||
##
|
||||
# Take a block of text and use various heuristics to determine it's
|
||||
# structure (paragraphs, lists, and so on). Invoke an event handler as we
|
||||
# identify significant chunks.
|
||||
|
||||
def initialize
|
||||
@am = AttributeManager.new
|
||||
@output = nil
|
||||
end
|
||||
|
||||
##
|
||||
# Add to the sequences used to add formatting to an individual word (such
|
||||
# as *bold*). Matching entries will generate attibutes that the output
|
||||
# formatters can recognize by their +name+.
|
||||
|
||||
def add_word_pair(start, stop, name)
|
||||
@am.add_word_pair(start, stop, name)
|
||||
end
|
||||
|
||||
##
|
||||
# Add to the sequences recognized as general markup.
|
||||
|
||||
def add_html(tag, name)
|
||||
@am.add_html(tag, name)
|
||||
end
|
||||
|
||||
##
|
||||
# Add to other inline sequences. For example, we could add WikiWords using
|
||||
# something like:
|
||||
#
|
||||
# parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD)
|
||||
#
|
||||
# Each wiki word will be presented to the output formatter via the
|
||||
# accept_special method.
|
||||
|
||||
def add_special(pattern, name)
|
||||
@am.add_special(pattern, name)
|
||||
end
|
||||
|
||||
##
|
||||
# We take a string, split it into lines, work out the type of each line,
|
||||
# and from there deduce groups of lines (for example all lines in a
|
||||
# paragraph). We then invoke the output formatter using a Visitor to
|
||||
# display the result.
|
||||
|
||||
def convert(str, op)
|
||||
@lines = Lines.new(str.split(/\r?\n/).collect { |aLine|
|
||||
Line.new(aLine) })
|
||||
return "" if @lines.empty?
|
||||
@lines.normalize
|
||||
assign_types_to_lines
|
||||
group = group_lines
|
||||
# call the output formatter to handle the result
|
||||
# group.to_a.each {|i| p i}
|
||||
group.accept(@am, op)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Look through the text at line indentation. We flag each line as being
|
||||
# Blank, a paragraph, a list element, or verbatim text.
|
||||
|
||||
def assign_types_to_lines(margin = 0, level = 0)
|
||||
|
||||
while line = @lines.next
|
||||
if line.isBlank?
|
||||
line.stamp(Line::BLANK, level)
|
||||
next
|
||||
end
|
||||
|
||||
# if a line contains non-blanks before the margin, then it must belong
|
||||
# to an outer level
|
||||
|
||||
text = line.text
|
||||
|
||||
for i in 0...margin
|
||||
if text[i] != SPACE
|
||||
@lines.unget
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
active_line = text[margin..-1]
|
||||
|
||||
# Rules (horizontal lines) look like
|
||||
#
|
||||
# --- (three or more hyphens)
|
||||
#
|
||||
# The more hyphens, the thicker the rule
|
||||
#
|
||||
|
||||
if /^(---+)\s*$/ =~ active_line
|
||||
line.stamp(Line::RULE, level, $1.length-2)
|
||||
next
|
||||
end
|
||||
|
||||
# Then look for list entries. First the ones that have to have
|
||||
# text following them (* xxx, - xxx, and dd. xxx)
|
||||
|
||||
if SIMPLE_LIST_RE =~ active_line
|
||||
|
||||
offset = margin + $1.length
|
||||
prefix = $2
|
||||
prefix_length = prefix.length
|
||||
|
||||
flag = case prefix
|
||||
when "*","-" then ListBase::BULLET
|
||||
when /^\d/ then ListBase::NUMBER
|
||||
when /^[A-Z]/ then ListBase::UPPERALPHA
|
||||
when /^[a-z]/ then ListBase::LOWERALPHA
|
||||
else raise "Invalid List Type: #{self.inspect}"
|
||||
end
|
||||
|
||||
line.stamp(Line::LIST, level+1, prefix, flag)
|
||||
text[margin, prefix_length] = " " * prefix_length
|
||||
assign_types_to_lines(offset, level + 1)
|
||||
next
|
||||
end
|
||||
|
||||
|
||||
if LABEL_LIST_RE =~ active_line
|
||||
offset = margin + $1.length
|
||||
prefix = $2
|
||||
prefix_length = prefix.length
|
||||
|
||||
next if handled_labeled_list(line, level, margin, offset, prefix)
|
||||
end
|
||||
|
||||
# Headings look like
|
||||
# = Main heading
|
||||
# == Second level
|
||||
# === Third
|
||||
#
|
||||
# Headings reset the level to 0
|
||||
|
||||
if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/
|
||||
prefix_length = $1.length
|
||||
prefix_length = 6 if prefix_length > 6
|
||||
line.stamp(Line::HEADING, 0, prefix_length)
|
||||
line.strip_leading(margin + prefix_length)
|
||||
next
|
||||
end
|
||||
|
||||
# If the character's a space, then we have verbatim text,
|
||||
# otherwise
|
||||
|
||||
if active_line[0] == SPACE
|
||||
line.strip_leading(margin) if margin > 0
|
||||
line.stamp(Line::VERBATIM, level)
|
||||
else
|
||||
line.stamp(Line::PARAGRAPH, level)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Handle labeled list entries, We have a special case to deal with.
|
||||
# Because the labels can be long, they force the remaining block of text
|
||||
# over the to right:
|
||||
#
|
||||
# this is a long label that I wrote:: and here is the
|
||||
# block of text with
|
||||
# a silly margin
|
||||
#
|
||||
# So we allow the special case. If the label is followed by nothing, and
|
||||
# if the following line is indented, then we take the indent of that line
|
||||
# as the new margin.
|
||||
#
|
||||
# this is a long label that I wrote::
|
||||
# here is a more reasonably indented block which
|
||||
# will be attached to the label.
|
||||
#
|
||||
|
||||
def handled_labeled_list(line, level, margin, offset, prefix)
|
||||
prefix_length = prefix.length
|
||||
text = line.text
|
||||
flag = nil
|
||||
case prefix
|
||||
when /^\[/
|
||||
flag = ListBase::LABELED
|
||||
prefix = prefix[1, prefix.length-2]
|
||||
when /:$/
|
||||
flag = ListBase::NOTE
|
||||
prefix.chop!
|
||||
else raise "Invalid List Type: #{self.inspect}"
|
||||
end
|
||||
|
||||
# body is on the next line
|
||||
|
||||
if text.length <= offset
|
||||
original_line = line
|
||||
line = @lines.next
|
||||
return(false) unless line
|
||||
text = line.text
|
||||
|
||||
for i in 0..margin
|
||||
if text[i] != SPACE
|
||||
@lines.unget
|
||||
return false
|
||||
end
|
||||
end
|
||||
i = margin
|
||||
i += 1 while text[i] == SPACE
|
||||
if i >= text.length
|
||||
@lines.unget
|
||||
return false
|
||||
else
|
||||
offset = i
|
||||
prefix_length = 0
|
||||
@lines.delete(original_line)
|
||||
end
|
||||
end
|
||||
|
||||
line.stamp(Line::LIST, level+1, prefix, flag)
|
||||
text[margin, prefix_length] = " " * prefix_length
|
||||
assign_types_to_lines(offset, level + 1)
|
||||
return true
|
||||
end
|
||||
|
||||
##
|
||||
# Return a block consisting of fragments which are paragraphs, list
|
||||
# entries or verbatim text. We merge consecutive lines of the same type
|
||||
# and level together. We are also slightly tricky with lists: the lines
|
||||
# following a list introduction look like paragraph lines at the next
|
||||
# level, and we remap them into list entries instead.
|
||||
|
||||
def group_lines
|
||||
@lines.rewind
|
||||
|
||||
inList = false
|
||||
wantedType = wantedLevel = nil
|
||||
|
||||
block = LineCollection.new
|
||||
group = nil
|
||||
|
||||
while line = @lines.next
|
||||
if line.level == wantedLevel and line.type == wantedType
|
||||
group.add_text(line.text)
|
||||
else
|
||||
group = block.fragment_for(line)
|
||||
block.add(group)
|
||||
if line.type == Line::LIST
|
||||
wantedType = Line::PARAGRAPH
|
||||
else
|
||||
wantedType = line.type
|
||||
end
|
||||
wantedLevel = line.type == Line::HEADING ? line.param : line.level
|
||||
end
|
||||
end
|
||||
|
||||
block.normalize
|
||||
block
|
||||
end
|
||||
|
||||
##
|
||||
# For debugging, we allow access to our line contents as text.
|
||||
|
||||
def content
|
||||
@lines.as_text
|
||||
end
|
||||
public :content
|
||||
|
||||
##
|
||||
# For debugging, return the list of line types.
|
||||
|
||||
def get_line_types
|
||||
@lines.line_types
|
||||
end
|
||||
public :get_line_types
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
module SM
|
||||
|
||||
##
|
||||
# Handle common directives that can occur in a block of text:
|
||||
#
|
||||
# : include : filename
|
||||
|
||||
class PreProcess
|
||||
|
||||
def initialize(input_file_name, include_path)
|
||||
@input_file_name = input_file_name
|
||||
@include_path = include_path
|
||||
end
|
||||
|
||||
##
|
||||
# Look for common options in a chunk of text. Options that we don't handle
|
||||
# are passed back to our caller as |directive, param|
|
||||
|
||||
def handle(text)
|
||||
text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
|
||||
prefix = $1
|
||||
directive = $2.downcase
|
||||
param = $3
|
||||
|
||||
case directive
|
||||
when "include"
|
||||
filename = param.split[0]
|
||||
include_file(filename, prefix)
|
||||
|
||||
else
|
||||
yield(directive, param)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Include a file, indenting it correctly.
|
||||
|
||||
def include_file(name, indent)
|
||||
if (full_name = find_include_file(name))
|
||||
content = File.open(full_name) {|f| f.read}
|
||||
# strip leading '#'s, but only if all lines start with them
|
||||
if content =~ /^[^#]/
|
||||
content.gsub(/^/, indent)
|
||||
else
|
||||
content.gsub(/^#?/, indent)
|
||||
end
|
||||
else
|
||||
$stderr.puts "Couldn't find file to include: '#{name}'"
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Look for the given file in the directory containing the current file,
|
||||
# and then in each of the directories specified in the RDOC_INCLUDE path
|
||||
|
||||
def find_include_file(name)
|
||||
to_search = [ File.dirname(@input_file_name) ].concat @include_path
|
||||
to_search.each do |dir|
|
||||
full_name = File.join(dir, name)
|
||||
stat = File.stat(full_name) rescue next
|
||||
return full_name if stat.readable?
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
require 'rdoc/markup/simple_markup/fragments'
|
||||
require 'rdoc/markup/simple_markup/inline'
|
||||
|
||||
require 'cgi'
|
||||
|
||||
module SM
|
||||
|
||||
class ToHtml
|
||||
|
||||
LIST_TYPE_TO_HTML = {
|
||||
ListBase::BULLET => [ "<ul>", "</ul>" ],
|
||||
ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
||||
ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
||||
ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
||||
ListBase::LABELED => [ "<dl>", "</dl>" ],
|
||||
ListBase::NOTE => [ "<table>", "</table>" ],
|
||||
}
|
||||
|
||||
InlineTag = Struct.new(:bit, :on, :off)
|
||||
|
||||
def initialize
|
||||
init_tags
|
||||
end
|
||||
|
||||
##
|
||||
# Set up the standard mapping of attributes to HTML tags
|
||||
|
||||
def init_tags
|
||||
@attr_tags = [
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new set of HTML tags for an attribute. We allow separate start and
|
||||
# end tags for flexibility.
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
@attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
|
||||
end
|
||||
|
||||
##
|
||||
# Given an HTML tag, decorate it with class information and the like if
|
||||
# required. This is a no-op in the base class, but is overridden in HTML
|
||||
# output classes that implement style sheets.
|
||||
|
||||
def annotate(tag)
|
||||
tag
|
||||
end
|
||||
|
||||
##
|
||||
# Here's the client side of the visitor pattern
|
||||
|
||||
def start_accepting
|
||||
@res = ""
|
||||
@in_list_entry = []
|
||||
end
|
||||
|
||||
def end_accepting
|
||||
@res
|
||||
end
|
||||
|
||||
def accept_paragraph(am, fragment)
|
||||
@res << annotate("<p>") + "\n"
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt)))
|
||||
@res << annotate("</p>") + "\n"
|
||||
end
|
||||
|
||||
def accept_verbatim(am, fragment)
|
||||
@res << annotate("<pre>") + "\n"
|
||||
@res << CGI.escapeHTML(fragment.txt)
|
||||
@res << annotate("</pre>") << "\n"
|
||||
end
|
||||
|
||||
def accept_rule(am, fragment)
|
||||
size = fragment.param
|
||||
size = 10 if size > 10
|
||||
@res << "<hr size=\"#{size}\"></hr>"
|
||||
end
|
||||
|
||||
def accept_list_start(am, fragment)
|
||||
@res << html_list_name(fragment.type, true) << "\n"
|
||||
@in_list_entry.push false
|
||||
end
|
||||
|
||||
def accept_list_end(am, fragment)
|
||||
if tag = @in_list_entry.pop
|
||||
@res << annotate(tag) << "\n"
|
||||
end
|
||||
@res << html_list_name(fragment.type, false) << "\n"
|
||||
end
|
||||
|
||||
def accept_list_item(am, fragment)
|
||||
if tag = @in_list_entry.last
|
||||
@res << annotate(tag) << "\n"
|
||||
end
|
||||
@res << list_item_start(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
|
||||
@in_list_entry[-1] = list_end_for(fragment.type)
|
||||
end
|
||||
|
||||
def accept_blank_line(am, fragment)
|
||||
# @res << annotate("<p />") << "\n"
|
||||
end
|
||||
|
||||
def accept_heading(am, fragment)
|
||||
@res << convert_heading(fragment.head_level, am.flow(fragment.txt))
|
||||
end
|
||||
|
||||
##
|
||||
# This is a higher speed (if messier) version of wrap
|
||||
|
||||
def wrap(txt, line_len = 76)
|
||||
res = ""
|
||||
sp = 0
|
||||
ep = txt.length
|
||||
while sp < ep
|
||||
# scan back for a space
|
||||
p = sp + line_len - 1
|
||||
if p >= ep
|
||||
p = ep
|
||||
else
|
||||
while p > sp and txt[p] != ?\s
|
||||
p -= 1
|
||||
end
|
||||
if p <= sp
|
||||
p = sp + line_len
|
||||
while p < ep and txt[p] != ?\s
|
||||
p += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
res << txt[sp...p] << "\n"
|
||||
sp = p
|
||||
sp += 1 while sp < ep and txt[sp] == ?\s
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_tags(res, item)
|
||||
attr_mask = item.turn_on
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << annotate(tag.on)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def off_tags(res, item)
|
||||
attr_mask = item.turn_off
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.reverse_each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << annotate(tag.off)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def convert_flow(flow)
|
||||
res = ""
|
||||
flow.each do |item|
|
||||
case item
|
||||
when String
|
||||
res << convert_string(item)
|
||||
when AttrChanger
|
||||
off_tags(res, item)
|
||||
on_tags(res, item)
|
||||
when Special
|
||||
res << convert_special(item)
|
||||
else
|
||||
raise "Unknown flow element: #{item.inspect}"
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
##
|
||||
# some of these patterns are taken from SmartyPants...
|
||||
|
||||
def convert_string(item)
|
||||
CGI.escapeHTML(item).
|
||||
|
||||
# convert -- to em-dash, (-- to en-dash)
|
||||
gsub(/---?/, '—'). #gsub(/--/, '–').
|
||||
|
||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||
gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
|
||||
|
||||
# convert single closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1’" }.
|
||||
gsub(%r{\'(?=\W|s\b)}) { "’" }.
|
||||
|
||||
# convert single opening quote
|
||||
gsub(/'/, '‘').
|
||||
|
||||
# convert double closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1”" }.
|
||||
|
||||
# convert double opening quote
|
||||
gsub(/'/, '“').
|
||||
|
||||
# convert copyright
|
||||
gsub(/\(c\)/, '©').
|
||||
|
||||
# convert and registered trademark
|
||||
gsub(/\(r\)/, '®')
|
||||
|
||||
end
|
||||
|
||||
def convert_special(special)
|
||||
handled = false
|
||||
Attribute.each_name_of(special.type) do |name|
|
||||
method_name = "handle_special_#{name}"
|
||||
if self.respond_to? method_name
|
||||
special.text = send(method_name, special)
|
||||
handled = true
|
||||
end
|
||||
end
|
||||
raise "Unhandled special: #{special}" unless handled
|
||||
special.text
|
||||
end
|
||||
|
||||
def convert_heading(level, flow)
|
||||
res =
|
||||
annotate("<h#{level}>") +
|
||||
convert_flow(flow) +
|
||||
annotate("</h#{level}>\n")
|
||||
end
|
||||
|
||||
def html_list_name(list_type, is_open_tag)
|
||||
tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
|
||||
annotate(tags[ is_open_tag ? 0 : 1])
|
||||
end
|
||||
|
||||
def list_item_start(am, fragment)
|
||||
case fragment.type
|
||||
when ListBase::BULLET, ListBase::NUMBER
|
||||
annotate("<li>")
|
||||
|
||||
when ListBase::UPPERALPHA
|
||||
annotate("<li type=\"A\">")
|
||||
|
||||
when ListBase::LOWERALPHA
|
||||
annotate("<li type=\"a\">")
|
||||
|
||||
when ListBase::LABELED
|
||||
annotate("<dt>") +
|
||||
convert_flow(am.flow(fragment.param)) +
|
||||
annotate("</dt>") +
|
||||
annotate("<dd>")
|
||||
|
||||
when ListBase::NOTE
|
||||
annotate("<tr>") +
|
||||
annotate("<td valign=\"top\">") +
|
||||
convert_flow(am.flow(fragment.param)) +
|
||||
annotate("</td>") +
|
||||
annotate("<td>")
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
def list_end_for(fragment_type)
|
||||
case fragment_type
|
||||
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
|
||||
ListBase::LOWERALPHA
|
||||
"</li>"
|
||||
when ListBase::LABELED
|
||||
"</dd>"
|
||||
when ListBase::NOTE
|
||||
"</td></tr>"
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,332 +0,0 @@
|
|||
require 'rdoc/markup/simple_markup/fragments'
|
||||
require 'rdoc/markup/simple_markup/inline'
|
||||
|
||||
require 'cgi'
|
||||
|
||||
module SM
|
||||
|
||||
# Convert SimpleMarkup to basic LaTeX report format
|
||||
|
||||
class ToLaTeX
|
||||
|
||||
BS = "\020" # \
|
||||
OB = "\021" # {
|
||||
CB = "\022" # }
|
||||
DL = "\023" # Dollar
|
||||
|
||||
BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
|
||||
HAT = "#{BS}symbol#{OB}94#{CB}"
|
||||
BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
|
||||
TILDE = "#{DL}#{BS}sim#{DL}"
|
||||
LESSTHAN = "#{DL}<#{DL}"
|
||||
GREATERTHAN = "#{DL}>#{DL}"
|
||||
|
||||
def self.l(str)
|
||||
str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
|
||||
end
|
||||
|
||||
def l(arg)
|
||||
SM::ToLaTeX.l(arg)
|
||||
end
|
||||
|
||||
LIST_TYPE_TO_LATEX = {
|
||||
ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
|
||||
ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
|
||||
ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
|
||||
ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
|
||||
ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
|
||||
ListBase::NOTE => [
|
||||
l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
|
||||
l("\\end{tabularx}") ],
|
||||
}
|
||||
|
||||
InlineTag = Struct.new(:bit, :on, :off)
|
||||
|
||||
def initialize
|
||||
init_tags
|
||||
@list_depth = 0
|
||||
@prev_list_types = []
|
||||
end
|
||||
|
||||
##
|
||||
# Set up the standard mapping of attributes to LaTeX
|
||||
|
||||
def init_tags
|
||||
@attr_tags = [
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Escape a LaTeX string
|
||||
|
||||
def escape(str)
|
||||
# $stderr.print "FE: ", str
|
||||
s = str.
|
||||
# sub(/\s+$/, '').
|
||||
gsub(/([_\${}&%#])/, "#{BS}\\1").
|
||||
gsub(/\\/, BACKSLASH).
|
||||
gsub(/\^/, HAT).
|
||||
gsub(/~/, TILDE).
|
||||
gsub(/</, LESSTHAN).
|
||||
gsub(/>/, GREATERTHAN).
|
||||
gsub(/,,/, ",{},").
|
||||
gsub(/\`/, BACKQUOTE)
|
||||
# $stderr.print "-> ", s, "\n"
|
||||
s
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new set of LaTeX tags for an attribute. We allow
|
||||
# separate start and end tags for flexibility
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
@attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
|
||||
end
|
||||
|
||||
##
|
||||
# Here's the client side of the visitor pattern
|
||||
|
||||
def start_accepting
|
||||
@res = ""
|
||||
@in_list_entry = []
|
||||
end
|
||||
|
||||
def end_accepting
|
||||
@res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
|
||||
end
|
||||
|
||||
def accept_paragraph(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt)))
|
||||
@res << "\n"
|
||||
end
|
||||
|
||||
def accept_verbatim(am, fragment)
|
||||
@res << "\n\\begin{code}\n"
|
||||
@res << fragment.txt.sub(/[\n\s]+\Z/, '')
|
||||
@res << "\n\\end{code}\n\n"
|
||||
end
|
||||
|
||||
def accept_rule(am, fragment)
|
||||
size = fragment.param
|
||||
size = 10 if size > 10
|
||||
@res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
|
||||
end
|
||||
|
||||
def accept_list_start(am, fragment)
|
||||
@res << list_name(fragment.type, true) << "\n"
|
||||
@in_list_entry.push false
|
||||
end
|
||||
|
||||
def accept_list_end(am, fragment)
|
||||
if tag = @in_list_entry.pop
|
||||
@res << tag << "\n"
|
||||
end
|
||||
@res << list_name(fragment.type, false) << "\n"
|
||||
end
|
||||
|
||||
def accept_list_item(am, fragment)
|
||||
if tag = @in_list_entry.last
|
||||
@res << tag << "\n"
|
||||
end
|
||||
@res << list_item_start(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
|
||||
@in_list_entry[-1] = list_end_for(fragment.type)
|
||||
end
|
||||
|
||||
def accept_blank_line(am, fragment)
|
||||
# @res << "\n"
|
||||
end
|
||||
|
||||
def accept_heading(am, fragment)
|
||||
@res << convert_heading(fragment.head_level, am.flow(fragment.txt))
|
||||
end
|
||||
|
||||
##
|
||||
# This is a higher speed (if messier) version of wrap
|
||||
|
||||
def wrap(txt, line_len = 76)
|
||||
res = ""
|
||||
sp = 0
|
||||
ep = txt.length
|
||||
while sp < ep
|
||||
# scan back for a space
|
||||
p = sp + line_len - 1
|
||||
if p >= ep
|
||||
p = ep
|
||||
else
|
||||
while p > sp and txt[p] != ?\s
|
||||
p -= 1
|
||||
end
|
||||
if p <= sp
|
||||
p = sp + line_len
|
||||
while p < ep and txt[p] != ?\s
|
||||
p += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
res << txt[sp...p] << "\n"
|
||||
sp = p
|
||||
sp += 1 while sp < ep and txt[sp] == ?\s
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_tags(res, item)
|
||||
attr_mask = item.turn_on
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << tag.on
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def off_tags(res, item)
|
||||
attr_mask = item.turn_off
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.reverse_each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << tag.off
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def convert_flow(flow)
|
||||
res = ""
|
||||
flow.each do |item|
|
||||
case item
|
||||
when String
|
||||
# $stderr.puts "Converting '#{item}'"
|
||||
res << convert_string(item)
|
||||
when AttrChanger
|
||||
off_tags(res, item)
|
||||
on_tags(res, item)
|
||||
when Special
|
||||
res << convert_special(item)
|
||||
else
|
||||
raise "Unknown flow element: #{item.inspect}"
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
##
|
||||
# some of these patterns are taken from SmartyPants...
|
||||
|
||||
def convert_string(item)
|
||||
escape(item).
|
||||
|
||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||
gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
|
||||
|
||||
# convert single closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }.
|
||||
gsub(%r{\'(?=\W|s\b)}) { "'" }.
|
||||
|
||||
# convert single opening quote
|
||||
gsub(/'/, '`').
|
||||
|
||||
# convert double closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }.
|
||||
|
||||
# convert double opening quote
|
||||
gsub(/"/, "``").
|
||||
|
||||
# convert copyright
|
||||
gsub(/\(c\)/, '\copyright{}')
|
||||
|
||||
end
|
||||
|
||||
def convert_special(special)
|
||||
handled = false
|
||||
Attribute.each_name_of(special.type) do |name|
|
||||
method_name = "handle_special_#{name}"
|
||||
if self.respond_to? method_name
|
||||
special.text = send(method_name, special)
|
||||
handled = true
|
||||
end
|
||||
end
|
||||
raise "Unhandled special: #{special}" unless handled
|
||||
special.text
|
||||
end
|
||||
|
||||
def convert_heading(level, flow)
|
||||
res =
|
||||
case level
|
||||
when 1 then "\\chapter{"
|
||||
when 2 then "\\section{"
|
||||
when 3 then "\\subsection{"
|
||||
when 4 then "\\subsubsection{"
|
||||
else "\\paragraph{"
|
||||
end +
|
||||
convert_flow(flow) +
|
||||
"}\n"
|
||||
end
|
||||
|
||||
def list_name(list_type, is_open_tag)
|
||||
tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
|
||||
if tags[2] # enumerate
|
||||
if is_open_tag
|
||||
@list_depth += 1
|
||||
if @prev_list_types[@list_depth] != tags[2]
|
||||
case @list_depth
|
||||
when 1
|
||||
roman = "i"
|
||||
when 2
|
||||
roman = "ii"
|
||||
when 3
|
||||
roman = "iii"
|
||||
when 4
|
||||
roman = "iv"
|
||||
else
|
||||
raise("Too deep list: level #{@list_depth}")
|
||||
end
|
||||
@prev_list_types[@list_depth] = tags[2]
|
||||
return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
|
||||
end
|
||||
else
|
||||
@list_depth -= 1
|
||||
end
|
||||
end
|
||||
tags[ is_open_tag ? 0 : 1]
|
||||
end
|
||||
|
||||
def list_item_start(am, fragment)
|
||||
case fragment.type
|
||||
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
|
||||
ListBase::LOWERALPHA
|
||||
"\\item "
|
||||
|
||||
when ListBase::LABELED
|
||||
"\\item[" + convert_flow(am.flow(fragment.param)) + "] "
|
||||
|
||||
when ListBase::NOTE
|
||||
convert_flow(am.flow(fragment.param)) + " & "
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
def list_end_for(fragment_type)
|
||||
case fragment_type
|
||||
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
|
||||
ListBase::LOWERALPHA, ListBase::LABELED
|
||||
""
|
||||
when ListBase::NOTE
|
||||
"\\\\\n"
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
require 'rdoc/markup/simple_markup/fragments'
|
||||
require 'rdoc/markup/simple_markup/inline'
|
||||
require 'rdoc/markup/fragments'
|
||||
require 'rdoc/markup/inline'
|
||||
require 'cgi'
|
||||
|
||||
module SM
|
||||
class RDoc::Markup
|
||||
|
||||
module Flow
|
||||
P = Struct.new(:body)
|
||||
|
@ -24,12 +24,12 @@ module SM
|
|||
|
||||
class ToFlow
|
||||
LIST_TYPE_TO_HTML = {
|
||||
SM::ListBase::BULLET => [ "<ul>", "</ul>" ],
|
||||
SM::ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
||||
SM::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
||||
SM::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
||||
SM::ListBase::LABELED => [ "<dl>", "</dl>" ],
|
||||
SM::ListBase::NOTE => [ "<table>", "</table>" ],
|
||||
RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
|
||||
RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
|
||||
RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
|
||||
}
|
||||
|
||||
InlineTag = Struct.new(:bit, :on, :off)
|
||||
|
@ -43,9 +43,9 @@ module SM
|
|||
|
||||
def init_tags
|
||||
@attr_tags = [
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
||||
InlineTag.new(SM::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -54,7 +54,7 @@ module SM
|
|||
# end tags for flexibility
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
@attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop)
|
||||
@attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
|
||||
end
|
||||
|
||||
##
|
286
lib/rdoc/markup/to_html.rb
Normal file
286
lib/rdoc/markup/to_html.rb
Normal file
|
@ -0,0 +1,286 @@
|
|||
require 'rdoc/markup/fragments'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
require 'cgi'
|
||||
|
||||
class RDoc::Markup::ToHtml
|
||||
|
||||
LIST_TYPE_TO_HTML = {
|
||||
RDoc::Markup::ListBase::BULLET => [ "<ul>", "</ul>" ],
|
||||
RDoc::Markup::ListBase::NUMBER => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::UPPERALPHA => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::LOWERALPHA => [ "<ol>", "</ol>" ],
|
||||
RDoc::Markup::ListBase::LABELED => [ "<dl>", "</dl>" ],
|
||||
RDoc::Markup::ListBase::NOTE => [ "<table>", "</table>" ],
|
||||
}
|
||||
|
||||
InlineTag = Struct.new(:bit, :on, :off)
|
||||
|
||||
def initialize
|
||||
init_tags
|
||||
end
|
||||
|
||||
##
|
||||
# Set up the standard mapping of attributes to HTML tags
|
||||
|
||||
def init_tags
|
||||
@attr_tags = [
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new set of HTML tags for an attribute. We allow separate start and
|
||||
# end tags for flexibility.
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
@attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
|
||||
end
|
||||
|
||||
##
|
||||
# Given an HTML tag, decorate it with class information and the like if
|
||||
# required. This is a no-op in the base class, but is overridden in HTML
|
||||
# output classes that implement style sheets.
|
||||
|
||||
def annotate(tag)
|
||||
tag
|
||||
end
|
||||
|
||||
##
|
||||
# Here's the client side of the visitor pattern
|
||||
|
||||
def start_accepting
|
||||
@res = ""
|
||||
@in_list_entry = []
|
||||
end
|
||||
|
||||
def end_accepting
|
||||
@res
|
||||
end
|
||||
|
||||
def accept_paragraph(am, fragment)
|
||||
@res << annotate("<p>") + "\n"
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt)))
|
||||
@res << annotate("</p>") + "\n"
|
||||
end
|
||||
|
||||
def accept_verbatim(am, fragment)
|
||||
@res << annotate("<pre>") + "\n"
|
||||
@res << CGI.escapeHTML(fragment.txt)
|
||||
@res << annotate("</pre>") << "\n"
|
||||
end
|
||||
|
||||
def accept_rule(am, fragment)
|
||||
size = fragment.param
|
||||
size = 10 if size > 10
|
||||
@res << "<hr size=\"#{size}\"></hr>"
|
||||
end
|
||||
|
||||
def accept_list_start(am, fragment)
|
||||
@res << html_list_name(fragment.type, true) << "\n"
|
||||
@in_list_entry.push false
|
||||
end
|
||||
|
||||
def accept_list_end(am, fragment)
|
||||
if tag = @in_list_entry.pop
|
||||
@res << annotate(tag) << "\n"
|
||||
end
|
||||
@res << html_list_name(fragment.type, false) << "\n"
|
||||
end
|
||||
|
||||
def accept_list_item(am, fragment)
|
||||
if tag = @in_list_entry.last
|
||||
@res << annotate(tag) << "\n"
|
||||
end
|
||||
@res << list_item_start(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
|
||||
@in_list_entry[-1] = list_end_for(fragment.type)
|
||||
end
|
||||
|
||||
def accept_blank_line(am, fragment)
|
||||
# @res << annotate("<p />") << "\n"
|
||||
end
|
||||
|
||||
def accept_heading(am, fragment)
|
||||
@res << convert_heading(fragment.head_level, am.flow(fragment.txt))
|
||||
end
|
||||
|
||||
##
|
||||
# This is a higher speed (if messier) version of wrap
|
||||
|
||||
def wrap(txt, line_len = 76)
|
||||
res = ""
|
||||
sp = 0
|
||||
ep = txt.length
|
||||
while sp < ep
|
||||
# scan back for a space
|
||||
p = sp + line_len - 1
|
||||
if p >= ep
|
||||
p = ep
|
||||
else
|
||||
while p > sp and txt[p] != ?\s
|
||||
p -= 1
|
||||
end
|
||||
if p <= sp
|
||||
p = sp + line_len
|
||||
while p < ep and txt[p] != ?\s
|
||||
p += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
res << txt[sp...p] << "\n"
|
||||
sp = p
|
||||
sp += 1 while sp < ep and txt[sp] == ?\s
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_tags(res, item)
|
||||
attr_mask = item.turn_on
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << annotate(tag.on)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def off_tags(res, item)
|
||||
attr_mask = item.turn_off
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.reverse_each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << annotate(tag.off)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def convert_flow(flow)
|
||||
res = ""
|
||||
|
||||
flow.each do |item|
|
||||
case item
|
||||
when String
|
||||
res << convert_string(item)
|
||||
when RDoc::Markup::AttrChanger
|
||||
off_tags(res, item)
|
||||
on_tags(res, item)
|
||||
when RDoc::Markup::Special
|
||||
res << convert_special(item)
|
||||
else
|
||||
raise "Unknown flow element: #{item.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
res
|
||||
end
|
||||
|
||||
##
|
||||
# some of these patterns are taken from SmartyPants...
|
||||
|
||||
def convert_string(item)
|
||||
CGI.escapeHTML(item).
|
||||
|
||||
# convert -- to em-dash, (-- to en-dash)
|
||||
gsub(/---?/, '—'). #gsub(/--/, '–').
|
||||
|
||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||
gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…').
|
||||
|
||||
# convert single closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1’" }.
|
||||
gsub(%r{\'(?=\W|s\b)}) { "’" }.
|
||||
|
||||
# convert single opening quote
|
||||
gsub(/'/, '‘').
|
||||
|
||||
# convert double closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1”" }.
|
||||
|
||||
# convert double opening quote
|
||||
gsub(/'/, '“').
|
||||
|
||||
# convert copyright
|
||||
gsub(/\(c\)/, '©').
|
||||
|
||||
# convert and registered trademark
|
||||
gsub(/\(r\)/, '®')
|
||||
|
||||
end
|
||||
|
||||
def convert_special(special)
|
||||
handled = false
|
||||
RDoc::Markup::Attribute.each_name_of(special.type) do |name|
|
||||
method_name = "handle_special_#{name}"
|
||||
if self.respond_to? method_name
|
||||
special.text = send(method_name, special)
|
||||
handled = true
|
||||
end
|
||||
end
|
||||
raise "Unhandled special: #{special}" unless handled
|
||||
special.text
|
||||
end
|
||||
|
||||
def convert_heading(level, flow)
|
||||
res =
|
||||
annotate("<h#{level}>") +
|
||||
convert_flow(flow) +
|
||||
annotate("</h#{level}>\n")
|
||||
end
|
||||
|
||||
def html_list_name(list_type, is_open_tag)
|
||||
tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
|
||||
annotate(tags[ is_open_tag ? 0 : 1])
|
||||
end
|
||||
|
||||
def list_item_start(am, fragment)
|
||||
case fragment.type
|
||||
when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER then
|
||||
annotate("<li>")
|
||||
|
||||
when RDoc::Markup::ListBase::UPPERALPHA then
|
||||
annotate("<li type=\"A\">")
|
||||
|
||||
when RDoc::Markup::ListBase::LOWERALPHA then
|
||||
annotate("<li type=\"a\">")
|
||||
|
||||
when RDoc::Markup::ListBase::LABELED then
|
||||
annotate("<dt>") +
|
||||
convert_flow(am.flow(fragment.param)) +
|
||||
annotate("</dt>") +
|
||||
annotate("<dd>")
|
||||
|
||||
when RDoc::Markup::ListBase::NOTE then
|
||||
annotate("<tr>") +
|
||||
annotate("<td valign=\"top\">") +
|
||||
convert_flow(am.flow(fragment.param)) +
|
||||
annotate("</td>") +
|
||||
annotate("<td>")
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
def list_end_for(fragment_type)
|
||||
case fragment_type
|
||||
when RDoc::Markup::ListBase::BULLET, RDoc::Markup::ListBase::NUMBER,
|
||||
RDoc::Markup::ListBase::UPPERALPHA,
|
||||
RDoc::Markup::ListBase::LOWERALPHA then
|
||||
"</li>"
|
||||
when RDoc::Markup::ListBase::LABELED then
|
||||
"</dd>"
|
||||
when RDoc::Markup::ListBase::NOTE then
|
||||
"</td></tr>"
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
331
lib/rdoc/markup/to_latex.rb
Normal file
331
lib/rdoc/markup/to_latex.rb
Normal file
|
@ -0,0 +1,331 @@
|
|||
require 'rdoc/markup/fragments'
|
||||
require 'rdoc/markup/inline'
|
||||
|
||||
require 'cgi'
|
||||
|
||||
##
|
||||
# Convert SimpleMarkup to basic LaTeX report format.
|
||||
|
||||
class RDoc::Markup::ToLaTeX
|
||||
|
||||
BS = "\020" # \
|
||||
OB = "\021" # {
|
||||
CB = "\022" # }
|
||||
DL = "\023" # Dollar
|
||||
|
||||
BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
|
||||
HAT = "#{BS}symbol#{OB}94#{CB}"
|
||||
BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
|
||||
TILDE = "#{DL}#{BS}sim#{DL}"
|
||||
LESSTHAN = "#{DL}<#{DL}"
|
||||
GREATERTHAN = "#{DL}>#{DL}"
|
||||
|
||||
def self.l(str)
|
||||
str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
|
||||
end
|
||||
|
||||
def l(arg)
|
||||
RDoc::Markup::ToLaTeX.l(arg)
|
||||
end
|
||||
|
||||
LIST_TYPE_TO_LATEX = {
|
||||
ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
|
||||
ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
|
||||
ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
|
||||
ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
|
||||
ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
|
||||
ListBase::NOTE => [
|
||||
l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
|
||||
l("\\end{tabularx}") ],
|
||||
}
|
||||
|
||||
InlineTag = Struct.new(:bit, :on, :off)
|
||||
|
||||
def initialize
|
||||
init_tags
|
||||
@list_depth = 0
|
||||
@prev_list_types = []
|
||||
end
|
||||
|
||||
##
|
||||
# Set up the standard mapping of attributes to LaTeX
|
||||
|
||||
def init_tags
|
||||
@attr_tags = [
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
|
||||
InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
|
||||
]
|
||||
end
|
||||
|
||||
##
|
||||
# Escape a LaTeX string
|
||||
|
||||
def escape(str)
|
||||
$stderr.print "FE: ", str
|
||||
s = str.
|
||||
sub(/\s+$/, '').
|
||||
gsub(/([_\${}&%#])/, "#{BS}\\1").
|
||||
gsub(/\\/, BACKSLASH).
|
||||
gsub(/\^/, HAT).
|
||||
gsub(/~/, TILDE).
|
||||
gsub(/</, LESSTHAN).
|
||||
gsub(/>/, GREATERTHAN).
|
||||
gsub(/,,/, ",{},").
|
||||
gsub(/\`/, BACKQUOTE)
|
||||
$stderr.print "-> ", s, "\n"
|
||||
s
|
||||
end
|
||||
|
||||
##
|
||||
# Add a new set of LaTeX tags for an attribute. We allow
|
||||
# separate start and end tags for flexibility
|
||||
|
||||
def add_tag(name, start, stop)
|
||||
@attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
|
||||
end
|
||||
|
||||
##
|
||||
# Here's the client side of the visitor pattern
|
||||
|
||||
def start_accepting
|
||||
@res = ""
|
||||
@in_list_entry = []
|
||||
end
|
||||
|
||||
def end_accepting
|
||||
@res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
|
||||
end
|
||||
|
||||
def accept_paragraph(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt)))
|
||||
@res << "\n"
|
||||
end
|
||||
|
||||
def accept_verbatim(am, fragment)
|
||||
@res << "\n\\begin{code}\n"
|
||||
@res << fragment.txt.sub(/[\n\s]+\Z/, '')
|
||||
@res << "\n\\end{code}\n\n"
|
||||
end
|
||||
|
||||
def accept_rule(am, fragment)
|
||||
size = fragment.param
|
||||
size = 10 if size > 10
|
||||
@res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
|
||||
end
|
||||
|
||||
def accept_list_start(am, fragment)
|
||||
@res << list_name(fragment.type, true) << "\n"
|
||||
@in_list_entry.push false
|
||||
end
|
||||
|
||||
def accept_list_end(am, fragment)
|
||||
if tag = @in_list_entry.pop
|
||||
@res << tag << "\n"
|
||||
end
|
||||
@res << list_name(fragment.type, false) << "\n"
|
||||
end
|
||||
|
||||
def accept_list_item(am, fragment)
|
||||
if tag = @in_list_entry.last
|
||||
@res << tag << "\n"
|
||||
end
|
||||
@res << list_item_start(am, fragment)
|
||||
@res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
|
||||
@in_list_entry[-1] = list_end_for(fragment.type)
|
||||
end
|
||||
|
||||
def accept_blank_line(am, fragment)
|
||||
# @res << "\n"
|
||||
end
|
||||
|
||||
def accept_heading(am, fragment)
|
||||
@res << convert_heading(fragment.head_level, am.flow(fragment.txt))
|
||||
end
|
||||
|
||||
##
|
||||
# This is a higher speed (if messier) version of wrap
|
||||
|
||||
def wrap(txt, line_len = 76)
|
||||
res = ""
|
||||
sp = 0
|
||||
ep = txt.length
|
||||
while sp < ep
|
||||
# scan back for a space
|
||||
p = sp + line_len - 1
|
||||
if p >= ep
|
||||
p = ep
|
||||
else
|
||||
while p > sp and txt[p] != ?\s
|
||||
p -= 1
|
||||
end
|
||||
if p <= sp
|
||||
p = sp + line_len
|
||||
while p < ep and txt[p] != ?\s
|
||||
p += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
res << txt[sp...p] << "\n"
|
||||
sp = p
|
||||
sp += 1 while sp < ep and txt[sp] == ?\s
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_tags(res, item)
|
||||
attr_mask = item.turn_on
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << tag.on
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def off_tags(res, item)
|
||||
attr_mask = item.turn_off
|
||||
return if attr_mask.zero?
|
||||
|
||||
@attr_tags.reverse_each do |tag|
|
||||
if attr_mask & tag.bit != 0
|
||||
res << tag.off
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def convert_flow(flow)
|
||||
res = ""
|
||||
flow.each do |item|
|
||||
case item
|
||||
when String
|
||||
$stderr.puts "Converting '#{item}'"
|
||||
res << convert_string(item)
|
||||
when AttrChanger
|
||||
off_tags(res, item)
|
||||
on_tags(res, item)
|
||||
when Special
|
||||
res << convert_special(item)
|
||||
else
|
||||
raise "Unknown flow element: #{item.inspect}"
|
||||
end
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
##
|
||||
# some of these patterns are taken from SmartyPants...
|
||||
|
||||
def convert_string(item)
|
||||
escape(item).
|
||||
|
||||
# convert ... to elipsis (and make sure .... becomes .<elipsis>)
|
||||
gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
|
||||
|
||||
# convert single closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }.
|
||||
gsub(%r{\'(?=\W|s\b)}) { "'" }.
|
||||
|
||||
# convert single opening quote
|
||||
gsub(/'/, '`').
|
||||
|
||||
# convert double closing quote
|
||||
gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }.
|
||||
|
||||
# convert double opening quote
|
||||
gsub(/"/, "``").
|
||||
|
||||
# convert copyright
|
||||
gsub(/\(c\)/, '\copyright{}')
|
||||
|
||||
end
|
||||
|
||||
def convert_special(special)
|
||||
handled = false
|
||||
Attribute.each_name_of(special.type) do |name|
|
||||
method_name = "handle_special_#{name}"
|
||||
if self.respond_to? method_name
|
||||
special.text = send(method_name, special)
|
||||
handled = true
|
||||
end
|
||||
end
|
||||
raise "Unhandled special: #{special}" unless handled
|
||||
special.text
|
||||
end
|
||||
|
||||
def convert_heading(level, flow)
|
||||
res =
|
||||
case level
|
||||
when 1 then "\\chapter{"
|
||||
when 2 then "\\section{"
|
||||
when 3 then "\\subsection{"
|
||||
when 4 then "\\subsubsection{"
|
||||
else "\\paragraph{"
|
||||
end +
|
||||
convert_flow(flow) +
|
||||
"}\n"
|
||||
end
|
||||
|
||||
def list_name(list_type, is_open_tag)
|
||||
tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
|
||||
if tags[2] # enumerate
|
||||
if is_open_tag
|
||||
@list_depth += 1
|
||||
if @prev_list_types[@list_depth] != tags[2]
|
||||
case @list_depth
|
||||
when 1
|
||||
roman = "i"
|
||||
when 2
|
||||
roman = "ii"
|
||||
when 3
|
||||
roman = "iii"
|
||||
when 4
|
||||
roman = "iv"
|
||||
else
|
||||
raise("Too deep list: level #{@list_depth}")
|
||||
end
|
||||
@prev_list_types[@list_depth] = tags[2]
|
||||
return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
|
||||
end
|
||||
else
|
||||
@list_depth -= 1
|
||||
end
|
||||
end
|
||||
tags[ is_open_tag ? 0 : 1]
|
||||
end
|
||||
|
||||
def list_item_start(am, fragment)
|
||||
case fragment.type
|
||||
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
|
||||
ListBase::LOWERALPHA
|
||||
"\\item "
|
||||
|
||||
when ListBase::LABELED
|
||||
"\\item[" + convert_flow(am.flow(fragment.param)) + "] "
|
||||
|
||||
when ListBase::NOTE
|
||||
convert_flow(am.flow(fragment.param)) + " & "
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
def list_end_for(fragment_type)
|
||||
case fragment_type
|
||||
when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA,
|
||||
ListBase::LOWERALPHA, ListBase::LABELED
|
||||
""
|
||||
when ListBase::NOTE
|
||||
"\\\\\n"
|
||||
else
|
||||
raise "Invalid list type"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
d
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue