asciidoctor 2.0.10 → 2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +294 -30
- data/LICENSE +1 -1
- data/README-de.adoc +16 -20
- data/README-fr.adoc +15 -22
- data/README-jp.adoc +15 -26
- data/README-zh_CN.adoc +21 -25
- data/README.adoc +161 -138
- data/asciidoctor.gemspec +6 -13
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +4 -4
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +8 -7
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +6 -5
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +6 -5
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +76 -76
- data/data/stylesheets/coderay-asciidoctor.css +9 -9
- data/lib/asciidoctor/abstract_block.rb +20 -13
- data/lib/asciidoctor/abstract_node.rb +23 -12
- data/lib/asciidoctor/attribute_list.rb +64 -72
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +3 -2
- data/lib/asciidoctor/cli/options.rb +32 -31
- data/lib/asciidoctor/convert.rb +168 -162
- data/lib/asciidoctor/converter/docbook5.rb +49 -34
- data/lib/asciidoctor/converter/html5.rb +180 -139
- data/lib/asciidoctor/converter/manpage.rb +118 -90
- data/lib/asciidoctor/converter/template.rb +15 -13
- data/lib/asciidoctor/converter.rb +19 -16
- data/lib/asciidoctor/core_ext/hash/merge.rb +1 -1
- data/lib/asciidoctor/document.rb +77 -86
- data/lib/asciidoctor/extensions.rb +22 -16
- data/lib/asciidoctor/helpers.rb +20 -15
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +103 -101
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +211 -220
- data/lib/asciidoctor/path_resolver.rb +17 -15
- data/lib/asciidoctor/reader.rb +87 -79
- data/lib/asciidoctor/rx.rb +9 -7
- data/lib/asciidoctor/section.rb +7 -0
- data/lib/asciidoctor/substitutors.rb +167 -148
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +3 -2
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +13 -5
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +19 -11
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +35 -20
- data/lib/asciidoctor/syntax_highlighter.rb +16 -16
- data/lib/asciidoctor/table.rb +70 -43
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/lib/asciidoctor.rb +45 -19
- data/man/asciidoctor.1 +29 -31
- data/man/asciidoctor.adoc +35 -29
- metadata +17 -70
data/lib/asciidoctor/document.rb
CHANGED
@@ -198,7 +198,7 @@ class Document < AbstractBlock
|
|
198
198
|
# Public: Get the document catalog Hash
|
199
199
|
attr_reader :catalog
|
200
200
|
|
201
|
-
# Public: Alias catalog property as references for backwards
|
201
|
+
# Public: Alias catalog property as references for backwards compatibility
|
202
202
|
alias references catalog
|
203
203
|
|
204
204
|
# Public: Get the Hash of document counters
|
@@ -259,12 +259,14 @@ class Document < AbstractBlock
|
|
259
259
|
options[:catalog_assets] = true if parent_doc.options[:catalog_assets]
|
260
260
|
@catalog = parent_doc.catalog.merge footnotes: []
|
261
261
|
# QUESTION should we support setting attribute in parent document from nested document?
|
262
|
-
|
263
|
-
@attribute_overrides = attr_overrides = parent_doc.attributes.merge
|
264
|
-
parent_doctype = attr_overrides.delete 'doctype'
|
262
|
+
@attribute_overrides = attr_overrides = (parent_doc.instance_variable_get :@attribute_overrides).merge parent_doc.attributes
|
265
263
|
attr_overrides.delete 'compat-mode'
|
264
|
+
parent_doctype = attr_overrides.delete 'doctype'
|
265
|
+
attr_overrides.delete 'notitle'
|
266
|
+
attr_overrides.delete 'showtitle'
|
267
|
+
# QUESTION if toc is hard unset in parent document, should it be hard unset in nested document?
|
266
268
|
attr_overrides.delete 'toc'
|
267
|
-
attr_overrides.delete 'toc-placement'
|
269
|
+
@attributes['toc-placement'] = (attr_overrides.delete 'toc-placement') || 'auto'
|
268
270
|
attr_overrides.delete 'toc-position'
|
269
271
|
@safe = parent_doc.safe
|
270
272
|
@attributes['compat-mode'] = '' if (@compat_mode = parent_doc.compat_mode)
|
@@ -284,7 +286,6 @@ class Document < AbstractBlock
|
|
284
286
|
footnotes: [],
|
285
287
|
links: [],
|
286
288
|
images: [],
|
287
|
-
#indexterms: [],
|
288
289
|
callouts: Callouts.new,
|
289
290
|
includes: {},
|
290
291
|
}
|
@@ -309,7 +310,7 @@ class Document < AbstractBlock
|
|
309
310
|
end
|
310
311
|
attr_overrides[key.downcase] = val
|
311
312
|
end
|
312
|
-
if (to_file = options[:to_file])
|
313
|
+
if ::String === (to_file = options[:to_file])
|
313
314
|
attr_overrides['outfilesuffix'] = Helpers.extname to_file
|
314
315
|
end
|
315
316
|
# safely resolve the safe mode from const, int or string
|
@@ -326,8 +327,8 @@ class Document < AbstractBlock
|
|
326
327
|
@sourcemap = options[:sourcemap]
|
327
328
|
@timings = options.delete :timings
|
328
329
|
@path_resolver = PathResolver.new
|
329
|
-
initialize_extensions = (defined? ::Asciidoctor::Extensions) ?
|
330
|
-
@extensions = nil # initialize
|
330
|
+
initialize_extensions = (defined? ::Asciidoctor::Extensions) || (options.key? :extensions) ? ::Asciidoctor::Extensions : nil
|
331
|
+
@extensions = nil # initialize further down if initialize_extensions is true
|
331
332
|
options[:standalone] = options[:header_footer] if (options.key? :header_footer) && !(options.key? :standalone)
|
332
333
|
end
|
333
334
|
|
@@ -339,61 +340,46 @@ class Document < AbstractBlock
|
|
339
340
|
(@options = options).freeze
|
340
341
|
|
341
342
|
attrs = @attributes
|
342
|
-
|
343
|
-
|
344
|
-
|
343
|
+
unless parent_doc
|
344
|
+
attrs['attribute-undefined'] = Compliance.attribute_undefined
|
345
|
+
attrs['attribute-missing'] = Compliance.attribute_missing
|
346
|
+
attrs.update DEFAULT_ATTRIBUTES
|
347
|
+
# TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc,
|
348
|
+
# load attributes from data/locale/attributes-<lang>.adoc
|
349
|
+
end
|
350
|
+
|
345
351
|
if standalone
|
346
|
-
attrs['copycss'] = ''
|
347
352
|
# sync embedded attribute with :standalone option value
|
348
353
|
attr_overrides['embedded'] = nil
|
354
|
+
attrs['copycss'] = ''
|
355
|
+
attrs['iconfont-remote'] = ''
|
356
|
+
attrs['stylesheet'] = ''
|
357
|
+
attrs['webfonts'] = ''
|
349
358
|
else
|
350
|
-
attrs['notitle'] = ''
|
351
359
|
# sync embedded attribute with :standalone option value
|
352
360
|
attr_overrides['embedded'] = ''
|
361
|
+
if (attr_overrides.key? 'showtitle') && (attr_overrides.keys & %w(notitle showtitle))[-1] == 'showtitle'
|
362
|
+
attr_overrides['notitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['showtitle']]
|
363
|
+
elsif attr_overrides.key? 'notitle'
|
364
|
+
attr_overrides['showtitle'] = { nil => '', false => '@', '@' => false }[attr_overrides['notitle']]
|
365
|
+
else
|
366
|
+
attrs['notitle'] = ''
|
367
|
+
end
|
353
368
|
end
|
354
|
-
attrs['stylesheet'] = ''
|
355
|
-
attrs['webfonts'] = ''
|
356
|
-
attrs['prewrap'] = ''
|
357
|
-
attrs['attribute-undefined'] = Compliance.attribute_undefined
|
358
|
-
attrs['attribute-missing'] = Compliance.attribute_missing
|
359
|
-
attrs['iconfont-remote'] = ''
|
360
|
-
|
361
|
-
# language strings
|
362
|
-
# TODO load these based on language settings
|
363
|
-
attrs['caution-caption'] = 'Caution'
|
364
|
-
attrs['important-caption'] = 'Important'
|
365
|
-
attrs['note-caption'] = 'Note'
|
366
|
-
attrs['tip-caption'] = 'Tip'
|
367
|
-
attrs['warning-caption'] = 'Warning'
|
368
|
-
attrs['example-caption'] = 'Example'
|
369
|
-
attrs['figure-caption'] = 'Figure'
|
370
|
-
#attrs['listing-caption'] = 'Listing'
|
371
|
-
attrs['table-caption'] = 'Table'
|
372
|
-
attrs['toc-title'] = 'Table of Contents'
|
373
|
-
#attrs['preface-title'] = 'Preface'
|
374
|
-
attrs['section-refsig'] = 'Section'
|
375
|
-
attrs['part-refsig'] = 'Part'
|
376
|
-
attrs['chapter-refsig'] = 'Chapter'
|
377
|
-
attrs['appendix-caption'] = attrs['appendix-refsig'] = 'Appendix'
|
378
|
-
attrs['untitled-label'] = 'Untitled'
|
379
|
-
attrs['version-label'] = 'Version'
|
380
|
-
attrs['last-update-label'] = 'Last updated'
|
381
369
|
|
382
370
|
attr_overrides['asciidoctor'] = ''
|
383
371
|
attr_overrides['asciidoctor-version'] = ::Asciidoctor::VERSION
|
384
372
|
|
385
373
|
attr_overrides['safe-mode-name'] = (safe_mode_name = SafeMode.name_for_value @safe)
|
386
|
-
attr_overrides[
|
374
|
+
attr_overrides[%(safe-mode-#{safe_mode_name})] = ''
|
387
375
|
attr_overrides['safe-mode-level'] = @safe
|
388
376
|
|
389
|
-
# the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc
|
377
|
+
# the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc.py
|
390
378
|
attr_overrides['max-include-depth'] ||= 64
|
391
379
|
|
392
380
|
# the only way to set the allow-uri-read attribute is via the API; disabled by default
|
393
381
|
attr_overrides['allow-uri-read'] ||= nil
|
394
382
|
|
395
|
-
attr_overrides['user-home'] = USER_HOME
|
396
|
-
|
397
383
|
# remap legacy attribute names
|
398
384
|
attr_overrides['sectnums'] = attr_overrides.delete 'numbered' if attr_overrides.key? 'numbered'
|
399
385
|
attr_overrides['hardbreaks-option'] = attr_overrides.delete 'hardbreaks' if attr_overrides.key? 'hardbreaks'
|
@@ -412,11 +398,11 @@ class Document < AbstractBlock
|
|
412
398
|
|
413
399
|
# allow common attributes backend and doctype to be set using options hash, coerce values to string
|
414
400
|
if (backend_val = options[:backend])
|
415
|
-
attr_overrides['backend'] =
|
401
|
+
attr_overrides['backend'] = backend_val.to_s
|
416
402
|
end
|
417
403
|
|
418
404
|
if (doctype_val = options[:doctype])
|
419
|
-
attr_overrides['doctype'] =
|
405
|
+
attr_overrides['doctype'] = doctype_val.to_s
|
420
406
|
end
|
421
407
|
|
422
408
|
if @safe >= SafeMode::SERVER
|
@@ -429,7 +415,7 @@ class Document < AbstractBlock
|
|
429
415
|
attr_overrides['docfile'] = attr_overrides['docfile'][(attr_overrides['docdir'].length + 1)..-1]
|
430
416
|
end
|
431
417
|
attr_overrides['docdir'] = ''
|
432
|
-
attr_overrides['user-home']
|
418
|
+
attr_overrides['user-home'] ||= '.'
|
433
419
|
if @safe >= SafeMode::SECURE
|
434
420
|
attr_overrides['max-attribute-value-size'] = 4096 unless attr_overrides.key? 'max-attribute-value-size'
|
435
421
|
# assign linkcss (preventing css embedding) unless explicitly disabled from the commandline or API
|
@@ -438,6 +424,8 @@ class Document < AbstractBlock
|
|
438
424
|
# restrict document from enabling icons
|
439
425
|
attr_overrides['icons'] ||= nil
|
440
426
|
end
|
427
|
+
else
|
428
|
+
attr_overrides['user-home'] ||= USER_HOME
|
441
429
|
end
|
442
430
|
|
443
431
|
# the only way to set the max-attribute-value-size attribute is via the API; disabled by default
|
@@ -505,10 +493,10 @@ class Document < AbstractBlock
|
|
505
493
|
::AsciidoctorJ::Extensions::ExtensionRegistry === ext_registry)
|
506
494
|
@extensions = ext_registry.activate self
|
507
495
|
end
|
508
|
-
elsif
|
496
|
+
elsif (ext_block = options[:extensions]).nil?
|
497
|
+
@extensions = Extensions::Registry.new.activate self unless Extensions.groups.empty?
|
498
|
+
elsif ::Proc === ext_block
|
509
499
|
@extensions = Extensions.create(&ext_block).activate self
|
510
|
-
elsif !Extensions.groups.empty?
|
511
|
-
@extensions = Extensions::Registry.new.activate self
|
512
500
|
end
|
513
501
|
end
|
514
502
|
|
@@ -577,13 +565,15 @@ class Document < AbstractBlock
|
|
577
565
|
# returns the next number in the sequence for the specified counter
|
578
566
|
def counter name, seed = nil
|
579
567
|
return @parent_document.counter name, seed if @parent_document
|
580
|
-
if (
|
581
|
-
|
568
|
+
if ((locked = attribute_locked? name) && (curr_val = @counters[name])) || !(curr_val = @attributes[name]).nil_or_empty?
|
569
|
+
next_val = @counters[name] = Helpers.nextval curr_val
|
582
570
|
elsif seed
|
583
|
-
|
571
|
+
next_val = @counters[name] = seed == seed.to_i.to_s ? seed.to_i : seed
|
584
572
|
else
|
585
|
-
|
573
|
+
next_val = @counters[name] = 1
|
586
574
|
end
|
575
|
+
@attributes[name] = next_val unless locked
|
576
|
+
next_val
|
587
577
|
end
|
588
578
|
|
589
579
|
# Public: Increment the specified counter and store it in the block's attributes
|
@@ -625,15 +615,29 @@ class Document < AbstractBlock
|
|
625
615
|
# @reftexts is set eagerly to prevent nested lazy init
|
626
616
|
(@reftexts = {}).tap {|accum| @catalog[:refs].each {|id, ref| accum[ref.xreftext] ||= id } }[text]
|
627
617
|
else
|
628
|
-
# @reftexts is set eagerly to prevent nested lazy init
|
629
618
|
resolved_id = nil
|
630
|
-
#
|
631
|
-
|
619
|
+
# @reftexts is set eagerly to prevent nested lazy init
|
620
|
+
@reftexts = accum = {}
|
621
|
+
@catalog[:refs].each do |id, ref|
|
622
|
+
# NOTE short-circuit early since we're throwing away this table anyway
|
623
|
+
if (xreftext = ref.xreftext) == text
|
624
|
+
resolved_id = id
|
625
|
+
break
|
626
|
+
end
|
627
|
+
accum[xreftext] ||= id
|
628
|
+
end
|
632
629
|
@reftexts = nil
|
633
630
|
resolved_id
|
634
631
|
end
|
635
632
|
end
|
636
633
|
|
634
|
+
# Public: Check whether this Document has any child Section objects.
|
635
|
+
#
|
636
|
+
# Returns A [Boolean] to indicate whether this Document has child Section objects
|
637
|
+
def sections?
|
638
|
+
@next_section_index > 0
|
639
|
+
end
|
640
|
+
|
637
641
|
def footnotes?
|
638
642
|
@catalog[:footnotes].empty? ? false : true
|
639
643
|
end
|
@@ -686,7 +690,7 @@ class Document < AbstractBlock
|
|
686
690
|
#
|
687
691
|
# title - the String title to assign as the title of the document header
|
688
692
|
#
|
689
|
-
# Returns the
|
693
|
+
# Returns the specified [String] title
|
690
694
|
def title= title
|
691
695
|
unless (sect = @header)
|
692
696
|
(sect = (@header = Section.new self, 0)).sectname = 'header'
|
@@ -772,7 +776,7 @@ class Document < AbstractBlock
|
|
772
776
|
end
|
773
777
|
|
774
778
|
def notitle
|
775
|
-
|
779
|
+
@attributes.key? 'notitle'
|
776
780
|
end
|
777
781
|
|
778
782
|
def noheader
|
@@ -968,8 +972,14 @@ class Document < AbstractBlock
|
|
968
972
|
|
969
973
|
# Public: Write the output to the specified file
|
970
974
|
#
|
971
|
-
# If the converter responds to :write, delegate the work of writing the
|
972
|
-
# to that method. Otherwise, write the output the specified file.
|
975
|
+
# If the converter responds to :write, delegate the work of writing the output
|
976
|
+
# to that method. Otherwise, write the output to the specified file. In the
|
977
|
+
# latter case, this method ensures the output has a trailing newline if the
|
978
|
+
# target responds to write and the output is not empty.
|
979
|
+
#
|
980
|
+
# output - The output to write. Unless the converter responds to write, this
|
981
|
+
# object is expected to be a String.
|
982
|
+
# target - The file to write, either a File object or a String path.
|
973
983
|
#
|
974
984
|
# Returns nothing
|
975
985
|
def write output, target
|
@@ -995,25 +1005,6 @@ class Document < AbstractBlock
|
|
995
1005
|
nil
|
996
1006
|
end
|
997
1007
|
|
998
|
-
=begin
|
999
|
-
def convert_to target, opts = {}
|
1000
|
-
start = ::Time.now.to_f if (monitor = opts[:monitor])
|
1001
|
-
output = (r = converter opts).convert
|
1002
|
-
monitor[:convert] = ::Time.now.to_f - start if monitor
|
1003
|
-
|
1004
|
-
unless target.respond_to? :write
|
1005
|
-
@attributes['outfile'] = target = ::File.expand_path target
|
1006
|
-
@attributes['outdir'] = ::File.dirname target
|
1007
|
-
end
|
1008
|
-
|
1009
|
-
start = ::Time.now.to_f if monitor
|
1010
|
-
r.write output, target
|
1011
|
-
monitor[:write] = ::Time.now.to_f - start if monitor
|
1012
|
-
|
1013
|
-
output
|
1014
|
-
end
|
1015
|
-
=end
|
1016
|
-
|
1017
1008
|
def content
|
1018
1009
|
# NOTE per AsciiDoc-spec, remove the title before converting the body
|
1019
1010
|
@attributes.delete('title')
|
@@ -1035,7 +1026,7 @@ class Document < AbstractBlock
|
|
1035
1026
|
def docinfo location = :head, suffix = nil
|
1036
1027
|
if safe < SafeMode::SECURE
|
1037
1028
|
qualifier = %(-#{location}) unless location == :head
|
1038
|
-
suffix
|
1029
|
+
suffix ||= @outfilesuffix
|
1039
1030
|
|
1040
1031
|
if (docinfo = @attributes['docinfo']).nil_or_empty?
|
1041
1032
|
if @attributes.key? 'docinfo2'
|
@@ -1092,7 +1083,7 @@ class Document < AbstractBlock
|
|
1092
1083
|
end
|
1093
1084
|
|
1094
1085
|
def to_s
|
1095
|
-
%(#<#{self.class}@#{object_id} {doctype: #{doctype.inspect}, doctitle: #{(@header
|
1086
|
+
%(#<#{self.class}@#{object_id} {doctype: #{doctype.inspect}, doctitle: #{(@header && @header.title).inspect}, blocks: #{@blocks.size}}>)
|
1096
1087
|
end
|
1097
1088
|
|
1098
1089
|
private
|
@@ -1221,8 +1212,8 @@ class Document < AbstractBlock
|
|
1221
1212
|
end
|
1222
1213
|
end
|
1223
1214
|
|
1224
|
-
if (@compat_mode = attrs.key? 'compat-mode')
|
1225
|
-
attrs['source-language'] = attrs['language']
|
1215
|
+
if (@compat_mode = attrs.key? 'compat-mode') && (attrs.key? 'language')
|
1216
|
+
attrs['source-language'] = attrs['language']
|
1226
1217
|
end
|
1227
1218
|
|
1228
1219
|
unless @parent_document
|
@@ -1395,7 +1386,7 @@ class Document < AbstractBlock
|
|
1395
1386
|
attrs[%(basebackend-#{current_basebackend}-doctype-#{new_doctype})] = '' if current_basebackend
|
1396
1387
|
end
|
1397
1388
|
attrs[%(doctype-#{new_doctype})] = ''
|
1398
|
-
|
1389
|
+
@doctype = attrs['doctype'] = new_doctype
|
1399
1390
|
end
|
1400
1391
|
end
|
1401
1392
|
end
|
@@ -134,14 +134,14 @@ module Extensions
|
|
134
134
|
if opts.fetch :numbered, (style == 'appendix')
|
135
135
|
sect.numbered = true
|
136
136
|
elsif !(opts.key? :numbered) && (doc.attr? 'sectnums', 'all')
|
137
|
-
sect.numbered = book && level == 1 ? :chapter : true
|
137
|
+
sect.numbered = (book && level == 1 ? :chapter : true)
|
138
138
|
end
|
139
139
|
elsif level > 0
|
140
140
|
if opts.fetch :numbered, (doc.attr? 'sectnums')
|
141
141
|
sect.numbered = sect.special ? parent.numbered && true : true
|
142
142
|
end
|
143
|
-
|
144
|
-
sect.numbered = true
|
143
|
+
elsif opts.fetch :numbered, (book && (doc.attr? 'partnums'))
|
144
|
+
sect.numbered = true
|
145
145
|
end
|
146
146
|
if (id = attrs['id']) == false
|
147
147
|
attrs.delete 'id'
|
@@ -229,7 +229,7 @@ module Extensions
|
|
229
229
|
def parse_attributes block, attrlist, opts = {}
|
230
230
|
return {} if attrlist ? attrlist.empty? : true
|
231
231
|
attrlist = block.sub_attributes attrlist if opts[:sub_attributes] && (attrlist.include? ATTR_REF_HEAD)
|
232
|
-
(AttributeList.new attrlist).parse
|
232
|
+
(AttributeList.new attrlist).parse opts[:positional_attributes] || []
|
233
233
|
end
|
234
234
|
|
235
235
|
# TODO fill out remaining methods
|
@@ -425,7 +425,7 @@ module Extensions
|
|
425
425
|
# TIP: Postprocessors can also be used to relocate assets needed by the published
|
426
426
|
# document.
|
427
427
|
#
|
428
|
-
# Postprocessor implementations must Postprocessor.
|
428
|
+
# Postprocessor implementations must extend Postprocessor.
|
429
429
|
class Postprocessor < Processor
|
430
430
|
def process document, output
|
431
431
|
raise ::NotImplementedError, %(#{Postprocessor} subclass #{self.class} must implement the ##{__method__} method)
|
@@ -511,6 +511,10 @@ module Extensions
|
|
511
511
|
# registered to handle this name and, if found, invokes its {Processor#process}
|
512
512
|
# method to build a corresponding node in the document tree.
|
513
513
|
#
|
514
|
+
# If the process method returns an instance of Block, the content model of that
|
515
|
+
# Block is :compound, and the Block contains at least one line, the parser will
|
516
|
+
# parse those lines into blocks an assigned them to the returned block.
|
517
|
+
#
|
514
518
|
# AsciiDoc example:
|
515
519
|
#
|
516
520
|
# [shout]
|
@@ -594,6 +598,10 @@ module Extensions
|
|
594
598
|
# Public: BlockMacroProcessors are used to handle block macros that have a
|
595
599
|
# custom name.
|
596
600
|
#
|
601
|
+
# If the process method returns an instance of Block, the content model of that
|
602
|
+
# Block is :compound, and the Block contains at least one line, the parser will
|
603
|
+
# parse those lines into blocks an assigned them to the returned block.
|
604
|
+
#
|
597
605
|
# BlockMacroProcessor implementations must extend BlockMacroProcessor.
|
598
606
|
class BlockMacroProcessor < MacroProcessor
|
599
607
|
def name
|
@@ -610,7 +618,7 @@ module Extensions
|
|
610
618
|
#--
|
611
619
|
# TODO break this out into different pattern types
|
612
620
|
# for example, FullInlineMacro, ShortInlineMacro (no target) and other patterns
|
613
|
-
# FIXME for inline
|
621
|
+
# FIXME for inline macro, we need to have some way to specify the text as a passthrough
|
614
622
|
class InlineMacroProcessor < MacroProcessor
|
615
623
|
@@rx_cache = {}
|
616
624
|
|
@@ -666,7 +674,7 @@ module Extensions
|
|
666
674
|
|
667
675
|
# Public: A specialization of the Extension proxy that additionally stores a
|
668
676
|
# reference to the {Processor#process} method. By storing this reference, its
|
669
|
-
# possible to
|
677
|
+
# possible to accommodate both concrete extension implementations and Procs.
|
670
678
|
class ProcessorExtension < Extension
|
671
679
|
attr_reader :process_method
|
672
680
|
|
@@ -954,7 +962,7 @@ module Extensions
|
|
954
962
|
end
|
955
963
|
|
956
964
|
# Public: Registers an {DocinfoProcessor} with the extension registry to
|
957
|
-
# add
|
965
|
+
# add additional docinfo to the document.
|
958
966
|
#
|
959
967
|
# The DocinfoProcessor may be one of four types:
|
960
968
|
#
|
@@ -1021,8 +1029,6 @@ module Extensions
|
|
1021
1029
|
else
|
1022
1030
|
@docinfo_processor_extensions
|
1023
1031
|
end
|
1024
|
-
else
|
1025
|
-
nil
|
1026
1032
|
end
|
1027
1033
|
end
|
1028
1034
|
|
@@ -1201,7 +1207,7 @@ module Extensions
|
|
1201
1207
|
# name - the String or Symbol (coersed to a Symbol) macro name
|
1202
1208
|
#
|
1203
1209
|
# Returns the [Extension] object stored in the registry that proxies the
|
1204
|
-
#
|
1210
|
+
# corresponding BlockMacroProcessor or nil if a match is not found.
|
1205
1211
|
def find_block_macro_extension name
|
1206
1212
|
@block_macro_extensions[name.to_sym]
|
1207
1213
|
end
|
@@ -1288,7 +1294,7 @@ module Extensions
|
|
1288
1294
|
# name - the String or Symbol (coersed to a Symbol) macro name
|
1289
1295
|
#
|
1290
1296
|
# Returns the [Extension] object stored in the registry that proxies the
|
1291
|
-
#
|
1297
|
+
# corresponding InlineMacroProcessor or nil if a match is not found.
|
1292
1298
|
def find_inline_macro_extension name
|
1293
1299
|
@inline_macro_extensions[name.to_sym]
|
1294
1300
|
end
|
@@ -1330,7 +1336,7 @@ module Extensions
|
|
1330
1336
|
kind_java_class = (defined? ::AsciidoctorJ) ? (::AsciidoctorJ::Extensions.const_get kind_class_symbol, false) : nil
|
1331
1337
|
kind_store = instance_variable_get(%(@#{kind}_extensions).to_sym) || instance_variable_set(%(@#{kind}_extensions).to_sym, [])
|
1332
1338
|
# style 1: specified as block
|
1333
|
-
|
1339
|
+
if block_given?
|
1334
1340
|
config = resolve_args args, 1
|
1335
1341
|
(processor = kind_class.new config).singleton_class.enable_dsl
|
1336
1342
|
if block.arity == 0
|
@@ -1342,7 +1348,7 @@ module Extensions
|
|
1342
1348
|
raise ::ArgumentError, %(No block specified to process #{kind_name} extension at #{block.source_location})
|
1343
1349
|
end
|
1344
1350
|
processor.freeze
|
1345
|
-
ProcessorExtension.new kind, processor
|
1351
|
+
extension = ProcessorExtension.new kind, processor
|
1346
1352
|
else
|
1347
1353
|
processor, config = resolve_args args, 2
|
1348
1354
|
# style 2: specified as Class or String class name
|
@@ -1352,12 +1358,12 @@ module Extensions
|
|
1352
1358
|
end
|
1353
1359
|
processor_instance = processor_class.new config
|
1354
1360
|
processor_instance.freeze
|
1355
|
-
ProcessorExtension.new kind, processor_instance
|
1361
|
+
extension = ProcessorExtension.new kind, processor_instance
|
1356
1362
|
# style 3: specified as instance
|
1357
1363
|
elsif kind_class === processor || (kind_java_class && kind_java_class === processor)
|
1358
1364
|
processor.update_config config
|
1359
1365
|
processor.freeze
|
1360
|
-
ProcessorExtension.new kind, processor
|
1366
|
+
extension = ProcessorExtension.new kind, processor
|
1361
1367
|
else
|
1362
1368
|
raise ::ArgumentError, %(Invalid arguments specified for registering #{kind_name} extension: #{args})
|
1363
1369
|
end
|
data/lib/asciidoctor/helpers.rb
CHANGED
@@ -56,25 +56,27 @@ module Helpers
|
|
56
56
|
# If a BOM is found at the beginning of the data, a best attempt is made to
|
57
57
|
# encode it to UTF-8 from the specified source encoding.
|
58
58
|
#
|
59
|
-
# data
|
59
|
+
# data - the source data Array to prepare (no nil entries allowed)
|
60
|
+
# trim_end - whether to trim whitespace from the end of each line;
|
61
|
+
# (true cleans all whitespace; false only removes trailing newline) (default: true)
|
60
62
|
#
|
61
63
|
# returns a String Array of prepared lines
|
62
|
-
def prepare_source_array data
|
64
|
+
def prepare_source_array data, trim_end = true
|
63
65
|
return [] if data.empty?
|
64
66
|
if (leading_2_bytes = (leading_bytes = (first = data[0]).unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
|
65
67
|
data[0] = first.byteslice 2, first.bytesize
|
66
68
|
# NOTE you can't split a UTF-16LE string using .lines when encoding is UTF-8; doing so will cause this line to fail
|
67
|
-
return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).rstrip }
|
69
|
+
return trim_end ? data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).rstrip } : data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16LE).chomp }
|
68
70
|
elsif leading_2_bytes == BOM_BYTES_UTF_16BE
|
69
71
|
data[0] = first.byteslice 2, first.bytesize
|
70
|
-
return data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).rstrip }
|
72
|
+
return trim_end ? data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).rstrip } : data.map {|line| (line.encode UTF_8, ::Encoding::UTF_16BE).chomp }
|
71
73
|
elsif leading_bytes == BOM_BYTES_UTF_8
|
72
74
|
data[0] = first.byteslice 3, first.bytesize
|
73
75
|
end
|
74
76
|
if first.encoding == UTF_8
|
75
|
-
data.map {|line| line.rstrip }
|
77
|
+
trim_end ? data.map {|line| line.rstrip } : data.map {|line| line.chomp }
|
76
78
|
else
|
77
|
-
data.map {|line| (line.encode UTF_8).rstrip }
|
79
|
+
trim_end ? data.map {|line| (line.encode UTF_8).rstrip } : data.map {|line| (line.encode UTF_8).chomp }
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
@@ -86,10 +88,12 @@ module Helpers
|
|
86
88
|
# If a BOM is found at the beginning of the data, a best attempt is made to
|
87
89
|
# encode it to UTF-8 from the specified source encoding.
|
88
90
|
#
|
89
|
-
# data
|
91
|
+
# data - the source data String to prepare
|
92
|
+
# trim_end - whether to trim whitespace from the end of each line;
|
93
|
+
# (true cleans all whitespace; false only removes trailing newline) (default: true)
|
90
94
|
#
|
91
95
|
# returns a String Array of prepared lines
|
92
|
-
def prepare_source_string data
|
96
|
+
def prepare_source_string data, trim_end = true
|
93
97
|
return [] if data.nil_or_empty?
|
94
98
|
if (leading_2_bytes = (leading_bytes = data.unpack 'C3').slice 0, 2) == BOM_BYTES_UTF_16LE
|
95
99
|
data = (data.byteslice 2, data.bytesize).encode UTF_8, ::Encoding::UTF_16LE
|
@@ -101,7 +105,11 @@ module Helpers
|
|
101
105
|
elsif data.encoding != UTF_8
|
102
106
|
data = data.encode UTF_8
|
103
107
|
end
|
104
|
-
|
108
|
+
if trim_end
|
109
|
+
[].tap {|lines| data.each_line {|line| lines << line.rstrip } }
|
110
|
+
else
|
111
|
+
[].tap {|lines| data.each_line {|line| lines << line.chomp } }
|
112
|
+
end
|
105
113
|
end
|
106
114
|
|
107
115
|
# Internal: Efficiently checks whether the specified String resembles a URI
|
@@ -266,13 +274,10 @@ module Helpers
|
|
266
274
|
def nextval current
|
267
275
|
if ::Integer === current
|
268
276
|
current + 1
|
277
|
+
elsif (intval = current.to_i).to_s == current.to_s
|
278
|
+
intval + 1
|
269
279
|
else
|
270
|
-
|
271
|
-
if intval.to_s != current.to_s
|
272
|
-
(current[0].ord + 1).chr
|
273
|
-
else
|
274
|
-
intval + 1
|
275
|
-
end
|
280
|
+
current.succ
|
276
281
|
end
|
277
282
|
end
|
278
283
|
|
data/lib/asciidoctor/list.rb
CHANGED
@@ -80,12 +80,8 @@ class ListItem < AbstractBlock
|
|
80
80
|
@text && (apply_subs @text, @subs)
|
81
81
|
end
|
82
82
|
|
83
|
-
# Public: Set the String text
|
84
|
-
|
85
|
-
# Returns the new String text assigned to this ListItem
|
86
|
-
def text= val
|
87
|
-
@text = val
|
88
|
-
end
|
83
|
+
# Public: Set the String text assigned to this ListItem
|
84
|
+
attr_writer :text
|
89
85
|
|
90
86
|
# Check whether this list item has simple content (no nested blocks aside from a single outline list).
|
91
87
|
# Primarily relevant for outline lists.
|