howl.ui.markup.markdown

render = (text) ->
  st = m text
  st.text, st.styles

returns the text as is when there is no markup

text, styles = render 'foo bar'
assert.equals 'foo bar', text
assert.same {}, styles

removes heading markers and styles headings

text, styles = render '# Title *x*\n#### Deep'
assert.equals 'Title x\nDeep', text
assert.same { 1, 'h1', 8, 7, 'emphasis', 8, 9, 'h3', 13 }, styles

styles inline code

text, styles = render 'a `b` c ``d`e``'
assert.equals 'a b c d`e', text
assert.same { 3, 'embedded', 4, 7, 'embedded', 10 }, styles

styles emphasis like the markdown mode does

text, styles = render '**b** and *i* and __u__'
assert.equals 'b and i and u', text
assert.same { 1, 'strong', 2, 7, 'emphasis', 8, 13, 'strong', 14 }, styles

styles nested spans with the enclosing span first

text, styles = render '**"`x`":** y'
assert.equals '"x": y', text
assert.same { 1, 'strong', 5, 2, 'embedded', 3 }, styles

leaves underscores within words and unpaired markers alone

text, styles = render 'a_b_c is _x_, 2 * 3'
assert.equals 'a_b_c is x, 2 * 3', text
assert.same { 10, 'emphasis', 11 }, styles

handles escapes and entities

text = render 'a\\_b\\* <x> & y'
assert.equals 'a_b* <x> & y', text
text, styles = render 'see [§2.5](#2.5) and [x][r], [not a link]'
assert.equals 'see §2.5 and x, [not a link]', text
assert.same { 5, 'link_label', 10, 15, 'link_label', 16 }, styles

shows bullets for list items

text, styles = render '- a *b*\n  * c'
assert.equals '• a b\n  • c', text
assert.same { 1, 'operator', 4, 7, 'emphasis', 8, 11, 'operator', 14 }, styles

styles the numbers of ordered list items

text, styles = render '1. x'
assert.equals '1. x', text
assert.same { 1, 'operator', 3 }, styles

shows a bar for block quotes

text, styles = render '> q'
assert.equals '│ q', text
assert.same { 1, 'operator', 4 }, styles

shows rules as wide as the widest line

text, styles = render 'abcde\n---\nx'
assert.equals 'abcde\n─────\nx', text
assert.same { 7, 'comment', 7 + #'─────' }, styles

styles indented code, but not indented list or paragraph lines

text, styles = render '-   item\n    more\n\n        code()\n\n    after\nline\n    not code'
assert.equals '•   item\n    more\n\n        code()\n\n    after\nline\n    not code', text
assert.same { 1, 'operator', 4, 30, 'embedded', 36 }, styles

collapses blank lines and removes trailing ones

assert.equals 'a\n\nb', (render '\na\n\n\n\nb\n\n')

handles CRLF line endings

assert.equals 'a\nb', (render 'a\r\nb')

fenced code

local lexer

before_each ->
  lexer = spy.new -> { 1, 'keyword', 3 }
  mode.register name: 'md-test', create: -> :lexer

after_each -> mode.unregister 'md-test'

removes the fences and highlights the code with the lexer of its language

text, styles = render '```md-test\nif x\n```\ndone'
assert.equals 'if x\ndone', text
assert.same { 1, 'embedded', 5, 1, { 1, 'keyword', 3 }, 'md-test|embedded' }, styles
assert.spy(lexer).was_called_with 'if x', nil, sub_lexing: true

styles code in unknown languages as embedded

text, styles = render '~~~nope\ncode\n~~~'
assert.equals 'code', text
assert.same { 1, 'embedded', 5 }, styles

runs an unclosed fence to the end

text, styles = render '```\na\n\n# b'
assert.equals 'a\n\n# b', text
assert.same { 1, 'embedded', 7 }, styles