Skip to content

Commit 8552c49

Browse files
committed
Compute synopsis using AST
Closes #2108. Closes #2110.
1 parent 009bc89 commit 8552c49

File tree

6 files changed

+72
-66
lines changed

6 files changed

+72
-66
lines changed

lib/ex_doc/doc_ast.ex

+31
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,37 @@ defmodule ExDoc.DocAST do
110110
def extract_title([{:h1, _attrs, inner, _meta} | ast]), do: {:ok, inner, ast}
111111
def extract_title(_ast), do: :error
112112

113+
@doc """
114+
Compute a synopsis from a document by looking at its first paragraph.
115+
"""
116+
def synopsis({:p, _attrs, [_ | _] = inner, meta}) do
117+
inner =
118+
case Enum.split(inner, -1) do
119+
{pre, [post]} when is_binary(post) ->
120+
pre ++ [String.trim_trailing(post, ":")]
121+
122+
_ ->
123+
inner
124+
end
125+
126+
ExDoc.DocAST.to_string({:p, [], remove_ids(inner), meta})
127+
end
128+
129+
def synopsis([head | _]), do: synopsis(head)
130+
def synopsis(_other), do: ""
131+
132+
@doc """
133+
Remove ids from elements.
134+
"""
135+
def remove_ids({tag, attrs, inner, meta}),
136+
do: {tag, Keyword.delete(attrs, :href), remove_ids(inner), meta}
137+
138+
def remove_ids(list) when is_list(list),
139+
do: Enum.map(list, &remove_ids/1)
140+
141+
def remove_ids(other),
142+
do: other
143+
113144
@doc """
114145
Returns text content from the given AST.
115146
"""

lib/ex_doc/formatter/html/templates.ex

-24
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,6 @@ defmodule ExDoc.Formatter.HTML.Templates do
4141
def module_type(%{type: :module}), do: ""
4242
def module_type(%{type: type}), do: "<small>#{type}</small>"
4343

44-
@doc """
45-
Gets the first paragraph of the documentation of a node. It strips
46-
surrounding white-spaces and trailing `:`.
47-
48-
If `doc` is `nil`, it returns `nil`.
49-
"""
50-
@spec synopsis(String.t()) :: String.t()
51-
@spec synopsis(nil) :: nil
52-
def synopsis(nil), do: nil
53-
54-
def synopsis(doc) when is_binary(doc) do
55-
doc =
56-
case :binary.split(doc, "</p>") do
57-
[left, _] -> String.trim_trailing(left, ":") <> "</p>"
58-
[all] -> all
59-
end
60-
61-
# Remove any anchors found in synopsis.
62-
# Old Erlang docs placed anchors at the top of the documentation
63-
# for links. Ideally they would have been removed but meanwhile
64-
# it is simpler to guarantee they won't be duplicated in docs.
65-
Regex.replace(~r|(<[^>]*) id="[^"]*"([^>]*>)|, doc, ~S"\1\2", [])
66-
end
67-
6844
defp enc(binary), do: URI.encode(binary)
6945

7046
@doc """

lib/ex_doc/formatter/html/templates/api_reference_entry_template.eex

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<span class="deprecated" title="<%= h(deprecated) %>">deprecated</span>
66
<% end %>
77
</div>
8-
<%= if doc = module_node.rendered_doc do %>
9-
<div class="summary-synopsis"><%= synopsis(doc) %></div>
8+
<%= if doc = module_node.doc do %>
9+
<div class="summary-synopsis"><%= ExDoc.DocAST.synopsis(doc) %></div>
1010
<% end %>
1111
</div>

lib/ex_doc/formatter/html/templates/summary_template.eex

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
<span class="deprecated" title="<%= h(deprecated) %>">deprecated</span>
1111
<% end %>
1212
</div>
13-
<%= if doc = node.rendered_doc do %>
14-
<div class="summary-synopsis"><%= synopsis(doc) %></div>
13+
<%= if doc = node.doc do %>
14+
<div class="summary-synopsis"><%= ExDoc.DocAST.synopsis(doc) %></div>
1515
<% end %>
1616
</div>
1717
<% end %>

test/ex_doc/doc_ast_test.exs

+37-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ defmodule ExDoc.DocASTTest do
104104

105105
test "void elements" do
106106
markdown = """
107-
foo
107+
foo\s\s
108108
bar
109109
"""
110110

@@ -114,6 +114,42 @@ defmodule ExDoc.DocASTTest do
114114
end
115115
end
116116

117+
describe "synopsis" do
118+
test "functionality" do
119+
assert synopsis("") == ""
120+
assert synopsis("<p>.</p>") == "<p>.</p>"
121+
assert synopsis("<p>::</p>") == "<p></p>"
122+
assert synopsis("<p>Description:</p>") == "<p>Description</p>"
123+
assert synopsis("<p>abcd</p>") == "<p>abcd</p>"
124+
end
125+
126+
test "should not end have trailing periods or semicolons" do
127+
doc1 = """
128+
Summaries should not be displayed with trailing semicolons :
129+
130+
## Example
131+
"""
132+
133+
doc2 = """
134+
Example function: Summary should display trailing period :.
135+
136+
## Example:
137+
"""
138+
139+
assert synopsis(doc1) ==
140+
"<p>Summaries should not be displayed with trailing semicolons </p>"
141+
142+
assert synopsis(doc2) ==
143+
"<p>Example function: Summary should display trailing period :.</p>"
144+
end
145+
146+
defp synopsis(markdown) do
147+
markdown
148+
|> ExDoc.DocAST.parse!("text/markdown")
149+
|> ExDoc.DocAST.synopsis()
150+
end
151+
end
152+
117153
describe "highlight" do
118154
test "with default class" do
119155
# Empty class

test/ex_doc/formatter/html/templates_test.exs

-37
Original file line numberDiff line numberDiff line change
@@ -161,43 +161,6 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
161161
end
162162
end
163163

164-
describe "synopsis" do
165-
test "functionality" do
166-
assert Templates.synopsis(nil) == nil
167-
assert Templates.synopsis("") == ""
168-
assert Templates.synopsis("<p>.</p>") == "<p>.</p>"
169-
assert Templates.synopsis("<p>::</p>") == "<p></p>"
170-
assert Templates.synopsis("<p>Description:</p>") == "<p>Description</p>"
171-
assert Templates.synopsis("<p>abcd</p>") == "<p>abcd</p>"
172-
end
173-
174-
test "should not end have trailing periods or semicolons" do
175-
doc1 = """
176-
Summaries should not be displayed with trailing semicolons :
177-
178-
## Example
179-
"""
180-
181-
doc2 = """
182-
Example function: Summary should display trailing period :.
183-
184-
## Example:
185-
"""
186-
187-
assert Templates.synopsis(to_html(doc1)) ==
188-
"<p>Summaries should not be displayed with trailing semicolons </p>"
189-
190-
assert Templates.synopsis(to_html(doc2)) ==
191-
"<p>Example function: Summary should display trailing period :.</p>"
192-
end
193-
end
194-
195-
defp to_html(markdown) do
196-
markdown
197-
|> ExDoc.DocAST.parse!("text/markdown")
198-
|> ExDoc.DocAST.to_string()
199-
end
200-
201164
describe "sidebar" do
202165
test "text links to homepage_url when set", context do
203166
content = Templates.sidebar_template(doc_config(context), :extra)

0 commit comments

Comments
 (0)