rdoc 7.1.0 → 8.0.0

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -4
  3. data/LICENSE.rdoc +4 -0
  4. data/README.md +43 -2
  5. data/doc/markup_reference/markdown.md +104 -3
  6. data/lib/rdoc/code_object/alias.rb +2 -8
  7. data/lib/rdoc/code_object/any_method.rb +11 -6
  8. data/lib/rdoc/code_object/attr.rb +12 -6
  9. data/lib/rdoc/code_object/class_module.rb +62 -32
  10. data/lib/rdoc/code_object/constant.rb +29 -3
  11. data/lib/rdoc/code_object/context/section.rb +30 -43
  12. data/lib/rdoc/code_object/context.rb +53 -37
  13. data/lib/rdoc/code_object/method_attr.rb +9 -15
  14. data/lib/rdoc/code_object/mixin.rb +3 -0
  15. data/lib/rdoc/code_object/top_level.rb +11 -3
  16. data/lib/rdoc/code_object.rb +2 -4
  17. data/lib/rdoc/comment.rb +1 -66
  18. data/lib/rdoc/cross_reference.rb +8 -30
  19. data/lib/rdoc/encoding.rb +3 -3
  20. data/lib/rdoc/generator/aliki.rb +17 -0
  21. data/lib/rdoc/generator/darkfish.rb +12 -6
  22. data/lib/rdoc/generator/json_index.rb +2 -2
  23. data/lib/rdoc/generator/markup.rb +56 -31
  24. data/lib/rdoc/generator/template/aliki/DESIGN.md +536 -0
  25. data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
  26. data/lib/rdoc/generator/template/aliki/_head.rhtml +6 -1
  27. data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
  28. data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
  29. data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
  30. data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
  31. data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
  32. data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
  33. data/lib/rdoc/generator/template/aliki/class.rhtml +61 -51
  34. data/lib/rdoc/generator/template/aliki/css/rdoc.css +365 -147
  35. data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
  36. data/lib/rdoc/generator/template/aliki/js/aliki.js +28 -20
  37. data/lib/rdoc/generator/template/aliki/js/bash_highlighter.js +167 -0
  38. data/lib/rdoc/generator/template/aliki/js/search_controller.js +1 -1
  39. data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
  40. data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
  41. data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
  42. data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
  43. data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
  44. data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
  45. data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
  46. data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
  47. data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
  48. data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
  49. data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
  50. data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
  51. data/lib/rdoc/i18n/text.rb +3 -3
  52. data/lib/rdoc/markdown.kpeg +36 -17
  53. data/lib/rdoc/markdown.rb +324 -125
  54. data/lib/rdoc/markup/document.rb +2 -2
  55. data/lib/rdoc/markup/formatter.rb +128 -115
  56. data/lib/rdoc/markup/heading.rb +3 -6
  57. data/lib/rdoc/markup/indented_paragraph.rb +1 -1
  58. data/lib/rdoc/markup/inline_parser.rb +312 -0
  59. data/lib/rdoc/markup/list.rb +2 -2
  60. data/lib/rdoc/markup/list_item.rb +2 -2
  61. data/lib/rdoc/markup/parser.rb +1 -1
  62. data/lib/rdoc/markup/pre_process.rb +0 -25
  63. data/lib/rdoc/markup/to_ansi.rb +52 -5
  64. data/lib/rdoc/markup/to_bs.rb +23 -43
  65. data/lib/rdoc/markup/to_html.rb +279 -226
  66. data/lib/rdoc/markup/to_html_crossref.rb +122 -136
  67. data/lib/rdoc/markup/to_html_snippet.rb +65 -65
  68. data/lib/rdoc/markup/to_joined_paragraph.rb +0 -5
  69. data/lib/rdoc/markup/to_label.rb +22 -23
  70. data/lib/rdoc/markup/to_markdown.rb +62 -38
  71. data/lib/rdoc/markup/to_rdoc.rb +88 -28
  72. data/lib/rdoc/markup/to_table_of_contents.rb +1 -1
  73. data/lib/rdoc/markup/to_test.rb +9 -1
  74. data/lib/rdoc/markup/to_tt_only.rb +10 -23
  75. data/lib/rdoc/markup/verbatim.rb +1 -1
  76. data/lib/rdoc/markup.rb +8 -30
  77. data/lib/rdoc/options.rb +36 -51
  78. data/lib/rdoc/parser/c.rb +7 -6
  79. data/lib/rdoc/parser/changelog.rb +21 -0
  80. data/lib/rdoc/parser/rbs.rb +275 -0
  81. data/lib/rdoc/parser/ruby.rb +955 -2067
  82. data/lib/rdoc/parser/ruby_colorizer.rb +253 -0
  83. data/lib/rdoc/parser.rb +3 -2
  84. data/lib/rdoc/rbs_helper.rb +186 -0
  85. data/lib/rdoc/rdoc.rb +196 -24
  86. data/lib/rdoc/ri/driver.rb +8 -2
  87. data/lib/rdoc/ri/paths.rb +1 -1
  88. data/lib/rdoc/{servlet.rb → ri/servlet.rb} +5 -5
  89. data/lib/rdoc/ri.rb +4 -3
  90. data/lib/rdoc/rubygems_hook.rb +11 -11
  91. data/lib/rdoc/server.rb +460 -0
  92. data/lib/rdoc/stats.rb +147 -124
  93. data/lib/rdoc/store.rb +212 -4
  94. data/lib/rdoc/task.rb +16 -15
  95. data/lib/rdoc/text.rb +24 -117
  96. data/lib/rdoc/token_stream.rb +11 -33
  97. data/lib/rdoc/version.rb +1 -1
  98. data/lib/rdoc.rb +35 -7
  99. data/lib/rubygems_plugin.rb +2 -11
  100. data/rdoc-logo.svg +43 -0
  101. data/rdoc.gemspec +6 -4
  102. metadata +37 -23
  103. data/lib/rdoc/code_object/anon_class.rb +0 -10
  104. data/lib/rdoc/code_object/ghost_method.rb +0 -6
  105. data/lib/rdoc/code_object/meta_method.rb +0 -6
  106. data/lib/rdoc/markup/attr_changer.rb +0 -22
  107. data/lib/rdoc/markup/attr_span.rb +0 -35
  108. data/lib/rdoc/markup/attribute_manager.rb +0 -432
  109. data/lib/rdoc/markup/attributes.rb +0 -70
  110. data/lib/rdoc/markup/regexp_handling.rb +0 -40
  111. data/lib/rdoc/parser/prism_ruby.rb +0 -1100
  112. data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
  113. data/lib/rdoc/parser/ruby_tools.rb +0 -163
