asciidoctor-pdf 1.5.0.alpha.7 → 1.5.0.alpha.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/NOTICE.adoc +2 -2
  3. data/README.adoc +127 -128
  4. data/Rakefile +5 -4
  5. data/bin/asciidoctor-pdf +15 -2
  6. data/data/fonts/notoserif-regular-latin.ttf +0 -0
  7. data/data/themes/default-theme.yml +15 -13
  8. data/docs/theme-schema.json +114 -0
  9. data/docs/theming-guide.adoc +386 -132
  10. data/lib/asciidoctor-pdf/asciidoctor_ext.rb +2 -0
  11. data/lib/asciidoctor-pdf/asciidoctor_ext/image.rb +18 -0
  12. data/lib/asciidoctor-pdf/converter.rb +377 -221
  13. data/lib/asciidoctor-pdf/core_ext.rb +2 -0
  14. data/lib/asciidoctor-pdf/core_ext/array.rb +10 -4
  15. data/lib/asciidoctor-pdf/core_ext/numeric.rb +11 -0
  16. data/lib/asciidoctor-pdf/core_ext/ostruct.rb +1 -1
  17. data/lib/asciidoctor-pdf/formatted_text.rb +8 -0
  18. data/lib/asciidoctor-pdf/{prawn_ext/formatted_text → formatted_text}/formatter.rb +6 -9
  19. data/lib/asciidoctor-pdf/formatted_text/inline_destination_marker.rb +16 -0
  20. data/lib/asciidoctor-pdf/formatted_text/inline_image_arranger.rb +125 -0
  21. data/lib/asciidoctor-pdf/formatted_text/inline_image_renderer.rb +45 -0
  22. data/lib/asciidoctor-pdf/{prawn_ext/formatted_text → formatted_text}/parser.rb +252 -218
  23. data/lib/asciidoctor-pdf/{prawn_ext/formatted_text → formatted_text}/parser.treetop +18 -9
  24. data/lib/asciidoctor-pdf/{prawn_ext/formatted_text → formatted_text}/transform.rb +80 -69
  25. data/lib/asciidoctor-pdf/prawn_ext.rb +2 -2
  26. data/lib/asciidoctor-pdf/prawn_ext/extensions.rb +164 -35
  27. data/lib/asciidoctor-pdf/prawn_ext/formatted_text/fragment.rb +37 -0
  28. data/lib/asciidoctor-pdf/prawn_ext/images.rb +11 -9
  29. data/lib/asciidoctor-pdf/temporary_path.rb +9 -0
  30. data/lib/asciidoctor-pdf/theme_loader.rb +40 -33
  31. data/lib/asciidoctor-pdf/version.rb +1 -1
  32. metadata +30 -14
@@ -0,0 +1,2 @@
1
+ require_relative 'core_ext/array'
2
+ require_relative 'core_ext/numeric'
@@ -1,5 +1,11 @@
1
1
  class Array
2
- def to_h
3
- Hash[to_a]
4
- end unless respond_to? :to_h
5
- end if RUBY_VERSION < '2.1.0'
2
+ if RUBY_VERSION < '2.1.0'
3
+ def to_h
4
+ Hash[to_a]
5
+ end unless respond_to? :to_h
6
+ end
7
+
8
+ def delete_all *entries
9
+ entries.map {|entry| delete entry }.compact
10
+ end unless respond_to? :delete_all
11
+ end
@@ -0,0 +1,11 @@
1
+ class Numeric
2
+ def with_precision precision
3
+ precision = precision.to_i
4
+ if precision > 0
5
+ factor = 10 ** precision
6
+ (self * factor).truncate / factor.to_f
7
+ else
8
+ self.truncate
9
+ end
10
+ end unless respond_to? :with_precision
11
+ end
@@ -6,4 +6,4 @@ class OpenStruct
6
6
  def []= key, val
