Class: MTProto::Markdown::Parser
- Inherits:
-
Object
- Object
- MTProto::Markdown::Parser
- Defined in:
- lib/mtproto/markdown.rb
Overview
Single-pass scanner. Paired markers (bold/italic/underline/strike/spoiler) use a nesting stack; code/pre/links/custom-emoji are consumed as self-contained spans; blockquotes are recognised at line starts. Everything is tracked in UTF-16 units so the emitted entity offsets match the wire.
Constant Summary collapse
- MARKERS =
{ '||' => :spoiler, '__' => :underline, '*' => :bold, '_' => :italic, '~' => :strike }.freeze
- MARKER_ORDER =
Longest first so
__/||win over_/|. ['```', '||', '__', '`', '*', '_', '~'].freeze
Instance Method Summary collapse
-
#initialize(source) ⇒ Parser
constructor
A new instance of Parser.
- #parse ⇒ Object
Constructor Details
#initialize(source) ⇒ Parser
Returns a new instance of Parser.
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/mtproto/markdown.rb', line 67 def initialize(source) @chars = source.to_s.chars @len = @chars.length @i = 0 @text = +'' @u16 = 0 @stack = [] @entities = [] @quote = nil @at_line_start = true end |
Instance Method Details
#parse ⇒ Object
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/mtproto/markdown.rb', line 79 def parse scan while @i < @len close_quote raise ParseError, "unclosed #{@stack.last[:type]}" unless @stack.empty? # Drop zero-length entities (e.g. from empty markup like "**") — Telegram # rejects them with ENTITY_BOUNDS_INVALID. kept = @entities.reject { |e| e.length.to_i <= 0 } [@text, kept.sort_by { |e| [e.offset, -e.length] }] end |