diff --git a/lib/earmark.ex b/lib/earmark.ex index 3abf282b..bcb46c32 100644 --- a/lib/earmark.ex +++ b/lib/earmark.ex @@ -410,6 +410,10 @@ defmodule Earmark do Pure links of the form `~r{\\bhttps?://\\S+\\b}` are rendered as links from now on. However, by setting the `pure_links` option to `false` this can be disabled and pre 1.4 behavior can be used. + + * `compact_output`: boolean + + If set to true, no cosmetic newlines will be emitted by Earmark. False by default. """ def as_html(lines, options \\ %Options{}) diff --git a/lib/earmark/options.ex b/lib/earmark/options.ex index b15085b7..9eee0a43 100644 --- a/lib/earmark/options.ex +++ b/lib/earmark/options.ex @@ -35,7 +35,8 @@ defmodule Earmark.Options do line: 1, # [{:error|:warning, lnb, text},...] messages: [], - pure_links: true + pure_links: true, + compact_output: false @type t :: %__MODULE__{ breaks: boolean, diff --git a/lib/earmark/transform.ex b/lib/earmark/transform.ex index 43617e32..8be25dac 100644 --- a/lib/earmark/transform.ex +++ b/lib/earmark/transform.ex @@ -26,13 +26,16 @@ defmodule Earmark.Transform do end + defp maybe_add_newline(%{compact_output: true}), do: [] + defp maybe_add_newline(_), do: ?\n + defp to_html(ast, options) do _to_html(ast, options, Map.get(options, :initial_indent, 0))|> IO.iodata_to_binary end defp _to_html(ast, options, level, verbatim \\ false) - defp _to_html({:comment, _, content, _}, _options, _level, _verbatim) do - "\n" + defp _to_html({:comment, _, content, _}, options, _level, _verbatim) do + ["", maybe_add_newline(options)] end defp _to_html({"code", atts, children, meta}, options, level, _verbatim) do verbatim = meta |> Map.get(:verbatim, false) @@ -44,10 +47,10 @@ defmodule Earmark.Transform do [open_tag(tag, atts), children |> Enum.map(&_to_html(&1, options, level, verbatim)), - ""] + "] end defp _to_html({tag, atts, _, _}, options, level, _verbatim) when tag in @void_elements do - [ make_indent(options, level), open_tag(tag, atts), "\n" ] + [ make_indent(options, level), open_tag(tag, atts), maybe_add_newline(options) ] end defp _to_html(elements, options, level, verbatim) when is_list(elements) do elements @@ -64,19 +67,19 @@ defmodule Earmark.Transform do [ make_indent(options, level), open_tag("pre", atts), _to_html(children, Map.put(options, :smartypants, false), level, verbatim), - "\n"] + "", maybe_add_newline(options)] end defp _to_html({tag, atts, children, meta}, options, level, _verbatim) do verbatim = meta |> Map.get(:verbatim, false) [ make_indent(options, level), open_tag(tag, atts), - "\n", + maybe_add_newline(options), _to_html(children, options, level+1, verbatim), close_tag(tag, options, level)] end defp close_tag(tag, options, level) do - [make_indent(options, level), "\n"] + [make_indent(options, level), ", maybe_add_newline(options)] end defp escape(element, options) @@ -101,10 +104,10 @@ defmodule Earmark.Transform do defp open_tag(tag, atts) defp open_tag(tag, atts) when tag in @void_elements do - ["<", "#{tag}", Enum.map(atts, &make_att(&1, tag)), " />"] + [?<, tag, Enum.map(atts, &make_att(&1, tag)), " />"] end defp open_tag(tag, atts) do - ["<", "#{tag}", Enum.map(atts, &make_att(&1, tag)), ">"] + [?<, tag, Enum.map(atts, &make_att(&1, tag)), ?>] end @em_dash_rgx ~r{---} diff --git a/test/acceptance/html/compact_output_test.exs b/test/acceptance/html/compact_output_test.exs new file mode 100644 index 00000000..a0f3ab79 --- /dev/null +++ b/test/acceptance/html/compact_output_test.exs @@ -0,0 +1,22 @@ +defmodule Acceptance.Html.CompactModeTest do + use Support.AcceptanceTestCase + + describe "Compact mode" do + test "avoids creating newlines" do + markdown = "# h1\n## h2\n### h3\n\n**bold** text *italics*\n>blockquote\n1. list element\n2. list element \n\n `code` [link](http://example.com)" + {:ok, html, _} = as_html(markdown, compact_output: true) + refute html =~ "\n" + end + test "preserves newlines in code blocks" do + markdown = """ + ```elixir + Earmark.as_html!(markdown, compact_output: true) + Earmark.as_html!(markdown, compact_output: false) + ``` + """ + expected = "
   Earmark.as_html!(markdown, compact_output: true)\n   Earmark.as_html!(markdown, compact_output: false)
" + {:ok, html, _} = as_html(markdown, compact_output: true) + assert html == expected + end + end +end