diff --git a/lib/markdown.ex b/lib/markdown.ex index 6bbf60a..34bfbd2 100644 --- a/lib/markdown.ex +++ b/lib/markdown.ex @@ -25,6 +25,20 @@ defmodule Markdown do * `:tables` - Enables Markdown Extra style tables (default: `false`) * `:fenced_code` - Enables fenced code blocks (default: `false`) * `:autolink` - Automatically turn URLs into links (default: `false`) + * `:strikethrough` - Parse ~~stikethrough~~ spans (default: `false`) + * `:underline` - Parse _underline_ instead of emphasis (default: `false`) + * `:highlight` - Parse ==highlight== spans (default: `false`) + * `:quote` - Render \"quotes\" as quotes (default: `false`) + * `:superscript` - Parse super^script (default: `false`) + * `:math` - Parse TeX $$math$$ syntax, Kramdown style (default: `false`) + * `:no_intra_emphasis` - Disable emphasis_between_words (default: `false`) + * `:space_headers` - Require a space after '#' in headers (default: `false`) + * `:math_explicit` - Instead of guessing by context, parse $inline math$ and $$always block math$$ (requires `math: true`) (default: `false`) + * `:disable_indented_code` - Don't parse indented code blocks (default: `false`) + * `:skip_html` - Strip all HTML tags (default: `false`) + * `:escape` - Escape all HTML (default: `false`) + * `:hard_wrap` - Render each linebreak as
(default: `false`) + * `:use_xhtml` - Render XHTML (default: `false`) """ @spec to_html(doc :: String.t) :: String.t diff --git a/src/markdown.c b/src/markdown.c index f33d58d..dd1ea02 100644 --- a/src/markdown.c +++ b/src/markdown.c @@ -14,6 +14,20 @@ typedef struct { ERL_NIF_TERM atom_tables; ERL_NIF_TERM atom_autolink; ERL_NIF_TERM atom_fenced_code; + ERL_NIF_TERM atom_strikethrough; + ERL_NIF_TERM atom_underline; + ERL_NIF_TERM atom_highlight; + ERL_NIF_TERM atom_quote; + ERL_NIF_TERM atom_superscript; + ERL_NIF_TERM atom_math; + ERL_NIF_TERM atom_no_intra_emphasis; + ERL_NIF_TERM atom_space_headers; + ERL_NIF_TERM atom_math_explicit; + ERL_NIF_TERM atom_disable_indented_code; + ERL_NIF_TERM atom_skip_html; + ERL_NIF_TERM atom_escape; + ERL_NIF_TERM atom_hard_wrap; + ERL_NIF_TERM atom_use_xhtml; } markdown_priv; static ERL_NIF_TERM @@ -27,6 +41,7 @@ to_html(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { const ERL_NIF_TERM* tuple; int tuple_size; unsigned int extensions; + unsigned int html_flags; hoedown_buffer* ob; hoedown_document* document; @@ -43,6 +58,7 @@ to_html(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { priv = enif_priv_data(env); options = argv[1]; extensions = 0; + html_flags = 0; while (enif_get_list_cell(env, options, &term, &options) != 0) { if (enif_get_tuple(env, term, &tuple_size, &tuple) != 0) { @@ -67,12 +83,110 @@ to_html(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { continue; } } + + if (enif_compare(tuple[0], priv->atom_strikethrough) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_STRIKETHROUGH; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_underline) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_UNDERLINE; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_highlight) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_HIGHLIGHT; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_quote) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_QUOTE; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_superscript) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_SUPERSCRIPT; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_math) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_MATH; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_no_intra_emphasis) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_NO_INTRA_EMPHASIS; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_space_headers) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_SPACE_HEADERS; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_math_explicit) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_MATH_EXPLICIT; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_disable_indented_code) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + extensions |= HOEDOWN_EXT_DISABLE_INDENTED_CODE; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_skip_html) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + html_flags |= HOEDOWN_HTML_SKIP_HTML; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_escape) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + html_flags |= HOEDOWN_HTML_ESCAPE; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_hard_wrap) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + html_flags |= HOEDOWN_HTML_HARD_WRAP; + continue; + } + } + + if (enif_compare(tuple[0], priv->atom_use_xhtml) == 0) { + if (enif_compare(tuple[1], priv->atom_true) == 0) { + html_flags |= HOEDOWN_HTML_USE_XHTML; + continue; + } + } } } } ob = hoedown_buffer_new(OUTPUT_UNIT); - renderer = hoedown_html_renderer_new(0, 0); + renderer = hoedown_html_renderer_new(html_flags, 0); document = hoedown_document_new(renderer, extensions, 16); hoedown_document_render(document, ob, (uint8_t*) input.data, input.size); @@ -102,6 +216,20 @@ load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info) { data->atom_tables = enif_make_atom(env, "tables"); data->atom_autolink = enif_make_atom(env, "autolink"); data->atom_fenced_code = enif_make_atom(env, "fenced_code"); + data->atom_strikethrough = enif_make_atom(env, "strikethrough"); + data->atom_underline = enif_make_atom(env, "underline"); + data->atom_highlight = enif_make_atom(env, "highlight"); + data->atom_quote = enif_make_atom(env, "quote"); + data->atom_superscript = enif_make_atom(env, "superscript"); + data->atom_math = enif_make_atom(env, "math"); + data->atom_no_intra_emphasis = enif_make_atom(env, "no_intra_emphasis"); + data->atom_space_headers = enif_make_atom(env, "space_headers"); + data->atom_math_explicit = enif_make_atom(env, "math_explicit"); + data->atom_disable_indented_code = enif_make_atom(env, "disable_indented_code"); + data->atom_skip_html = enif_make_atom(env, "skip_html"); + data->atom_escape = enif_make_atom(env, "escape"); + data->atom_hard_wrap = enif_make_atom(env, "hard_wrap"); + data->atom_use_xhtml = enif_make_atom(env, "use_xhtml"); *priv = (void*) data; return 0; diff --git a/test/markdown_test.exs b/test/markdown_test.exs index afc7305..6ccc7b8 100644 --- a/test/markdown_test.exs +++ b/test/markdown_test.exs @@ -30,4 +30,110 @@ defmodule MarkdownTest do html = Markdown.to_html(markdown, fenced_code: true) assert html =~ ~r// end + + test :strikethrough do + markdown = "~~strike~~" + html = Markdown.to_html(markdown, strikethrough: true) + assert html == "

strike

\n" + end + + test :underline do + markdown = "_underline_" + html = Markdown.to_html(markdown, underline: true) + assert html == "

underline

\n" + end + + test :highlight do + markdown = "==highlight==" + html = Markdown.to_html(markdown, highlight: true) + assert html == "

highlight

\n" + end + + test :quote do + markdown = "\"quotes\"" + html = Markdown.to_html(markdown, quote: true) + assert html == "

quotes

\n" + end + + test :superscript do + markdown = "super^script" + html = Markdown.to_html(markdown, superscript: true) + assert html == "

superscript

\n" + end + + test :math do + markdown = "Euler's formula is remarkable: $$e^{i\\pi} + 1 = 0$$" + html = Markdown.to_html(markdown, math: true) + assert html == "

Euler's formula is remarkable: \\(e^{i\\pi} + 1 = 0\\)

\n" + end + + test :no_intra_emphasis do + markdown = "Disable emphasis_between_words" + html = Markdown.to_html(markdown, no_intra_emphasis: true) + assert html == "

Disable emphasis_between_words

\n" + end + + test :space_headers do + markdown = """ + #Not a headline + """ + + html = Markdown.to_html(markdown, space_headers: true) + assert html == "

