1
require 'rdoc/markup/simple_markup/lines.rb'
2
#require 'rdoc/markup/simple_markup/to_flow.rb'
7
# A Fragment is a chunk of text, subclassed as a paragraph, a list
8
# entry, or verbatim text
11
attr_reader :level, :param, :txt
14
def initialize(level, param, type, txt)
23
@txt << " " if @txt.length > 0
24
@txt << txt.tr_s("\n ", " ").strip
28
"L#@level: #{self.class.name.split('::')[-1]}\n#@txt"
32
# This is a simple factory system that lets us associate fragement
33
# types (a string) with a subclass of fragment
37
def Fragment.type_name(name)
41
def Fragment.for(line)
42
klass = TYPE_MAP[line.type] ||
43
raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'")
44
return klass.new(line.level, line.param, line.flag, line.text)
49
# A paragraph is a fragment which gets wrapped to fit. We remove all
50
# newlines when we're created, and have them put back on output
52
class Paragraph < Fragment
53
type_name Line::PARAGRAPH
56
class BlankLine < Paragraph
60
class Heading < Paragraph
61
type_name Line::HEADING
69
# A List is a fragment with some kind of label
72
class ListBase < Paragraph
76
UPPERALPHA = :UPPERALPHA
77
LOWERALPHA = :LOWERALPHA
82
class ListItem < ListBase
86
# am = AttributeManager.new(@param)
91
class ListStart < ListBase
92
def initialize(level, param, type)
93
super(level, param, type, nil)
97
class ListEnd < ListBase
98
def initialize(level, type)
99
super(level, "", type, nil)
104
# Verbatim code contains lines that don't get wrapped.
106
class Verbatim < Fragment
107
type_name Line::VERBATIM
110
@txt << txt.chomp << "\n"
117
class Rule < Fragment
122
# Collect groups of lines together. Each group
123
# will end up containing a flow of text
132
@fragments << fragment
141
@fragments.map {|fragment| fragment.to_s}
144
# Factory for different fragment types
145
def fragment_for(*args)
151
change_verbatim_blank_lines
152
add_list_start_and_ends
158
@fragments.join("\n----\n")
161
def accept(am, visitor)
163
visitor.start_accepting
165
@fragments.each do |fragment|
168
visitor.accept_verbatim(am, fragment)
170
visitor.accept_rule(am, fragment)
172
visitor.accept_list_start(am, fragment)
174
visitor.accept_list_end(am, fragment)
176
visitor.accept_list_item(am, fragment)
178
visitor.accept_blank_line(am, fragment)
180
visitor.accept_heading(am, fragment)
182
visitor.accept_paragraph(am, fragment)
186
visitor.end_accepting
194
# normal paragraph text.
200
# You'll end up with the fragments Paragraph, BlankLine,
201
# Verbatim, BlankLine, Verbatim, BlankLine, etc
203
# The BlankLine in the middle of the verbatim chunk needs to
204
# be changed to a real verbatim newline, and the two
205
# verbatim blocks merged
208
def change_verbatim_blank_lines
211
@fragments.each_with_index do |frag, i|
213
frag_block = frag if Verbatim === frag
217
blank_count.times { frag_block.add_text("\n") }
219
frag_block.add_text(frag.txt)
220
@fragments[i] = nil # remove out current fragment
235
# List nesting is implicit given the level of
236
# Make it explicit, just to make life a tad
237
# easier for the output processors
239
def add_list_start_and_ends
244
@fragments.each do |fragment|
245
# $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}"
246
new_level = fragment.level
247
while (level < new_level)
250
res << ListStart.new(level, fragment.param, type) if type
252
# $stderr.puts "Start: #{level}"
255
while level > new_level
256
type = type_stack.pop
257
res << ListEnd.new(level, type) if type
259
# $stderr.puts "End: #{level}, #{type}"
263
level = fragment.level
265
level.downto(1) do |i|
266
type = type_stack.pop
267
res << ListEnd.new(i, type) if type
273
# now insert start/ends between list entries at the
274
# same level that have different element types
282
res.each do |fragment|
285
list_stack.push fragment
287
start = list_stack.pop
288
fragment.type = start.type
291
if fragment.type != l.type
292
@fragments << ListEnd.new(l.level, l.type)
293
start = ListStart.new(l.level, fragment.param, fragment.type)
296
list_stack.push start
301
@fragments << fragment
305
# Finally tidy up the blank lines:
306
# * change Blank/ListEnd into ListEnd/Blank
307
# * remove blank lines at the front
310
(@fragments.size - 1).times do |i|
311
if @fragments[i].kind_of?(BlankLine) and
312
@fragments[i+1].kind_of?(ListEnd)
313
@fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i]
317
# remove leading blanks
318
@fragments.each_with_index do |f, i|
319
break unless f.kind_of? BlankLine