iownbey-rdoc 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +61 -0
  3. data/README.txt +34 -0
  4. data/bin/rdoc +22 -0
  5. data/bin/ri +6 -0
  6. data/lib/rdoc.rb +277 -0
  7. data/lib/rdoc/code_objects.rb +776 -0
  8. data/lib/rdoc/diagram.rb +338 -0
  9. data/lib/rdoc/dot.rb +249 -0
  10. data/lib/rdoc/generator.rb +1050 -0
  11. data/lib/rdoc/generator/chm.rb +113 -0
  12. data/lib/rdoc/generator/chm/chm.rb +98 -0
  13. data/lib/rdoc/generator/html.rb +370 -0
  14. data/lib/rdoc/generator/html/hefss.rb +414 -0
  15. data/lib/rdoc/generator/html/html.rb +704 -0
  16. data/lib/rdoc/generator/html/kilmer.rb +418 -0
  17. data/lib/rdoc/generator/html/one_page_html.rb +121 -0
  18. data/lib/rdoc/generator/ri.rb +229 -0
  19. data/lib/rdoc/generator/texinfo.rb +84 -0
  20. data/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  21. data/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  22. data/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  23. data/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  24. data/lib/rdoc/generator/xml.rb +120 -0
  25. data/lib/rdoc/generator/xml/rdf.rb +113 -0
  26. data/lib/rdoc/generator/xml/xml.rb +111 -0
  27. data/lib/rdoc/markup.rb +473 -0
  28. data/lib/rdoc/markup/attribute_manager.rb +274 -0
  29. data/lib/rdoc/markup/formatter.rb +14 -0
  30. data/lib/rdoc/markup/fragments.rb +337 -0
  31. data/lib/rdoc/markup/inline.rb +101 -0
  32. data/lib/rdoc/markup/lines.rb +152 -0
  33. data/lib/rdoc/markup/preprocess.rb +71 -0
  34. data/lib/rdoc/markup/to_flow.rb +185 -0
  35. data/lib/rdoc/markup/to_html.rb +354 -0
  36. data/lib/rdoc/markup/to_html_crossref.rb +86 -0
  37. data/lib/rdoc/markup/to_latex.rb +328 -0
  38. data/lib/rdoc/markup/to_test.rb +50 -0
  39. data/lib/rdoc/markup/to_texinfo.rb +69 -0
  40. data/lib/rdoc/options.rb +621 -0
  41. data/lib/rdoc/parsers/parse_c.rb +775 -0
  42. data/lib/rdoc/parsers/parse_f95.rb +1841 -0
  43. data/lib/rdoc/parsers/parse_rb.rb +2584 -0
  44. data/lib/rdoc/parsers/parse_simple.rb +40 -0
  45. data/lib/rdoc/parsers/parserfactory.rb +99 -0
  46. data/lib/rdoc/rdoc.rb +277 -0
  47. data/lib/rdoc/ri.rb +4 -0
  48. data/lib/rdoc/ri/cache.rb +188 -0
  49. data/lib/rdoc/ri/descriptions.rb +150 -0
  50. data/lib/rdoc/ri/display.rb +274 -0
  51. data/lib/rdoc/ri/driver.rb +452 -0
  52. data/lib/rdoc/ri/formatter.rb +616 -0
  53. data/lib/rdoc/ri/paths.rb +102 -0
  54. data/lib/rdoc/ri/reader.rb +106 -0
  55. data/lib/rdoc/ri/util.rb +81 -0
  56. data/lib/rdoc/ri/writer.rb +68 -0
  57. data/lib/rdoc/stats.rb +25 -0
  58. data/lib/rdoc/template.rb +64 -0
  59. data/lib/rdoc/tokenstream.rb +33 -0
  60. data/test/test_rdoc_c_parser.rb +261 -0
  61. data/test/test_rdoc_info_formatting.rb +179 -0
  62. data/test/test_rdoc_info_sections.rb +93 -0
  63. data/test/test_rdoc_markup.rb +613 -0
  64. data/test/test_rdoc_markup_attribute_manager.rb +224 -0
  65. data/test/test_rdoc_ri_attribute_formatter.rb +42 -0
  66. data/test/test_rdoc_ri_default_display.rb +295 -0
  67. data/test/test_rdoc_ri_formatter.rb +318 -0
  68. data/test/test_rdoc_ri_overstrike_formatter.rb +69 -0
  69. metadata +142 -0