#Not a headline

\n" + end + + test :math_explicit do + markdown = """ + Euler's formula is remarkable: $$e^{i\\pi} + 1 = 0$$ + """ + + html = Markdown.to_html(markdown, math: true, math_explicit: true) + assert html == "

Euler's formula is remarkable: \\[e^{i\\pi} + 1 = 0\\]

\n" + end + + test :disable_indented_code do + markdown = """ + msg = "Not rendered as code block" + """ + + html = Markdown.to_html(markdown, disable_indented_code: true) + assert html == "

msg = "Not rendered as code block"

\n" + end + + test :skip_html do + markdown = "Some html" + + html = Markdown.to_html(markdown, skip_html: true) + assert html == "

Some html

\n" + end + + test :escape_html do + markdown = "Some html" + + html = Markdown.to_html(markdown, escape: true) + assert html == "

Some <b>html</b>

\n" + end + + test :hard_wraps do + markdown = """ + Hard wraps + between lines + """ + + html = Markdown.to_html(markdown, hard_wrap: true) + assert html == "

Hard wraps
\nbetween lines

\n" + end + + test :use_xhtml do + markdown = """ + Emit tags + + --- + + compatible with XHTML + """ + + html = Markdown.to_html(markdown, use_xhtml: true) + assert html == "

Emit tags

\n\n
\n\n

compatible with XHTML

\n" + end end