Skip to content

Commit

Permalink
Merge pull request #331 from pragdave/i228-block-level-html
Browse files Browse the repository at this point in the history
Fixes: #228
  • Loading branch information
RobertDober authored Mar 19, 2020
2 parents 77f960b + ced71fc commit 721c359
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 43 deletions.
6 changes: 3 additions & 3 deletions lib/earmark/line_scanner.ex
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ defmodule Earmark.LineScanner do
[_, tag] = match
%Line.HtmlOpenTag{tag: tag, content: line, indent: 0}

match = !recursive && Regex.run(~r/\A<\/([-\w]+?)>/, line) ->
[_, tag] = match
%Line.HtmlCloseTag{tag: tag, indent: 0}
match = !recursive && Regex.run(~r/\A(\s{0,3})<\/([-\w]+?)>/, line) ->
[_, leading_spaces, tag] = match
%Line.HtmlCloseTag{tag: tag, indent: String.length(leading_spaces)}

match = Regex.run(@id_re, line) ->
[_, leading, id, url | title] = match
Expand Down
47 changes: 23 additions & 24 deletions lib/earmark/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,13 +220,12 @@ defmodule Earmark.Parser do
# HTML block #
##############
defp _parse([ opener = %Line.HtmlOpenTag{tag: tag, lnb: lnb} | rest], result, options, recursive) do
{html_lines, rest, unclosed} = html_match_to_closing(opener, rest)
{html_lines, rest1, unclosed} = _html_match_to_closing(opener, rest)
options1 = add_messages(options,
unclosed
|> Enum.map(fn %{lnb: lnb1, tag: tag} -> {:warning, lnb1, "Failed to find closing <#{tag}>"} end))

html = (for line <- Enum.reverse(html_lines), do: line.line)
_parse(rest, [ %Block.Html{tag: tag, html: html, lnb: lnb} | result ], options1, recursive)
html = Enum.reverse(html_lines)
_parse(rest1, [ %Block.Html{tag: tag, html: html, lnb: lnb} | result ], options1, recursive)
end

####################
Expand Down Expand Up @@ -351,7 +350,7 @@ defmodule Earmark.Parser do
end

defp _consolidate_para( [line | rest] = lines, result, pending ) do
case inline_or_text?( line, pending ) do
case _inline_or_text?( line, pending ) do
%{pending: still_pending, continue: true} -> _consolidate_para( rest, [line | result], still_pending )
_ -> {result, lines, @not_pending}
end
Expand Down Expand Up @@ -492,46 +491,46 @@ defmodule Earmark.Parser do
# Consume HTML, taking care of nesting. Assumes one tag per line. #
###################################################################

defp html_match_to_closing(opener, rest), do: find_closing_tags([opener], rest, [opener])
defp _html_match_to_closing(opener, rest), do: _find_closing_tags([opener], rest, [String.trim_leading(opener.line)])

defp _find_closing_tags(needed, input, html_lines)
# No more open tags, happy case
defp find_closing_tags([], rest, html_lines), do: {html_lines, rest, []}

defp _find_closing_tags([], rest, html_lines), do: {html_lines, rest, []}
# run out of input, unhappy case
defp find_closing_tags(needed, [], html_lines), do: {html_lines, [], needed}

defp _find_closing_tags(needed, [], html_lines), do: {html_lines, [], needed}
# still more lines, still needed closing
defp find_closing_tags(needed = [needed_hd|needed_tl], [rest_hd|rest_tl], html_lines) do
defp _find_closing_tags(needed = [needed_hd|needed_tl], [rest_hd|rest_tl], html_lines) do
cond do
closes_tag?(rest_hd, needed_hd) -> find_closing_tags(needed_tl, rest_tl, [rest_hd|html_lines])
opens_tag?(rest_hd) -> find_closing_tags([rest_hd|needed], rest_tl, [rest_hd|html_lines])
true -> find_closing_tags(needed, rest_tl, [rest_hd|html_lines])
_closes_tag?(rest_hd, needed_hd) -> _find_closing_tags(needed_tl, rest_tl, [String.trim_leading(rest_hd.line)|html_lines])
_opens_tag?(rest_hd) -> _find_closing_tags([rest_hd|needed], rest_tl, [String.trim_leading(rest_hd.line)|html_lines])
true -> _find_closing_tags(needed, rest_tl, [rest_hd.line|html_lines])
end
end

###########
# Helpers #
###########

defp closes_tag?(%Line.HtmlCloseTag{tag: ctag}, %Line.HtmlOpenTag{tag: otag}), do: ctag == otag
defp closes_tag?(_, _), do: false
defp _closes_tag?(%Line.HtmlCloseTag{tag: ctag}, %Line.HtmlOpenTag{tag: otag}) do
ctag == otag
end
defp _closes_tag?(_, _), do: false

