From ca3f7a789d7b371805e4f88f512f787a30ee1399 Mon Sep 17 00:00:00 2001 From: Felipe Renan Date: Tue, 29 Oct 2024 17:45:20 +0000 Subject: [PATCH] Formatter - Keep intentional newlines when formatting comments This PR improves the HTML formatter so that it keeps at least one line (which usually are lines we want to keep intentionally) when formatting comments. --- lib/phoenix_live_view/html_algebra.ex | 38 ++++++++++++++----- lib/phoenix_live_view/html_formatter.ex | 7 +++- .../phoenix_live_view/html_formatter_test.exs | 36 ++++++++++++++++++ .../integrations/html_formatter_test.exs | 1 + 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/lib/phoenix_live_view/html_algebra.ex b/lib/phoenix_live_view/html_algebra.ex index 0b436da08d..65d65c4344 100644 --- a/lib/phoenix_live_view/html_algebra.ex +++ b/lib/phoenix_live_view/html_algebra.ex @@ -25,17 +25,37 @@ defmodule Phoenix.LiveView.HTMLAlgebra do concat(doc, next_doc) end) - force_unfit? = - Enum.any?(block, fn - {:text, text, %{newlines: newlines}} -> newlines > 0 or String.contains?(text, "\n") - _ -> false + {force_unfit?, meta} = + Enum.find_value(block, fn + {:text, text, meta} -> + {String.contains?(text, "\n"), meta} + + _ -> + {false, %{}} end) - if force_unfit? do - concat |> force_unfit() |> group() - else - concat |> group() - end + doc = + if force_unfit? do + concat |> force_unfit() |> group() + else + concat |> group() + end + + newline_or_empty_before_text = + if meta[:newlines_before_text] && meta[:newlines_before_text] > 1 do + line() + else + empty() + end + + newline_or_empty_after_text = + if meta[:newlines_after_text] && meta[:newlines_after_text] > 1 do + line() + else + empty() + end + + concat([newline_or_empty_before_text, doc, newline_or_empty_after_text]) end defp block_to_algebra([head | tail], context) do diff --git a/lib/phoenix_live_view/html_formatter.ex b/lib/phoenix_live_view/html_formatter.ex index 905da519f5..0d9c072ed8 100644 --- a/lib/phoenix_live_view/html_formatter.ex +++ b/lib/phoenix_live_view/html_formatter.ex @@ -446,7 +446,12 @@ defmodule Phoenix.LiveView.HTMLFormatter do stack, source ) do - to_tree(tokens, [{:html_comment, [{:text, String.trim(text), %{}}]} | buffer], stack, source) + meta = %{ + newlines_before_text: count_newlines_until_text(text, 0), + newlines_after_text: text |> String.reverse() |> count_newlines_until_text(0) + } + + to_tree(tokens, [{:html_comment, [{:text, String.trim(text), meta}]} | buffer], stack, source) end defp to_tree([{:text, text, _meta} | tokens], buffer, stack, source) do diff --git a/test/phoenix_live_view/html_formatter_test.exs b/test/phoenix_live_view/html_formatter_test.exs index f98216d032..a9eb0dd0eb 100644 --- a/test/phoenix_live_view/html_formatter_test.exs +++ b/test/phoenix_live_view/html_formatter_test.exs @@ -2100,6 +2100,42 @@ defmodule Phoenix.LiveView.HTMLFormatterTest do """) end + test "keep intentional lines breaks from HTML comments" do + assert_formatter_doesnt_change(""" +

Title

+ + +

Text

+ """) + + assert_formatter_doesnt_change(""" +

Title

+ + + +

Text

+ """) + + assert_formatter_output( + """ +

Title

+ + + + + +

Text

+ """, + """ +

Title

+ + + +

Text

+ """ + ) + end + # TODO: Remove this `if` when we require Elixir 1.14+ if function_exported?(EEx, :tokenize, 2) do test "handle EEx comments" do diff --git a/test/phoenix_live_view/integrations/html_formatter_test.exs b/test/phoenix_live_view/integrations/html_formatter_test.exs index e1c80e0de4..b36e13a5f6 100644 --- a/test/phoenix_live_view/integrations/html_formatter_test.exs +++ b/test/phoenix_live_view/integrations/html_formatter_test.exs @@ -95,6 +95,7 @@ defmodule Phoenix.LiveView.Integrations.HTMLFormatterTest do <% end %> +

Hello