@@ -8,9 +8,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
8
8
 
9
9
  # :stopdoc:
10
10
  ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP
11
- CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR
12
11
  CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP
13
- METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR
14
12
  # :startdoc:
15
13
 
16
14
  ##
@@ -29,15 +27,19 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
29
27
  # references are removed unless +show_hash+ is true. Only method names
30
28
  # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
31
29
 
32
- def initialize(options, from_path, context, markup = nil)
30
+ def initialize(from_path, context, pipe: false, output_decoration: true,
31
+ hyperlink_all: false, show_hash: false,
32
+ autolink_excluded_words: [], warn_missing_rdoc_ref: true)
33
33
  raise ArgumentError, 'from_path cannot be nil' if from_path.nil?
34
34
 
35
- super options, markup
35
+ super(pipe: pipe, output_decoration: output_decoration)
36
36
 
37
37
  @context = context
38
38
  @from_path = from_path
39
- @hyperlink_all = @options.hyperlink_all
40
- @show_hash = @options.show_hash
39
+ @hyperlink_all = hyperlink_all
40
+ @show_hash = show_hash
41
+ @autolink_excluded_words = autolink_excluded_words
42
+ @warn_missing_rdoc_ref = warn_missing_rdoc_ref
41
43
 
42
44
  @cross_reference = RDoc::CrossReference.new @context
43
45
  end
@@ -48,29 +50,30 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
48
50
 
49
51
  # The crossref must be linked before tidylink because Klass.method[:sym]
50
52
  # will be processed as a tidylink first and will be broken.
51
- crossref_re = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
53
+ crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
52
54
  @markup.add_regexp_handling crossref_re, :CROSSREF
53
-
54
- add_regexp_handling_TIDYLINK
55
55
  end
56
56
 
57
57
  ##
58
58
  # Creates a link to the reference +name+ if the name exists. If +text+ is
59
59
  # given it is used as the link text, otherwise +name+ is used.
60
+ # Returns +nil+ if the link target could not be resolved.
60
61
 
