class Markdown
class Markdown
lib/markdown.tya:2
Markdown provides the markdown/Markdown standard library API.
Source
# Markdown provides the markdown/Markdown standard library API.
class Markdown
# Markdown.source stores instance state.
# @type Nil
source: nil
# Markdown.initialize stores source Markdown text.
# @param source String source value.
# @return Self the initialized object.
initialize: source ->
self.source = source
# Markdown.escape_attr provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
escape_attr: text ->
text = text.replace("&", "&")
text = text.replace("\"", """)
text = text.replace("<", "<")
text = text.replace(">", ">")
text
# Markdown.escape_html provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
escape_html: text ->
text = text.replace("&", "&")
text = text.replace("<", "<")
text = text.replace(">", ">")
text = text.replace("\"", """)
text = text.replace("'", "'")
text
# Markdown.find_byte provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param b Int b value.
# @param start Int start value.
# @return Any the resulting value.
find_byte: text, b, start ->
n = text.byte_len()
i = start
while i < n
if text[i] == b
return i
i = i + 1
-1
# Markdown.find_double provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param b Int b value.
# @param start Int start value.
# @return Any the resulting value.
find_double: text, b, start ->
n = text.byte_len()
i = start
while i < n - 1
if text[i] == b and text[i + 1] == b
return i
i = i + 1
-1
# Markdown.flush_paragraph provides the markdown/Markdown standard library operation.
# @param blocks Any blocks value.
# @param para Any para value.
# @return Any the resulting value.
flush_paragraph: blocks, para ->
if para.len() == 0
return nil
text = para.join("\n")
blocks.push({ kind: "p", text: text })
nil
# Markdown.heading_level provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
heading_level: s ->
n = s.byte_len()
i = 0
while i < n and i < 6 and s[i] == "#"
i = i + 1
if i == 0
return 0
if i >= n
return 0
if s[i] != " "
return 0
i
# Markdown.heading_rest provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @param level Any level value.
# @return Any the resulting value.
heading_rest: s, level ->
n = s.byte_len()
rest = ""
i = level + 1
while i < n
rest = rest + s[i]
i = i + 1
rest.trim()
# Markdown.inline provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
inline: text ->
Markdown(nil).inline_with_refs(text, {})
# Markdown.inline_with_refs provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param refs Any refs value.
# @return Any the resulting value.
inline_with_refs: text, refs ->
n = text.byte_len()
out = ""
i = 0
while i < n
c = text[i]
if c == "\\" and i + 1 < n
out = out + Markdown(nil).escape_html(text[i + 1])
i = i + 2
continue
if c == "`"
end = Markdown(nil).find_byte(text, "`", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out + "<code>" + Markdown(nil).escape_html(inner) + "</code>"
i = end + 1
continue
if c == "~" and i + 1 < n and text[i + 1] == "~"
end = Markdown(nil).find_double(text, "~", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<del>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</del>"
i = end + 2
continue
if c == "*" and i + 1 < n and text[i + 1] == "*"
end = Markdown(nil).find_double(text, "*", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<strong>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</strong>"
i = end + 2
continue
if c == "_" and i + 1 < n and text[i + 1] == "_"
end = Markdown(nil).find_double(text, "_", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<strong>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</strong>"
i = end + 2
continue
if c == "*"
end = Markdown(nil).find_byte(text, "*", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out
+ "<em>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</em>"
i = end + 1
continue
if c == "_"
end = Markdown(nil).find_byte(text, "_", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out
+ "<em>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</em>"
i = end + 1
continue
if c == "!" and i + 1 < n and text[i + 1] == "["
image = Markdown(nil).try_image(text, i, refs)
if image != nil
out = out + image["html"]
i = image["end"]
continue
if c == "["
link = Markdown(nil).try_link(text, i, refs)
if link != nil
out = out + link["html"]
i = link["end"]
continue
if c == "<"
auto = Markdown(nil).try_autolink(text, i)
if auto != nil
out = out + auto["html"]
i = auto["end"]
continue
out = out + Markdown(nil).escape_html(c)
i = i + 1
out
# Markdown.is_html_block_start provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_html_block_start: s ->
s.starts_with("<div") or s.starts_with("<section") or s.starts_with("<article") or s.starts_with("<p") or s.starts_with("<table") or s.starts_with("<h1") or s.starts_with("<h2") or s.starts_with("<h3") or s.starts_with("<ul") or s.starts_with("<ol")
# Markdown.is_nested_unordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_nested_unordered_item: s ->
(s.starts_with(" - ") or s.starts_with(" * ") or s.starts_with(" + ")) and Markdown(nil).is_unordered_item(s.trim())
# Markdown.is_ordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_ordered_item: s ->
n = s.byte_len()
i = 0
while i < n and "0123456789".contains(s[i])
i = i + 1
if i == 0
return false
if i + 1 >= n
return false
if s[i] != "."
return false
if s[i + 1] != " "
return false
true
# Markdown.is_reference_def provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_reference_def: s ->
if not s.starts_with("[")
return false
close = Markdown(nil).find_byte(s, "]", 1)
if close <= 1
return false
if close + 1 >= s.byte_len()
return false
s[close + 1] == ":"
# Markdown.is_setext_underline provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_setext_underline: s ->
if s == ""
return false
marker = s[0]
if marker != "=" and marker != "-"
return false
i = 0
while i < s.byte_len()
if s[i] != marker
return false
i = i + 1
true
# Markdown.is_table_separator provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_table_separator: s ->
if not s.contains("|")
return false
cells = Markdown(nil).table_cells(s)
if cells.len() == 0
return false
for cell in cells
c = cell.trim()
if c == ""
return false
i = 0
seen_dash = false
while i < c.byte_len()
if c[i] == "-"
seen_dash = true
elseif c[i] != ":"
return false
i = i + 1
if not seen_dash
return false
true
# Markdown.is_table_start provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @param i Int i value.
# @return Boolean the resulting value.
is_table_start: lines, i ->
if i + 1 >= lines.len()
return false
head = lines[i].trim()
sep = lines[i + 1].trim()
head.contains("|") and Markdown(nil).is_table_separator(sep)
# Markdown.is_task_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_task_item: s ->
s.starts_with("- [ ] ") or s.starts_with("- [x] ") or s.starts_with("- [X] ")
# Markdown.is_thematic_break provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_thematic_break: s ->
if s == "---"
return true
if s == "***"
return true
if s == "___"
return true
false
# Markdown.is_unordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_unordered_item: s ->
if s.starts_with("- ")
return true
if s.starts_with("* ")
return true
if s.starts_with("+ ")
return true
false
# Markdown.parse provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
parse: text = nil ->
if text == nil
text = self.source
lines = text.split("\n")
refs = Markdown(nil).reference_defs(lines)
{ kind: "document", blocks: Markdown(nil).parse_blocks(lines), references: refs }
# Markdown.parse_blocks provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @return Any the resulting value.
parse_blocks: lines ->
blocks = []
para = []
i = 0
n = lines.len()
while i < n
line = lines[i]
stripped = line.trim()
if Markdown(nil).is_reference_def(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
continue
if stripped == ""
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
continue
if i + 1 < n and Markdown(nil).is_setext_underline(lines[i + 1].trim())
Markdown(nil).flush_paragraph(blocks, para)
para = []
level = 2
if lines[i + 1].trim().starts_with("=")
level = 1
blocks.push({ kind: "h", level: level, text: stripped })
i = i + 2
continue
if Markdown(nil).is_thematic_break(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
blocks.push({ kind: "hr" })
i = i + 1
continue
if Markdown(nil).is_html_block_start(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
html_lines = []
while i < n and lines[i].trim() != ""
html_lines.push(lines[i])
i = i + 1
blocks.push({ kind: "html", text: html_lines.join("\n") })
continue
heading_level = Markdown(nil).heading_level(stripped)
if heading_level > 0
Markdown(nil).flush_paragraph(blocks, para)
para = []
rest = Markdown(nil).heading_rest(stripped, heading_level)
blocks.push({ kind: "h", level: heading_level, text: rest })
i = i + 1
continue
if stripped.starts_with("```")
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
code_lines = []
info = Markdown(nil).trim_left_n(stripped, 3).trim()
while i < n and not lines[i].trim().starts_with("```")
code_lines.push(lines[i])
i = i + 1
if i < n
i = i + 1
blocks.push({ kind: "code", lines: code_lines, info: info })
continue
if stripped.starts_with("> ") or stripped == ">"
Markdown(nil).flush_paragraph(blocks, para)
para = []
quote_lines = []
while i < n
q = lines[i].trim()
if q == ""
break
if not (q.starts_with("> ") or q == ">")
break
if q == ">"
quote_lines.push("")
else
quote_lines.push(Markdown(nil).trim_left_n(q, 2))
i = i + 1
blocks.push({ kind: "quote", lines: quote_lines })
continue
if Markdown(nil).is_task_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_task_item(lines[i].trim())
task = Markdown(nil).parse_task_item(lines[i].trim())
items.push(task)
i = i + 1
blocks.push({ kind: "task_list", items: items })
continue
if Markdown(nil).is_table_start(lines, i)
Markdown(nil).flush_paragraph(blocks, para)
para = []
headers = Markdown(nil).table_cells(stripped)
i = i + 2
rows = []
while i < n and lines[i].trim().contains("|") and lines[i].trim() != ""
rows.push(Markdown(nil).table_cells(lines[i].trim()))
i = i + 1
blocks.push({ kind: "table", headers: headers, rows: rows })
continue
if Markdown(nil).is_unordered_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_unordered_item(lines[i].trim())
item_text = Markdown(nil).strip_list_marker(lines[i].trim())
children = []
i = i + 1
while i < n and Markdown(nil).is_nested_unordered_item(lines[i])
children.push(Markdown(nil).strip_list_marker(lines[i].trim()))
i = i + 1
items.push({ text: item_text, children: children })
blocks.push({ kind: "ul", items: items })
continue
if Markdown(nil).is_ordered_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_ordered_item(lines[i].trim())
item_text = Markdown(nil).strip_ordered_marker(lines[i].trim())
items.push(item_text)
i = i + 1
blocks.push({ kind: "ol", items: items })
continue
para.push(stripped)
i = i + 1
Markdown(nil).flush_paragraph(blocks, para)
blocks
# Markdown.parse_task_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
parse_task_item: s ->
checked = s.starts_with("- [x] ") or s.starts_with("- [X] ")
{ checked: checked, text: Markdown(nil).trim_left_n(s, 6) }
# Markdown.reference_defs provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @return Any the resulting value.
reference_defs: lines ->
refs = {}
for line in lines
s = line.trim()
if Markdown(nil).is_reference_def(s)
close = Markdown(nil).find_byte(s, "]", 1)
label = s.slice(1, close).trim().lower()
url = s.slice(close + 2, s.len()).trim()
refs[label] = url
refs
# Markdown.render provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @param options Dict options value.
# @return Any the resulting value.
render: ast, options ->
self.render_html_ast(ast, options)
# Markdown.render_block provides the markdown/Markdown standard library operation.
# @param block Function block value.
# @param refs Any refs value.
# @param options Dict options value.
# @return Any the resulting value.
render_block: block, refs, options ->
kind = block["kind"]
if kind == "hr"
return "<hr/>\n"
if kind == "h"
level = block["level"].to_s()
inner = Markdown(nil).inline_with_refs(block["text"], refs)
return "<h" + level + ">" + inner + "</h" + level + ">\n"
if kind == "p"
return "<p>" + Markdown(nil).inline_with_refs(block["text"], refs) + "</p>\n"
if kind == "code"
body = ""
for line in block["lines"]
body = body + Markdown(nil).escape_html(line) + "\n"
info = block["info"]
if info != nil and info != ""
return "<pre><code class=\"language-" + Markdown(nil).escape_attr(info) + "\">" + body + "</code></pre>\n"
return "<pre><code>" + body + "</code></pre>\n"
if kind == "quote"
inner_text = block["lines"].join("\n")
return "<blockquote>\n<p>" + Markdown(nil).inline_with_refs(inner_text, refs) + "</p>\n</blockquote>\n"
if kind == "ul"
out = "<ul>\n"
for item in block["items"]
text = item
children = []
if item["text"] != nil
text = item["text"]
children = item["children"]
out = out + "<li>" + Markdown(nil).inline_with_refs(text, refs)
if children.len() > 0
out = out + "\n<ul>\n"
for child in children
out = out
+ "<li>"
+ Markdown(nil).inline_with_refs(child, refs)
+ "</li>\n"
out = out + "</ul>\n"
out = out + "</li>\n"
out = out + "</ul>\n"
return out
if kind == "ol"
out = "<ol>\n"
for item in block["items"]
out = out
+ "<li>"
+ Markdown(nil).inline_with_refs(item, refs)
+ "</li>\n"
out = out + "</ol>\n"
return out
if kind == "task_list"
out = "<ul class=\"task-list\">\n"
for item in block["items"]
checked = ""
if item["checked"]
checked = " checked"
out = out
+ "<li><input type=\"checkbox\" disabled"
+ checked
+ "/> "
+ Markdown(nil).inline_with_refs(item["text"], refs)
+ "</li>\n"
out = out + "</ul>\n"
return out
if kind == "table"
out = "<table>\n<thead><tr>"
for cell in block["headers"]
out = out
+ "<th>"
+ Markdown(nil).inline_with_refs(cell, refs)
+ "</th>"
out = out + "</tr></thead>\n<tbody>\n"
for row in block["rows"]
out = out + "<tr>"
for cell in row
out = out
+ "<td>"
+ Markdown(nil).inline_with_refs(cell, refs)
+ "</td>"
out = out + "</tr>\n"
out = out + "</tbody>\n</table>\n"
return out
if kind == "html"
if options["raw_html"] == true
return block["text"] + "\n"
return "<p>" + Markdown(nil).escape_html(block["text"]) + "</p>\n"
""
# Markdown.render_html_ast provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @param options Dict options value.
# @return Any the resulting value.
render_html_ast: ast, options = nil ->
if options == nil
options = {}
refs = {}
blocks = ast
if ast["kind"] == "document" or ast["kind"] == "html_document"
blocks = ast["blocks"]
refs = ast["references"]
parts = []
for block in blocks
parts.push(Markdown(nil).render_block(block, refs, options))
parts.join("")
# Markdown.strip_list_marker provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
strip_list_marker: s ->
Markdown(nil).trim_left_n(s, 2)
# Markdown.strip_ordered_marker provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
strip_ordered_marker: s ->
n = s.byte_len()
i = 0
while i < n and "0123456789".contains(s[i])
i = i + 1
Markdown(nil).trim_left_n(s, i + 2)
# Markdown.table_cells provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
table_cells: s ->
text = s
if text.starts_with("|")
text = text.slice(1, text.len())
if text.ends_with("|")
text = text.slice(0, text.len() - 1)
raw = text.split("|")
cells = []
for cell in raw
cells.push(cell.trim())
cells
# Markdown.to_html provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
to_html: text = nil ->
if text == nil
text = self.source
Markdown(nil).render_html_ast(
Markdown(nil).to_html_ast(Markdown(nil).parse(text))
)
# Markdown.to_html_ast provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @return Any the resulting value.
to_html_ast: ast ->
{ kind: "html_document", blocks: ast["blocks"], references: ast["references"] }
# Markdown.trim_left_n provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @param k Any k value.
# @return Any the resulting value.
trim_left_n: s, k ->
n = s.byte_len()
out = ""
i = k
while i < n
out = out + s[i]
i = i + 1
out
# Markdown.try_autolink provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @return Any the resulting value.
try_autolink: text, start ->
close = Markdown(nil).find_byte(text, ">", start + 1)
if close < 0
return nil
inner = text.slice(start + 1, close)
if not (inner.starts_with("http://") or inner.starts_with("https://"))
return nil
html = "<a href=\""
+ Markdown(nil).escape_attr(inner)
+ "\">"
+ Markdown(nil).escape_html(inner)
+ "</a>"
{ html: html, end: close + 1 }
# Markdown.try_image provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @param refs Any refs value.
# @return Any the resulting value.
try_image: text, start, refs ->
n = text.byte_len()
if start + 1 >= n or text[start + 1] != "["
return nil
close_text = Markdown(nil).find_byte(text, "]", start + 2)
if close_text < 0 or close_text + 1 >= n
return nil
alt = text.slice(start + 2, close_text)
url = nil
end = close_text + 1
if text[close_text + 1] == "("
close_url = Markdown(nil).find_byte(text, ")", close_text + 2)
if close_url < 0
return nil
url = text.slice(close_text + 2, close_url)
end = close_url + 1
elseif text[close_text + 1] == "["
close_ref = Markdown(nil).find_byte(text, "]", close_text + 2)
if close_ref < 0
return nil
label = text.slice(close_text + 2, close_ref).trim().lower()
if label == ""
label = alt.trim().lower()
if not refs.has(label)
return nil
url = refs[label]
end = close_ref + 1
else
return nil
html = "<img src=\""
+ Markdown(nil).escape_attr(url)
+ "\" alt=\""
+ Markdown(nil).escape_attr(alt)
+ "\"/>"
{ html: html, end: end }
# Markdown.try_link provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @param refs Any refs value.
# @return Any the resulting value.
try_link: text, start, refs ->
n = text.byte_len()
close_text = Markdown(nil).find_byte(text, "]", start + 1)
if close_text < 0
return nil
if close_text + 1 >= n
return nil
inner = text.slice(start + 1, close_text)
url = nil
end = close_text + 1
if text[close_text + 1] == "("
close_url = Markdown(nil).find_byte(text, ")", close_text + 2)
if close_url < 0
return nil
url = text.slice(close_text + 2, close_url)
end = close_url + 1
elseif text[close_text + 1] == "["
close_ref = Markdown(nil).find_byte(text, "]", close_text + 2)
if close_ref < 0
return nil
label = text.slice(close_text + 2, close_ref).trim().lower()
if label == ""
label = inner.trim().lower()
if not refs.has(label)
return nil
url = refs[label]
end = close_ref + 1
else
return nil
html = "<a href=\""
+ Markdown(nil).escape_attr(url)
+ "\">"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</a>"
{ html: html, end: end }
Instance Variables
source
Markdown.source
lib/markdown.tya:5
Markdown.source stores instance state.
Source
# Markdown.source stores instance state.
# @type Nil
source: nil
Methods
escape_attr
Markdown.escape_attr(text)
lib/markdown.tya:16
Markdown.escape_attr provides the markdown/Markdown standard library operation.
Source
# Markdown.escape_attr provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
escape_attr: text ->
text = text.replace("&", "&")
text = text.replace("\"", """)
text = text.replace("<", "<")
text = text.replace(">", ">")
text
escape_html
Markdown.escape_html(text)
lib/markdown.tya:26
Markdown.escape_html provides the markdown/Markdown standard library operation.
Source
# Markdown.escape_html provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
escape_html: text ->
text = text.replace("&", "&")
text = text.replace("<", "<")
text = text.replace(">", ">")
text = text.replace("\"", """)
text = text.replace("'", "'")
text
find_byte
Markdown.find_byte(text, b, start)
lib/markdown.tya:39
Markdown.find_byte provides the markdown/Markdown standard library operation.
Source
# Markdown.find_byte provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param b Int b value.
# @param start Int start value.
# @return Any the resulting value.
find_byte: text, b, start ->
n = text.byte_len()
i = start
while i < n
if text[i] == b
return i
i = i + 1
-1
find_double
Markdown.find_double(text, b, start)
lib/markdown.tya:53
Markdown.find_double provides the markdown/Markdown standard library operation.
Source
# Markdown.find_double provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param b Int b value.
# @param start Int start value.
# @return Any the resulting value.
find_double: text, b, start ->
n = text.byte_len()
i = start
while i < n - 1
if text[i] == b and text[i + 1] == b
return i
i = i + 1
-1
flush_paragraph
Markdown.flush_paragraph(blocks, para)
lib/markdown.tya:66
Markdown.flush_paragraph provides the markdown/Markdown standard library operation.
Source
# Markdown.flush_paragraph provides the markdown/Markdown standard library operation.
# @param blocks Any blocks value.
# @param para Any para value.
# @return Any the resulting value.
flush_paragraph: blocks, para ->
if para.len() == 0
return nil
text = para.join("\n")
blocks.push({ kind: "p", text: text })
nil
heading_level
Markdown.heading_level(s)
lib/markdown.tya:76
Markdown.heading_level provides the markdown/Markdown standard library operation.
Source
# Markdown.heading_level provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
heading_level: s ->
n = s.byte_len()
i = 0
while i < n and i < 6 and s[i] == "#"
i = i + 1
if i == 0
return 0
if i >= n
return 0
if s[i] != " "
return 0
i
heading_rest
Markdown.heading_rest(s, level)
lib/markdown.tya:93
Markdown.heading_rest provides the markdown/Markdown standard library operation.
Source
# Markdown.heading_rest provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @param level Any level value.
# @return Any the resulting value.
heading_rest: s, level ->
n = s.byte_len()
rest = ""
i = level + 1
while i < n
rest = rest + s[i]
i = i + 1
rest.trim()
initialize
Markdown.initialize(source)
lib/markdown.tya:10
Markdown.initialize stores source Markdown text.
Source
# Markdown.initialize stores source Markdown text.
# @param source String source value.
# @return Self the initialized object.
initialize: source ->
self.source = source
inline
Markdown.inline(text)
lib/markdown.tya:105
Markdown.inline provides the markdown/Markdown standard library operation.
Source
# Markdown.inline provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
inline: text ->
Markdown(nil).inline_with_refs(text, {})
inline_with_refs
Markdown.inline_with_refs(text, refs)
lib/markdown.tya:112
Markdown.inline_with_refs provides the markdown/Markdown standard library operation.
Source
# Markdown.inline_with_refs provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param refs Any refs value.
# @return Any the resulting value.
inline_with_refs: text, refs ->
n = text.byte_len()
out = ""
i = 0
while i < n
c = text[i]
if c == "\\" and i + 1 < n
out = out + Markdown(nil).escape_html(text[i + 1])
i = i + 2
continue
if c == "`"
end = Markdown(nil).find_byte(text, "`", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out + "<code>" + Markdown(nil).escape_html(inner) + "</code>"
i = end + 1
continue
if c == "~" and i + 1 < n and text[i + 1] == "~"
end = Markdown(nil).find_double(text, "~", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<del>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</del>"
i = end + 2
continue
if c == "*" and i + 1 < n and text[i + 1] == "*"
end = Markdown(nil).find_double(text, "*", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<strong>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</strong>"
i = end + 2
continue
if c == "_" and i + 1 < n and text[i + 1] == "_"
end = Markdown(nil).find_double(text, "_", i + 2)
if end >= 0
inner = text.slice(i + 2, end)
out = out
+ "<strong>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</strong>"
i = end + 2
continue
if c == "*"
end = Markdown(nil).find_byte(text, "*", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out
+ "<em>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</em>"
i = end + 1
continue
if c == "_"
end = Markdown(nil).find_byte(text, "_", i + 1)
if end >= 0
inner = text.slice(i + 1, end)
out = out
+ "<em>"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</em>"
i = end + 1
continue
if c == "!" and i + 1 < n and text[i + 1] == "["
image = Markdown(nil).try_image(text, i, refs)
if image != nil
out = out + image["html"]
i = image["end"]
continue
if c == "["
link = Markdown(nil).try_link(text, i, refs)
if link != nil
out = out + link["html"]
i = link["end"]
continue
if c == "<"
auto = Markdown(nil).try_autolink(text, i)
if auto != nil
out = out + auto["html"]
i = auto["end"]
continue
out = out + Markdown(nil).escape_html(c)
i = i + 1
out
is_html_block_start
Markdown.is_html_block_start(s)
lib/markdown.tya:204
Markdown.is_html_block_start provides the markdown/Markdown standard library operation.
Source
# Markdown.is_html_block_start provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_html_block_start: s ->
s.starts_with("<div") or s.starts_with("<section") or s.starts_with("<article") or s.starts_with("<p") or s.starts_with("<table") or s.starts_with("<h1") or s.starts_with("<h2") or s.starts_with("<h3") or s.starts_with("<ul") or s.starts_with("<ol")
is_nested_unordered_item
Markdown.is_nested_unordered_item(s)
lib/markdown.tya:210
Markdown.is_nested_unordered_item provides the markdown/Markdown standard library operation.
Source
# Markdown.is_nested_unordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_nested_unordered_item: s ->
(s.starts_with(" - ") or s.starts_with(" * ") or s.starts_with(" + ")) and Markdown(nil).is_unordered_item(s.trim())
is_ordered_item
Markdown.is_ordered_item(s)
lib/markdown.tya:216
Markdown.is_ordered_item provides the markdown/Markdown standard library operation.
Source
# Markdown.is_ordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_ordered_item: s ->
n = s.byte_len()
i = 0
while i < n and "0123456789".contains(s[i])
i = i + 1
if i == 0
return false
if i + 1 >= n
return false
if s[i] != "."
return false
if s[i + 1] != " "
return false
true
is_reference_def
Markdown.is_reference_def(s)
lib/markdown.tya:234
Markdown.is_reference_def provides the markdown/Markdown standard library operation.
Source
# Markdown.is_reference_def provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_reference_def: s ->
if not s.starts_with("[")
return false
close = Markdown(nil).find_byte(s, "]", 1)
if close <= 1
return false
if close + 1 >= s.byte_len()
return false
s[close + 1] == ":"
is_setext_underline
Markdown.is_setext_underline(s)
lib/markdown.tya:247
Markdown.is_setext_underline provides the markdown/Markdown standard library operation.
Source
# Markdown.is_setext_underline provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_setext_underline: s ->
if s == ""
return false
marker = s[0]
if marker != "=" and marker != "-"
return false
i = 0
while i < s.byte_len()
if s[i] != marker
return false
i = i + 1
true
is_table_separator
Markdown.is_table_separator(s)
lib/markdown.tya:263
Markdown.is_table_separator provides the markdown/Markdown standard library operation.
Source
# Markdown.is_table_separator provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_table_separator: s ->
if not s.contains("|")
return false
cells = Markdown(nil).table_cells(s)
if cells.len() == 0
return false
for cell in cells
c = cell.trim()
if c == ""
return false
i = 0
seen_dash = false
while i < c.byte_len()
if c[i] == "-"
seen_dash = true
elseif c[i] != ":"
return false
i = i + 1
if not seen_dash
return false
true
is_table_start
Markdown.is_table_start(lines, i)
lib/markdown.tya:289
Markdown.is_table_start provides the markdown/Markdown standard library operation.
Source
# Markdown.is_table_start provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @param i Int i value.
# @return Boolean the resulting value.
is_table_start: lines, i ->
if i + 1 >= lines.len()
return false
head = lines[i].trim()
sep = lines[i + 1].trim()
head.contains("|") and Markdown(nil).is_table_separator(sep)
is_task_item
Markdown.is_task_item(s)
lib/markdown.tya:299
Markdown.is_task_item provides the markdown/Markdown standard library operation.
Source
# Markdown.is_task_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_task_item: s ->
s.starts_with("- [ ] ") or s.starts_with("- [x] ") or s.starts_with("- [X] ")
is_thematic_break
Markdown.is_thematic_break(s)
lib/markdown.tya:305
Markdown.is_thematic_break provides the markdown/Markdown standard library operation.
Source
# Markdown.is_thematic_break provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_thematic_break: s ->
if s == "---"
return true
if s == "***"
return true
if s == "___"
return true
false
is_unordered_item
Markdown.is_unordered_item(s)
lib/markdown.tya:317
Markdown.is_unordered_item provides the markdown/Markdown standard library operation.
Source
# Markdown.is_unordered_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Boolean the resulting value.
is_unordered_item: s ->
if s.starts_with("- ")
return true
if s.starts_with("* ")
return true
if s.starts_with("+ ")
return true
false
parse
Markdown.parse(text = nil)
lib/markdown.tya:329
Markdown.parse provides the markdown/Markdown standard library operation.
Source
# Markdown.parse provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
parse: text = nil ->
if text == nil
text = self.source
lines = text.split("\n")
refs = Markdown(nil).reference_defs(lines)
{ kind: "document", blocks: Markdown(nil).parse_blocks(lines), references: refs }
parse_blocks
Markdown.parse_blocks(lines)
lib/markdown.tya:339
Markdown.parse_blocks provides the markdown/Markdown standard library operation.
Source
# Markdown.parse_blocks provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @return Any the resulting value.
parse_blocks: lines ->
blocks = []
para = []
i = 0
n = lines.len()
while i < n
line = lines[i]
stripped = line.trim()
if Markdown(nil).is_reference_def(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
continue
if stripped == ""
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
continue
if i + 1 < n and Markdown(nil).is_setext_underline(lines[i + 1].trim())
Markdown(nil).flush_paragraph(blocks, para)
para = []
level = 2
if lines[i + 1].trim().starts_with("=")
level = 1
blocks.push({ kind: "h", level: level, text: stripped })
i = i + 2
continue
if Markdown(nil).is_thematic_break(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
blocks.push({ kind: "hr" })
i = i + 1
continue
if Markdown(nil).is_html_block_start(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
html_lines = []
while i < n and lines[i].trim() != ""
html_lines.push(lines[i])
i = i + 1
blocks.push({ kind: "html", text: html_lines.join("\n") })
continue
heading_level = Markdown(nil).heading_level(stripped)
if heading_level > 0
Markdown(nil).flush_paragraph(blocks, para)
para = []
rest = Markdown(nil).heading_rest(stripped, heading_level)
blocks.push({ kind: "h", level: heading_level, text: rest })
i = i + 1
continue
if stripped.starts_with("```")
Markdown(nil).flush_paragraph(blocks, para)
para = []
i = i + 1
code_lines = []
info = Markdown(nil).trim_left_n(stripped, 3).trim()
while i < n and not lines[i].trim().starts_with("```")
code_lines.push(lines[i])
i = i + 1
if i < n
i = i + 1
blocks.push({ kind: "code", lines: code_lines, info: info })
continue
if stripped.starts_with("> ") or stripped == ">"
Markdown(nil).flush_paragraph(blocks, para)
para = []
quote_lines = []
while i < n
q = lines[i].trim()
if q == ""
break
if not (q.starts_with("> ") or q == ">")
break
if q == ">"
quote_lines.push("")
else
quote_lines.push(Markdown(nil).trim_left_n(q, 2))
i = i + 1
blocks.push({ kind: "quote", lines: quote_lines })
continue
if Markdown(nil).is_task_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_task_item(lines[i].trim())
task = Markdown(nil).parse_task_item(lines[i].trim())
items.push(task)
i = i + 1
blocks.push({ kind: "task_list", items: items })
continue
if Markdown(nil).is_table_start(lines, i)
Markdown(nil).flush_paragraph(blocks, para)
para = []
headers = Markdown(nil).table_cells(stripped)
i = i + 2
rows = []
while i < n and lines[i].trim().contains("|") and lines[i].trim() != ""
rows.push(Markdown(nil).table_cells(lines[i].trim()))
i = i + 1
blocks.push({ kind: "table", headers: headers, rows: rows })
continue
if Markdown(nil).is_unordered_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_unordered_item(lines[i].trim())
item_text = Markdown(nil).strip_list_marker(lines[i].trim())
children = []
i = i + 1
while i < n and Markdown(nil).is_nested_unordered_item(lines[i])
children.push(Markdown(nil).strip_list_marker(lines[i].trim()))
i = i + 1
items.push({ text: item_text, children: children })
blocks.push({ kind: "ul", items: items })
continue
if Markdown(nil).is_ordered_item(stripped)
Markdown(nil).flush_paragraph(blocks, para)
para = []
items = []
while i < n and Markdown(nil).is_ordered_item(lines[i].trim())
item_text = Markdown(nil).strip_ordered_marker(lines[i].trim())
items.push(item_text)
i = i + 1
blocks.push({ kind: "ol", items: items })
continue
para.push(stripped)
i = i + 1
Markdown(nil).flush_paragraph(blocks, para)
blocks
parse_task_item
Markdown.parse_task_item(s)
lib/markdown.tya:472
Markdown.parse_task_item provides the markdown/Markdown standard library operation.
Source
# Markdown.parse_task_item provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
parse_task_item: s ->
checked = s.starts_with("- [x] ") or s.starts_with("- [X] ")
{ checked: checked, text: Markdown(nil).trim_left_n(s, 6) }
reference_defs
Markdown.reference_defs(lines)
lib/markdown.tya:479
Markdown.reference_defs provides the markdown/Markdown standard library operation.
Source
# Markdown.reference_defs provides the markdown/Markdown standard library operation.
# @param lines Array lines value.
# @return Any the resulting value.
reference_defs: lines ->
refs = {}
for line in lines
s = line.trim()
if Markdown(nil).is_reference_def(s)
close = Markdown(nil).find_byte(s, "]", 1)
label = s.slice(1, close).trim().lower()
url = s.slice(close + 2, s.len()).trim()
refs[label] = url
refs
render
Markdown.render(ast, options)
lib/markdown.tya:494
Markdown.render provides the markdown/Markdown standard library operation.
Source
# Markdown.render provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @param options Dict options value.
# @return Any the resulting value.
render: ast, options ->
self.render_html_ast(ast, options)
render_block
Markdown.render_block(block, refs, options)
lib/markdown.tya:502
Markdown.render_block provides the markdown/Markdown standard library operation.
Source
# Markdown.render_block provides the markdown/Markdown standard library operation.
# @param block Function block value.
# @param refs Any refs value.
# @param options Dict options value.
# @return Any the resulting value.
render_block: block, refs, options ->
kind = block["kind"]
if kind == "hr"
return "<hr/>\n"
if kind == "h"
level = block["level"].to_s()
inner = Markdown(nil).inline_with_refs(block["text"], refs)
return "<h" + level + ">" + inner + "</h" + level + ">\n"
if kind == "p"
return "<p>" + Markdown(nil).inline_with_refs(block["text"], refs) + "</p>\n"
if kind == "code"
body = ""
for line in block["lines"]
body = body + Markdown(nil).escape_html(line) + "\n"
info = block["info"]
if info != nil and info != ""
return "<pre><code class=\"language-" + Markdown(nil).escape_attr(info) + "\">" + body + "</code></pre>\n"
return "<pre><code>" + body + "</code></pre>\n"
if kind == "quote"
inner_text = block["lines"].join("\n")
return "<blockquote>\n<p>" + Markdown(nil).inline_with_refs(inner_text, refs) + "</p>\n</blockquote>\n"
if kind == "ul"
out = "<ul>\n"
for item in block["items"]
text = item
children = []
if item["text"] != nil
text = item["text"]
children = item["children"]
out = out + "<li>" + Markdown(nil).inline_with_refs(text, refs)
if children.len() > 0
out = out + "\n<ul>\n"
for child in children
out = out
+ "<li>"
+ Markdown(nil).inline_with_refs(child, refs)
+ "</li>\n"
out = out + "</ul>\n"
out = out + "</li>\n"
out = out + "</ul>\n"
return out
if kind == "ol"
out = "<ol>\n"
for item in block["items"]
out = out
+ "<li>"
+ Markdown(nil).inline_with_refs(item, refs)
+ "</li>\n"
out = out + "</ol>\n"
return out
if kind == "task_list"
out = "<ul class=\"task-list\">\n"
for item in block["items"]
checked = ""
if item["checked"]
checked = " checked"
out = out
+ "<li><input type=\"checkbox\" disabled"
+ checked
+ "/> "
+ Markdown(nil).inline_with_refs(item["text"], refs)
+ "</li>\n"
out = out + "</ul>\n"
return out
if kind == "table"
out = "<table>\n<thead><tr>"
for cell in block["headers"]
out = out
+ "<th>"
+ Markdown(nil).inline_with_refs(cell, refs)
+ "</th>"
out = out + "</tr></thead>\n<tbody>\n"
for row in block["rows"]
out = out + "<tr>"
for cell in row
out = out
+ "<td>"
+ Markdown(nil).inline_with_refs(cell, refs)
+ "</td>"
out = out + "</tr>\n"
out = out + "</tbody>\n</table>\n"
return out
if kind == "html"
if options["raw_html"] == true
return block["text"] + "\n"
return "<p>" + Markdown(nil).escape_html(block["text"]) + "</p>\n"
""
render_html_ast
Markdown.render_html_ast(ast, options = nil)
lib/markdown.tya:594
Markdown.render_html_ast provides the markdown/Markdown standard library operation.
Source
# Markdown.render_html_ast provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @param options Dict options value.
# @return Any the resulting value.
render_html_ast: ast, options = nil ->
if options == nil
options = {}
refs = {}
blocks = ast
if ast["kind"] == "document" or ast["kind"] == "html_document"
blocks = ast["blocks"]
refs = ast["references"]
parts = []
for block in blocks
parts.push(Markdown(nil).render_block(block, refs, options))
parts.join("")
strip_list_marker
Markdown.strip_list_marker(s)
lib/markdown.tya:610
Markdown.strip_list_marker provides the markdown/Markdown standard library operation.
Source
# Markdown.strip_list_marker provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
strip_list_marker: s ->
Markdown(nil).trim_left_n(s, 2)
strip_ordered_marker
Markdown.strip_ordered_marker(s)
lib/markdown.tya:616
Markdown.strip_ordered_marker provides the markdown/Markdown standard library operation.
Source
# Markdown.strip_ordered_marker provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
strip_ordered_marker: s ->
n = s.byte_len()
i = 0
while i < n and "0123456789".contains(s[i])
i = i + 1
Markdown(nil).trim_left_n(s, i + 2)
table_cells
Markdown.table_cells(s)
lib/markdown.tya:626
Markdown.table_cells provides the markdown/Markdown standard library operation.
Source
# Markdown.table_cells provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @return Any the resulting value.
table_cells: s ->
text = s
if text.starts_with("|")
text = text.slice(1, text.len())
if text.ends_with("|")
text = text.slice(0, text.len() - 1)
raw = text.split("|")
cells = []
for cell in raw
cells.push(cell.trim())
cells
to_html
Markdown.to_html(text = nil)
lib/markdown.tya:641
Markdown.to_html provides the markdown/Markdown standard library operation.
Source
# Markdown.to_html provides the markdown/Markdown standard library operation.
# @param text String text value.
# @return Any the resulting value.
to_html: text = nil ->
if text == nil
text = self.source
Markdown(nil).render_html_ast(
Markdown(nil).to_html_ast(Markdown(nil).parse(text))
)
to_html_ast
Markdown.to_html_ast(ast)
lib/markdown.tya:651
Markdown.to_html_ast provides the markdown/Markdown standard library operation.
Source
# Markdown.to_html_ast provides the markdown/Markdown standard library operation.
# @param ast Any ast value.
# @return Any the resulting value.
to_html_ast: ast ->
{ kind: "html_document", blocks: ast["blocks"], references: ast["references"] }
trim_left_n
Markdown.trim_left_n(s, k)
lib/markdown.tya:658
Markdown.trim_left_n provides the markdown/Markdown standard library operation.
Source
# Markdown.trim_left_n provides the markdown/Markdown standard library operation.
# @param s Any s value.
# @param k Any k value.
# @return Any the resulting value.
trim_left_n: s, k ->
n = s.byte_len()
out = ""
i = k
while i < n
out = out + s[i]
i = i + 1
out
try_autolink
Markdown.try_autolink(text, start)
lib/markdown.tya:671
Markdown.try_autolink provides the markdown/Markdown standard library operation.
Source
# Markdown.try_autolink provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @return Any the resulting value.
try_autolink: text, start ->
close = Markdown(nil).find_byte(text, ">", start + 1)
if close < 0
return nil
inner = text.slice(start + 1, close)
if not (inner.starts_with("http://") or inner.starts_with("https://"))
return nil
html = "<a href=\""
+ Markdown(nil).escape_attr(inner)
+ "\">"
+ Markdown(nil).escape_html(inner)
+ "</a>"
{ html: html, end: close + 1 }
try_image
Markdown.try_image(text, start, refs)
lib/markdown.tya:690
Markdown.try_image provides the markdown/Markdown standard library operation.
Source
# Markdown.try_image provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @param refs Any refs value.
# @return Any the resulting value.
try_image: text, start, refs ->
n = text.byte_len()
if start + 1 >= n or text[start + 1] != "["
return nil
close_text = Markdown(nil).find_byte(text, "]", start + 2)
if close_text < 0 or close_text + 1 >= n
return nil
alt = text.slice(start + 2, close_text)
url = nil
end = close_text + 1
if text[close_text + 1] == "("
close_url = Markdown(nil).find_byte(text, ")", close_text + 2)
if close_url < 0
return nil
url = text.slice(close_text + 2, close_url)
end = close_url + 1
elseif text[close_text + 1] == "["
close_ref = Markdown(nil).find_byte(text, "]", close_text + 2)
if close_ref < 0
return nil
label = text.slice(close_text + 2, close_ref).trim().lower()
if label == ""
label = alt.trim().lower()
if not refs.has(label)
return nil
url = refs[label]
end = close_ref + 1
else
return nil
html = "<img src=\""
+ Markdown(nil).escape_attr(url)
+ "\" alt=\""
+ Markdown(nil).escape_attr(alt)
+ "\"/>"
{ html: html, end: end }
try_link
Markdown.try_link(text, start, refs)
lib/markdown.tya:731
Markdown.try_link provides the markdown/Markdown standard library operation.
Source
# Markdown.try_link provides the markdown/Markdown standard library operation.
# @param text String text value.
# @param start Int start value.
# @param refs Any refs value.
# @return Any the resulting value.
try_link: text, start, refs ->
n = text.byte_len()
close_text = Markdown(nil).find_byte(text, "]", start + 1)
if close_text < 0
return nil
if close_text + 1 >= n
return nil
inner = text.slice(start + 1, close_text)
url = nil
end = close_text + 1
if text[close_text + 1] == "("
close_url = Markdown(nil).find_byte(text, ")", close_text + 2)
if close_url < 0
return nil
url = text.slice(close_text + 2, close_url)
end = close_url + 1
elseif text[close_text + 1] == "["
close_ref = Markdown(nil).find_byte(text, "]", close_text + 2)
if close_ref < 0
return nil
label = text.slice(close_text + 2, close_ref).trim().lower()
if label == ""
label = inner.trim().lower()
if not refs.has(label)
return nil
url = refs[label]
end = close_ref + 1
else
return nil
html = "<a href=\""
+ Markdown(nil).escape_attr(url)
+ "\">"
+ Markdown(nil).inline_with_refs(inner, refs)
+ "</a>"
{ html: html, end: end }