asciidoctor 2.0.12 → 2.0.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +142 -22
- data/LICENSE +1 -1
- data/README-de.adoc +15 -6
- data/README-fr.adoc +14 -8
- data/README-jp.adoc +15 -6
- data/README-zh_CN.adoc +14 -5
- data/README.adoc +135 -125
- data/asciidoctor.gemspec +4 -11
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-it.adoc +4 -4
- data/data/locale/attributes-nl.adoc +6 -6
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +51 -52
- data/lib/asciidoctor.rb +12 -12
- data/lib/asciidoctor/abstract_block.rb +4 -4
- data/lib/asciidoctor/abstract_node.rb +10 -9
- data/lib/asciidoctor/attribute_list.rb +6 -6
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +0 -1
- data/lib/asciidoctor/cli/options.rb +27 -26
- data/lib/asciidoctor/convert.rb +1 -0
- data/lib/asciidoctor/converter.rb +5 -3
- data/lib/asciidoctor/converter/docbook5.rb +45 -26
- data/lib/asciidoctor/converter/html5.rb +89 -69
- data/lib/asciidoctor/converter/manpage.rb +113 -86
- data/lib/asciidoctor/converter/template.rb +11 -12
- data/lib/asciidoctor/document.rb +44 -51
- data/lib/asciidoctor/extensions.rb +10 -12
- data/lib/asciidoctor/helpers.rb +3 -6
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +13 -11
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +135 -150
- data/lib/asciidoctor/path_resolver.rb +3 -3
- data/lib/asciidoctor/reader.rb +72 -71
- data/lib/asciidoctor/rx.rb +4 -3
- data/lib/asciidoctor/substitutors.rb +117 -117
- 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 +6 -5
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +33 -26
- 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 +10 -11
- data/man/asciidoctor.adoc +8 -7
- metadata +14 -67
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
@@ -119,7 +119,7 @@ class Parser
|
|
119
119
|
# returns the Hash of orphan block attributes captured above the header
|
120
120
|
def self.parse_document_header(reader, document)
|
121
121
|
# capture lines of block-level metadata and plow away comment lines that precede first block
|
122
|
-
block_attrs = parse_block_metadata_lines reader, document
|
122
|
+
block_attrs = reader.skip_blank_lines ? (parse_block_metadata_lines reader, document) : {}
|
123
123
|
doc_attrs = document.attributes
|
124
124
|
|
125
125
|
# special case, block title is not allowed above document title,
|
@@ -144,7 +144,10 @@ class Parser
|
|
144
144
|
l0_section_title = nil
|
145
145
|
else
|
146
146
|
document.title = l0_section_title
|
147
|
-
doc_attrs['doctitle'] = doctitle_attr_val = document.
|
147
|
+
if (doc_attrs['doctitle'] = doctitle_attr_val = document.sub_specialchars l0_section_title).include? ATTR_REF_HEAD
|
148
|
+
# QUESTION should we defer substituting attributes until the end of the header? or should we substitute again if necessary?
|
149
|
+
doc_attrs['doctitle'] = doctitle_attr_val = document.sub_attributes doctitle_attr_val, attribute_missing: 'skip'
|
150
|
+
end
|
148
151
|
end
|
149
152
|
document.header.source_location = source_location if source_location
|
150
153
|
# default to compat-mode if document has setext doctitle
|
@@ -215,9 +218,6 @@ class Parser
|
|
215
218
|
name_section = initialize_section reader, document, {}
|
216
219
|
name_section_buffer = (reader.read_lines_until break_on_blank_lines: true, skip_line_comments: true).map {|l| l.lstrip }.join ' '
|
217
220
|
if ManpageNamePurposeRx =~ name_section_buffer
|
218
|
-
doc_attrs['manname-title'] ||= name_section.title
|
219
|
-
doc_attrs['manname-id'] = name_section.id if name_section.id
|
220
|
-
doc_attrs['manpurpose'] = $2
|
221
221
|
if (manname = $1).include? ATTR_REF_HEAD
|
222
222
|
manname = document.sub_attributes manname
|
223
223
|
end
|
@@ -226,8 +226,14 @@ class Parser
|
|
226
226
|
else
|
227
227
|
mannames = [manname]
|
228
228
|
end
|
229
|
+
if (manpurpose = $2).include? ATTR_REF_HEAD
|
230
|
+
manpurpose = document.sub_attributes manpurpose
|
231
|
+
end
|
232
|
+
doc_attrs['manname-title'] ||= name_section.title
|
233
|
+
doc_attrs['manname-id'] = name_section.id if name_section.id
|
229
234
|
doc_attrs['manname'] = manname
|
230
235
|
doc_attrs['mannames'] = mannames
|
236
|
+
doc_attrs['manpurpose'] = manpurpose
|
231
237
|
if document.backend == 'manpage'
|
232
238
|
doc_attrs['docname'] = manname
|
233
239
|
doc_attrs['outfilesuffix'] = %(.#{manvolnum})
|
@@ -327,7 +333,7 @@ class Parser
|
|
327
333
|
if current_level == 0
|
328
334
|
part = book
|
329
335
|
elsif current_level == 1 && section.special
|
330
|
-
# NOTE technically preface
|
336
|
+
# NOTE technically preface sections are only permitted in the book doctype
|
331
337
|
unless (sectname = section.sectname) == 'appendix' || sectname == 'preface' || sectname == 'abstract'
|
332
338
|
expected_next_level = nil
|
333
339
|
end
|
@@ -415,9 +421,6 @@ class Parser
|
|
415
421
|
|
416
422
|
(intro || section).blocks << new_block
|
417
423
|
attributes.clear
|
418
|
-
#else
|
419
|
-
# # don't clear attributes if we don't find a block because they may
|
420
|
-
# # be trailing attributes that didn't get associated with a block
|
421
424
|
end
|
422
425
|
end
|
423
426
|
|
@@ -452,7 +455,7 @@ class Parser
|
|
452
455
|
# of a section that need to get transfered to the next section
|
453
456
|
# see "trailing block attributes transfer to the following section" in
|
454
457
|
# test/attributes_test.rb for an example
|
455
|
-
[section
|
458
|
+
[section == parent ? nil : section, attributes.merge]
|
456
459
|
end
|
457
460
|
|
458
461
|
# Public: Parse and return the next Block at the Reader's current location
|
@@ -820,8 +823,8 @@ class Parser
|
|
820
823
|
if comma_idx > 0
|
821
824
|
language = (language.slice 0, comma_idx).strip
|
822
825
|
attributes['linenums'] = '' if comma_idx < ll - 4
|
823
|
-
|
824
|
-
attributes['linenums'] = ''
|
826
|
+
elsif ll > 4
|
827
|
+
attributes['linenums'] = ''
|
825
828
|
end
|
826
829
|
else
|
827
830
|
language = language.lstrip
|
@@ -902,9 +905,7 @@ class Parser
|
|
902
905
|
# FIXME title and caption should be assigned when block is constructed (though we need to handle all cases)
|
903
906
|
if attributes['title']
|
904
907
|
block.title = block_title = attributes.delete 'title'
|
905
|
-
|
906
|
-
block.assign_caption (attributes.delete 'caption')
|
907
|
-
end
|
908
|
+
block.assign_caption attributes.delete 'caption' if CAPTION_ATTRIBUTE_NAMES[block.context]
|
908
909
|
end
|
909
910
|
# TODO eventually remove the style attribute from the attributes hash
|
910
911
|
#block.style = attributes.delete 'style'
|
@@ -966,17 +967,12 @@ class Parser
|
|
966
967
|
# special case for fenced code blocks
|
967
968
|
if Compliance.markdown_syntax && (tip.start_with? '`')
|
968
969
|
if tip_len == 4
|
969
|
-
if tip == '````'
|
970
|
-
return
|
971
|
-
elsif (tip = tip.chop) == '```'
|
972
|
-
line = tip
|
973
|
-
line_len = tip_len = 3
|
974
|
-
else
|
970
|
+
if tip == '````' || (tip = tip.chop) != '```'
|
975
971
|
return
|
976
972
|
end
|
977
|
-
|
978
|
-
|
979
|
-
|
973
|
+
line = tip
|
974
|
+
line_len = tip_len = 3
|
975
|
+
elsif tip != '```'
|
980
976
|
return
|
981
977
|
end
|
982
978
|
elsif tip_len == 3
|
@@ -994,9 +990,10 @@ class Parser
|
|
994
990
|
# if terminator is false, that means the all the lines in the reader should be parsed
|
995
991
|
# NOTE could invoke filter in here, before and after parsing
|
996
992
|
def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
|
997
|
-
|
993
|
+
case content_model
|
994
|
+
when :skip
|
998
995
|
skip_processing, parse_as_content_model = true, :simple
|
999
|
-
|
996
|
+
when :raw
|
1000
997
|
skip_processing, parse_as_content_model = false, :simple
|
1001
998
|
else
|
1002
999
|
skip_processing, parse_as_content_model = false, content_model
|
@@ -1025,14 +1022,15 @@ class Parser
|
|
1025
1022
|
block_reader = Reader.new reader.read_lines_until(terminator: terminator, skip_processing: skip_processing, context: block_context, cursor: :at_mark), block_cursor
|
1026
1023
|
end
|
1027
1024
|
|
1028
|
-
|
1025
|
+
case content_model
|
1026
|
+
when :verbatim
|
1029
1027
|
tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i
|
1030
1028
|
if (indent = attributes['indent'])
|
1031
1029
|
adjust_indentation! lines, indent.to_i, tab_size
|
1032
1030
|
elsif tab_size > 0
|
1033
1031
|
adjust_indentation! lines, -1, tab_size
|
1034
1032
|
end
|
1035
|
-
|
1033
|
+
when :skip
|
1036
1034
|
# QUESTION should we still invoke process method if extension is specified?
|
1037
1035
|
return
|
1038
1036
|
end
|
@@ -1293,7 +1291,8 @@ class Parser
|
|
1293
1291
|
has_text = true
|
1294
1292
|
list_item = ListItem.new(list_block, (item_text = match[2]))
|
1295
1293
|
list_item.source_location = reader.cursor if list_block.document.sourcemap
|
1296
|
-
|
1294
|
+
case list_type
|
1295
|
+
when :ulist
|
1297
1296
|
list_item.marker = sibling_trait
|
1298
1297
|
if item_text.start_with?('[')
|
1299
1298
|
if style && style == 'bibliography'
|
@@ -1311,13 +1310,13 @@ class Parser
|
|
1311
1310
|
list_item.text = item_text.slice(4, item_text.length)
|
1312
1311
|
end
|
1313
1312
|
end
|
1314
|
-
|
1313
|
+
when :olist
|
1315
1314
|
sibling_trait, implicit_style = resolve_ordered_list_marker(sibling_trait, (ordinal = list_block.items.size), true, reader)
|
1316
1315
|
list_item.marker = sibling_trait
|
1317
1316
|
if ordinal == 0 && !style
|
1318
1317
|
# using list level makes more sense, but we don't track it
|
1319
|
-
# basing style on marker level is compliant with AsciiDoc
|
1320
|
-
list_block.style = implicit_style || (
|
1318
|
+
# basing style on marker level is compliant with AsciiDoc.py
|
1319
|
+
list_block.style = implicit_style || (ORDERED_LIST_STYLES[sibling_trait.length - 1] || 'arabic').to_s
|
1321
1320
|
end
|
1322
1321
|
if item_text.start_with?('[[') && LeadingInlineAnchorRx =~ item_text
|
1323
1322
|
catalog_inline_anchor $1, $2, list_item, reader
|
@@ -1443,95 +1442,89 @@ class Parser
|
|
1443
1442
|
# FIXME to be AsciiDoc compliant, we shouldn't break if style in attribute line is "literal" (i.e., [literal])
|
1444
1443
|
elsif dlist && continuation != :active && (BlockAttributeLineRx.match? this_line)
|
1445
1444
|
break
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
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 }
|
1458
|
-
else
|
1459
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1460
|
-
end
|
1461
|
-
continuation = :inactive
|
1462
|
-
# let block metadata play out until we find the block
|
1463
|
-
elsif (BlockTitleRx.match? this_line) || (BlockAttributeLineRx.match? this_line) || (AttributeEntryRx.match? this_line)
|
1464
|
-
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 }
|
1465
1456
|
else
|
1466
|
-
|
1467
|
-
within_nested_list = true
|
1468
|
-
if nested_list_type == :dlist && $3.nil_or_empty?
|
1469
|
-
# get greedy again
|
1470
|
-
has_text = false
|
1471
|
-
end
|
1472
|
-
end
|
1473
|
-
buffer << this_line
|
1474
|
-
continuation = :inactive
|
1457
|
+
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1475
1458
|
end
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
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
|
1483
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
|
1484
1482
|
|
1485
|
-
|
1486
|
-
|
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 })
|
1487
1492
|
buffer << this_line
|
1488
|
-
else
|
1489
|
-
# has_text is only relevant for dlist, which is more greedy until it has text for an item
|
1490
|
-
# for all other lists, has_text is always true
|
1491
|
-
# in this block, we have to see whether we stay in the list
|
1492
|
-
if has_text
|
1493
|
-
# TODO any way to combine this with the check after skipping blank lines?
|
1494
|
-
if is_sibling_list_item?(this_line, list_type, sibling_trait)
|
1495
|
-
break
|
1496
|
-
elsif nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line }
|
1497
|
-
buffer << this_line
|
1498
|
-
within_nested_list = true
|
1499
|
-
if nested_list_type == :dlist && $3.nil_or_empty?
|
1500
|
-
# get greedy again
|
1501
|
-
has_text = false
|
1502
|
-
end
|
1503
|
-
# slurp up any literal paragraph offset by blank lines
|
1504
|
-
# NOTE we have to check for indented list items first
|
1505
|
-
elsif LiteralParagraphRx.match? this_line
|
1506
|
-
reader.unshift_line this_line
|
1507
|
-
if dlist
|
1508
|
-
# we may be in an indented list disguised as a literal paragraph
|
1509
|
-
# so we need to make sure we don't slurp up a legitimate sibling
|
1510
|
-
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 }
|
1511
|
-
else
|
1512
|
-
buffer.concat reader.read_lines_until(preserve_last_line: true, break_on_blank_lines: true, break_on_list_continuation: true)
|
1513
|
-
end
|
1514
|
-
else
|
1515
|
-
break
|
1516
|
-
end
|
1517
|
-
else # only dlist in need of item text, so slurp it up!
|
1518
|
-
# pop the blank line so it's not interpretted as a list continuation
|
1519
|
-
buffer.pop unless within_nested_list
|
1520
|
-
buffer << this_line
|
1521
|
-
has_text = true
|
1522
|
-
end
|
1523
|
-
end
|
1524
|
-
else
|
1525
|
-
has_text = true unless this_line.empty?
|
1526
|
-
if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
|
1527
1493
|
within_nested_list = true
|
1528
1494
|
if nested_list_type == :dlist && $3.nil_or_empty?
|
1529
1495
|
# get greedy again
|
1530
1496
|
has_text = false
|
1531
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
|
1532
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
|
1533
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
|
1534
1526
|
end
|
1527
|
+
buffer << this_line
|
1535
1528
|
end
|
1536
1529
|
this_line = nil
|
1537
1530
|
end
|
@@ -1572,12 +1565,6 @@ class Parser
|
|
1572
1565
|
sect_style = attributes[1]
|
1573
1566
|
sect_id, sect_reftext, sect_title, sect_level, sect_atx = parse_section_title reader, document, attributes['id']
|
1574
1567
|
|
1575
|
-
if sect_reftext
|
1576
|
-
attributes['reftext'] = sect_reftext
|
1577
|
-
else
|
1578
|
-
sect_reftext = attributes['reftext']
|
1579
|
-
end
|
1580
|
-
|
1581
1568
|
if sect_style
|
1582
1569
|
if book && sect_style == 'abstract'
|
1583
1570
|
sect_name, sect_level = 'chapter', 1
|
@@ -1596,6 +1583,7 @@ class Parser
|
|
1596
1583
|
sect_name = 'section'
|
1597
1584
|
end
|
1598
1585
|
|
1586
|
+
attributes['reftext'] = sect_reftext if sect_reftext
|
1599
1587
|
section = Section.new parent, sect_level
|
1600
1588
|
section.id, section.title, section.sectname, section.source_location = sect_id, sect_title, sect_name, source_location
|
1601
1589
|
if sect_special
|
@@ -1603,7 +1591,7 @@ class Parser
|
|
1603
1591
|
if sect_numbered
|
1604
1592
|
section.numbered = true
|
1605
1593
|
elsif document.attributes['sectnums'] == 'all'
|
1606
|
-
section.numbered = book && sect_level == 1 ? :chapter : true
|
1594
|
+
section.numbered = (book && sect_level == 1 ? :chapter : true)
|
1607
1595
|
end
|
1608
1596
|
elsif document.attributes['sectnums'] && sect_level > 0
|
1609
1597
|
# NOTE a special section here is guaranteed to be nested in another section
|
@@ -1615,7 +1603,7 @@ class Parser
|
|
1615
1603
|
# generate an ID if one was not embedded or specified as anchor above section title
|
1616
1604
|
if (id = section.id || (section.id = (document.attributes.key? 'sectids') ? (generated_id = Section.generate_id section.title, document) : nil))
|
1617
1605
|
# convert title to resolve attributes while in scope
|
1618
|
-
section.title
|
1606
|
+
section.title unless generated_id || !(sect_title.include? ATTR_REF_HEAD)
|
1619
1607
|
unless document.register :refs, [id, section]
|
1620
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))
|
1621
1609
|
end
|
@@ -1634,9 +1622,8 @@ class Parser
|
|
1634
1622
|
#
|
1635
1623
|
# Returns the Integer section level if the Reader is positioned at a section title or nil otherwise
|
1636
1624
|
def self.is_next_line_section?(reader, attributes)
|
1637
|
-
if (style = attributes[1]) && (style == 'discrete' || style == 'float')
|
1638
|
-
|
1639
|
-
elsif Compliance.underline_style_section_titles
|
1625
|
+
return if (style = attributes[1]) && (style == 'discrete' || style == 'float')
|
1626
|
+
if Compliance.underline_style_section_titles
|
1640
1627
|
next_lines = reader.peek_lines 2, style && style == 'comment'
|
1641
1628
|
is_section_title?(next_lines[0] || '', next_lines[1])
|
1642
1629
|
else
|
@@ -1877,13 +1864,12 @@ class Parser
|
|
1877
1864
|
if explicit
|
1878
1865
|
# rebuild implicit author names to reparse
|
1879
1866
|
authors.each_with_index do |author, idx|
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
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 ' '
|
1887
1873
|
end if sparse
|
1888
1874
|
# process as names only
|
1889
1875
|
author_metadata = process_authors authors, true, false
|
@@ -2066,6 +2052,7 @@ class Parser
|
|
2066
2052
|
return true
|
2067
2053
|
end
|
2068
2054
|
end
|
2055
|
+
nil
|
2069
2056
|
end
|
2070
2057
|
|
2071
2058
|
# Process consecutive attribute entry lines, ignoring adjacent line comments and comment blocks.
|
@@ -2170,9 +2157,10 @@ class Parser
|
|
2170
2157
|
#
|
2171
2158
|
# Returns the String 0-index marker for this list item
|
2172
2159
|
def self.resolve_list_marker(list_type, marker, ordinal = 0, validate = false, reader = nil)
|
2173
|
-
|
2160
|
+
case list_type
|
2161
|
+
when :ulist
|
2174
2162
|
marker
|
2175
|
-
|
2163
|
+
when :olist
|
2176
2164
|
resolve_ordered_list_marker(marker, ordinal, validate, reader)[0]
|
2177
2165
|
else # :colist
|
2178
2166
|
'<1>'
|
@@ -2475,7 +2463,7 @@ class Parser
|
|
2475
2463
|
|
2476
2464
|
if pos == :start
|
2477
2465
|
if line.include? delimiter
|
2478
|
-
spec_part,
|
2466
|
+
spec_part, _, rest = line.partition delimiter
|
2479
2467
|
if (m = CellSpecStartRx.match spec_part)
|
2480
2468
|
return [{}, rest] if m[0].empty?
|
2481
2469
|
else
|
@@ -2484,14 +2472,12 @@ class Parser
|
|
2484
2472
|
else
|
2485
2473
|
return [nil, line]
|
2486
2474
|
end
|
2487
|
-
|
2488
|
-
if
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
return [{}, line]
|
2494
|
-
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]
|
2495
2481
|
end
|
2496
2482
|
|
2497
2483
|
spec = {}
|
@@ -2499,10 +2485,11 @@ class Parser
|
|
2499
2485
|
colspec, rowspec = m[1].split '.'
|
2500
2486
|
colspec = colspec.nil_or_empty? ? 1 : colspec.to_i
|
2501
2487
|
rowspec = rowspec.nil_or_empty? ? 1 : rowspec.to_i
|
2502
|
-
|
2488
|
+
case m[2]
|
2489
|
+
when '+'
|
2503
2490
|
spec['colspan'] = colspec unless colspec == 1
|
2504
2491
|
spec['rowspan'] = rowspec unless rowspec == 1
|
2505
|
-
|
2492
|
+
when '*'
|
2506
2493
|
spec['repeatcol'] = colspec unless colspec == 1
|
2507
2494
|
end
|
2508
2495
|
end
|
@@ -2527,7 +2514,7 @@ class Parser
|
|
2527
2514
|
# Public: Parse the first positional attribute and assign named attributes
|
2528
2515
|
#
|
2529
2516
|
# Parse the first positional attribute to extract the style, role and id
|
2530
|
-
# parts, assign the values to their
|
2517
|
+
# parts, assign the values to their corresponding attribute keys and return
|
2531
2518
|
# the parsed style from the first positional attribute.
|
2532
2519
|
#
|
2533
2520
|
# attributes - The Hash of attributes to process and update
|
@@ -2567,7 +2554,7 @@ class Parser
|
|
2567
2554
|
accum = ''
|
2568
2555
|
name = :option
|
2569
2556
|
else
|
2570
|
-
accum
|
2557
|
+
accum += c
|
2571
2558
|
end
|
2572
2559
|
end
|
2573
2560
|
|
@@ -2658,9 +2645,9 @@ class Parser
|
|
2658
2645
|
if tab_size > 0 && lines.any? {|line| line.include? TAB }
|
2659
2646
|
full_tab_space = ' ' * tab_size
|
2660
2647
|
lines.map! do |line|
|
2661
|
-
if line.empty?
|
2648
|
+
if line.empty? || (tab_idx = line.index TAB).nil?
|
2662
2649
|
line
|
2663
|
-
|
2650
|
+
else
|
2664
2651
|
if tab_idx == 0
|
2665
2652
|
leading_tabs = 0
|
2666
2653
|
line.each_byte do |b|
|
@@ -2678,22 +2665,20 @@ class Parser
|
|
2678
2665
|
if c == TAB
|
2679
2666
|
# calculate how many spaces this tab represents, then replace tab with spaces
|
2680
2667
|
if (offset = idx + spaces_added) % tab_size == 0
|
2681
|
-
spaces_added +=
|
2682
|
-
result
|
2668
|
+
spaces_added += tab_size - 1
|
2669
|
+
result += full_tab_space
|
2683
2670
|
else
|
2684
2671
|
unless (spaces = tab_size - offset % tab_size) == 1
|
2685
|
-
spaces_added +=
|
2672
|
+
spaces_added += spaces - 1
|
2686
2673
|
end
|
2687
|
-
result
|
2674
|
+
result += ' ' * spaces
|
2688
2675
|
end
|
2689
2676
|
else
|
2690
|
-
result
|
2677
|
+
result += c
|
2691
2678
|
end
|
2692
2679
|
idx += 1
|
2693
2680
|
end
|
2694
2681
|
result
|
2695
|
-
else
|
2696
|
-
line
|
2697
2682
|
end
|
2698
2683
|
end
|
2699
2684
|
end
|