defp opens_tag?(%Line.HtmlOpenTag{}), do: true
defp opens_tag?(_), do: false
defp _opens_tag?(%Line.HtmlOpenTag{}), do: true
defp _opens_tag?(_), do: false


# (_,{'nil' | binary(),number()}) -> #{}jj
defp inline_or_text?(line, pending)
defp inline_or_text?(line = %Line.Text{}, @not_pending) do
defp _inline_or_text?(line, pending)
defp _inline_or_text?(line = %Line.Text{}, @not_pending) do
pending = opens_inline_code(line)
%{pending: pending, continue: true}
end
defp inline_or_text?(line = %Line.TableLine{}, @not_pending) do
defp _inline_or_text?(line = %Line.TableLine{}, @not_pending) do
pending = opens_inline_code(line)
%{pending: pending, continue: true}
end
defp inline_or_text?( _line, @not_pending), do: %{pending: @not_pending, continue: false}
defp inline_or_text?( line, pending ) do
defp _inline_or_text?( _line, @not_pending), do: %{pending: @not_pending, continue: false}
defp _inline_or_text?( line, pending ) do
pending = still_inline_code(line, pending)
%{pending: pending, continue: true}
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Acceptance.Ast.HtmlBlocksTest do
defmodule Acceptance.Ast.Html.BlockTest do
use ExUnit.Case, async: true
import Support.Helpers, only: [as_ast: 1, parse_html: 1]
import Support.AstHelpers, only: [p: 1, void_tag: 1]
Expand Down Expand Up @@ -246,20 +246,7 @@ defmodule Acceptance.Ast.HtmlBlocksTest do
assert as_ast(markdown) == {:ok, ast, messages}
end
end

describe "arbitrary tags" do
# Needs a fix with issue [#326](https://github.com/pragdave/earmark/issues/326)
@tag :wip
test "mixture of tags (was regtest #103)" do
markdown = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
html = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
ast = parse_html(html)
messages = Enum.zip(1..3, ~w[x y z])
|> Enum.map(fn {lnb, tag} -> {:warning, lnb, "Failed to find closing <#{tag}>"} end)

assert as_ast(markdown) == {:error, [ast], messages}
end
end
end

# SPDX-License-Identifier: Apache-2.0

40 changes: 40 additions & 0 deletions test/acceptance/ast/html/permissive_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule Acceptance.Ast.Html.PermissiveTest do
use ExUnit.Case, async: true
import Support.Helpers, only: [as_ast: 1]

@verbatim %{meta: %{verbatim: true}}

describe "some nesting" do
test "simple case" do
markdown = "<div>\ncontent\n </div>"
ast = [{"div", [], ["content"], @verbatim}]
messages = []

assert as_ast(markdown) == {:ok, ast, messages}
end

test "more nesting" do
markdown = "<div>\n<section>\n<span>content</span>\n</section>\n</div>"
ast = [{"div", [],
["<section>", "<span>content</span>", "</section>"], @verbatim}]
messages = []

assert as_ast(markdown) == {:ok, ast, messages}
end
end

describe "arbitrary tags" do
# Needs a fix with issue [#326](https://github.com/pragdave/earmark/issues/326)
test "mixture of tags (was regtest #103)" do
markdown = "<x>a\n<y></y>\n<y>\n<z>\n</z>\n<z>\n</x>"
ast = [{"x", '', ["a", "<y></y>", "<y>", "<z>", "</z>", "<z>"], @verbatim}]
messages = Enum.zip([1, 3, 6], ~w[x y z])
|> Enum.map(fn {lnb, tag} -> {:warning, lnb, "Failed to find closing <#{tag}>"} end)

assert as_ast(markdown) == {:error, ast, messages}
end
end
end

# SPDX-License-Identifier: Apache-2.0

1 change: 1 addition & 0 deletions test/functional/scanner/line_type_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ defmodule Functional.Scanner.LineTypeTest do
{ "<pre>", %Line.HtmlOpenTag{tag: "pre", content: "<pre>"} },
{ "<pre class='123'>", %Line.HtmlOpenTag{tag: "pre", content: "<pre class='123'>"} },
{ "</pre>", %Line.HtmlCloseTag{tag: "pre"} },
{ " </pre>", %Line.HtmlCloseTag{indent: 3, tag: "pre"} },

{ "<pre>a</pre>", %Line.HtmlOneLine{tag: "pre", content: "<pre>a</pre>"} },

Expand Down
2 changes: 1 addition & 1 deletion test/performance/longer_input_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Performance.LongerInputTest do
describe "some test data" do
test "medium" do
ast = convert_file("medium.md", :ast, 100)
assert Enum.count(ast) == 8300
assert Enum.count(ast) == 8500
end

test "show data" do
Expand Down

0 comments on commit 721c359

Please sign in to comment.