asciidoctor 1.5.6 → 1.5.6.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of asciidoctor might be problematic. Click here for more details.

@@ -561,11 +561,6 @@ class AbstractNode
561
561
  :target_name => asset_name, :recover => autocorrect)
562
562
  end
563
563
 
564
- # Public: Calculate the relative path to this absolute filename from the Document#base_dir
565
- #def relative_path(filename)
566
- # (@path_resolver ||= PathResolver.new).relative_path filename, @document.base_dir
567
- #end
568
-
569
564
  # Public: Check whether the specified String is a URI by
570
565
  # matching it against the Asciidoctor::UriSniffRx regex.
571
566
  #
@@ -1025,7 +1025,7 @@ Your browser does not support the video tag.
1025
1025
  def inline_anchor node
1026
1026
  case node.type
1027
1027
  when :xref
1028
- unless (text = node.text)
1028
+ unless (text = node.text) || (text = node.attributes['path'])
1029
1029
  if AbstractNode === (ref = node.document.catalog[:refs][refid = node.attributes['refid']])
1030
1030
  text = ref.xreftext((@xrefstyle ||= node.document.attributes['xrefstyle'])) || %([#{refid}])
1031
1031
  else
@@ -162,9 +162,8 @@ module Extensions
162
162
  # QUESTION is parse_content the right method name? should we wrap in open block automatically?
163
163
  def parse_content parent, content, attributes = nil
164
164
  reader = Reader === content ? content : (Reader.new content)
165
- while reader.has_more_lines?
166
- block = Parser.next_block reader, parent, (attributes ? attributes.dup : {})
167
- parent << block if block
165
+ while ((block = Parser.next_block reader, parent, (attributes ? attributes.dup : {})) && parent << block) ||
166
+ reader.has_more_lines?
168
167
  end
169
168
  parent
170
169
  end
@@ -486,7 +485,7 @@ module Extensions
486
485
  include SyntaxDsl
487
486
 
488
487
  def contexts *value
489
- option :contexts, value.flatten
488
+ option :contexts, value.flatten.to_set
490
489
  end
491
490
  alias on_contexts contexts
492
491
  alias on_context contexts
@@ -1426,7 +1425,7 @@ module Extensions
1426
1425
  unless args.empty?
1427
1426
  raise ::ArgumentError, %(Wrong number of arguments (#{argc} for 1..2))
1428
1427
  end
1429
- groups[name] = resolved_group
1428
+ groups[name.to_sym] = resolved_group
1430
1429
  end
1431
1430
 
1432
1431
  # Public: Unregister all statically-registered extension groups.
@@ -133,12 +133,12 @@ class Parser
133
133
  # if the first line is the document title, add a header to the document and parse the header metadata
134
134
  if implicit_doctitle
135
135
  source_location = reader.cursor if document.sourcemap
136
- document.id, _, doctitle, _, single_line = parse_section_title reader, document
136
+ document.id, _, doctitle, _, atx = parse_section_title reader, document
137
137
  unless assigned_doctitle
138
138
  document.title = assigned_doctitle = doctitle
139
139
  end
140
140
  # default to compat-mode if document uses atx-style doctitle
141
- document.set_attr 'compat-mode' unless single_line || (document.attribute_locked? 'compat-mode')
141
+ document.set_attr 'compat-mode' unless atx || (document.attribute_locked? 'compat-mode')
142
142
  if (separator = block_attributes.delete 'separator')
143
143
  document.set_attr 'title-separator', separator unless document.attribute_locked? 'title-separator'
144
144
  end
@@ -371,7 +371,7 @@ class Parser
371
371
  end
372
372
  end
373
373
 
374
- reader.skip_blank_lines
374
+ reader.skip_blank_lines || break
375
375
  end
376
376
 
377
377
  if part
@@ -425,11 +425,8 @@ class Parser
425
425
  # Returns a Block object built from the parsed content of the processed
426
426
  # lines, or nothing if no block is found.
427
427
  def self.next_block(reader, parent, attributes = {}, options = {})
428
- # Skip ahead to the block content
429
- skipped = reader.skip_blank_lines
430
-
431
- # bail if we've reached the end of the parent block or document
432
- return unless reader.has_more_lines?
428
+ # skip ahead to the block content; bail if we've reached the end of the reader
429
+ return unless (skipped = reader.skip_blank_lines)
433
430
 
434
431
  # check for option to find list item text only
435
432
  # if skipped a line, assume a list continuation was
@@ -444,12 +441,10 @@ class Parser
444
441
  if options.fetch :parse_metadata, true
445
442
  # read lines until there are no more metadata lines to read
446
443
  while parse_block_metadata_line reader, document, attributes, options
447
- advanced = reader.advance
448
- end
449
- if advanced && !reader.has_more_lines?
450
- # NOTE there are no cases when these attributes are used, but clear them anyway
451
- attributes.clear
452
- return
444
+ # discard the line just processed
445
+ reader.shift
446
+ # QUESTION should we clear the attributes? no known cases when it's necessary
447
+ reader.skip_blank_lines || return
453
448
  end
454
449
  end
455
450
 
@@ -515,7 +510,7 @@ class Parser
515
510
  else
516
511
  indented, ch0 = false, this_line.chr
517
512
  layout_break_chars = md_syntax ? HYBRID_LAYOUT_BREAK_CHARS : LAYOUT_BREAK_CHARS
518
- if (layout_break_chars.key? ch0) && (md_syntax ? (HybridLayoutBreakRx.match? this_line) :
513
+ if (layout_break_chars.key? ch0) && (md_syntax ? (ExtLayoutBreakRx.match? this_line) :
519
514
  (this_line == ch0 * (ll = this_line.length) && ll > 2))
520
515
  # NOTE we're letting break lines (horizontal rule, page_break, etc) have attributes
521
516
  block = Block.new(parent, layout_break_chars[ch0], :content_model => :empty)
@@ -537,7 +532,7 @@ class Parser
537
532
  block.parse_attributes(match[3], posattrs, :sub_input => true, :sub_result => false, :into => attributes)
538
533
  # style doesn't have special meaning for media macros
539
534
  attributes.delete 'style' if attributes.key? 'style'
540
- if (target.include? '{') && (target = block.sub_attributes target, :attribute_missing => 'drop-line').empty?
535
+ if (target.include? ATTR_REF_HEAD) && (target = block.sub_attributes target, :attribute_missing => 'drop-line').empty?
541
536
  # retain as unparsed if attribute-missing is skip
542
537
  if document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip'
543
538
  return Block.new(parent, :paragraph, :content_model => :simple, :source => [this_line])
@@ -594,7 +589,7 @@ class Parser
594
589
  end
595
590
 
596
591
  # haven't found anything yet, continue
597
- if !indented && CALLOUT_LIST_LEADERS.include?(ch0 ||= this_line.chr) &&
592
+ if !indented && CALLOUT_LIST_HEADS.include?(ch0 ||= this_line.chr) &&
598
593
  (CalloutListSniffRx.match? this_line) && (match = CalloutListRx.match this_line)
599
594
  block = List.new(parent, :colist)
600
595
  attributes['style'] = 'arabic'
@@ -654,7 +649,7 @@ class Parser
654
649
  break
655
650
 
656
651
  elsif (style == 'float' || style == 'discrete') && (Compliance.underline_style_section_titles ?
657
- (is_section_title? this_line, (reader.peek_line true)) : !indented && (is_section_title? this_line))
652
+ (is_section_title? this_line, reader.peek_line) : !indented && (atx_section_title? this_line))
658
653
  reader.unshift_line this_line
659
654
  float_id, float_reftext, float_title, float_level, _ = parse_section_title(reader, document)
660
655
  attributes['reftext'] = float_reftext if float_reftext
@@ -711,17 +706,9 @@ class Parser
711
706
 
712
707
  # a normal paragraph: contiguous non-blank/non-continuation lines (left-indented or normal style)
713
708
  else
709
+ # NOTE we only get here if there's at least one line that's not a line comment
714
710
  lines = read_paragraph_lines reader, break_at_list, :skip_line_comments => true
715
711
 
716
- # NOTE we need this logic because we've asked the reader to skip
717
- # line comments, which may leave us w/ an empty buffer if those
718
- # were the only lines found
719
- if in_list && lines.empty?
720
- # call advance since the reader preserved the last line
721
- reader.advance
722
- return
723
- end
724
-
725
712
  # NOTE don't check indented here since it's extremely rare
726
713
  #if text_only || indented
727
714
  if text_only
@@ -729,7 +716,7 @@ class Parser
729
716
  # QUESTION do we even need to shift since whitespace is normalized by XML in this case?
730
717
  adjust_indentation! lines if indented && style == 'normal'
731
718
  block = Block.new(parent, :paragraph, :content_model => :simple, :source => lines, :attributes => attributes)
732
- elsif (ADMONITION_STYLE_LEADERS.include? ch0) && (this_line.include? ':') && (AdmonitionParagraphRx =~ this_line)
719
+ elsif (ADMONITION_STYLE_HEADS.include? ch0) && (this_line.include? ':') && (AdmonitionParagraphRx =~ this_line)
733
720
  lines[0] = $' # string after match
734
721
  attributes['name'] = admonition_name = (attributes['style'] = $1).downcase
735
722
  attributes['textlabel'] = (attributes.delete 'caption') || document.attributes[%(#{admonition_name}-caption)]
@@ -743,8 +730,8 @@ class Parser
743
730
  lines.pop while lines[-1].empty?
744
731
  end
745
732
  attributes['style'] = 'quote'
746
- # NOTE will only detect headings that are floating titles (not section titles)
747
- # TODO could assume a floating title when inside a block context
733
+ # NOTE will only detect discrete (aka free-floating) headings
734
+ # TODO could assume a discrete heading when inside a block context
748
735
  # FIXME Reader needs to be created w/ line info
749
736
  block = build_block(:quote, :compound, false, parent, Reader.new(lines), attributes)
750
737
  elsif ch0 == '"' && lines.size > 1 && (lines[-1].start_with? '-- ') && (lines[-2].end_with? '"')
@@ -783,6 +770,7 @@ class Parser
783
770
 
784
771
  when :comment
785
772
  build_block(block_context, :skip, terminator, parent, reader, attributes)
773
+ attributes.clear
786
774
  return
787
775
 
788
776
  when :example
@@ -879,7 +867,7 @@ class Parser
879
867
  attributes['cloaked-context'] = cloaked_context
880
868
  end
881
869
  block = build_block block_context, content_model, terminator, parent, reader, attributes, :extension => extension
882
- unless block && content_model != :skip
870
+ unless block
883
871
  attributes.clear
884
872
  return
885
873
  end
@@ -938,7 +926,7 @@ class Parser
938
926
  # returns the match data if this line is the first line of a delimited block or nil if not
939
927
  def self.is_delimited_block? line, return_match_data = false
940
928
  # highly optimized for best performance
941
- return unless (line_len = line.length) > 1 && DELIMITED_BLOCK_LEADERS.include?(line.slice 0, 2)
929
+ return unless (line_len = line.length) > 1 && DELIMITED_BLOCK_HEADS.include?(line.slice 0, 2)
942
930
  # catches open block
943
931
  if line_len == 2
944
932
  tip = line
@@ -1009,14 +997,11 @@ class Parser
1009
997
  # NOTE could invoke filter in here, before and after parsing
1010
998
  def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
1011
999
  if content_model == :skip
1012
- skip_processing = true
1013
- parse_as_content_model = :simple
1000
+ skip_processing, parse_as_content_model = true, :simple
1014
1001
  elsif content_model == :raw
1015
- skip_processing = false
1016
- parse_as_content_model = :simple
1002
+ skip_processing, parse_as_content_model = false, :simple
1017
1003
  else
1018
- skip_processing = false
1019
- parse_as_content_model = content_model
1004
+ skip_processing, parse_as_content_model = false, content_model
1020
1005
  end
1021
1006
 
1022
1007
  if terminator.nil?
@@ -1041,18 +1026,15 @@ class Parser
1041
1026
  block_reader = Reader.new reader.read_lines_until(:terminator => terminator, :skip_processing => skip_processing), reader.cursor
1042
1027
  end
1043
1028
 
1044
- if content_model == :skip
1045
- attributes.clear
1046
- # FIXME we shouldn't be mixing return types
1047
- return lines
1048
- end
1049
-
1050
1029
  if content_model == :verbatim
1051
1030
  if (indent = attributes['indent'])
1052
1031
  adjust_indentation! lines, indent, (attributes['tabsize'] || parent.document.attributes['tabsize'])
1053
1032
  elsif (tab_size = (attributes['tabsize'] || parent.document.attributes['tabsize']).to_i) > 0
1054
1033
  adjust_indentation! lines, nil, tab_size
1055
1034
  end
1035
+ elsif content_model == :skip
1036
+ # QUESTION should we still invoke process method if extension is specified?
1037
+ return
1056
1038
  end
1057
1039
 
1058
1040
  if (extension = options[:extension])
@@ -1068,7 +1050,6 @@ class Parser
1068
1050
  block_reader = Reader.new lines
1069
1051
  end
1070
1052
  else
1071
- # FIXME need a test to verify this returns nil at the right time
1072
1053
  return
1073
1054
  end
1074
1055
  else
@@ -1100,8 +1081,7 @@ class Parser
1100
1081
  #
1101
1082
  # Returns nothing.
1102
1083
  def self.parse_blocks(reader, parent)
1103
- while (block = next_block reader, parent)
1104
- parent << block
1084
+ while ((block = next_block reader, parent) && parent << block) || reader.has_more_lines?
1105
1085
  end
1106
1086
  end
1107
1087
 
@@ -1155,7 +1135,7 @@ class Parser
1155
1135
  list_block << list_item if list_item
1156
1136
  list_item = nil
1157
1137
 
1158
- reader.skip_blank_lines
1138
+ reader.skip_blank_lines || break
1159
1139
  end
1160
1140
 
1161
1141
  list_block
@@ -1190,13 +1170,13 @@ class Parser
1190
1170
  text.scan(InlineAnchorScanRx) do
1191
1171
  if (id = $1)
1192
1172
  if (reftext = $2)
1193
- next if (reftext.include? '{') && (reftext = document.sub_attributes reftext).empty?
1173
+ next if (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
1194
1174
  end
1195
1175
  else
1196
1176
  id = $3
1197
1177
  if (reftext = $4)
1198
1178
  reftext = reftext.gsub '\]', ']' if reftext.include? ']'
1199
- next if (reftext.include? '{') && (reftext = document.sub_attributes reftext).empty?
1179
+ next if (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
1200
1180
  end
1201
1181
  end
1202
1182
  unless document.register :refs, [id, (Inline.new block, :anchor, reftext, :type => :ref, :id => id), reftext]
@@ -1306,7 +1286,7 @@ class Parser
1306
1286
  end
1307
1287
 
1308
1288
  # first skip the line with the marker / term
1309
- reader.advance
1289
+ reader.shift
1310
1290
  list_item_reader = Reader.new read_lines_for_list_item(reader, list_type, sibling_trait, has_text), reader.cursor
1311
1291
  if list_item_reader.has_more_lines?
1312
1292
  # NOTE peek on the other side of any comment lines
@@ -1329,13 +1309,10 @@ class Parser
1329
1309
  # only relevant for :dlist
1330
1310
  options = {:text => !has_text}
1331
1311
 
1332
- # we can look for blocks until there are no more lines (and not worry
1333
- # about sections) since the reader is confined within the boundaries of a
1334
- # list
1335
- while list_item_reader.has_more_lines?
1336
- if (new_block = next_block(list_item_reader, list_item, {}, options))
1337
- list_item << new_block
1338
- end
1312
+ # we can look for blocks until lines are exhausted without worrying about
1313
+ # sections since reader is confined to boundaries of list
1314
+ while ((block = next_block list_item_reader, list_item, {}, options) && list_item << block) ||
1315
+ list_item_reader.has_more_lines?
1339
1316
  end
1340
1317
 
1341
1318
  list_item.fold_first(continuation_connects_first_block, content_adjacent)
@@ -1463,10 +1440,10 @@ class Parser
1463
1440
  elsif prev_line && prev_line.empty?
1464
1441
  # advance to the next line of content
1465
1442
  if this_line.empty?
1466
- reader.skip_blank_lines
1467
- this_line = reader.read_line
1468
- # stop reading if we hit eof or a sibling list item
1469
- break unless this_line && !is_sibling_list_item?(this_line, list_type, sibling_trait)
1443
+ # stop reading if we reach eof
1444
+ break unless (this_line = reader.skip_blank_lines && reader.read_line)
1445
+ # stop reading if we hit a sibling list item
1446
+ break if is_sibling_list_item? this_line, list_type, sibling_trait
1470
1447
  end
1471
1448
 
1472
1449
  if this_line == LIST_CONTINUATION
@@ -1554,7 +1531,7 @@ class Parser
1554
1531
  def self.initialize_section reader, parent, attributes = {}
1555
1532
  document = parent.document
1556
1533
  source_location = reader.cursor if document.sourcemap
1557
- sect_id, sect_reftext, sect_title, sect_level, single_line = parse_section_title reader, document
1534
+ sect_id, sect_reftext, sect_title, sect_level, atx = parse_section_title reader, document
1558
1535
  if sect_reftext
1559
1536
  attributes['reftext'] = sect_reftext
1560
1537
  elsif attributes.key? 'reftext'
@@ -1602,7 +1579,7 @@ class Parser
1602
1579
  if (id = section.id ||= (attributes['id'] ||
1603
1580
  ((document.attributes.key? 'sectids') ? (Section.generate_id section.title, document) : nil)))
1604
1581
  unless document.register :refs, [id, section, sect_reftext || section.title]
1605
- warn %(asciidoctor: WARNING: #{reader.path}: line #{reader.lineno - (single_line ? 1 : 2)}: id assigned to section already in use: #{id})
1582
+ warn %(asciidoctor: WARNING: #{reader.path}: line #{reader.lineno - (atx ? 1 : 2)}: id assigned to section already in use: #{id})
1606
1583
  end
1607
1584
  end
1608
1585
 
@@ -1619,10 +1596,12 @@ class Parser
1619
1596
  #
1620
1597
  # Returns the Integer section level if the Reader is positioned at a section title or nil otherwise
1621
1598
  def self.is_next_line_section?(reader, attributes)
1622
- if attributes.key?(1) && (attr1 = attributes[1] || '').start_with?('float', 'discrete') && FloatingTitleStyleRx.match?(attr1)
1599
+ if (style = attributes[1]) && (style.start_with? 'discrete', 'float') && (DiscreteHeadingStyleRx.match? style)
1623
1600
  return
1624
1601
  elsif reader.has_more_lines?
1625
- Compliance.underline_style_section_titles ? is_section_title?(*reader.peek_lines(2)) : is_section_title?(reader.peek_line)
1602
+ Compliance.underline_style_section_titles ?
1603
+ is_section_title?(*reader.peek_lines(2, style && style == 'comment')) :
1604
+ atx_section_title?(reader.peek_line)
1626
1605
  end
1627
1606
  end
1628
1607
 
@@ -1641,25 +1620,37 @@ class Parser
1641
1620
  end
1642
1621
  end
1643
1622
 
1644
- # Public: Checks if these lines are a section title
1623
+ # Public: Checks whether the lines given are an atx or setext section title.
1645
1624
  #
1646
- # line1 - the first line as a String
1647
- # line2 - the second line as a String (default: nil)
1625
+ # line1 - [String] candidate title.
1626
+ # line2 - [String] candidate underline (default: nil).
1648
1627
  #
1649
- # Returns the Integer section level if these lines are a section title or nil otherwise
1628
+ # Returns the [Integer] section level if these lines are a section title, otherwise nothing.
1650
1629
  def self.is_section_title?(line1, line2 = nil)
1651
- is_single_line_section_title?(line1) || (line2.nil_or_empty? ? nil : is_two_line_section_title?(line1, line2))
1630
+ atx_section_title?(line1) || (line2.nil_or_empty? ? nil : setext_section_title?(line1, line2))
1652
1631
  end
1653
1632
 
1654
- def self.is_single_line_section_title?(line1)
1655
- if (line1.start_with?('=') || (Compliance.markdown_syntax && line1.start_with?('#'))) && AtxSectionRx =~ line1
1656
- #if line1.start_with?('=', '#') && AtxSectionRx =~ line1 && (line1.start_with?('=') || Compliance.markdown_syntax)
1657
- # NOTE level is 1 less than number of line markers
1633
+ # Checks whether the line given is an atx section title.
1634
+ #
1635
+ # The level returned is 1 less than number of leading markers.
1636
+ #
1637
+ # line - [String] candidate title with leading atx marker.
1638
+ #
1639
+ # Returns the [Integer] section level if this line is an atx section title, otherwise nothing.
1640
+ def self.atx_section_title? line
1641
+ if Compliance.markdown_syntax ? ((line.start_with? '=', '#') && ExtAtxSectionTitleRx =~ line) :
1642
+ ((line.start_with? '=') && AtxSectionTitleRx =~ line)
1658
1643
  $1.length - 1
1659
1644
  end
1660
1645
  end
1661
1646
 
1662
- def self.is_two_line_section_title?(line1, line2)
1647
+ # Checks whether the lines given are an setext section title.
1648
+ #
1649
+ # line1 - [String] candidate title
1650
+ # line2 - [String] candidate underline
1651
+ #
1652
+ # Returns the [Integer] section level if these lines are an setext section title, otherwise nothing.
1653
+ def self.setext_section_title? line1, line2
1663
1654
  if (level = SETEXT_SECTION_LEVELS[line2_ch1 = line2.chr]) &&
1664
1655
  line2_ch1 * (line2_len = line2.length) == line2 && SetextSectionTitleRx.match?(line1) &&
1665
1656
  (line_length(line1) - line2_len).abs < 2
@@ -1669,18 +1660,20 @@ class Parser
1669
1660
 
1670
1661
  # Internal: Parse the section title from the current position of the reader
1671
1662
  #
1672
- # Parse a single or double-line section title. After this method is called,
1663
+ # Parse an atx (single-line) or setext (underlined) section title. After this method is called,
1673
1664
  # the Reader will be positioned at the line after the section title.
1674
1665
  #
1675
- # reader - the source reader, positioned at a section title
1676
- # document- the current document
1666
+ # For efficiency, we don't reuse methods internally that check for a section title.
1667
+ #
1668
+ # reader - the source [Reader], positioned at a section title.
1669
+ # document - the current [Document].
1677
1670
  #
1678
1671
  # Examples
1679
1672
  #
1680
1673
  # reader.lines
1681
1674
  # # => ["Foo", "~~~"]
1682
1675
  #
1683
- # id, reftext, title, level, single = parse_section_title(reader, document)
1676
+ # id, reftext, title, level, atx = parse_section_title(reader, document)
1684
1677
  #
1685
1678
  # title
1686
1679
  # # => "Foo"
@@ -1688,13 +1681,13 @@ class Parser
1688
1681
  # # => 2
1689
1682
  # id
1690
1683
  # # => nil
1691
- # single
1684
+ # atx
1692
1685
  # # => false
1693
1686
  #
1694
1687
  # line1
1695
1688
  # # => "==== Foo"
1696
1689
  #
1697
- # id, reftext, title, level, single = parse_section_title(reader, document)
1690
+ # id, reftext, title, level, atx = parse_section_title(reader, document)
1698
1691
  #
1699
1692
  # title
1700
1693
  # # => "Foo"
@@ -1702,22 +1695,20 @@ class Parser
1702
1695
  # # => 3
1703
1696
  # id
1704
1697
  # # => nil
1705
- # single
1698
+ # atx
1706
1699
  # # => true
1707
1700
  #
1708
- # returns an Array of [String, String, Integer, String, Boolean], representing the
1709
- # id, reftext, title, level and line count of the Section, or nil.
1710
- #
1711
- #--
1712
- # NOTE for efficiency, we don't reuse methods that check for a section title
1701
+ # Returns an 5-element [Array] containing the id (String), reftext (String),
1702
+ # title (String), level (Integer), and flag (Boolean) indicating whether an
1703
+ # atx section title was matched, or nothing.
1713
1704
  def self.parse_section_title(reader, document)
1714
1705
  sect_id = sect_reftext = nil
1715
1706
  line1 = reader.read_line
1716
1707
 
1717
- #if line1.start_with?('=', '#') && AtxSectionRx =~ line1 && (line1.start_with?('=') || Compliance.markdown_syntax)
1718
- if (line1.start_with?('=') || (Compliance.markdown_syntax && line1.start_with?('#'))) && AtxSectionRx =~ line1
1708
+ if Compliance.markdown_syntax ? ((line1.start_with? '=', '#') && ExtAtxSectionTitleRx =~ line1) :
1709
+ ((line1.start_with? '=') && AtxSectionTitleRx =~ line1)
1719
1710
  # NOTE level is 1 less than number of line markers
1720
- sect_level, sect_title, single_line = $1.length - 1, $2, true
1711
+ sect_level, sect_title, atx = $1.length - 1, $2, true
1721
1712
  if sect_title.end_with?(']]') && InlineSectionAnchorRx =~ sect_title && !$1 # escaped
1722
1713
  sect_title, sect_id, sect_reftext = (sect_title.slice 0, sect_title.length - $&.length), $2, $3
1723
1714
  end
@@ -1725,16 +1716,16 @@ class Parser
1725
1716
  (sect_level = SETEXT_SECTION_LEVELS[line2_ch1 = line2.chr]) &&
1726
1717
  line2_ch1 * (line2_len = line2.length) == line2 && (sect_title = SetextSectionTitleRx =~ line1 && $1) &&
1727
1718
  (line_length(line1) - line2_len).abs < 2
1728
- single_line = false
1719
+ atx = false
1729
1720
  if sect_title.end_with?(']]') && InlineSectionAnchorRx =~ sect_title && !$1 # escaped
1730
1721
  sect_title, sect_id, sect_reftext = (sect_title.slice 0, sect_title.length - $&.length), $2, $3
1731
1722
  end
1732
- reader.advance
1723
+ reader.shift
1733
1724
  else
1734
1725
  raise %(Unrecognized section at #{reader.prev_line_info})
1735
1726
  end
1736
1727
  sect_level += document.attr('leveloffset').to_i if document.attr?('leveloffset')
1737
- [sect_id, sect_reftext, sect_title, sect_level, single_line]
1728
+ [sect_id, sect_reftext, sect_title, sect_level, atx]
1738
1729
  end
1739
1730
 
1740
1731
  # Public: Calculate the number of unicode characters in the line, excluding the endline
@@ -1981,8 +1972,8 @@ class Parser
1981
1972
  def self.parse_block_metadata_lines reader, document, attributes = {}, options = {}
1982
1973
  while parse_block_metadata_line reader, document, attributes, options
1983
1974
  # discard the line just processed
1984
- reader.advance
1985
- reader.skip_blank_lines
1975
+ reader.shift
1976
+ reader.skip_blank_lines || break
1986
1977
  end
1987
1978
  attributes
1988
1979
  end
@@ -2016,7 +2007,7 @@ class Parser
2016
2007
  # NOTE registration of id and reftext is deferred until block is processed
2017
2008
  attributes['id'] = $1
2018
2009
  if (reftext = $2)
2019
- attributes['reftext'] = (reftext.include? '{') ? (document.sub_attributes reftext) : reftext
2010
+ attributes['reftext'] = (reftext.include? ATTR_REF_HEAD) ? (document.sub_attributes reftext) : reftext
2020
2011
  end
2021
2012
  return true
2022
2013
  end
@@ -2054,7 +2045,7 @@ class Parser
2054
2045
  reader.skip_comment_lines
2055
2046
  while process_attribute_entry reader, document, attributes
2056
2047
  # discard line just processed
2057
- reader.advance
2048
+ reader.shift
2058
2049
  reader.skip_comment_lines
2059
2050
  end
2060
2051
  end
@@ -2266,11 +2257,11 @@ class Parser
2266
2257
  explicit_colspecs = true
2267
2258
  end
2268
2259
 
2269
- skipped = table_reader.skip_blank_lines
2270
-
2260
+ skipped = table_reader.skip_blank_lines || 0
2271
2261
  parser_ctx = Table::ParserContext.new table_reader, table, attributes
2272
2262
  format, loop_idx, implicit_header_boundary = parser_ctx.format, -1, nil
2273
2263
  implicit_header = true unless skipped > 0 || (attributes.key? 'header-option') || (attributes.key? 'noheader-option')
2264
+
2274
2265
  while (line = table_reader.read_line)
2275
2266
  if (loop_idx += 1) > 0 && line.empty?
2276
2267
  line = nil
@@ -2361,11 +2352,11 @@ class Parser
2361
2352
  end
2362
2353
  end
2363
2354
 
2364
- table_reader.skip_blank_lines unless parser_ctx.cell_open?
2365
-
2366
- unless table_reader.has_more_lines?
2367
- # NOTE may have already closed cell in csv or dsv table (see previous call to parser_ctx.close_cell(true))
2368
- parser_ctx.close_cell true if parser_ctx.cell_open?
2355
+ # NOTE cell may already be closed if table format is csv or dsv
2356
+ if parser_ctx.cell_open?
2357
+ parser_ctx.close_cell true unless table_reader.has_more_lines?
2358
+ else
2359
+ table_reader.skip_blank_lines || break
2369
2360
  end
2370
2361
  end
2371
2362