# SEE: `String::md_to_html` for a shortcut.
class MarkdownProcessor
- # `MarkdownEmitter` used for ouput.
- var emitter: MarkdownEmitter is noinit, protected writable
-
# Work in extended mode (default).
#
# Behavior changes when using extended mode:
# Default = `false`
var no_location = false is writable
- init do self.emitter = new MarkdownEmitter(self)
-
# Process the mardown `input` string and return the processed output.
fun process(input: String): Writable do
# init processor
parent.remove_surrounding_empty_lines
recurse(parent, false)
# output processed text
- return emitter.emit(parent.kind)
+ decorator.headlines.clear
+ return emit(parent.kind)
end
# Split `input` string into `MDLines` and create a parent `MDBlock` with it.
return -1
end
- # Location used for next parsed token.
- #
- # This location can be changed by the emitter to adjust with `\n` found
- # in the input.
- private fun current_loc: MDLocation do return emitter.current_loc
-end
-
-# Emit output corresponding to blocks content.
-#
-# Blocks are created by a previous pass in `MarkdownProcessor`.
-# The emitter use a `Decorator` to select the output format.
-class MarkdownEmitter
-
- # Kind of processor used for parsing.
- type PROCESSOR: MarkdownProcessor
-
- # Processor containing link refs.
- var processor: PROCESSOR
-
# Kind of decorator used for decoration.
type DECORATOR: Decorator
end
# Create a new `MarkdownEmitter` using a custom `decorator`.
- init with_decorator(processor: PROCESSOR, decorator: DECORATOR) do
- init processor
+ init with_decorator(decorator: DECORATOR) do
self.decorator = decorator
end
current_loc.line_start += 1
current_loc.column_start = -current_pos
end
- var mt = processor.token_at(text, current_pos)
+ var mt = token_at(text, current_pos)
if (token != null and not token isa TokenNone) and
(mt.is_same_type(token) or
(token isa TokenEmStar and mt isa TokenStrongStar) or
# Default decorator used is `HTMLDecorator`.
interface Decorator
- # Kind of emitter used for decoration.
- type EMITTER: MarkdownEmitter
+ # Kind of processor used
+ type PROCESSOR: MarkdownProcessor
# Render a single plain char.
#
# Redefine this method to add special escaping for plain text.
- fun add_char(v: EMITTER, c: Char) do v.addc c
+ fun add_char(v: PROCESSOR, c: Char) do v.addc c
# Render a ruler block.
- fun add_ruler(v: EMITTER, block: BlockRuler) is abstract
+ fun add_ruler(v: PROCESSOR, block: BlockRuler) is abstract
# Render a headline block with corresponding level.
- fun add_headline(v: EMITTER, block: BlockHeadline) is abstract
+ fun add_headline(v: PROCESSOR, block: BlockHeadline) is abstract
# Render a paragraph block.
- fun add_paragraph(v: EMITTER, block: BlockParagraph) is abstract
+ fun add_paragraph(v: PROCESSOR, block: BlockParagraph) is abstract
# Render a code or fence block.
- fun add_code(v: EMITTER, block: BlockCode) is abstract
+ fun add_code(v: PROCESSOR, block: BlockCode) is abstract
# Render a blockquote.
- fun add_blockquote(v: EMITTER, block: BlockQuote) is abstract
+ fun add_blockquote(v: PROCESSOR, block: BlockQuote) is abstract
# Render an unordered list.
- fun add_unorderedlist(v: EMITTER, block: BlockUnorderedList) is abstract
+ fun add_unorderedlist(v: PROCESSOR, block: BlockUnorderedList) is abstract
# Render an ordered list.
- fun add_orderedlist(v: EMITTER, block: BlockOrderedList) is abstract
+ fun add_orderedlist(v: PROCESSOR, block: BlockOrderedList) is abstract
# Render a list item.
- fun add_listitem(v: EMITTER, block: BlockListItem) is abstract
+ fun add_listitem(v: PROCESSOR, block: BlockListItem) is abstract
# Render an emphasis text.
- fun add_em(v: EMITTER, text: Text) is abstract
+ fun add_em(v: PROCESSOR, text: Text) is abstract
# Render a strong text.
- fun add_strong(v: EMITTER, text: Text) is abstract
+ fun add_strong(v: PROCESSOR, text: Text) is abstract
# Render a strike text.
#
# Extended mode only (see `MarkdownProcessor::ext_mode`)
- fun add_strike(v: EMITTER, text: Text) is abstract
+ fun add_strike(v: PROCESSOR, text: Text) is abstract
# Render a link.
- fun add_link(v: EMITTER, link: Text, name: Text, comment: nullable Text) is abstract
+ fun add_link(v: PROCESSOR, link: Text, name: Text, comment: nullable Text) is abstract
# Render an image.
- fun add_image(v: EMITTER, link: Text, name: Text, comment: nullable Text) is abstract
+ fun add_image(v: PROCESSOR, link: Text, name: Text, comment: nullable Text) is abstract
# Render an abbreviation.
- fun add_abbr(v: EMITTER, name: Text, comment: Text) is abstract
+ fun add_abbr(v: PROCESSOR, name: Text, comment: Text) is abstract
# Render a code span reading from a buffer.
- fun add_span_code(v: EMITTER, buffer: Text, from, to: Int) is abstract
+ fun add_span_code(v: PROCESSOR, buffer: Text, from, to: Int) is abstract
# Render a text and escape it.
- fun append_value(v: EMITTER, value: Text) is abstract
+ fun append_value(v: PROCESSOR, value: Text) is abstract
# Render code text from buffer and escape it.
- fun append_code(v: EMITTER, buffer: Text, from, to: Int) is abstract
+ fun append_code(v: PROCESSOR, buffer: Text, from, to: Int) is abstract
# Render a character escape.
- fun escape_char(v: EMITTER, char: Char) is abstract
+ fun escape_char(v: PROCESSOR, char: Char) is abstract
# Render a line break
- fun add_line_break(v: EMITTER) is abstract
+ fun add_line_break(v: PROCESSOR) is abstract
# Generate a new html valid id from a `String`.
fun strip_id(txt: String): String is abstract
text.append "\n"
line = line.next
end
+ var block = first_block
+ while block != null do
+ text.append block.text
+ text.append "\n"
+ block = block.next
+ end
return text.write_to_string
end
end
var block: MDBlock
# Output `self` using `v.decorator`.
- fun emit(v: MarkdownEmitter) do v.emit_in(self)
+ fun emit(v: MarkdownProcessor) do v.emit_in(self)
# Emit the containts of `self`, lines or blocks.
- fun emit_in(v: MarkdownEmitter) do
+ fun emit_in(v: MarkdownProcessor) do
block.remove_surrounding_empty_lines
if block.has_lines then
emit_lines(v)
end
# Emit lines contained in `block`.
- fun emit_lines(v: MarkdownEmitter) do
+ fun emit_lines(v: MarkdownProcessor) do
var tpl = v.push_buffer
var line = block.first_line
while line != null do
end
# Emit sub-blocks contained in `block`.
- fun emit_blocks(v: MarkdownEmitter) do
+ fun emit_blocks(v: MarkdownProcessor) do
var block = self.block.first_block
while block != null do
v.push_loc(block.location)
var char: Char
# Output that token using `MarkdownEmitter::decorator`.
- fun emit(v: MarkdownEmitter) do v.decorator.add_char(v, char)
+ fun emit(v: MarkdownProcessor) do v.decorator.add_char(v, char)
end
# A token without a specific meaning.
redef fun emit(v) do
var current_text = v.current_text.as(not null)
var a = pos + next_pos + 1
- var b = v.processor.find_token(current_text, a, self)
+ var b = v.find_token(current_text, a, self)
if b > 0 then
v.current_pos = b + next_pos
while a < b and current_text[a] == ' ' do a += 1
end
# Emit the hyperlink as link or image.
- private fun emit_hyper(v: MarkdownEmitter) is abstract
+ private fun emit_hyper(v: MarkdownProcessor) is abstract
# Check if the link is a valid link.
- private fun check_link(v: MarkdownEmitter, out: FlatBuffer, start: Int, token: Token): Int do
+ private fun check_link(v: MarkdownProcessor, out: FlatBuffer, start: Int, token: Token): Int do
var md = v.current_text
if md == null then return -1
var pos
pos = md.skip_spaces(pos)
if pos < start then
var tid = name.as(not null).write_to_string.to_lower
- if v.processor.link_refs.has_key(tid) then
- var lr = v.processor.link_refs[tid]
+ if v.link_refs.has_key(tid) then
+ var lr = v.link_refs[tid]
is_abbrev = lr.is_abbrev
link = lr.link
comment = lr.title
id = name
end
var tid = id.as(not null).write_to_string.to_lower
- if v.processor.link_refs.has_key(tid) then
- var lr = v.processor.link_refs[tid]
+ if v.link_refs.has_key(tid) then
+ var lr = v.link_refs[tid]
link = lr.link
comment = lr.title
end
else
var tid = name.as(not null).write_to_string.replace("\n", " ").to_lower
- if v.processor.link_refs.has_key(tid) then
- var lr = v.processor.link_refs[tid]
+ if v.link_refs.has_key(tid) then
+ var lr = v.link_refs[tid]
link = lr.link
comment = lr.title
pos = old_pos
# Is the HTML valid?
# Also take care of link and mailto shortcuts.
- private fun check_html(v: MarkdownEmitter, out: FlatBuffer, md: Text, start: Int): Int do
+ private fun check_html(v: MarkdownProcessor, out: FlatBuffer, md: Text, start: Int): Int do
# check for auto links
var tmp = new FlatBuffer
var pos = md.read_until(tmp, start + 1, ':', ' ', '>', '\n')