61
62
  def cross_reference(name, text = nil, code = true, rdoc_ref: false)
62
- lookup = name
63
-
64
- name = name[1..-1] unless @show_hash if name[0, 1] == '#'
65
-
66
- if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
67
- text ||= [CGI.unescape($'), (" at <code>#{$1}</code>" if $~.begin(1))].join("")
63
+ # Strip '#' for link display text (e.g. #method shows as "method" in links)
64
+ display = !@show_hash && name.start_with?('#') ? name[1..] : name
65
+
66
+ if !display.end_with?('+@', '-@') && match = display.match(/(.*[^#:])?@(.*)/)
67
+ context_name = match[1]
68
+ label = convert_string(RDoc::Text.decode_legacy_label(match[2]))
69
+ text ||= "#{label} at <code>#{convert_string(context_name)}</code>" if context_name
70
+ text ||= label
68
71
  code = false
69
72
  else
70
- text ||= name
73
+ text ||= convert_string(display)
71
74
  end
72
75
 
73
- link lookup, text, code, rdoc_ref: rdoc_ref
76
+ link(name, text, code, rdoc_ref: rdoc_ref)
74
77
  end
75
78
 
76
79
  ##
@@ -80,10 +83,9 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
80
83
  # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix,
81
84
  # because we look for it in module Markup first.
82
85
 
83
- def handle_regexp_CROSSREF(target)
84
- name = target.text
85
-
86
- return name if @options.autolink_excluded_words&.include?(name)
86
+ def handle_regexp_CROSSREF(name)
87
+ return convert_string(name) if in_tidylink_label?
88
+ return name if @autolink_excluded_words&.include?(name)
87
89
 
88
90
  return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails
89
91
 
@@ -93,20 +95,20 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
93
95
  # cross-references to "new" in text, for instance)
94
96
  return name if name =~ /\A[a-z]*\z/
95
97
  end
96
-
97
- cross_reference name, rdoc_ref: false
98
+ cross_reference(name, rdoc_ref: false) || convert_string(name)
98
99
  end
99
100
 
100
101
  ##
101
102
  # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to
102
103
  # handle other schemes.
103
104
 
104
- def handle_regexp_HYPERLINK(target)
105
- url = target.text
105
+ def handle_regexp_HYPERLINK(url)
106
+ return convert_string(url) if in_tidylink_label?
106
107
 
107
108
  case url
108
109
  when /\Ardoc-ref:/
109
- cross_reference $', rdoc_ref: true
110
+ ref = $'
111
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
110
112
  else
111
113
  super
112
114
  end
@@ -120,12 +122,15 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
120
122
  # All other contents are handled by
121
123
  # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK]
122
124
 
123
- def handle_regexp_RDOCLINK(target)
124
- url = target.text
125
-
125
+ def handle_regexp_RDOCLINK(url)
126
126
  case url
127
127
  when /\Ardoc-ref:/
128
- cross_reference $', rdoc_ref: true
128
+ if in_tidylink_label?
129
+ convert_string(url)
130
+ else
131
+ ref = $'
132
+ cross_reference(ref, rdoc_ref: true) || convert_string(ref)
133
+ end
129
134
  else
130
135
  super
131
136
  end
@@ -138,138 +143,119 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
138
143
  def gen_url(url, text)
139
144
  if url =~ /\Ardoc-ref:/
140
145
  name = $'
141
- cross_reference name, text, name == text, rdoc_ref: true
146
+ cross_reference(name, text, name == text, rdoc_ref: true) || text
142
147
  else
143
148
  super
144
149
  end
145
150
  end
146
151
 
147
152
  ##
148
- # Creates an HTML link to +name+ with the given +text+.
153
+ # Creates an HTML link to +name+ with the given +html_string+.
154
+ # +html_string+ should be already escaped and may contain HTML tags.
155
+ # Returns the link HTML string, or +nil+ if the reference could not be resolved.
149
156
 
150
- def link(name, text, code = true, rdoc_ref: false)
157
+ def link(name, html_string, code = true, rdoc_ref: false)
151
158
  if !(name.end_with?('+@', '-@')) and name =~ /(.*[^#:])?@/
152
159
  name = $1
153
160
  label = $'
154
161
  end
155
162
 
156
- ref = @cross_reference.resolve name, text if name
163
+ ref = @cross_reference.resolve name if name
157
164
 
158
- case ref
159
- when String then
160
- if rdoc_ref && @options.warn_missing_rdoc_ref
161
- puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{text}`"
162
- end
163
- ref
164
- else
165
- path = ref ? ref.as_href(@from_path) : +""
165
+ # Non-text source files (C, Ruby, etc.) don't get HTML pages generated,
166
+ # so don't auto-link to them. Explicit rdoc-ref: links are still allowed.
167
+ if !rdoc_ref && RDoc::TopLevel === ref && !ref.text?
168
+ return
169
+ end
170
+
171
+ if ref
172
+ path = ref.as_href(@from_path)
166
173
 
167
174
  if code and RDoc::CodeObject === ref and !(RDoc::TopLevel === ref)
168
- text = "<code>#{CGI.escapeHTML text}</code>"
175
+ html_string = "<code>#{html_string}</code>"
169
176
  end
170
-
171
- if label
172
- # Convert label to GitHub-style anchor format
173
- # First convert + to space (URL encoding), then apply GitHub-style rules
174
- formatted_label = RDoc::Text.to_anchor(label.tr('+', ' '))
175
-
176
- # Case 1: Path already has an anchor (e.g., method link)
177
- # Input: C1#method@label -> path="C1.html#method-i-m"
178
- # Output: C1.html#method-i-m-label
179
- if path =~ /#/
180
- path << "-#{formatted_label}"
181
-
182
- # Case 2: Label matches a section title
183
- # Input: C1@Section -> path="C1.html", section "Section" exists
184
- # Output: C1.html#section (uses section.aref for GitHub-style)
185
- elsif (section = ref&.sections&.find { |s| label.tr('+', ' ') == s.title })
186
- path << "##{section.aref}"
187
-
188
- # Case 3: Ref has an aref (class/module context)
189
- # Input: C1@heading -> path="C1.html", ref=C1 class
190
- # Output: C1.html#class-c1-heading
191
- elsif ref.respond_to?(:aref)
192
- path << "##{ref.aref}-#{formatted_label}"
193
-
194
- # Case 4: No context, just the label (e.g., TopLevel/file)
195
- # Input: README@section -> path="README_md.html"
196
- # Output: README_md.html#section
197
- else
198
- path << "##{formatted_label}"
199
- end
177
+ elsif name
178
+ if rdoc_ref && @warn_missing_rdoc_ref
179
+ puts "#{@from_path}: `rdoc-ref:#{name}` can't be resolved for `#{html_string}`"
200
180
  end
201
-
202
- "<a href=\"#{path}\">#{text}</a>"
181
+ return
182
+ else
183
+ # A bare label reference like @foo still produces a valid anchor link
184
+ return unless label
185
+ path = +""
203
186
  end
204
- end
205
187
 
206
- def convert_flow(flow_items, &block)
207
- res = []
208
-
209
- i = 0
210
- while i < flow_items.size
211
- item = flow_items[i]
212
-
213
- case item
214
- when RDoc::Markup::AttrChanger
215
- if !tidy_link_capturing? && (text = convert_tt_crossref(flow_items, i))
216
- text = block.call(text, res) if block
217
- append_flow_fragment res, text
218
- i += 3
219
- next
220
- end
221
-
222
- off_tags res, item
223
- on_tags res, item
224
- i += 1
225
- when String
226
- text = convert_string(item)
227
- text = block.call(text, res) if block
228
- append_flow_fragment res, text
229
- i += 1
230
- when RDoc::Markup::RegexpHandling
231
- text = convert_regexp_handling(item)
232
- text = block.call(text, res) if block
233
- append_flow_fragment res, text
234
- i += 1
188
+ if label
189
+ # Decode legacy labels (e.g., "What-27s+Here" -> "What's Here")
190
+ # then convert to GitHub-style anchor format
191
+ decoded_label = RDoc::Text.decode_legacy_label(label)
192
+ formatted_label = RDoc::Text.to_anchor(decoded_label)
193
+
194
+ # Case 1: Path already has an anchor (e.g., method link)
195
+ # Input: C1#method@label -> path="C1.html#method-i-m"
196
+ # Output: C1.html#method-i-m-label
197
+ if path =~ /#/
198
+ path << "-#{formatted_label}"
199
+
200
+ # Case 2: Label matches a section title
201
+ # Input: C1@Section -> path="C1.html", section "Section" exists
202
+ # Output: C1.html#section (uses section.aref for GitHub-style)
203
+ elsif (section = ref&.sections&.find { |s| decoded_label == s.title })
204
+ path << "##{section.aref}"
205
+
206
+ # Case 3: Ref has an aref (class/module context)
207
+ # Input: C1@heading -> path="C1.html", ref=C1 class
208
+ # Output: C1.html#class-c1-heading
209
+ elsif ref.respond_to?(:aref)
210
+ path << "##{ref.aref}-#{formatted_label}"
211
+
212
+ # Case 4: No context, just the label (e.g., TopLevel/file)
213
+ # Input: README@section -> path="README_md.html"
214
+ # Output: README_md.html#section
235
215
  else
236
- raise "Unknown flow element: #{item.inspect}"
216
+ path << "##{formatted_label}"
237
217
  end
238
218
  end
239
219
 
240
- res.join('')
220
+ "<a href=\"#{path}\">#{html_string}</a>"
241
221
  end
242
222
 
243
- private
244
-
245
- ##
246
- # Detects <tt>...</tt> spans that contain a single cross-reference candidate.
247
- # When the candidate occupies the whole span (aside from trailing
248
- # punctuation), the tt markup is replaced by the resolved cross-reference.
249
-
250
- def convert_tt_crossref(flow_items, index)
251
- opener = flow_items[index]
252
- return unless tt_tag?(opener.turn_on)
253
-
254
- string = flow_items[index + 1]
255
- closer = flow_items[index + 2]
256
-
257
- return unless String === string
258
- return unless RDoc::Markup::AttrChanger === closer
259
- return unless tt_tag?(closer.turn_off, true)
260
-
261
- crossref_regexp = @options.hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
262
- match = crossref_regexp.match(string)
263
- return unless match
264
- return unless match.begin(1).zero?
265
-
266
- trailing = match.post_match
267
- # Only convert when the remainder is punctuation/whitespace so other tt text stays literal.
268
- return unless trailing.match?(/\A[[:punct:]\s]*\z/)
223
+ def handle_TT(code)
224
+ emit_inline(tt_cross_reference(code) || "<code>#{convert_string(code)}</code>")
225
+ end
269
226
 
270
- text = cross_reference(string)
271
- return if text == string
227
+ # Applies additional special handling on top of the one defined in ToHtml.
228
+ # When a tidy link is <tt>{Foo}[rdoc-ref:Foo]</tt>, the label part is surrounded by <tt><code></code></tt>.
229
+ # TODO: reconsider this workaround.
230
+ def apply_tidylink_label_special_handling(label, url)
231
+ if url == "rdoc-ref:#{label}" && cross_reference(label)&.include?('<code>')
232
+ "<code>#{convert_string(label)}</code>"
233
+ else
234
+ super
235
+ end
236
+ end
272
237
 
273
- text
238
+ # Handles cross-reference and suppressed-crossref inside tt tag.
239
+ # Returns nil if code is not an existing cross-reference nor a suppressed-crossref.
240
+ def tt_cross_reference(code)
241
+ return if in_tidylink_label?
242
+
243
+ crossref_regexp = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
244
+ # REGEXP sometimes matches a string that starts with a backslash but is not a
245
+ # suppressed cross-reference (for example, `\+`), so the backslash-removed
246
+ # part needs to be checked against crossref_regexp.
247
+ match = crossref_regexp.match(code.delete_prefix('\\'))
248
+ return unless match && match.begin(1).zero?
249
+ return unless match.post_match.match?(/\A[[:punct:]\s]*\z/)
250
+
251
+ # cross_reference(file_page) may return a link without code tag.
252
+ # We need to check it because this method shouldn't return an html text without code tag.
253
+ if code.start_with?('\\')
254
+ # Remove leading backslash if crossref exists
255
+ "<code>#{convert_string(code[1..])}</code>" if cross_reference(code[1..])&.include?('<code>')
256
+ else
257
+ html = cross_reference(code)
258
+ html if html&.include?('<code>')
259
+ end
274
260
  end
275
261
  end
@@ -34,8 +34,8 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
34
34
  # next word boundary after the given number of +characters+ or +paragraphs+
35
35
  # of text have been encountered.
36
36
 
37
- def initialize(options, characters = 100, paragraphs = 3, markup = nil)
38
- super options, markup
37
+ def initialize(characters = 100, paragraphs = 3)
38
+ super()
39
39
 
40
40
  @character_limit = characters
41
41
  @paragraph_limit = paragraphs
@@ -107,9 +107,9 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
107
107
  def accept_verbatim(verbatim)
108
108
  throw :done if @characters >= @character_limit
109
109
  input = verbatim.text.rstrip
110
-
111
- text = truncate input
112
- text << ' ...' unless text == input
110
+ text = truncate(input, @character_limit - @characters)
111
+ @characters += input.length
112
+ text << " #{TO_HTML_CHARACTERS[text.encoding][:ellipsis]}" unless text == input
113
113
 
114
114
  super RDoc::Markup::Verbatim.new text
115
115
 
@@ -128,16 +128,8 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
128
128
  ##
129
129
  # Removes escaping from the cross-references in +target+
130
130
 
131
- def handle_regexp_CROSSREF(target)
132
- target.text.sub(/\A\\/, '')
133
- end
134
-
135
- ##
136
- # +target+ is a <code><br></code>
137
-
138
- def handle_regexp_HARD_BREAK(target)
139
- @characters -= 4
140
- '<br>'
131
+ def handle_regexp_CROSSREF(text)
132
+ text.sub(/\A\\/, '')
141
133
  end
142
134
 
143
135
  ##
@@ -212,74 +204,82 @@ class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml
212
204
  end_accepting
213
205
  end
214
206
 
215
- ##
216
- # Converts flow items +flow+
207
+ def handle_PLAIN_TEXT(text) # :nodoc:
208
+ return if inline_limit_reached?
217
209
 
218
- def convert_flow(flow)
219
- throw :done if @characters >= @character_limit
210
+ truncated = truncate(text, @inline_character_limit)
211
+ @inline_character_limit -= text.size
212
+ emit_inline(convert_string(truncated))
213
+ end
220
214
 
221
- res = []
222
- @mask = 0
223
-
224
- flow.each do |item|
225
- case item
226
- when RDoc::Markup::AttrChanger then
227
- off_tags res, item
228
- on_tags res, item
229
- when String then
230
- text = convert_string item
231
- res << truncate(text)
232
- when RDoc::Markup::RegexpHandling then
233
- text = convert_regexp_handling item
234
- res << truncate(text)
235
- else
236
- raise "Unknown flow element: #{item.inspect}"
237
- end
238
-
239
- if @characters >= @character_limit then
240
- off_tags res, RDoc::Markup::AttrChanger.new(0, @mask)
241
- break
242
- end
243
- end
215
+ def handle_REGEXP_HANDLING_TEXT(text) # :nodoc:
216
+ return if inline_limit_reached?
244
217
 
245
- res << ' ...' if @characters >= @character_limit
218
+ # We can't truncate text including html tags.
219
+ # Just emit as is, and count all characters including html tag part.
220
+ emit_inline(text)
221
+ @inline_character_limit -= text.size
222
+ end
246
223
 
247
- res.join
224
+ def handle_BOLD(nodes)
225
+ super unless inline_limit_reached?
248
226
  end
249
227
 
250
- ##
251
- # Maintains a bitmask to allow HTML elements to be closed properly. See
252
- # RDoc::Markup::Formatter.
228
+ def handle_BOLD_WORD(word)
229
+ super unless inline_limit_reached?
230
+ end
253
231
 
254
- def on_tags(res, item)
255
- @mask ^= item.turn_on
232
+ def handle_EM(nodes)
233
+ super unless inline_limit_reached?
234
+ end
256
235
 
257
- super
236
+ def handle_EM_WORD(word)
237
+ super unless inline_limit_reached?
258
238
  end
259
239
 
260
- ##
261
- # Maintains a bitmask to allow HTML elements to be closed properly. See
262
- # RDoc::Markup::Formatter.
240
+ def handle_TT(code)
241
+ super unless inline_limit_reached?
242
+ end
263
243
 
264
- def off_tags(res, item)
265
- @mask ^= item.turn_off
244
+ def handle_STRIKE(nodes)
245
+ super unless inline_limit_reached?
246
+ end
266
247
 
267
- super
248
+ def handle_HARD_BREAK
249
+ super unless inline_limit_reached?
268
250
  end
269
251
 
270
- ##
271
- # Truncates +text+ at the end of the first word after the character_limit.
252
+ def handle_TIDYLINK(label_part, url)
253
+ traverse_inline_nodes(label_part) unless inline_limit_reached?
254
+ end
272
255
 
273
- def truncate(text)
274
- length = text.length
275
- characters = @characters
276
- @characters += length
256
+ def inline_limit_reached?
257
+ @inline_character_limit <= 0
258
+ end
277
259
 
278
- return text if @characters < @character_limit
260
+ def handle_inline(text)
261
+ limit = @character_limit - @characters
262
+ return ['', 0] if limit <= 0
263
+ @inline_character_limit = limit
264
+ res = super
265
+ res << " #{TO_HTML_CHARACTERS[text.encoding][:ellipsis]}" if @inline_character_limit <= 0
266
+ @characters += limit - @inline_character_limit
267
+ res
268
+ end
269
+
270
+ def to_html(item)
271
+ throw :done if @characters >= @character_limit
272
+ handle_inline(item)
273
+ end
274
+
275
+ ##
276
+ # Truncates +text+ at the end of the first word after the limit.
279
277
 
280
- remaining = @character_limit - characters
278
+ def truncate(text, limit)
279
+ return text if limit >= text.size
280
+ return '' if limit <= 0
281
281
 
282
- text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s?
282
+ text =~ /\A(.{#{limit},}?)(\s|$)/m # TODO word-break instead of \s?
283
283
 
284
284
  $1
285
285
  end
@@ -8,11 +8,6 @@
8
8
  # other markup syntax items will not work.
9
9
 
10
10
  class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter
11
-
12
- def initialize # :nodoc:
13
- super nil
14
- end
15
-
16
11
  def start_accepting # :nodoc:
17
12
  end
18
13
 
@@ -14,24 +14,37 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
14
14
  ##
15
15
  # Creates a new formatter that will output HTML-safe labels
16
16
 
17
- def initialize(markup = nil)
18
- super nil, markup
17
+ def initialize
18
+ super
19
19
 
20
20
  @markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
21
- @markup.add_regexp_handling(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK)
22
21
 
23
- add_tag :BOLD, '', ''
24
- add_tag :TT, '', ''
25
- add_tag :EM, '', ''
22
+ @res = []
23
+ end
24
+
25
+ def handle_PLAIN_TEXT(text)
26
+ @res << text
27
+ end
28
+
29
+ def handle_REGEXP_HANDLING_TEXT(text)
30
+ @res << text
31
+ end
32
+
33
+ def handle_TT(text)
34
+ @res << text
35
+ end
26
36
 
37
+ def extract_plaintext(text)
27
38
  @res = []
39
+ handle_inline(text)
40
+ @res.join
28
41
  end
29
42
 
30
43
  ##
31
44
  # Converts +text+ to an HTML-safe label using GitHub-style anchor formatting.
32
45
 
33
46
  def convert(text)
34
- label = convert_flow @am.flow text
47
+ label = extract_plaintext(text)
35
48
 
36
49
  RDoc::Text.to_anchor(label)
37
50
  end
@@ -41,7 +54,7 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
41
54
  # Used for generating backward-compatible anchor aliases.
42
55
 
43
56
  def convert_legacy(text)
44
- label = convert_flow @am.flow text
57
+ label = extract_plaintext(text)
45
58
 
46
59
  CGI.escape(label).gsub('%', '-').sub(/^-/, '')
47
60
  end
@@ -50,23 +63,10 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
50
63
  # Converts the CROSSREF +target+ to plain text, removing the suppression
51
64
  # marker, if any
52
65
 
53
- def handle_regexp_CROSSREF(target)
54
- text = target.text
55
-
66
+ def handle_regexp_CROSSREF(text)
56
67
  text.sub(/^\\/, '')
57
68
  end
58
69
 
59
- ##
60
- # Converts the TIDYLINK +target+ to just the text part
61
-
62
- def handle_regexp_TIDYLINK(target)
63
- text = target.text
64
-
65
- return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/
66
-
67
- $1
68
- end
69
-
70
70
  alias accept_blank_line ignore
71
71
  alias accept_block_quote ignore
72
72
  alias accept_heading ignore
@@ -79,7 +79,6 @@ class RDoc::Markup::ToLabel < RDoc::Markup::Formatter
79
79
  alias accept_rule ignore
80
80
  alias accept_verbatim ignore
81
81
  alias end_accepting ignore
82
- alias handle_regexp_HARD_BREAK ignore
83
82
  alias start_accepting ignore
84
83
 
85
84
  end