asciidoctor 2.0.15 → 2.0.16
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.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +38 -2
- data/LICENSE +1 -1
- data/README-de.adoc +3 -3
- data/README-fr.adoc +3 -3
- data/README-jp.adoc +3 -3
- data/README-zh_CN.adoc +3 -3
- data/README.adoc +2 -2
- data/asciidoctor.gemspec +1 -8
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/stylesheets/asciidoctor-default.css +50 -48
- data/lib/asciidoctor.rb +7 -7
- data/lib/asciidoctor/abstract_block.rb +4 -4
- data/lib/asciidoctor/abstract_node.rb +9 -8
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +0 -1
- data/lib/asciidoctor/cli/options.rb +22 -22
- data/lib/asciidoctor/convert.rb +1 -0
- data/lib/asciidoctor/converter.rb +5 -3
- data/lib/asciidoctor/converter/docbook5.rb +20 -22
- data/lib/asciidoctor/converter/html5.rb +70 -60
- data/lib/asciidoctor/converter/manpage.rb +61 -52
- data/lib/asciidoctor/converter/template.rb +11 -12
- data/lib/asciidoctor/document.rb +22 -37
- data/lib/asciidoctor/extensions.rb +10 -10
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +10 -9
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +122 -141
- data/lib/asciidoctor/path_resolver.rb +3 -3
- data/lib/asciidoctor/reader.rb +67 -68
- data/lib/asciidoctor/rx.rb +2 -1
- data/lib/asciidoctor/substitutors.rb +97 -99
- data/lib/asciidoctor/syntax_highlighter.rb +8 -11
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +2 -1
- data/lib/asciidoctor/table.rb +17 -19
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +8 -9
- data/man/asciidoctor.adoc +7 -6
- metadata +7 -61
data/lib/asciidoctor/load.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Asciidoctor
|
2
3
|
class << self
|
3
4
|
# Public: Parse the AsciiDoc source input into a {Document}
|
@@ -53,7 +54,7 @@ module Asciidoctor
|
|
53
54
|
end
|
54
55
|
|
55
56
|
if ::File === input
|
56
|
-
# File#mtime on JRuby for Windows doesn't honor TZ environment variable; see https://github.com/jruby/jruby/issues/6659
|
57
|
+
# File#mtime on JRuby 9.1 for Windows doesn't honor TZ environment variable; see https://github.com/jruby/jruby/issues/6659
|
57
58
|
options[:input_mtime] = RUBY_ENGINE == 'jruby' ? (::Time.at input.mtime.to_i) : input.mtime
|
58
59
|
# NOTE defer setting infile and indir until we get a better sense of their purpose
|
59
60
|
# TODO cli checks if input path can be read and is file, but might want to add check to API too
|
@@ -84,23 +85,23 @@ module Asciidoctor
|
|
84
85
|
|
85
86
|
timings.record :parse if timings
|
86
87
|
doc
|
87
|
-
rescue =>
|
88
|
+
rescue => e
|
88
89
|
begin
|
89
90
|
context = %(asciidoctor: FAILED: #{attrs['docfile'] || '<stdin>'}: Failed to load AsciiDoc document)
|
90
|
-
if
|
91
|
+
if e.respond_to? :exception
|
91
92
|
# The original message must be explicitly preserved when wrapping a Ruby exception
|
92
|
-
|
93
|
+
wrapped_e = e.exception %(#{context} - #{e.message})
|
93
94
|
# JRuby automatically sets backtrace; MRI did not until 2.6
|
94
|
-
|
95
|
+
wrapped_e.set_backtrace e.backtrace
|
95
96
|
else
|
96
97
|
# Likely a Java exception class
|
97
|
-
|
98
|
-
|
98
|
+
wrapped_e = e.class.new context, e
|
99
|
+
wrapped_e.stack_trace = e.stack_trace
|
99
100
|
end
|
100
101
|
rescue
|
101
|
-
|
102
|
+
wrapped_e = e
|
102
103
|
end
|
103
|
-
raise
|
104
|
+
raise wrapped_e
|
104
105
|
end
|
105
106
|
|
106
107
|
# Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
|
data/lib/asciidoctor/logging.rb
CHANGED
@@ -20,10 +20,10 @@ class Logger < ::Logger
|
|
20
20
|
end
|
21
21
|
|
22
22
|
class BasicFormatter < Formatter
|
23
|
-
|
23
|
+
SEVERITY_LABEL_SUBSTITUTES = { 'WARN' => 'WARNING', 'FATAL' => 'FAILED' }
|
24
24
|
|
25
25
|
def call severity, _, progname, msg
|
26
|
-
%(#{progname}: #{
|
26
|
+
%(#{progname}: #{SEVERITY_LABEL_SUBSTITUTES[severity] || severity}: #{::String === msg ? msg : msg.inspect}#{LF})
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -35,7 +35,7 @@ class Logger < ::Logger
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class MemoryLogger < ::Logger
|
38
|
-
|
38
|
+
SEVERITY_SYMBOL_BY_VALUE = (Severity.constants false).map {|c| [(Severity.const_get c), c] }.to_h
|
39
39
|
|
40
40
|
attr_reader :messages
|
41
41
|
|
@@ -45,8 +45,8 @@ class MemoryLogger < ::Logger
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def add severity, message = nil, progname = nil
|
48
|
-
message
|
49
|
-
@messages << { severity:
|
48
|
+
message ||= block_given? ? yield : progname
|
49
|
+
@messages << { severity: SEVERITY_SYMBOL_BY_VALUE[severity || UNKNOWN], message: message }
|
50
50
|
true
|
51
51
|
end
|
52
52
|
|
@@ -59,7 +59,7 @@ class MemoryLogger < ::Logger
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def max_severity
|
62
|
-
empty? ? nil : @messages.map {|m| Severity.const_get m[:severity]
|
62
|
+
empty? ? nil : @messages.map {|m| Severity.const_get m[:severity] }.max
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -89,6 +89,7 @@ module LoggerManager
|
|
89
89
|
@logger ||= (@logger_class.new pipe)
|
90
90
|
end
|
91
91
|
|
92
|
+
# Returns the specified Logger
|
92
93
|
def logger= new_logger
|
93
94
|
@logger = new_logger || (@logger_class.new $stderr)
|
94
95
|
end
|
@@ -110,9 +111,10 @@ module Logging
|
|
110
111
|
# into - The Class that includes the {Logging} module
|
111
112
|
#
|
112
113
|
# Returns nothing
|
113
|
-
|
114
|
+
def self.included into
|
114
115
|
into.extend Logging
|
115
|
-
end
|
116
|
+
end
|
117
|
+
private_class_method :included # use separate declaration for Ruby 2.0.x
|
116
118
|
|
117
119
|
def logger
|
118
120
|
LoggerManager.logger
|
data/lib/asciidoctor/parser.rb
CHANGED
@@ -421,9 +421,6 @@ class Parser
|
|
421
421
|
|
422
422
|
(intro || section).blocks << new_block
|
423
423
|
attributes.clear
|
424
|
-
#else
|
425
|
-
# # don't clear attributes if we don't find a block because they may
|
426
|
-
# # be trailing attributes that didn't get associated with a block
|
427
424
|
end
|
428
425
|
end
|
429
426
|
|
@@ -458,7 +455,7 @@ class Parser
|
|
458
455
|
# of a section that need to get transfered to the next section
|
459
456
|
# see "trailing block attributes transfer to the following section" in
|
460
457
|
# test/attributes_test.rb for an example
|
461
|
-
[section
|
458
|
+
[section == parent ? nil : section, attributes.merge]
|
462
459
|
end
|
463
460
|
|
464
461
|
# Public: Parse and return the next Block at the Reader's current location
|
@@ -826,8 +823,8 @@ class Parser
|
|
826
823
|
if comma_idx > 0
|
827
824
|
language = (language.slice 0, comma_idx).strip
|
828
825
|
attributes['linenums'] = '' if comma_idx < ll - 4
|
829
|
-
|
830
|
-
attributes['linenums'] = ''
|
826
|
+
elsif ll > 4
|
827
|
+
attributes['linenums'] = ''
|
831
828
|
end
|
832
829
|
else
|
833
830
|
language = language.lstrip
|
@@ -908,7 +905,7 @@ class Parser
|
|
908
905
|
# FIXME title and caption should be assigned when block is constructed (though we need to handle all cases)
|
909
906
|
if attributes['title']
|
910
907
|
block.title = block_title = attributes.delete 'title'
|
911
|
-
block.assign_caption
|
908
|
+
block.assign_caption attributes.delete 'caption' if CAPTION_ATTRIBUTE_NAMES[block.context]
|
912
909
|
end
|
913
910
|
# TODO eventually remove the style attribute from the attributes hash
|
914
911
|
#block.style = attributes.delete 'style'
|
@@ -970,17 +967,12 @@ class Parser
|
|
970
967
|
# special case for fenced code blocks
|
971
968
|
if Compliance.markdown_syntax && (tip.start_with? '`')
|
972
969
|
if tip_len == 4
|
973
|
-
if tip == '````'
|
974
|
-
return
|
975
|
-
elsif (tip = tip.chop) == '```'
|
976
|
-
line = tip
|
977
|
-
line_len = tip_len = 3
|
978
|
-
else
|
970
|
+
if tip == '````' || (tip = tip.chop) != '```'
|
979
971
|
return
|
980
972
|
end
|
981
|
-
|
982
|
-
|
983
|
-
|
973
|
+
line = tip
|
974
|
+
line_len = tip_len = 3
|
975
|
+
elsif tip != '```'
|
984
976
|
return
|
985
977
|
end
|
986
978
|
elsif tip_len == 3
|
@@ -998,9 +990,10 @@ class Parser
|
|
998
990
|
# if terminator is false, that means the all the lines in the reader should be parsed
|
999
991
|
# NOTE could invoke filter in here, before and after parsing
|
1000
992
|
def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
|
1001
|
-
|
993
|
+
case content_model
|
994
|
+
when :skip
|
1002
995
|
skip_processing, parse_as_content_model = true, :simple
|
1003
|
-
|
996
|
+
when :raw
|
1004
997
|
skip_processing, parse_as_content_model = false, :simple
|
1005
998
|
else
|
1006
999
|
skip_processing, parse_as_content_model = false, content_model
|
@@ -1029,14 +1022,15 @@ class Parser
|
|
1029
1022
|
block_reader = Reader.new reader.read_lines_until(terminator: terminator, skip_processing: skip_processing, context: block_context, cursor: :at_mark), block_cursor
|
1030
1023
|
end
|
1031
1024
|
|
1032
|
-
|
1025
|
+
case content_model
|
1026
|
+
when :verbatim
|
1033
1027
|
tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i
|
1034
1028
|
if (indent = attributes['indent'])
|
1035
1029
|
adjust_indentation! lines, indent.to_i, tab_size
|
1036
1030
|
elsif tab_size > 0
|
1037
1031
|
adjust_indentation! lines, -1, tab_size
|
1038
1032
|
end
|
1039
|
-
|
1033
|
+
when :skip
|
1040
1034
|
# QUESTION should we still invoke process method if extension is specified?
|
1041
1035
|
return
|
1042
1036
|
end
|
@@ -1297,7 +1291,8 @@ class Parser
|
|
1297
1291
|
has_text = true
|
1298
1292
|
list_item = ListItem.new(list_block, (item_text = match[2]))
|
1299
1293
|
list_item.source_location = reader.cursor if list_block.document.sourcemap
|
1300
|
-
|
1294
|
+
case list_type
|
1295
|
+
when :ulist
|
1301
1296
|
list_item.marker = sibling_trait
|
1302
1297
|
if item_text.start_with?('[')
|
1303
1298
|
if style && style == 'bibliography'
|
@@ -1315,13 +1310,13 @@ class Parser
|
|
1315
1310
|
list_item.text = item_text.slice(4, item_text.length)
|
1316
1311
|
end
|
1317
1312
|
end
|
1318
|
-
|
1313
|
+
when :olist
|
1319
1314
|
sibling_trait, implicit_style = resolve_ordered_list_marker(sibling_trait, (ordinal = list_block.items.size), true, reader)
|
1320
1315
|
list_item.marker = sibling_trait
|
1321
1316
|
if ordinal == 0 && !style
|
1322
1317
|
# using list level makes more sense, but we don't track it
|
1323
1318
|
# basing style on marker level is compliant with AsciiDoc.py
|
1324
|
-
list_block.style = implicit_style || (
|
1319
|
+
list_block.style = implicit_style || (ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s
|
1325
1320
|
end
|
1326
1321
|
if item_text.start_with?('[[') && LeadingInlineAnchorRx =~ item_text
|
1327
1322
|
catalog_inline_anchor $1, $2, list_item, reader
|
@@ -1447,95 +1442,89 @@ class Parser
|
|
1447
1442
|
# FIXME to be AsciiDoc compliant, we shouldn't break if style in attribute line is "literal" (i.e., [literal])
|
1448
1443
|
elsif dlist && continuation != :active && (BlockAttributeLineRx.match? this_line)
|
1449
1444
|
break
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
|
1462
|
-
else
|
1463
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1464
|
-
end
|
1465
|
-
continuation = :inactive
|
1466
|
-
# let block metadata play out until we find the block
|
1467
|
-
elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
|
1468
|
-
buffer << this_line
|
1445
|
+
elsif continuation == :active && !this_line.empty?
|
1446
|
+
# literal paragraphs have special considerations (and this is one of
|
1447
|
+
# two entry points into one)
|
1448
|
+
# if we don't process it as a whole, then a line in it that looks like a
|
1449
|
+
# list item will throw off the exit from it
|
1450
|
+
if LiteralParagraphRx.match? this_line
|
1451
|
+
reader.unshift_line this_line
|
1452
|
+
if dlist
|
1453
|
+
# we may be in an indented list disguised as a literal paragraph
|
1454
|
+
# so we need to make sure we don't slurp up a legitimate sibling
|
1455
|
+
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
|
1469
1456
|
else
|
1470
|
-
|
1471
|
-
within_nested_list = true
|
1472
|
-
if nested_list_type == :dlist && $3.nil_or_empty?
|
1473
|
-
# get greedy again
|
1474
|
-
has_text = false
|
1475
|
-
end
|
1476
|
-
end
|
1477
|
-
buffer << this_line
|
1478
|
-
continuation = :inactive
|
1457
|
+
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1479
1458
|
end
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1484
|
-
|
1485
|
-
|
1486
|
-
|
1459
|
+
continuation = :inactive
|
1460
|
+
# let block metadata play out until we find the block
|
1461
|
+
elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
|
1462
|
+
buffer << this_line
|
1463
|
+
else
|
1464
|
+
if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx].match? this_line })
|
1465
|
+
within_nested_list = true
|
1466
|
+
if nested_list_type == :dlist && $3.nil_or_empty?
|
1467
|
+
# get greedy again
|
1468
|
+
has_text = false
|
1469
|
+
end
|
1487
1470
|
end
|
1471
|
+
buffer << this_line
|
1472
|
+
continuation = :inactive
|
1473
|
+
end
|
1474
|
+
elsif prev_line && prev_line.empty?
|
1475
|
+
# advance to the next line of content
|
1476
|
+
if this_line.empty?
|
1477
|
+
# stop reading if we reach eof
|
1478
|
+
break unless (this_line = reader.skip_blank_lines && reader.read_line)
|
1479
|
+
# stop reading if we hit a sibling list item
|
1480
|
+
break if is_sibling_list_item? this_line, list_type, sibling_trait
|
1481
|
+
end
|
1488
1482
|
|
1489
|
-
|
1490
|
-
|
1483
|
+
if this_line == LIST_CONTINUATION
|
1484
|
+
detached_continuation = buffer.size
|
1485
|
+
buffer << this_line
|
1486
|
+
elsif has_text # has_text only relevant for dlist, which is more greedy until it has text for an item; has_text is always true for all other lists
|
1487
|
+
# in this block, we have to see whether we stay in the list
|
1488
|
+
# TODO any way to combine this with the check after skipping blank lines?
|
1489
|
+
if is_sibling_list_item?(this_line, list_type, sibling_trait)
|
1490
|
+
break
|
1491
|
+
elsif (nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line })
|
1491
1492
|
buffer << this_line
|
1492
|
-
else
|
1493
|
-
# has_text is only relevant for dlist, which is more greedy until it has text for an item
|
1494
|
-
# for all other lists, has_text is always true
|
1495
|
-
# in this block, we have to see whether we stay in the list
|
1496
|
-
if has_text
|
1497
|
-
# TODO any way to combine this with the check after skipping blank lines?
|
1498
|
-
if is_sibling_list_item?(this_line, list_type, sibling_trait)
|
1499
|
-
break
|
1500
|
-
elsif nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line }
|
1501
|
-
buffer << this_line
|
1502
|
-
within_nested_list = true
|
1503
|
-
if nested_list_type == :dlist && $3.nil_or_empty?
|
1504
|
-
# get greedy again
|
1505
|
-
has_text = false
|
1506
|
-
end
|
1507
|
-
# slurp up any literal paragraph offset by blank lines
|
1508
|
-
# NOTE we have to check for indented list items first
|
1509
|
-
elsif LiteralParagraphRx.match? this_line
|
1510
|
-
reader.unshift_line this_line
|
1511
|
-
if dlist
|
1512
|
-
# we may be in an indented list disguised as a literal paragraph
|
1513
|
-
# so we need to make sure we don't slurp up a legitimate sibling
|
1514
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
|
1515
|
-
else
|
1516
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1517
|
-
end
|
1518
|
-
else
|
1519
|
-
break
|
1520
|
-
end
|
1521
|
-
else # only dlist in need of item text, so slurp it up!
|
1522
|
-
# pop the blank line so it's not interpretted as a list continuation
|
1523
|
-
buffer.pop unless within_nested_list
|
1524
|
-
buffer << this_line
|
1525
|
-
has_text = true
|
1526
|
-
end
|
1527
|
-
end
|
1528
|
-
else
|
1529
|
-
has_text = true unless this_line.empty?
|
1530
|
-
if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
|
1531
1493
|
within_nested_list = true
|
1532
1494
|
if nested_list_type == :dlist && $3.nil_or_empty?
|
1533
1495
|
# get greedy again
|
1534
1496
|
has_text = false
|
1535
1497
|
end
|
1498
|
+
# slurp up any literal paragraph offset by blank lines
|
1499
|
+
# NOTE we have to check for indented list items first
|
1500
|
+
elsif LiteralParagraphRx.match? this_line
|
1501
|
+
reader.unshift_line this_line
|
1502
|
+
if dlist
|
1503
|
+
# we may be in an indented list disguised as a literal paragraph
|
1504
|
+
# so we need to make sure we don't slurp up a legitimate sibling
|
1505
|
+
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true) {|line| is_sibling_list_item? line, list_type, sibling_trait }
|
1506
|
+
else
|
1507
|
+
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1508
|
+
end
|
1509
|
+
else
|
1510
|
+
break
|
1536
1511
|
end
|
1512
|
+
else # only dlist in need of item text, so slurp it up!
|
1513
|
+
# pop the blank line so it's not interpretted as a list continuation
|
1514
|
+
buffer.pop unless within_nested_list
|
1537
1515
|
buffer << this_line
|
1516
|
+
has_text = true
|
1517
|
+
end
|
1518
|
+
else
|
1519
|
+
has_text = true unless this_line.empty?
|
1520
|
+
if (nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line })
|
1521
|
+
within_nested_list = true
|
1522
|
+
if nested_list_type == :dlist && $3.nil_or_empty?
|
1523
|
+
# get greedy again
|
1524
|
+
has_text = false
|
1525
|
+
end
|
1538
1526
|
end
|
1527
|
+
buffer << this_line
|
1539
1528
|
end
|
1540
1529
|
this_line = nil
|
1541
1530
|
end
|
@@ -1576,12 +1565,6 @@ class Parser
|
|
1576
1565
|
sect_style = attributes[1]
|
1577
1566
|
sect_id, sect_reftext, sect_title, sect_level, sect_atx = parse_section_title reader, document, attributes['id']
|
1578
1567
|
|
1579
|
-
if sect_reftext
|
1580
|
-
attributes['reftext'] = sect_reftext
|
1581
|
-
else
|
1582
|
-
sect_reftext = attributes['reftext']
|
1583
|
-
end
|
1584
|
-
|
1585
1568
|
if sect_style
|
1586
1569
|
if book && sect_style == 'abstract'
|
1587
1570
|
sect_name, sect_level = 'chapter', 1
|
@@ -1600,6 +1583,7 @@ class Parser
|
|
1600
1583
|
sect_name = 'section'
|
1601
1584
|
end
|
1602
1585
|
|
1586
|
+
attributes['reftext'] = sect_reftext if sect_reftext
|
1603
1587
|
section = Section.new parent, sect_level
|
1604
1588
|
section.id, section.title, section.sectname, section.source_location = sect_id, sect_title, sect_name, source_location
|
1605
1589
|
if sect_special
|
@@ -1607,7 +1591,7 @@ class Parser
|
|
1607
1591
|
if sect_numbered
|
1608
1592
|
section.numbered = true
|
1609
1593
|
elsif document.attributes['sectnums'] == 'all'
|
1610
|
-
section.numbered = book && sect_level == 1 ? :chapter : true
|
1594
|
+
section.numbered = (book && sect_level == 1 ? :chapter : true)
|
1611
1595
|
end
|
1612
1596
|
elsif document.attributes['sectnums'] && sect_level > 0
|
1613
1597
|
# NOTE a special section here is guaranteed to be nested in another section
|
@@ -1619,7 +1603,7 @@ class Parser
|
|
1619
1603
|
# generate an ID if one was not embedded or specified as anchor above section title
|
1620
1604
|
if (id = section.id || (section.id = (document.attributes.key? 'sectids') ? (generated_id = Section.generate_id section.title, document) : nil))
|
1621
1605
|
# convert title to resolve attributes while in scope
|
1622
|
-
section.title
|
1606
|
+
section.title unless generated_id || !(sect_title.include? ATTR_REF_HEAD)
|
1623
1607
|
unless document.register :refs, [id, section]
|
1624
1608
|
logger.warn message_with_context %(id assigned to section already in use: #{id}), source_location: (reader.cursor_at_line reader.lineno - (sect_atx ? 1 : 2))
|
1625
1609
|
end
|
@@ -1638,9 +1622,8 @@ class Parser
|
|
1638
1622
|
#
|
1639
1623
|
# Returns the Integer section level if the Reader is positioned at a section title or nil otherwise
|
1640
1624
|
def self.is_next_line_section?(reader, attributes)
|
1641
|
-
if (style = attributes[1]) && (style == 'discrete' || style == 'float')
|
1642
|
-
|
1643
|
-
elsif Compliance.underline_style_section_titles
|
1625
|
+
return if (style = attributes[1]) && (style == 'discrete' || style == 'float')
|
1626
|
+
if Compliance.underline_style_section_titles
|
1644
1627
|
next_lines = reader.peek_lines 2, style && style == 'comment'
|
1645
1628
|
is_section_title?(next_lines[0] || '', next_lines[1])
|
1646
1629
|
else
|
@@ -1881,13 +1864,12 @@ class Parser
|
|
1881
1864
|
if explicit
|
1882
1865
|
# rebuild implicit author names to reparse
|
1883
1866
|
authors.each_with_index do |author, idx|
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
end
|
1867
|
+
next if author
|
1868
|
+
authors[idx] = [
|
1869
|
+
author_metadata[%(firstname_#{name_idx = idx + 1})],
|
1870
|
+
author_metadata[%(middlename_#{name_idx})],
|
1871
|
+
author_metadata[%(lastname_#{name_idx})]
|
1872
|
+
].compact.map {|it| it.tr ' ', '_' }.join ' '
|
1891
1873
|
end if sparse
|
1892
1874
|
# process as names only
|
1893
1875
|
author_metadata = process_authors authors, true, false
|
@@ -2070,6 +2052,7 @@ class Parser
|
|
2070
2052
|
return true
|
2071
2053
|
end
|
2072
2054
|
end
|
2055
|
+
nil
|
2073
2056
|
end
|
2074
2057
|
|
2075
2058
|
# Process consecutive attribute entry lines, ignoring adjacent line comments and comment blocks.
|
@@ -2174,9 +2157,10 @@ class Parser
|
|
2174
2157
|
#
|
2175
2158
|
# Returns the String 0-index marker for this list item
|
2176
2159
|
def self.resolve_list_marker(list_type, marker, ordinal = 0, validate = false, reader = nil)
|
2177
|
-
|
2160
|
+
case list_type
|
2161
|
+
when :ulist
|
2178
2162
|
marker
|
2179
|
-
|
2163
|
+
when :olist
|
2180
2164
|
resolve_ordered_list_marker(marker, ordinal, validate, reader)[0]
|
2181
2165
|
else # :colist
|
2182
2166
|
'<1>'
|
@@ -2479,7 +2463,7 @@ class Parser
|
|
2479
2463
|
|
2480
2464
|
if pos == :start
|
2481
2465
|
if line.include? delimiter
|
2482
|
-
spec_part,
|
2466
|
+
spec_part, _, rest = line.partition delimiter
|
2483
2467
|
if (m = CellSpecStartRx.match spec_part)
|
2484
2468
|
return [{}, rest] if m[0].empty?
|
2485
2469
|
else
|
@@ -2488,14 +2472,12 @@ class Parser
|
|
2488
2472
|
else
|
2489
2473
|
return [nil, line]
|
2490
2474
|
end
|
2491
|
-
|
2492
|
-
if
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
return [{}, line]
|
2498
|
-
end
|
2475
|
+
elsif (m = CellSpecEndRx.match line) # when pos == :end
|
2476
|
+
# NOTE return the line stripped of trailing whitespace if no cellspec is found in this case
|
2477
|
+
return [{}, line.rstrip] if m[0].lstrip.empty?
|
2478
|
+
rest = m.pre_match
|
2479
|
+
else
|
2480
|
+
return [{}, line]
|
2499
2481
|
end
|
2500
2482
|
|
2501
2483
|
spec = {}
|
@@ -2503,10 +2485,11 @@ class Parser
|
|
2503
2485
|
colspec, rowspec = m[1].split '.'
|
2504
2486
|
colspec = colspec.nil_or_empty? ? 1 : colspec.to_i
|
2505
2487
|
rowspec = rowspec.nil_or_empty? ? 1 : rowspec.to_i
|
2506
|
-
|
2488
|
+
case m[2]
|
2489
|
+
when '+'
|
2507
2490
|
spec['colspan'] = colspec unless colspec == 1
|
2508
2491
|
spec['rowspan'] = rowspec unless rowspec == 1
|
2509
|
-
|
2492
|
+
when '*'
|
2510
2493
|
spec['repeatcol'] = colspec unless colspec == 1
|
2511
2494
|
end
|
2512
2495
|
end
|
@@ -2531,7 +2514,7 @@ class Parser
|
|
2531
2514
|
# Public: Parse the first positional attribute and assign named attributes
|
2532
2515
|
#
|
2533
2516
|
# Parse the first positional attribute to extract the style, role and id
|
2534
|
-
# parts, assign the values to their
|
2517
|
+
# parts, assign the values to their corresponding attribute keys and return
|
2535
2518
|
# the parsed style from the first positional attribute.
|
2536
2519
|
#
|
2537
2520
|
# attributes - The Hash of attributes to process and update
|
@@ -2571,7 +2554,7 @@ class Parser
|
|
2571
2554
|
accum = ''
|
2572
2555
|
name = :option
|
2573
2556
|
else
|
2574
|
-
accum
|
2557
|
+
accum += c
|
2575
2558
|
end
|
2576
2559
|
end
|
2577
2560
|
|
@@ -2662,9 +2645,9 @@ class Parser
|
|
2662
2645
|
if tab_size > 0 && lines.any? {|line| line.include? TAB }
|
2663
2646
|
full_tab_space = ' ' * tab_size
|
2664
2647
|
lines.map! do |line|
|
2665
|
-
if line.empty?
|
2648
|
+
if line.empty? || (tab_idx = line.index TAB).nil?
|
2666
2649
|
line
|
2667
|
-
|
2650
|
+
else
|
2668
2651
|
if tab_idx == 0
|
2669
2652
|
leading_tabs = 0
|
2670
2653
|
line.each_byte do |b|
|
@@ -2682,22 +2665,20 @@ class Parser
|
|
2682
2665
|
if c == TAB
|
2683
2666
|
# calculate how many spaces this tab represents, then replace tab with spaces
|
2684
2667
|
if (offset = idx + spaces_added) % tab_size == 0
|
2685
|
-
spaces_added +=
|
2686
|
-
result
|
2668
|
+
spaces_added += tab_size - 1
|
2669
|
+
result += full_tab_space
|
2687
2670
|
else
|
2688
2671
|
unless (spaces = tab_size - offset % tab_size) == 1
|
2689
|
-
spaces_added +=
|
2672
|
+
spaces_added += spaces - 1
|
2690
2673
|
end
|
2691
|
-
result
|
2674
|
+
result += ' ' * spaces
|
2692
2675
|
end
|
2693
2676
|
else
|
2694
|
-
result
|
2677
|
+
result += c
|
2695
2678
|
end
|
2696
2679
|
idx += 1
|
2697
2680
|
end
|
2698
2681
|
result
|
2699
|
-
else
|
2700
|
-
line
|
2701
2682
|
end
|
2702
2683
|
end
|
2703
2684
|
end
|