Class: RedQuilt::BlockParser
- Inherits:
-
Object
- Object
- RedQuilt::BlockParser
- Defined in:
- lib/red_quilt/block_parser.rb
Instance Attribute Summary collapse
-
#arena ⇒ Object
readonly
Returns the value of attribute arena.
-
#diagnostics ⇒ Object
readonly
Returns the value of attribute diagnostics.
-
#references ⇒ Object
readonly
Returns the value of attribute references.
Instance Method Summary collapse
-
#initialize(arena, footnotes: nil) ⇒ BlockParser
constructor
A new instance of BlockParser.
-
#lazy_break?(lines, index) ⇒ Boolean
A line at less-than-N indent breaks lazy continuation when it would itself start a new block (heading, thematic break, fenced/indented code, html block, blockquote, list item, table).
- #paragraph_eligible_line?(content) ⇒ Boolean
- #parse ⇒ Object
-
#parse_lines(parent_id, lines, transformed:) ⇒ Object
parse_lines returns true if it encountered a blank line BETWEEN two block-level constructs at this scope.
- #thematic_break?(text) ⇒ Boolean
Constructor Details
#initialize(arena, footnotes: nil) ⇒ BlockParser
Returns a new instance of BlockParser.
5 6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/red_quilt/block_parser.rb', line 5 def initialize(arena, footnotes: nil) @arena = arena @lines = build_lines(arena.source) @references = {} @footnotes = footnotes @diagnostics = [] # Cached collaborator parsers — created once and reused for every # block of the corresponding type (including nested ones) so the # dispatch path stays allocation-free. @list_parser = List::Parser.new(self) @blockquote_parser = Blockquote::Parser.new(self) @footnote_parser = FootnoteDefinition::Parser.new(self) end |
Instance Attribute Details
#arena ⇒ Object (readonly)
Returns the value of attribute arena.
19 20 21 |
# File 'lib/red_quilt/block_parser.rb', line 19 def arena @arena end |
#diagnostics ⇒ Object (readonly)
Returns the value of attribute diagnostics.
19 20 21 |
# File 'lib/red_quilt/block_parser.rb', line 19 def diagnostics @diagnostics end |
#references ⇒ Object (readonly)
Returns the value of attribute references.
19 20 21 |
# File 'lib/red_quilt/block_parser.rb', line 19 def references @references end |
Instance Method Details
#lazy_break?(lines, index) ⇒ Boolean
A line at less-than-N indent breaks lazy continuation when it would itself start a new block (heading, thematic break, fenced/indented code, html block, blockquote, list item, table). Same predicate as paragraph_interrupt? minus the “index > 0” guard.
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/red_quilt/block_parser.rb', line 100 def lazy_break?(lines, index) line = lines[index] return true if atx_heading(line.content) return true if thematic_break?(line.content) return true if fenced_code_start(line.content) # HTML type 7 doesn't break lazy continuation either. if (type = html_block_type(line.content)) && type != 7 return true end return true if Blockquote.match?(line.content) if (li = List.match(line.content)) && List.interrupts_paragraph?(li) return true end return true if table_start?(lines, index) false end |
#paragraph_eligible_line?(content) ⇒ Boolean
130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/red_quilt/block_parser.rb', line 130 def paragraph_eligible_line?(content) return false if indented_code_line?(content) return false if fenced_code_start(content) return false if atx_heading(content) return false if thematic_break?(content) return false if html_block_start?(content) return false if List.match(content) return false if Blockquote.match?(content) true end |
#parse ⇒ Object
21 22 23 24 25 26 |
# File 'lib/red_quilt/block_parser.rb', line 21 def parse @root_id = @arena.add_node(NodeType::DOCUMENT, source_start: 0, source_len: @arena.source.bytesize) parse_lines(@root_id, @lines, transformed: false) @footnote_parser.move_section_to_end(@root_id) if @footnotes @root_id end |
#parse_lines(parent_id, lines, transformed:) ⇒ Object
parse_lines returns true if it encountered a blank line BETWEEN two block-level constructs at this scope. parse_list uses that to decide an item’s looseness — the spec says an item is loose when it “directly contains two block-level elements with a blank line between them”, and ref-defs / fence openers that don’t emit an arena child still count as block-level elements.
‘seen_block` guards against treating the empty marker line of a list item (e.g. `-` alone) as a blank “between” anything: the blank only counts after at least one real block has been emitted.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/red_quilt/block_parser.rb', line 38 def parse_lines(parent_id, lines, transformed:) saw_blank = false seen_block = false blank_then_block = false index = 0 while index < lines.length line = lines[index] if line.blank saw_blank = true if seen_block index += 1 next end blank_then_block = true if saw_blank saw_blank = false seen_block = true content = line.content if paragraph_only_line?(content) # Fast path: nothing in this line can possibly start a # different block, so skip the eight predicate checks below. index = parse_paragraph(parent_id, lines, index, transformed) next end if (fence = fenced_code_start(content)) index = parse_fenced_code(parent_id, lines, index, fence) elsif (heading = atx_heading(content)) append_heading(parent_id, line, heading, transformed) index += 1 elsif thematic_break?(content) @arena.append_child(parent_id, @arena.add_node(NodeType::THEMATIC_BREAK, source_start: line.start_byte, source_len: span_len(line))) index += 1 elsif @footnotes && (footnote = FootnoteDefinition.match(content)) index = @footnote_parser.parse(lines, index, footnote, @footnotes, @root_id) elsif (reference = ReferenceDefinition.consume(lines, index)) store_reference(reference[:reference], reference[:source_span]) index += reference[:consumed] elsif table_start?(lines, index) index = parse_table(parent_id, lines, index) elsif html_block_start?(content) index = parse_html_block(parent_id, lines, index) elsif Blockquote.match?(content) index = @blockquote_parser.parse(parent_id, lines, index) elsif List.match(content) index = @list_parser.parse(parent_id, lines, index) elsif indented_code_line?(content) index = parse_indented_code(parent_id, lines, index) else index = parse_paragraph(parent_id, lines, index, transformed) end end blank_then_block end |
#thematic_break?(text) ⇒ Boolean
126 127 128 |
# File 'lib/red_quilt/block_parser.rb', line 126 def thematic_break?(text) THEMATIC_BREAK_RE.match?(text) end |