7
7
  send %(#{key}=), val
8
8
  end unless respond_to? :[]=
9
- end if RUBY_VERSION < '2.0.0'
9
+ end if RUBY_ENGINE == 'rbx' || RUBY_VERSION < '2.0.0'
@@ -0,0 +1,8 @@
1
+ require 'treetop'
2
+ require 'set' unless defined? Set
3
+ require_relative 'formatted_text/parser'
4
+ require_relative 'formatted_text/transform'
5
+ require_relative 'formatted_text/formatter'
6
+ require_relative 'formatted_text/inline_destination_marker'
7
+ require_relative 'formatted_text/inline_image_arranger'
8
+ require_relative 'formatted_text/inline_image_renderer'
@@ -1,16 +1,12 @@
1
- require 'treetop'
2
- require 'set'
3
- require_relative 'parser'
4
- require_relative 'transform'
5
-
6
1
  module Asciidoctor
7
- module Prawn
8
- class FormattedTextFormatter
2
+ module Pdf
3
+ module FormattedText
4
+ class Formatter
9
5
  FormattingSnifferPattern = /[<&]/
10
6
 
11
7
  def initialize options = {}
12
- @parser = FormattedTextParser.new
13
- @transform = FormattedTextTransform.new merge_adjacent_text_nodes: true, theme: options[:theme]
8
+ @parser = MarkupParser.new
9
+ @transform = Transform.new merge_adjacent_text_nodes: true, theme: options[:theme]
14
10
  end
15
11
 
16
12
  def format string, *args
@@ -27,3 +23,4 @@ class FormattedTextFormatter
27
23
  end
28
24
  end
29
25
  end
26
+ end
@@ -0,0 +1,16 @@
1
+ module Asciidoctor::Pdf::FormattedText
2
+ module InlineDestinationMarker
3
+ module_function
4
+
5
+ # render_behind is called before the text is printed
6
+ def render_behind fragment
7
+ unless (pdf = fragment.document).scratch?
8
+ if (name = fragment.format_state[:name])
9
+ # get precise position of the reference (x, y)
10
+ dest_rect = fragment.absolute_bounding_box
11
+ pdf.add_dest name, (pdf.dest_xyz dest_rect.first, dest_rect.last)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,125 @@
1
+ module Asciidoctor::Pdf::FormattedText
2
+ module InlineImageArranger
3
+ #ImagePlaceholderChar = [0x00a0].pack 'U*'
4
+ ImagePlaceholderChar = '.'
5
+ begin
6
+ require 'thread_safe' unless defined? ::ThreadSafe
7
+ PlaceholderWidthCache = ::ThreadSafe::Cache.new
8
+ rescue
9
+ PlaceholderWidthCache = {}
10
+ end
11
+
12
+ if ::RUBY_MIN_VERSION_2
13
+ def wrap fragments
14
+ arrange_images fragments
15
+ super
16
+ end
17
+ else
18
+ class << self
19
+ def extended base
20
+ base.class.__send__ :alias_method, :_initial_wrap, :wrap
21
+ end
22
+ end
23
+
24
+ def wrap fragments
25
+ arrange_images fragments
26
+ _initial_wrap fragments
27
+ end
28
+ end
29
+
30
+ # Iterates over the fragments that represent inline images and prepares the
31
+ # image data to be embedded into the document.
32
+ #
33
+ # This method populates the image_width, image_height, image_obj and
34
+ # image_info (PNG only) keys on the fragment. The text is replaced with
35
+ # placeholder text that will be used to reserve enough room in the line to
36
+ # fit the image.
37
+ #
38
+ # The image height is scaled down to 75% of the specified width (px to pt
39
+ # conversion). If the image height is more than 1.5x the height of the
40
+ # surrounding line of text, the font size and line metrics of the fragment
41
+ # are modified to fit the image in the line.
42
+ #
43
+ # If this is the scratch document, the image renderer callback is removed so
44
+ # that the image is not embedded.
45
+ #
46
+ # This method is called each time the set of fragments overflow to another
47
+ # page, so it's necessary to short-circuit if that case is detected.
48
+ def arrange_images fragments
49
+ doc = @document
50
+ scratch = doc.scratch?
51
+ fragments.select {|f| (f.key? :image_path) && !(f.key? :image_obj) }.each do |fragment|
52
+ begin
53
+ image_path = fragment[:image_path]
54
+
55
+ if (image_w = fragment[:image_width])
56
+ image_w *= 0.75
57
+ end
58
+
59
+ # TODO make helper method to calculate width and height of image
60
+ if fragment[:image_type] == 'svg'
61
+ svg_obj = ::Prawn::Svg::Interface.new (::IO.read image_path), doc, at: doc.bounds.top_left, width: image_w
62
+ if image_w
63
+ fragment[:image_width] = svg_obj.document.sizing.output_width
64
+ fragment[:image_height] = svg_obj.document.sizing.output_height
65
+ else
66
+ fragment[:image_width] = svg_obj.document.sizing.output_width * 0.75
67
+ fragment[:image_height] = svg_obj.document.sizing.output_height * 0.75
68
+ end
69
+ fragment[:image_obj] = svg_obj
70
+ else
71
+ # TODO cache image info based on path (Prawn cached based on SHA1 of content)
72
+ image_obj, image_info = doc.build_image_object image_path
73
+ if image_w
74
+ fragment[:image_width], fragment[:image_height] = image_info.calc_image_dimensions width: image_w
75
+ else
76
+ fragment[:image_width] = image_info.width * 0.75
77
+ fragment[:image_height] = image_info.height * 0.75
78
+ end
79
+ fragment[:image_obj] = image_obj
80
+ fragment[:image_info] = image_info
81
+ end
82
+
83
+ spacer_w = nil
84
+ doc.fragment_font fragment do
85
+ # NOTE if image height exceeds line height by more than 1.5x, increase the line height
86
+ # HACK we could really use a nicer API from Prawn here; this is an ugly hack
87
+ if (f_height = fragment[:image_height]) > ((line_font = doc.font).height * 1.5)
88
+ fragment[:ascender] = f_height
89
+ fragment[:descender] = line_font.descender
90
+ doc.font_size(fragment[:size] = f_height * (doc.font_size / line_font.height))
91
+ fragment[:line_height_increased] = true
92
+ end
93
+
94
+ unless (spacer_w = PlaceholderWidthCache[f_info = doc.font_info])
95
+ spacer_w = PlaceholderWidthCache[f_info] = doc.width_of ImagePlaceholderChar
96
+ end
97
+ end
98
+
99
+ # NOTE make room for the image by repeating the image placeholder character
100
+ # TODO could use character spacing as an alternative to repeating characters
101
+ # HACK we could use a nicer API from Prawn here to reserve width in a line
102
+ fragment[:text] = ImagePlaceholderChar * (fragment[:image_width] / spacer_w).ceil
103
+ #fragment[:width] = fragment[:image_width]
104
+ ensure
105
+ # NOTE skip rendering image in scratch document
106
+ if scratch
107
+ fragment.delete :callback
108
+ fragment.delete :image_obj
109
+ fragment.delete :image_info
110
+ # NOTE in main document, tmp image path is unlinked by renderer
111
+ ::File.unlink image_path if fragment[:image_tmp]
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ if ::RUBY_MIN_VERSION_2
119
+ class ::Prawn::Text::Formatted::Box
120
+ prepend InlineImageArranger
121
+ end
122
+ else
123
+ ::Prawn::Text::Formatted::Box.extensions << InlineImageArranger
124
+ end
125
+ end
@@ -0,0 +1,45 @@
1
+ module Asciidoctor::Pdf::FormattedText
2
+ module InlineImageRenderer
3
+ module_function
4
+
5
+ # Embeds the image object in this fragment into the document in place of the
6
+ # text that was previously used to reserve space for the image in the line.
7
+ #
8
+ # If the image height is less than 1.5x the height of the surrounding text,
9
+ # it is centered vertically in the line. If the image height is greater, then
10
+ # the image is aligned to the bottom of the text.
11
+ #
12
+ # Note that render_behind is called before the text is printed.
13
+ #
14
+ # This handler is only used on the main document (not the scratch document).
15
+ #
16
+ def render_behind fragment
17
+ pdf = fragment.document
18
+ data = fragment.format_state
19
+ image_top = if data.key? :line_height_increased
20
+ # align image to bottom of line (differs from fragment.top by descender value)
21
+ fragment.bottom + data[:image_height]
22
+ else
23
+ # center image in line
24
+ fragment.top - ((fragment.height - data[:image_height]) / 2.0)
25
+ end
26
+ image_left = fragment.left + ((fragment.width - data[:image_width]) / 2.0)
27
+ case data[:image_type]
28
+ when 'svg'
29
+ # prawn-svg messes with the cursor; use float as a workaround
30
+ pdf.float do
31
+ data[:image_obj].tap {|obj| obj.options[:at] = [image_left, image_top] }.draw
32
+ end
33
+ else
34
+ pdf.embed_image data[:image_obj], data[:image_info], at: [image_left, image_top], width: data[:image_width]
35
+ end
36
+ # ...or use the public interface, loading the image again
37
+ #pdf.image data[:image_path], at: [image_left, image_top], width: data[:image_width]
38
+
39
+ # prevent any text from being written
40
+ fragment.conceal
41
+ ensure
42
+ ::File.unlink data[:image_path] if data[:image_tmp]
43
+ end
44
+ end
45
+ end
@@ -1,9 +1,11 @@
1
+ # regenerate parser.rb using `tt parser.treetop`
1
2
  # Autogenerated from a Treetop grammar. Edits may be lost.
2
3
 
3
4
 
4
5
  module Asciidoctor
5
- module Prawn
6
+ module Pdf
6
7
  module FormattedText
8
+ module Markup
7
9
  include Treetop::Runtime
8
10
 
9
11
  def root
@@ -15,7 +17,7 @@ module FormattedText
15
17
  if node_cache[:text].has_key?(index)
16
18
  cached = node_cache[:text][index]
17
19
  if cached
18
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
20
+ node_cache[:text][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
19
21
  @index = cached.interval.end
20
22
  end
21
23
  return cached
@@ -39,7 +41,7 @@ module FormattedText
39
41
  if node_cache[:complex].has_key?(index)
40
42
  cached = node_cache[:complex][index]
41
43
  if cached
42
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
44
+ node_cache[:complex][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
43
45
  @index = cached.interval.end
44
46
  end
45
47
  return cached
@@ -50,14 +52,17 @@ module FormattedText
50
52
  i1 = index
51
53
  r2 = _nt_cdata
52
54
  if r2
55
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
53
56
  r1 = r2
54
57
  else
55
58
  r3 = _nt_element
56
59
  if r3
60
+ r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
57
61
  r1 = r3
58
62
  else
59
63
  r4 = _nt_entity
60
64
  if r4
65
+ r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true
61
66
  r1 = r4
62
67
  else
63
68
  @index = i1
@@ -94,7 +99,7 @@ module FormattedText
94
99
  end
95
100
 
96
101
  module Element1
97
- # NOTE content only applies to non-empty element
102
+ # NOTE content only applies to non-void elements (second part of rule)
98
103
  def content
99
104
  { type: :element, name: (tag_element = elements[0]).name.to_sym, attributes: tag_element.attributes, pcdata: elements[1].content }
100
105
  end
@@ -105,15 +110,16 @@ module FormattedText
105
110
  if node_cache[:element].has_key?(index)
106
111
  cached = node_cache[:element][index]
107
112
  if cached
108
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
113
+ node_cache[:element][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
109
114
  @index = cached.interval.end
110
115
  end
111
116
  return cached
112
117
  end
113
118
 
114
119
  i0 = index
115
- r1 = _nt_empty_element
120
+ r1 = _nt_void_element
116
121
  if r1
122
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
117
123
  r0 = r1
118
124
  else
119
125
  i2, s2 = index, []
@@ -136,6 +142,7 @@ module FormattedText
136
142
  r2 = nil
137
143
  end
138
144
  if r2
145
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
139
146
  r0 = r2
140
147
  else
141
148
  @index = i0
@@ -148,91 +155,107 @@ module FormattedText
148
155
  r0
149
156
  end
150
157
 
151
- module EmptyElement0
158
+ module VoidElement0
152
159
  end
153
160
 
154
- module EmptyElement1
161
+ module VoidElement1
162
+ def void_tag_name
163
+ elements[1]
164
+ end
165
+
166
+ def attributes
167
+ elements[2]
168
+ end
169
+
155
170
  end
156
171
 
157
- module EmptyElement2
172
+ module VoidElement2
158
173
  def content
159
- { type: :element, name: :br, attributes: {} }
174
+ { type: :element, name: elements[1].text_value.to_sym, attributes: elements[2].content }
160
175
  end
161
176
  end
162
177
 
163
- def _nt_empty_element
178
+ def _nt_void_element
164
179
  start_index = index
165
- if node_cache[:empty_element].has_key?(index)
166
- cached = node_cache[:empty_element][index]
180
+ if node_cache[:void_element].has_key?(index)
181
+ cached = node_cache[:void_element][index]
167
182
  if cached
168
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
183
+ node_cache[:void_element][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
169
184
  @index = cached.interval.end
170
185
  end
171
186
  return cached
172
187
  end
173
188
 
174
189
  i0, s0 = index, []
175
- if has_terminal?('<br', false, index)
176
- r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
177
- @index += 3
190
+ if (match_len = has_terminal?('<', false, index))
191
+ r1 = true
192
+ @index += match_len
178
193
  else
179
- terminal_parse_failure('<br')
194
+ terminal_parse_failure('<')
180
195
  r1 = nil
181
196
  end
182
197
  s0 << r1
183
198
  if r1
184
- i3, s3 = index, []
185
- r5 = _nt_spaces
186
- if r5
187
- r4 = r5
188
- else
189
- r4 = instantiate_node(SyntaxNode,input, index...index)
190
- end
191
- s3 << r4
192
- if r4
193
- if has_terminal?('/', false, index)
194
- r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
195
- @index += 1
196
- else
197
- terminal_parse_failure('/')
198
- r6 = nil
199
- end
200
- s3 << r6
201
- end
202
- if s3.last
203
- r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
204
- r3.extend(EmptyElement0)
205
- else
206
- @index = i3
207
- r3 = nil
208
- end
209
- if r3
210
- r2 = r3
211
- else
212
- r2 = instantiate_node(SyntaxNode,input, index...index)
213
- end
199
+ r2 = _nt_void_tag_name
214
200
  s0 << r2
215
201
  if r2
216
- if has_terminal?('>', false, index)
217
- r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
218
- @index += 1
219
- else
220
- terminal_parse_failure('>')
221
- r7 = nil
202
+ r3 = _nt_attributes
203
+ s0 << r3
204
+ if r3
205
+ i5, s5 = index, []
206
+ r7 = _nt_spaces
207
+ if r7
208
+ r6 = r7
209
+ else
210
+ r6 = instantiate_node(SyntaxNode,input, index...index)
211
+ end
212
+ s5 << r6
213
+ if r6
214
+ if (match_len = has_terminal?('/', false, index))
215
+ r8 = true
216
+ @index += match_len
217
+ else
218
+ terminal_parse_failure('/')
219
+ r8 = nil
220
+ end
221
+ s5 << r8
222
+ end
223
+ if s5.last
224
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
225
+ r5.extend(VoidElement0)
226
+ else
227
+ @index = i5
228
+ r5 = nil
229
+ end
230
+ if r5
231
+ r4 = r5
232
+ else
233
+ r4 = instantiate_node(SyntaxNode,input, index...index)
234
+ end
235
+ s0 << r4
236
+ if r4
237
+ if (match_len = has_terminal?('>', false, index))
238
+ r9 = true
239
+ @index += match_len
240
+ else
241
+ terminal_parse_failure('>')
242
+ r9 = nil
243
+ end
244
+ s0 << r9
245
+ end
222
246
  end
223
- s0 << r7
224
247
  end
225
248
  end
226
249
  if s0.last
227
250
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
228
- r0.extend(EmptyElement1)
229
- r0.extend(EmptyElement2)
251
+ r0.extend(VoidElement1)
252
+ r0.extend(VoidElement2)
230
253
  else
231
254
  @index = i0
232
255
  r0 = nil
233
256
  end
234
257
 
235
- node_cache[:empty_element][start_index] = r0
258
+ node_cache[:void_element][start_index] = r0
236
259
 
237
260
  r0
238
261
  end
@@ -263,16 +286,16 @@ module FormattedText
263
286
  if node_cache[:start_tag].has_key?(index)
264
287
  cached = node_cache[:start_tag][index]
265
288
  if cached
266
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
289
+ node_cache[:start_tag][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
267
290
  @index = cached.interval.end
268
291
  end
269
292
  return cached
270
293
  end
271
294
 
272
295
  i0, s0 = index, []
273
- if has_terminal?('<', false, index)
274
- r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
275
- @index += 1
296
+ if (match_len = has_terminal?('<', false, index))
297
+ r1 = true
298
+ @index += match_len
276
299
  else
277
300
  terminal_parse_failure('<')
278
301
  r1 = nil
@@ -285,9 +308,9 @@ module FormattedText
285
308
  r3 = _nt_attributes
286
309
  s0 << r3
287
310
  if r3
288
- if has_terminal?('>', false, index)
289
- r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
290
- @index += 1
311
+ if (match_len = has_terminal?('>', false, index))
312
+ r4 = true
313
+ @index += match_len
291
314
  else
292
315
  terminal_parse_failure('>')
293
316
  r4 = nil
@@ -315,170 +338,125 @@ module FormattedText
315
338
  if node_cache[:tag_name].has_key?(index)
316
339
  cached = node_cache[:tag_name][index]
317
340
  if cached
318
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
341
+ node_cache[:tag_name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
319
342
  @index = cached.interval.end
320
343
  end
321
344
  return cached
322
345
  end
323
346
 
324
347
  i0 = index
325
- if has_terminal?('a', false, index)
326
- r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
327
- @index += 1
348
+ if (match_len = has_terminal?('a', false, index))
349
+ r1 = true
350
+ @index += match_len
328
351
  else
329
352
  terminal_parse_failure('a')
330
353
  r1 = nil
331
354
  end
332
355
  if r1
356
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
333
357
  r0 = r1
334
358
  else
335
- if has_terminal?('b', false, index)
336
- r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
337
- @index += 1
359
+ if (match_len = has_terminal?('code', false, index))
360
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
361
+ @index += match_len
338
362
  else
339
- terminal_parse_failure('b')
363
+ terminal_parse_failure('code')
340
364
  r2 = nil
341
365
  end
342
366
  if r2
367
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
343
368
  r0 = r2
344
369
  else
345
- if has_terminal?('code', false, index)
346
- r3 = instantiate_node(SyntaxNode,input, index...(index + 4))
347
- @index += 4
370
+ if (match_len = has_terminal?('color', false, index))
371
+ r3 = instantiate_node(SyntaxNode,input, index...(index + match_len))
372
+ @index += match_len
348
373
  else
349
- terminal_parse_failure('code')
374
+ terminal_parse_failure('color')
350
375
  r3 = nil
351
376
  end
352
377
  if r3
378
+ r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
353
379
  r0 = r3
354
380
  else
355
- if has_terminal?('color', false, index)
356
- r4 = instantiate_node(SyntaxNode,input, index...(index + 5))
357
- @index += 5
381
+ if (match_len = has_terminal?('del', false, index))
382
+ r4 = instantiate_node(SyntaxNode,input, index...(index + match_len))
383
+ @index += match_len
358
384
  else
359
- terminal_parse_failure('color')
385
+ terminal_parse_failure('del')
360
386
  r4 = nil
361
387
  end
362
388
  if r4
389
+ r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true
363
390
  r0 = r4
364
391
  else
365
- if has_terminal?('del', false, index)
366
- r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
367
- @index += 3
392
+ if (match_len = has_terminal?('em', false, index))
393
+ r5 = instantiate_node(SyntaxNode,input, index...(index + match_len))
394
+ @index += match_len
368
395
  else
369
- terminal_parse_failure('del')
396
+ terminal_parse_failure('em')
370
397
  r5 = nil
371
398
  end
372
399
  if r5
400
+ r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true
373
401
  r0 = r5
374
402
  else
375
- if has_terminal?('em', false, index)
376
- r6 = instantiate_node(SyntaxNode,input, index...(index + 2))
377
- @index += 2
403
+ if (match_len = has_terminal?('font', false, index))
404
+ r6 = instantiate_node(SyntaxNode,input, index...(index + match_len))
405
+ @index += match_len
378
406
  else
379
- terminal_parse_failure('em')
407
+ terminal_parse_failure('font')
380
408
  r6 = nil
381
409
  end
382
410
  if r6
411
+ r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true
383
412
  r0 = r6
384
413
  else
385
- if has_terminal?('font', false, index)
386
- r7 = instantiate_node(SyntaxNode,input, index...(index + 4))
387
- @index += 4
414
+ if (match_len = has_terminal?('span', false, index))
415
+ r7 = instantiate_node(SyntaxNode,input, index...(index + match_len))
416
+ @index += match_len
388
417
  else
389
- terminal_parse_failure('font')
418
+ terminal_parse_failure('span')
390
419
  r7 = nil
391
420
  end
392
421
  if r7
422
+ r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true
393
423
  r0 = r7
394
424
  else
395
- if has_terminal?('i', false, index)
396
- r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
397
- @index += 1
425
+ if (match_len = has_terminal?('strong', false, index))
426
+ r8 = instantiate_node(SyntaxNode,input, index...(index + match_len))
427
+ @index += match_len
398
428
  else
399
- terminal_parse_failure('i')
429
+ terminal_parse_failure('strong')
400
430
  r8 = nil
401
431
  end
402
432
  if r8
433
+ r8 = SyntaxNode.new(input, (index-1)...index) if r8 == true
403
434
  r0 = r8
404
435
  else
405
- if has_terminal?('link', false, index)
406
- r9 = instantiate_node(SyntaxNode,input, index...(index + 4))
407
- @index += 4
436
+ if (match_len = has_terminal?('sub', false, index))
437
+ r9 = instantiate_node(SyntaxNode,input, index...(index + match_len))
438
+ @index += match_len
408
439
  else
409
- terminal_parse_failure('link')
440
+ terminal_parse_failure('sub')
410
441
  r9 = nil
411
442
  end
412
443
  if r9
444
+ r9 = SyntaxNode.new(input, (index-1)...index) if r9 == true
413
445
  r0 = r9
414
446
  else
415
- if has_terminal?('span', false, index)
416
- r10 = instantiate_node(SyntaxNode,input, index...(index + 4))
417
- @index += 4
447
+ if (match_len = has_terminal?('sup', false, index))
448
+ r10 = instantiate_node(SyntaxNode,input, index...(index + match_len))
449
+ @index += match_len
418
450
  else
419
- terminal_parse_failure('span')
451
+ terminal_parse_failure('sup')
420
452
  r10 = nil
421
453
  end
422
454
  if r10
455
+ r10 = SyntaxNode.new(input, (index-1)...index) if r10 == true
423
456
  r0 = r10
424
457
  else
425
- if has_terminal?('strikethrough', false, index)
426
- r11 = instantiate_node(SyntaxNode,input, index...(index + 13))
427
- @index += 13
428
- else
429
- terminal_parse_failure('strikethrough')
430
- r11 = nil
431
- end
432
- if r11
433
- r0 = r11
434
- else
435
- if has_terminal?('strong', false, index)
436
- r12 = instantiate_node(SyntaxNode,input, index...(index + 6))
437
- @index += 6
438
- else
439
- terminal_parse_failure('strong')
440
- r12 = nil
441
- end
442
- if r12
443
- r0 = r12
444
- else
445
- if has_terminal?('sub', false, index)
446
- r13 = instantiate_node(SyntaxNode,input, index...(index + 3))
447
- @index += 3
448
- else
449
- terminal_parse_failure('sub')
450
- r13 = nil
451
- end
452
- if r13
453
- r0 = r13
454
- else
455
- if has_terminal?('sup', false, index)
456
- r14 = instantiate_node(SyntaxNode,input, index...(index + 3))
457
- @index += 3
458
- else
459
- terminal_parse_failure('sup')
460
- r14 = nil
461
- end
462
- if r14
463
- r0 = r14
464
- else
465
- if has_terminal?('u', false, index)
466
- r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
467
- @index += 1
468
- else
469
- terminal_parse_failure('u')
470
- r15 = nil
471
- end
472
- if r15
473
- r0 = r15
474
- else
475
- @index = i0
476
- r0 = nil
477
- end
478
- end
479
- end
480
- end
481
- end
458
+ @index = i0
459
+ r0 = nil
482
460
  end
483
461
  end
484
462
  end
@@ -495,6 +473,50 @@ module FormattedText
495
473
  r0
496
474
  end
497
475
 
476
+ def _nt_void_tag_name
477
+ start_index = index
478
+ if node_cache[:void_tag_name].has_key?(index)
479
+ cached = node_cache[:void_tag_name][index]
480
+ if cached
481
+ node_cache[:void_tag_name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
482
+ @index = cached.interval.end
483
+ end
484
+ return cached
485
+ end
486
+
487
+ i0 = index
488
+ if (match_len = has_terminal?('br', false, index))
489
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
490
+ @index += match_len
491
+ else
492
+ terminal_parse_failure('br')
493
+ r1 = nil
494
+ end
495
+ if r1
496
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
497
+ r0 = r1
498
+ else
499
+ if (match_len = has_terminal?('img', false, index))
500
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
501
+ @index += match_len
502
+ else
503
+ terminal_parse_failure('img')
504
+ r2 = nil
505
+ end
506
+ if r2
507
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
508
+ r0 = r2
509
+ else
510
+ @index = i0
511
+ r0 = nil
512
+ end
513
+ end
514
+
515
+ node_cache[:void_tag_name][start_index] = r0
516
+
517
+ r0
518
+ end
519
+
498
520
  module Attributes0
499
521
  def content
500
522
  attrs = {}
@@ -511,7 +533,7 @@ module FormattedText
511
533
  if node_cache[:attributes].has_key?(index)
512
534
  cached = node_cache[:attributes][index]
513
535
  if cached
514
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
536
+ node_cache[:attributes][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
515
537
  @index = cached.interval.end
516
538
  end
517
539
  return cached
@@ -552,7 +574,7 @@ module FormattedText
552
574
  if node_cache[:attribute].has_key?(index)
553
575
  cached = node_cache[:attribute][index]
554
576
  if cached
555
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
577
+ node_cache[:attribute][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
556
578
  @index = cached.interval.end
557
579
  end
558
580
  return cached
@@ -564,10 +586,11 @@ module FormattedText
564
586
  if r1
565
587
  s2, i2 = [], index
566
588
  loop do
567
- if has_terminal?('\G[a-z_]', true, index)
589
+ if has_terminal?(@regexps[gr = '\A[a-z_]'] ||= Regexp.new(gr), :regexp, index)
568
590
  r3 = true
569
591
  @index += 1
570
592
  else
593
+ terminal_parse_failure('[a-z_]')
571
594
  r3 = nil
572
595
  end
573
596
  if r3
@@ -584,18 +607,18 @@ module FormattedText
584
607
  end
585
608
  s0 << r2
586
609
  if r2
587
- if has_terminal?('=', false, index)
588
- r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
589
- @index += 1
610
+ if (match_len = has_terminal?('=', false, index))
611
+ r4 = true
612
+ @index += match_len
590
613
  else
591
614
  terminal_parse_failure('=')
592
615
  r4 = nil
593
616
  end
594
617
  s0 << r4
595
618
  if r4
596
- if has_terminal?('"', false, index)
597
- r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
598
- @index += 1
619
+ if (match_len = has_terminal?('"', false, index))
620
+ r5 = true
621
+ @index += match_len
599
622
  else
600
623
  terminal_parse_failure('"')
601
624
  r5 = nil
@@ -604,10 +627,11 @@ module FormattedText
604
627
  if r5
605
628
  s6, i6 = [], index
606
629
  loop do
607
- if has_terminal?('\G[^"]', true, index)
630
+ if has_terminal?(@regexps[gr = '\A[^"]'] ||= Regexp.new(gr), :regexp, index)
608
631
  r7 = true
609
632
  @index += 1
610
633
  else
634
+ terminal_parse_failure('[^"]')
611
635
  r7 = nil
612
636
  end
613
637
  if r7
@@ -619,9 +643,9 @@ module FormattedText
619
643
  r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
620
644
  s0 << r6
621
645
  if r6
622
- if has_terminal?('"', false, index)
623
- r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
624
- @index += 1
646
+ if (match_len = has_terminal?('"', false, index))
647
+ r8 = true
648
+ @index += match_len
625
649
  else
626
650
  terminal_parse_failure('"')
627
651
  r8 = nil
@@ -664,16 +688,16 @@ module FormattedText
664
688
  if node_cache[:end_tag].has_key?(index)
665
689
  cached = node_cache[:end_tag][index]
666
690
  if cached
667
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
691
+ node_cache[:end_tag][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
668
692
  @index = cached.interval.end
669
693
  end
670
694
  return cached
671
695
  end
672
696
 
673
697
  i0, s0 = index, []
674
- if has_terminal?('</', false, index)
675
- r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
676
- @index += 2
698
+ if (match_len = has_terminal?('</', false, index))
699
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
700
+ @index += match_len
677
701
  else
678
702
  terminal_parse_failure('</')
679
703
  r1 = nil
@@ -683,9 +707,9 @@ module FormattedText
683
707
  r2 = _nt_tag_name
684
708
  s0 << r2
685
709
  if r2
686
- if has_terminal?('>', false, index)
687
- r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
688
- @index += 1
710
+ if (match_len = has_terminal?('>', false, index))
711
+ r3 = true
712
+ @index += match_len
689
713
  else
690
714
  terminal_parse_failure('>')
691
715
  r3 = nil
@@ -718,7 +742,7 @@ module FormattedText
718
742
  if node_cache[:cdata].has_key?(index)
719
743
  cached = node_cache[:cdata][index]
720
744
  if cached
721
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
745
+ node_cache[:cdata][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
722
746
  @index = cached.interval.end
723
747
  end
724
748
  return cached
@@ -726,10 +750,11 @@ module FormattedText
726
750
 
727
751
  s0, i0 = [], index
728
752
  loop do
729
- if has_terminal?('\G[^<&]', true, index)
753
+ if has_terminal?(@regexps[gr = '\A[^<&]'] ||= Regexp.new(gr), :regexp, index)
730
754
  r1 = true
731
755
  @index += 1
732
756
  else
757
+ terminal_parse_failure('[^<&]')
733
758
  r1 = nil
734
759
  end
735
760
  if r1
@@ -775,16 +800,16 @@ module FormattedText
775
800
  if node_cache[:entity].has_key?(index)
776
801
  cached = node_cache[:entity][index]
777
802
  if cached
778
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
803
+ node_cache[:entity][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
779
804
  @index = cached.interval.end
780
805
  end
781
806
  return cached
782
807
  end
783
808
 
784
809
  i0, s0 = index, []
785
- if has_terminal?('&', false, index)
786
- r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
787
- @index += 1
810
+ if (match_len = has_terminal?('&', false, index))
811
+ r1 = true
812
+ @index += match_len
788
813
  else
789
814
  terminal_parse_failure('&')
790
815
  r1 = nil
@@ -793,9 +818,9 @@ module FormattedText
793
818
  if r1
794
819
  i2 = index
795
820
  i3, s3 = index, []
796
- if has_terminal?('#', false, index)
797
- r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
798
- @index += 1
821
+ if (match_len = has_terminal?('#', false, index))
822
+ r4 = true
823
+ @index += match_len
799
824
  else
800
825
  terminal_parse_failure('#')
801
826
  r4 = nil
@@ -813,10 +838,12 @@ module FormattedText
813
838
  r3 = nil
814
839
  end
815
840
  if r3
841
+ r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
816
842
  r2 = r3
817
843
  else
818
844
  r6 = _nt_entity_name
819
845
  if r6
846
+ r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true
820
847
  r2 = r6
821
848
  else
822
849
  @index = i2
@@ -825,9 +852,9 @@ module FormattedText
825
852
  end
826
853
  s0 << r2
827
854
  if r2
828
- if has_terminal?(';', false, index)
829
- r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
830
- @index += 1
855
+ if (match_len = has_terminal?(';', false, index))
856
+ r7 = true
857
+ @index += match_len
831
858
  else
832
859
  terminal_parse_failure(';')
833
860
  r7 = nil
@@ -854,7 +881,7 @@ module FormattedText
854
881
  if node_cache[:entity_number].has_key?(index)
855
882
  cached = node_cache[:entity_number][index]
856
883
  if cached
857
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
884
+ node_cache[:entity_number][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
858
885
  @index = cached.interval.end
859
886
  end
860
887
  return cached
@@ -862,10 +889,11 @@ module FormattedText
862
889
 
863
890
  s0, i0 = [], index
864
891
  loop do
865
- if has_terminal?('\G[0-9]', true, index)
892
+ if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
866
893
  r1 = true
867
894
  @index += 1
868
895
  else
896
+ terminal_parse_failure('[0-9]')
869
897
  r1 = nil
870
898
  end
871
899
  if r1
@@ -894,61 +922,66 @@ module FormattedText
894
922
  if node_cache[:entity_name].has_key?(index)
895
923
  cached = node_cache[:entity_name][index]
896
924
  if cached
897
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
925
+ node_cache[:entity_name][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
898
926
  @index = cached.interval.end
899
927
  end
900
928
  return cached
901
929
  end
902
930
 
903
931
  i0 = index
904
- if has_terminal?('amp', false, index)
905
- r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
906
- @index += 3
932
+ if (match_len = has_terminal?('amp', false, index))
933
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
934
+ @index += match_len
907
935
  else
908
936
  terminal_parse_failure('amp')
909
937
  r1 = nil
910
938
  end
911
939
  if r1
940
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
912
941
  r0 = r1
913
942
  else
914
- if has_terminal?('apos', false, index)
915
- r2 = instantiate_node(SyntaxNode,input, index...(index + 4))
916
- @index += 4
943
+ if (match_len = has_terminal?('apos', false, index))
944
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
945
+ @index += match_len
917
946
  else
918
947
  terminal_parse_failure('apos')
919
948
  r2 = nil
920
949
  end
921
950
  if r2
951
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
922
952
  r0 = r2
923
953
  else
924
- if has_terminal?('gt', false, index)
925
- r3 = instantiate_node(SyntaxNode,input, index...(index + 2))
926
- @index += 2
954
+ if (match_len = has_terminal?('gt', false, index))
955
+ r3 = instantiate_node(SyntaxNode,input, index...(index + match_len))
956
+ @index += match_len
927
957
  else
928
958
  terminal_parse_failure('gt')
929
959
  r3 = nil
930
960
  end
931
961
  if r3
962
+ r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
932
963
  r0 = r3
933
964
  else
934
- if has_terminal?('lt', false, index)
935
- r4 = instantiate_node(SyntaxNode,input, index...(index + 2))
936
- @index += 2
965
+ if (match_len = has_terminal?('lt', false, index))
966
+ r4 = instantiate_node(SyntaxNode,input, index...(index + match_len))
967
+ @index += match_len
937
968
  else
938
969
  terminal_parse_failure('lt')
939
970
  r4 = nil
940
971
  end
941
972
  if r4
973
+ r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true
942
974
  r0 = r4
943
975
  else
944
- if has_terminal?('quot', false, index)
945
- r5 = instantiate_node(SyntaxNode,input, index...(index + 4))
946
- @index += 4
976
+ if (match_len = has_terminal?('quot', false, index))
977
+ r5 = instantiate_node(SyntaxNode,input, index...(index + match_len))
978
+ @index += match_len
947
979
  else
948
980
  terminal_parse_failure('quot')
949
981
  r5 = nil
950
982
  end
951
983
  if r5
984
+ r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true
952
985
  r0 = r5
953
986
  else
954
987
  @index = i0
@@ -969,7 +1002,7 @@ module FormattedText
969
1002
  if node_cache[:spaces].has_key?(index)
970
1003
  cached = node_cache[:spaces][index]
971
1004
  if cached
972
- cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
1005
+ node_cache[:spaces][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
973
1006
  @index = cached.interval.end
974
1007
  end
975
1008
  return cached
@@ -977,9 +1010,9 @@ module FormattedText
977
1010
 
978
1011
  s0, i0 = [], index
979
1012
  loop do
980
- if has_terminal?(' ', false, index)
981
- r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
982
- @index += 1
1013
+ if (match_len = has_terminal?(' ', false, index))
1014
+ r1 = true
1015
+ @index += match_len
983
1016
  else
984
1017
  terminal_parse_failure(' ')
985
1018
  r1 = nil
@@ -1004,9 +1037,10 @@ module FormattedText
1004
1037
 
1005
1038
  end
1006
1039
 
1007
- class FormattedTextParser < Treetop::Runtime::CompiledParser
1008
- include FormattedText
1040
+ class MarkupParser < Treetop::Runtime::CompiledParser
1041
+ include Markup
1009
1042
  end
1010
1043
 
1011
1044
  end
1012
1045
  end
1046
+ end