Module: RedQuilt::Blockquote
- Defined in:
- lib/red_quilt/blockquote.rb
Overview
CommonMark spec 5.1 blockquotes.
Module-level functions are stateless helpers used by BlockParser's
predicate dispatch. Blockquote::Parser is a cached collaborator
created once in BlockParser#initialize and reused for every
blockquote (including nested ones) — per-call state lives in method
locals so reentrant #parse calls are safe.
Defined Under Namespace
Classes: Parser
Constant Summary collapse
- BLOCKQUOTE_PREFIX_RE =
/\A {0,3}>/
Class Method Summary collapse
-
.marker_offset(text) ⇒ Object
Byte offset of the
>within the line, or nil when there is no prefix. - .match?(text) ⇒ Boolean
-
.strip_prefix(line) ⇒ Object
Strip the leading
>(and at most one column of whitespace after it) from a blockquote line.
Class Method Details
.marker_offset(text) ⇒ Object
Byte offset of the > within the line, or nil when there is no prefix.
Only spaces may precede it (at most 3), so the character index returned
by the match doubles as a byte offset.
23 24 25 26 |
# File 'lib/red_quilt/blockquote.rb', line 23 def marker_offset(text) match = BLOCKQUOTE_PREFIX_RE.match(text) match && (match.end(0) - 1) end |
.match?(text) ⇒ Boolean
16 17 18 |
# File 'lib/red_quilt/blockquote.rb', line 16 def match?(text) text.match?(BLOCKQUOTE_PREFIX_RE) end |
.strip_prefix(line) ⇒ Object
Strip the leading > (and at most one column of whitespace after
it) from a blockquote line. Returns a new Line whose
content is the inner text. If the line has no > prefix, the
original line is returned unchanged (wrapped in a fresh Line so
the caller treats it uniformly).
33 34 35 36 37 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 |
# File 'lib/red_quilt/blockquote.rb', line 33 def strip_prefix(line) content = line.content bytes = content.bytesize i = 0 abs_col = 0 # Up to 3 spaces of indent before `>`. while i < 3 && i < bytes && content.getbyte(i) == 0x20 i += 1 abs_col += 1 end unless i < bytes && content.getbyte(i) == 0x3E return Line.new(content, line.start_byte, line.end_byte, !content.match?(/\S/)) end i += 1 abs_col += 1 # consume `>` # Count column width of leading whitespace after `>` using # absolute-column tracking so a tab right after `>` (at col 1) is # correctly billed as only 3 columns of indent, not 4. ws_start_col = abs_col j = i while j < bytes b = content.getbyte(j) if b == 0x20 abs_col += 1 elsif b == 0x09 abs_col = ((abs_col / 4) + 1) * 4 else break end j += 1 end ws_cols = abs_col - ws_start_col if ws_cols >= 1 tail = (" " * (ws_cols - 1)) + content.byteslice(j..) offset = j else tail = content.byteslice(i..) offset = i end Line.new(tail, line.start_byte + offset, line.end_byte, !tail.match?(/\S/)) end |