Skip to content

Commit

Permalink
Add compact_output option
Browse files Browse the repository at this point in the history
As discussed in
#393 (comment).
I did not name the option "single_line", since newlines in code blocks
are preserved even with it on and since Earmark passes
the single newlines from the input to the final output.

Also removes some string concatenations and replaces single-character
binaries with character codes.

I did not find a file the tests for this feature would fit in, so
I created a new one at `test/acceptance/html/compact_output_test.exs`

Closes #391
  • Loading branch information
rinpatch committed Nov 25, 2020
1 parent 1193ce4 commit 884ce43
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
4 changes: 4 additions & 0 deletions lib/earmark.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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{})

Expand Down
3 changes: 2 additions & 1 deletion lib/earmark/options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
21 changes: 12 additions & 9 deletions lib/earmark/transform.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
"<!--#{content |> Enum.intersperse("\n")}-->\n"
defp _to_html({:comment, _, content, _}, options, _level, _verbatim) do
["<!--", Enum.intersperse(content, ?\n), "-->", maybe_add_newline(options)]
end
defp _to_html({"code", atts, children, meta}, options, level, _verbatim) do
verbatim = meta |> Map.get(:verbatim, false)
Expand All @@ -44,10 +47,10 @@ defmodule Earmark.Transform do
[open_tag(tag, atts),
children
|> Enum.map(&_to_html(&1, options, level, verbatim)),
"</#{tag}>"]
"</", tag, ?>]
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
Expand All @@ -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),
"</pre>\n"]
"</pre>", 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), "</", tag, ">\n"]
[make_indent(options, level), "</", tag, ?>, maybe_add_newline(options)]
end

defp escape(element, options)
Expand All @@ -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{---}
Expand Down
22 changes: 22 additions & 0 deletions test/acceptance/html/compact_output_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule Acceptance.Html.CompactModeTest do
use Support.AcceptanceTestCase

describe "Compact output option" 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 = "<pre><code class=\"elixir\"> Earmark.as_html!(markdown, compact_output: true)\n Earmark.as_html!(markdown, compact_output: false)</code></pre>"
{:ok, html, _} = as_html(markdown, compact_output: true)
assert html == expected
end
end
end

0 comments on commit 884ce43

Please sign in to comment.