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 18 19 20 |
# 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) @code_block_parser = CodeBlock::Parser.new(self) @html_block_parser = HtmlBlock::Parser.new(self) @table_parser = Table::Parser.new(self) end |
Instance Attribute Details
#arena ⇒ Object (readonly)
Returns the value of attribute arena.
22 23 24 |
# File 'lib/red_quilt/block_parser.rb', line 22 def arena @arena end |
#diagnostics ⇒ Object (readonly)
Returns the value of attribute diagnostics.
22 23 24 |
# File 'lib/red_quilt/block_parser.rb', line 22 def diagnostics @diagnostics end |
#references ⇒ Object (readonly)
Returns the value of attribute references.
22 23 24 |
# File 'lib/red_quilt/block_parser.rb', line 22 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.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/red_quilt/block_parser.rb', line 103 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 CodeBlock.fenced_start(line.content) # HTML type 7 doesn't break lazy continuation either. if (type = HtmlBlock.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
133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/red_quilt/block_parser.rb', line 133 def paragraph_eligible_line?(content) return false if CodeBlock.indented_line?(content) return false if CodeBlock.fenced_start(content) return false if atx_heading(content) return false if thematic_break?(content) return false if HtmlBlock.start?(content) return false if List.match(content) return false if Blockquote.match?(content) true end |
#parse ⇒ Object
24 25 26 27 28 29 |
# File 'lib/red_quilt/block_parser.rb', line 24 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.
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 92 93 94 |
# File 'lib/red_quilt/block_parser.rb', line 41 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 = CodeBlock.fenced_start(content)) index = @code_block_parser.parse_fenced(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: line.span_len)) 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 = @table_parser.parse(parent_id, lines, index) elsif HtmlBlock.start?(content) index = @html_block_parser.parse(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 CodeBlock.indented_line?(content) index = @code_block_parser.parse_indented(parent_id, lines, index) else index = parse_paragraph(parent_id, lines, index, transformed) end end blank_then_block end |
#thematic_break?(text) ⇒ Boolean
129 130 131 |
# File 'lib/red_quilt/block_parser.rb', line 129 def thematic_break?(text) THEMATIC_BREAK_RE.match?(text) end |