diff --git a/lib/floki/html_tree.ex b/lib/floki/html_tree.ex
index 69d732bd..53c48776 100644
--- a/lib/floki/html_tree.ex
+++ b/lib/floki/html_tree.ex
@@ -328,4 +328,77 @@ defmodule Floki.HTMLTree do
do_reduce(tree, fun.(head_node, acc), fun)
end
end
+
+ defimpl Inspect do
+ import Inspect.Algebra
+
+ def inspect(html_tree, opts) do
+ open = "#Floki.HTMLTree["
+ close = "]"
+ container_opts = [separator: "", break: :flex]
+
+ container_doc(
+ open,
+ nodes_with_tree(html_tree, html_tree.root_nodes_ids),
+ close,
+ opts,
+ &fun/2,
+ container_opts
+ )
+ end
+
+ defp fun({html_tree, %HTMLNode{} = html_node}, opts) do
+ {open, close, container_opts} = build_node(html_node, opts)
+
+ container_doc(
+ open,
+ nodes_with_tree(html_tree, html_node.children_nodes_ids),
+ close,
+ opts,
+ &fun/2,
+ container_opts
+ )
+ end
+
+ defp fun(%Comment{content: comment}, opts),
+ do: color(concat([""]), :comment, opts)
+
+ defp fun(%Text{content: text}, opts), do: color(text, :string, opts)
+
+ defp nodes_with_tree(html_tree, nodes_ids) do
+ nodes_ids
+ |> Enum.reverse()
+ |> Enum.map(fn node_id ->
+ with %HTMLNode{} = html_node <- Map.get(html_tree.nodes, node_id) do
+ {html_tree, html_node}
+ end
+ end)
+ end
+
+ defp build_node(%HTMLNode{} = node, opts) do
+ tag_color = :map
+ attribute_color = :map
+
+ built_attributes =
+ for {name, value} <- node.attributes do
+ concat([
+ color(" #{name}=", attribute_color, opts),
+ color("\"#{value}\"", :string, opts)
+ ])
+ end
+ |> concat()
+
+ open =
+ concat([
+ color("<#{node.type}", tag_color, opts),
+ built_attributes,
+ color(">", tag_color, opts)
+ ])
+
+ close = color("#{node.type}>", tag_color, opts)
+ container_opts = [separator: "", break: :strict]
+
+ {open, close, container_opts}
+ end
+ end
end
diff --git a/test/floki/html_tree_test.exs b/test/floki/html_tree_test.exs
index 572233af..2db89ee7 100644
--- a/test/floki/html_tree_test.exs
+++ b/test/floki/html_tree_test.exs
@@ -256,4 +256,42 @@ defmodule Floki.HTMLTreeTest do
refute Enum.member?(html_tree, %{html_node3 | type: "marquee"})
refute Enum.member?(html_tree, 42)
end
+
+ test "inspect works with HTMLTree" do
+ html_tree = %HTMLTree{
+ root_nodes_ids: [1],
+ node_ids: [1],
+ nodes: %{
+ 1 => %Text{content: "hello world", node_id: 1}
+ }
+ }
+
+ assert inspect(html_tree) ==
+ ~s|#Floki.HTMLTree[hello world]|
+ end
+
+ test "inspect works with HTMLTree with nested nodes" do
+ html_tree =
+ %HTMLTree{
+ root_nodes_ids: [1],
+ node_ids: [6, 5, 4, 3, 2, 1],
+ nodes: %{
+ 1 => %HTMLNode{type: "html", children_nodes_ids: [6, 3, 2], node_id: 1},
+ 2 => %Comment{content: "start of the stack", node_id: 2, parent_node_id: 1},
+ 3 => %HTMLNode{
+ type: "a",
+ attributes: [{"class", "link"}],
+ parent_node_id: 1,
+ children_nodes_ids: [4],
+ node_id: 3
+ },
+ 4 => %HTMLNode{type: "b", parent_node_id: 3, children_nodes_ids: [5], node_id: 4},
+ 5 => %Text{content: "click me", parent_node_id: 4, node_id: 5},
+ 6 => %HTMLNode{type: "span", parent_node_id: 1, node_id: 6}
+ }
+ }
+
+ assert inspect(html_tree) ==
+ ~s|#Floki.HTMLTree[ click me ]|
+ end
end