@@ -0,0 +1,354 @@
1
+ require 'rdoc/markup/formatter'
2
+ require 'rdoc/markup/fragments'
3
+ require 'rdoc/markup/inline'
4
+ require 'rdoc/generator'
5
+
6
+ require 'cgi'
7
+
8
+ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
9
+
10
+ LIST_TYPE_TO_HTML = {
11
+ :BULLET => %w[<ul> </ul>],
12
+ :NUMBER => %w[<ol> </ol>],
13
+ :UPPERALPHA => %w[<ol> </ol>],
14
+ :LOWERALPHA => %w[<ol> </ol>],
15
+ :LABELED => %w[<dl> </dl>],
16
+ :NOTE => %w[<table> </table>],
17
+ }
18
+
19
+ InlineTag = Struct.new(:bit, :on, :off)
20
+
21
+ def initialize
22
+ super
23
+
24
+ # external hyperlinks
25
+ @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
26
+
27
+ # and links of the form <text>[<url>]
28
+ @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
29
+
30
+ init_tags
31
+ end
32
+
33
+ ##
34
+ # Generate a hyperlink for url, labeled with text. Handle the
35
+ # special cases for img: and link: described under handle_special_HYPEDLINK
36
+
37
+ def gen_url(url, text)
38
+ if url =~ /([A-Za-z]+):(.*)/ then
39
+ type = $1
40
+ path = $2
41
+ else
42
+ type = "http"
43
+ path = url
44
+ url = "http://#{url}"
45
+ end
46
+
47
+ if type == "link" then
48
+ url = if path[0, 1] == '#' then # is this meaningful?
49
+ path
50
+ else
51
+ RDoc::Generator.gen_url @from_path, path
52
+ end
53
+ end
54
+
55
+ if (type == "http" or type == "link") and
56
+ url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then
57
+ "<img src=\"#{url}\" />"
58
+ else
59
+ "<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>"
60
+ end
61
+ end
62
+
63
+ ##
64
+ # And we're invoked with a potential external hyperlink mailto:
65
+ # just gets inserted. http: links are checked to see if they
66
+ # reference an image. If so, that image gets inserted using an
67
+ # <img> tag. Otherwise a conventional <a href> is used. We also
68
+ # support a special type of hyperlink, link:, which is a reference
69
+ # to a local file whose path is relative to the --op directory.
70
+
71
+ def handle_special_HYPERLINK(special)
72
+ url = special.text
73
+ gen_url url, url
74
+ end
75
+
76
+ ##
77
+ # Here's a hypedlink where the label is different to the URL
78
+ # <label>[url] or {long label}[url]
79
+
80
+ def handle_special_TIDYLINK(special)
81
+ text = special.text
82
+
83
+ return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
84
+
85
+ label = $1
86
+ url = $2
87
+ gen_url url, label
88
+ end
89
+
90
+ ##
91
+ # Set up the standard mapping of attributes to HTML tags
92
+
93
+ def init_tags
94
+ @attr_tags = [
95
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
96
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
97
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
98
+ ]
99
+ end
100
+
101
+ ##
102
+ # Add a new set of HTML tags for an attribute. We allow separate start and
103
+ # end tags for flexibility.
104
+
105
+ def add_tag(name, start, stop)
106
+ @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
107
+ end
108
+
109
+ ##
110
+ # Given an HTML tag, decorate it with class information and the like if
111
+ # required. This is a no-op in the base class, but is overridden in HTML
112
+ # output classes that implement style sheets.
113
+
114
+ def annotate(tag)
115
+ tag
116
+ end
117
+
118
+ ##
119
+ # Here's the client side of the visitor pattern
120
+
121
+ def start_accepting
122
+ @res = ""
123
+ @in_list_entry = []
124
+ end
125
+
126
+ def end_accepting
127
+ @res
128
+ end
129
+
130
+ def accept_paragraph(am, fragment)
131
+ @res << annotate("<p>") + "\n"
132
+ @res << wrap(convert_flow(am.flow(fragment.txt)))
133
+ @res << annotate("</p>") + "\n"
134
+ end
135
+
136
+ def accept_verbatim(am, fragment)
137
+ @res << annotate("<pre>") + "\n"
138
+ @res << CGI.escapeHTML(fragment.txt)
139
+ @res << annotate("</pre>") << "\n"
140
+ end
141
+
142
+ def accept_rule(am, fragment)
143
+ size = fragment.param
144
+ size = 10 if size > 10
145
+ @res << "<hr size=\"#{size}\"></hr>"
146
+ end
147
+
148
+ def accept_list_start(am, fragment)
149
+ @res << html_list_name(fragment.type, true) << "\n"
150
+ @in_list_entry.push false
151
+ end
152
+
153
+ def accept_list_end(am, fragment)
154
+ if tag = @in_list_entry.pop
155
+ @res << annotate(tag) << "\n"
156
+ end
157
+ @res << html_list_name(fragment.type, false) << "\n"
158
+ end
159
+
160
+ def accept_list_item(am, fragment)
161
+ if tag = @in_list_entry.last
162
+ @res << annotate(tag) << "\n"
163
+ end
164
+
165
+ @res << list_item_start(am, fragment)
166
+
167
+ @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
168
+
169
+ @in_list_entry[-1] = list_end_for(fragment.type)
170
+ end
171
+
172
+ def accept_blank_line(am, fragment)
173
+ # @res << annotate("<p />") << "\n"
174
+ end
175
+
176
+ def accept_heading(am, fragment)
177
+ @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
178
+ end
179
+
180
+ ##
181
+ # This is a higher speed (if messier) version of wrap
182
+
183
+ def wrap(txt, line_len = 76)
184
+ res = ""
185
+ sp = 0
186
+ ep = txt.length
187
+ while sp < ep
188
+ # scan back for a space
189
+ p = sp + line_len - 1
190
+ if p >= ep
191
+ p = ep
192
+ else
193
+ while p > sp and txt[p] != ?\s
194
+ p -= 1
195
+ end
196
+ if p <= sp
197
+ p = sp + line_len
198
+ while p < ep and txt[p] != ?\s
199
+ p += 1
200
+ end
201
+ end
202
+ end
203
+ res << txt[sp...p] << "\n"
204
+ sp = p
205
+ sp += 1 while sp < ep and txt[sp] == ?\s
206
+ end
207
+ res
208
+ end
209
+
210
+ private
211
+
212
+ def on_tags(res, item)
213
+ attr_mask = item.turn_on
214
+ return if attr_mask.zero?
215
+
216
+ @attr_tags.each do |tag|
217
+ if attr_mask & tag.bit != 0
218
+ res << annotate(tag.on)
219
+ end
220
+ end
221
+ end
222
+
223
+ def off_tags(res, item)
224
+ attr_mask = item.turn_off
225
+ return if attr_mask.zero?
226
+
227
+ @attr_tags.reverse_each do |tag|
228
+ if attr_mask & tag.bit != 0
229
+ res << annotate(tag.off)
230
+ end
231
+ end
232
+ end
233
+
234
+ def convert_flow(flow)
235
+ res = ""
236
+
237
+ flow.each do |item|
238
+ case item
239
+ when String
240
+ res << convert_string(item)
241
+ when RDoc::Markup::AttrChanger
242
+ off_tags(res, item)
243
+ on_tags(res, item)
244
+ when RDoc::Markup::Special
245
+ res << convert_special(item)
246
+ else
247
+ raise "Unknown flow element: #{item.inspect}"
248
+ end
249
+ end
250
+
251
+ res
252
+ end
253
+
254
+ ##
255
+ # some of these patterns are taken from SmartyPants...
256
+
257
+ def convert_string(item)
258
+ CGI.escapeHTML(item).
259
+
260
+ # convert -- to em-dash, (-- to en-dash)
261
+ gsub(/---?/, '&#8212;'). #gsub(/--/, '&#8211;').
262
+
263
+ # convert ... to elipsis (and make sure .... becomes .<elipsis>)
264
+ gsub(/\.\.\.\./, '.&#8230;').gsub(/\.\.\./, '&#8230;').
265
+
266
+ # convert single closing quote
267
+ gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1&#8217;').
268
+ gsub(%r{\'(?=\W|s\b)}, '&#8217;').
269
+
270
+ # convert single opening quote
271
+ gsub(/'/, '&#8216;').
272
+
273
+ # convert double closing quote
274
+ gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}, '\1&#8221;').
275
+
276
+ # convert double opening quote
277
+ gsub(/'/, '&#8220;').
278
+
279
+ # convert copyright
280
+ gsub(/\(c\)/, '&#169;').
281
+
282
+ # convert and registered trademark
283
+ gsub(/\(r\)/, '&#174;')
284
+
285
+ end
286
+
287
+ def convert_special(special)
288
+ handled = false
289
+ RDoc::Markup::Attribute.each_name_of(special.type) do |name|
290
+ method_name = "handle_special_#{name}"
291
+ if self.respond_to? method_name
292
+ special.text = send(method_name, special)
293
+ handled = true
294
+ end
295
+ end
296
+ raise "Unhandled special: #{special}" unless handled
297
+ special.text
298
+ end
299
+
300
+ def convert_heading(level, flow)
301
+ res =
302
+ annotate("<h#{level}>") +
303
+ convert_flow(flow) +
304
+ annotate("</h#{level}>\n")
305
+ end
306
+
307
+ def html_list_name(list_type, is_open_tag)
308
+ tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}")
309
+ annotate(tags[ is_open_tag ? 0 : 1])
310
+ end
311
+
312
+ def list_item_start(am, fragment)
313
+ case fragment.type
314
+ when :BULLET, :NUMBER then
315
+ annotate("<li>")
316
+
317
+ when :UPPERALPHA then
318
+ annotate("<li type=\"A\">")
319
+
320
+ when :LOWERALPHA then
321
+ annotate("<li type=\"a\">")
322
+
323
+ when :LABELED then
324
+ annotate("<dt>") +
325
+ convert_flow(am.flow(fragment.param)) +
326
+ annotate("</dt>") +
327
+ annotate("<dd>")
328
+
329
+ when :NOTE then
330
+ annotate("<tr>") +
331
+ annotate("<td valign=\"top\">") +
332
+ convert_flow(am.flow(fragment.param)) +
333
+ annotate("</td>") +
334
+ annotate("<td>")
335
+ else
336
+ raise "Invalid list type"
337
+ end
338
+ end
339
+
340
+ def list_end_for(fragment_type)
341
+ case fragment_type
342
+ when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
343
+ "</li>"
344
+ when :LABELED then
345
+ "</dd>"
346
+ when :NOTE then
347
+ "</td></tr>"
348
+ else
349
+ raise "Invalid list type"
350
+ end
351
+ end
352
+
353
+ end
354
+
@@ -0,0 +1,86 @@
1
+ require 'rdoc/markup/to_html'
2
+
3
+ ##
4
+ # Subclass of the RDoc::Markup::ToHtml class that supports looking up words in
5
+ # the AllReferences list. Those that are found (like AllReferences in this
6
+ # comment) will be hyperlinked
7
+
8
+ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
9
+
10
+ attr_accessor :context
11
+
12
+ ##
13
+ # We need to record the html path of our caller so we can generate
14
+ # correct relative paths for any hyperlinks that we find
15
+
16
+ def initialize(from_path, context, show_hash)
17
+ super()
18
+
19
+ # class names, variable names, or instance variables
20
+ @markup.add_special(/(
21
+ # A::B.meth(**) (for operator in Fortran95)
22
+ \w+(::\w+)*[.\#]\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?
23
+ # meth(**) (for operator in Fortran95)
24
+ | \#\w+(\([.\w\*\/\+\-\=\<\>]+\))?
25
+ | \b([A-Z]\w*(::\w+)*[.\#]\w+) # A::B.meth
26
+ | \b([A-Z]\w+(::\w+)*) # A::B
27
+ | \#\w+[!?=]? # #meth_name
28
+ | \\?\b\w+([_\/\.]+\w+)*[!?=]? # meth_name
29
+ )/x,
30
+ :CROSSREF)
31
+
32
+ @from_path = from_path
33
+ @context = context
34
+ @show_hash = show_hash
35
+
36
+ @seen = {}
37
+ end
38
+
39
+ ##
40
+ # We're invoked when any text matches the CROSSREF pattern
41
+ # (defined in MarkUp). If we fine the corresponding reference,
42
+ # generate a hyperlink. If the name we're looking for contains
43
+ # no punctuation, we look for it up the module/class chain. For
44
+ # example, HyperlinkHtml is found, even without the Generator::
45
+ # prefix, because we look for it in module Generator first.
46
+
47
+ def handle_special_CROSSREF(special)
48
+ name = special.text
49
+
50
+ return @seen[name] if @seen.include? name
51
+
52
+ if name[0,1] == '#' then
53
+ lookup = name[1..-1]
54
+ name = lookup unless @show_hash
55
+ else
56
+ lookup = name
57
+ end
58
+
59
+ # Find class, module, or method in class or module.
60
+ if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup then
61
+ container = $1
62
+ method = $2
63
+ ref = @context.find_symbol container, method
64
+ elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup then
65
+ container = $1
66
+ method = $2
67
+ ref = @context.find_symbol container, method
68
+ else
69
+ ref = @context.find_symbol lookup
70
+ end
71
+
72
+ out = if lookup =~ /^\\/ then
73
+ $'
74
+ elsif ref and ref.document_self then
75
+ "<a href=\"#{ref.as_href(@from_path)}\">#{name}</a>"
76
+ else
77
+ name
78
+ end
79
+
80
+ @seen[name] = out
81
+
82
+ out
83
+ end
84
+
85
+ end
86
+
@@ -0,0 +1,328 @@
1
+ require 'rdoc/markup/formatter'
2
+ require 'rdoc/markup/fragments'
3
+ require 'rdoc/markup/inline'
4
+
5
+ require 'cgi'
6
+
7
+ ##
8
+ # Convert SimpleMarkup to basic LaTeX report format.
9
+
10
+ class RDoc::Markup::ToLaTeX < RDoc::Markup::Formatter
11
+
12
+ BS = "\020" # \
13
+ OB = "\021" # {
14
+ CB = "\022" # }
15
+ DL = "\023" # Dollar
16
+
17
+ BACKSLASH = "#{BS}symbol#{OB}92#{CB}"
18
+ HAT = "#{BS}symbol#{OB}94#{CB}"
19
+ BACKQUOTE = "#{BS}symbol#{OB}0#{CB}"
20
+ TILDE = "#{DL}#{BS}sim#{DL}"
21
+ LESSTHAN = "#{DL}<#{DL}"
22
+ GREATERTHAN = "#{DL}>#{DL}"
23
+
24
+ def self.l(str)
25
+ str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL)
26
+ end
27
+
28
+ def l(arg)
29
+ RDoc::Markup::ToLaTeX.l(arg)
30
+ end
31
+
32
+ LIST_TYPE_TO_LATEX = {
33
+ :BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ],
34
+ :NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ],
35
+ :UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ],
36
+ :LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ],
37
+ :LABELED => [ l("\\begin{description}"), l("\\end{description}") ],
38
+ :NOTE => [
39
+ l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"),
40
+ l("\\end{tabularx}") ],
41
+ }
42
+
43
+ InlineTag = Struct.new(:bit, :on, :off)
44
+
45
+ def initialize
46
+ init_tags
47
+ @list_depth = 0
48
+ @prev_list_types = []
49
+ end
50
+
51
+ ##
52
+ # Set up the standard mapping of attributes to LaTeX
53
+
54
+ def init_tags
55
+ @attr_tags = [
56
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")),
57
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")),
58
+ InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")),
59
+ ]
60
+ end
61
+
62
+ ##
63
+ # Escape a LaTeX string
64
+
65
+ def escape(str)
66
+ $stderr.print "FE: ", str if $DEBUG_RDOC
67
+ s = str.
68
+ sub(/\s+$/, '').
69
+ gsub(/([_\${}&%#])/, "#{BS}\\1").
70
+ gsub(/\\/, BACKSLASH).
71
+ gsub(/\^/, HAT).
72
+ gsub(/~/, TILDE).
73
+ gsub(/</, LESSTHAN).
74
+ gsub(/>/, GREATERTHAN).
75
+ gsub(/,,/, ",{},").
76
+ gsub(/\`/, BACKQUOTE)
77
+ $stderr.print "-> ", s, "\n" if $DEBUG_RDOC
78
+ s
79
+ end
80
+
81
+ ##
82
+ # Add a new set of LaTeX tags for an attribute. We allow
83
+ # separate start and end tags for flexibility
84
+
85
+ def add_tag(name, start, stop)
86
+ @attr_tags << InlineTag.new(RDoc::Markup::Attribute.bitmap_for(name), start, stop)
87
+ end
88
+
89
+ ##
90
+ # Here's the client side of the visitor pattern
91
+
92
+ def start_accepting
93
+ @res = ""
94
+ @in_list_entry = []
95
+ end
96
+
97
+ def end_accepting
98
+ @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$')
99
+ end
100
+
101
+ def accept_paragraph(am, fragment)
102
+ @res << wrap(convert_flow(am.flow(fragment.txt)))
103
+ @res << "\n"
104
+ end
105
+
106
+ def accept_verbatim(am, fragment)
107
+ @res << "\n\\begin{code}\n"
108
+ @res << fragment.txt.sub(/[\n\s]+\Z/, '')
109
+ @res << "\n\\end{code}\n\n"
110
+ end
111
+
112
+ def accept_rule(am, fragment)
113
+ size = fragment.param
114
+ size = 10 if size > 10
115
+ @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n"
116
+ end
117
+
118
+ def accept_list_start(am, fragment)
119
+ @res << list_name(fragment.type, true) << "\n"
120
+ @in_list_entry.push false
121
+ end
122
+
123
+ def accept_list_end(am, fragment)
124
+ if tag = @in_list_entry.pop
125
+ @res << tag << "\n"
126
+ end
127
+ @res << list_name(fragment.type, false) << "\n"
128
+ end
129
+
130
+ def accept_list_item(am, fragment)
131
+ if tag = @in_list_entry.last
132
+ @res << tag << "\n"
133
+ end
134
+ @res << list_item_start(am, fragment)
135
+ @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n"
136
+ @in_list_entry[-1] = list_end_for(fragment.type)
137
+ end
138
+
139
+ def accept_blank_line(am, fragment)
140
+ # @res << "\n"
141
+ end
142
+
143
+ def accept_heading(am, fragment)
144
+ @res << convert_heading(fragment.head_level, am.flow(fragment.txt))
145
+ end
146
+
147
+ ##
148
+ # This is a higher speed (if messier) version of wrap
149
+
150
+ def wrap(txt, line_len = 76)
151
+ res = ""
152
+ sp = 0
153
+ ep = txt.length
154
+ while sp < ep
155
+ # scan back for a space
156
+ p = sp + line_len - 1
157
+ if p >= ep
158
+ p = ep
159
+ else
160
+ while p > sp and txt[p] != ?\s
161
+ p -= 1
162
+ end
163
+ if p <= sp
164
+ p = sp + line_len
165
+ while p < ep and txt[p] != ?\s
166
+ p += 1
167
+ end
168
+ end
169
+ end
170
+ res << txt[sp...p] << "\n"
171
+ sp = p
172
+ sp += 1 while sp < ep and txt[sp] == ?\s
173
+ end
174
+ res
175
+ end
176
+
177
+ private
178
+
179
+ def on_tags(res, item)
180
+ attr_mask = item.turn_on
181
+ return if attr_mask.zero?
182
+
183
+ @attr_tags.each do |tag|
184
+ if attr_mask & tag.bit != 0
185
+ res << tag.on
186
+ end
187
+ end
188
+ end
189
+
190
+ def off_tags(res, item)
191
+ attr_mask = item.turn_off
192
+ return if attr_mask.zero?
193
+
194
+ @attr_tags.reverse_each do |tag|
195
+ if attr_mask & tag.bit != 0
196
+ res << tag.off
197
+ end
198
+ end
199
+ end
200
+
201
+ def convert_flow(flow)
202
+ res = ""
203
+ flow.each do |item|
204
+ case item
205
+ when String
206
+ $stderr.puts "Converting '#{item}'" if $DEBUG_RDOC
207
+ res << convert_string(item)
208
+ when AttrChanger
209
+ off_tags(res, item)
210
+ on_tags(res, item)
211
+ when Special
212
+ res << convert_special(item)
213
+ else
214
+ raise "Unknown flow element: #{item.inspect}"
215
+ end
216
+ end
217
+ res
218
+ end
219
+
220
+ ##
221
+ # some of these patterns are taken from SmartyPants...
222
+
223
+ def convert_string(item)
224
+ escape(item).
225
+
226
+ # convert ... to elipsis (and make sure .... becomes .<elipsis>)
227
+ gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}').
228
+
229
+ # convert single closing quote
230
+ gsub(%r{([^ \t\r\n\[\{\(])\'}, '\1\'').
231
+ gsub(%r{\'(?=\W|s\b)}, "'" ).
232
+
233
+ # convert single opening quote
234
+ gsub(/'/, '`').
235
+
236
+ # convert double closing quote
237
+ gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}, "\\1''").
238
+
239
+ # convert double opening quote
240
+ gsub(/"/, "``").
241
+
242
+ # convert copyright
243
+ gsub(/\(c\)/, '\copyright{}')
244
+
245
+ end
246
+
247
+ def convert_special(special)
248
+ handled = false
249
+ Attribute.each_name_of(special.type) do |name|
250
+ method_name = "handle_special_#{name}"
251
+ if self.respond_to? method_name
252
+ special.text = send(method_name, special)
253
+ handled = true
254
+ end
255
+ end
256
+ raise "Unhandled special: #{special}" unless handled
257
+ special.text
258
+ end
259
+
260
+ def convert_heading(level, flow)
261
+ res =
262
+ case level
263
+ when 1 then "\\chapter{"
264
+ when 2 then "\\section{"
265
+ when 3 then "\\subsection{"
266
+ when 4 then "\\subsubsection{"
267
+ else "\\paragraph{"
268
+ end +
269
+ convert_flow(flow) +
270
+ "}\n"
271
+ end
272
+
273
+ def list_name(list_type, is_open_tag)
274
+ tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}")
275
+ if tags[2] # enumerate
276
+ if is_open_tag
277
+ @list_depth += 1
278
+ if @prev_list_types[@list_depth] != tags[2]
279
+ case @list_depth
280
+ when 1
281
+ roman = "i"
282
+ when 2
283
+ roman = "ii"
284
+ when 3
285
+ roman = "iii"
286
+ when 4
287
+ roman = "iv"
288
+ else
289
+ raise("Too deep list: level #{@list_depth}")
290
+ end
291
+ @prev_list_types[@list_depth] = tags[2]
292
+ return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0]
293
+ end
294
+ else
295
+ @list_depth -= 1
296
+ end
297
+ end
298
+ tags[ is_open_tag ? 0 : 1]
299
+ end
300
+
301
+ def list_item_start(am, fragment)
302
+ case fragment.type
303
+ when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then
304
+ "\\item "
305
+
306
+ when :LABELED then
307
+ "\\item[" + convert_flow(am.flow(fragment.param)) + "] "
308
+
309
+ when :NOTE then
310
+ convert_flow(am.flow(fragment.param)) + " & "
311
+ else
312
+ raise "Invalid list type"
313
+ end
314
+ end
315
+
316
+ def list_end_for(fragment_type)
317
+ case fragment_type
318
+ when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA, :LABELED then
319
+ ""
320
+ when :NOTE
321
+ "\\\\\n"
322
+ else
323
+ raise "Invalid list type"
324
+ end
325
+ end
326
+
327
+ end
328
+