Skip to content

Commit f552c02

Browse files
committed
templates & rendering improvements, in part copied from elixir-lang#1992
1 parent 6c3a809 commit f552c02

File tree

8 files changed

+51
-67
lines changed

8 files changed

+51
-67
lines changed

lib/ex_doc/formatter/markdown/templates.ex

+13-41
Original file line numberDiff line numberDiff line change
@@ -43,63 +43,35 @@ defmodule ExDoc.Formatter.MARKDOWN.Templates do
4343
@spec synopsis(nil) :: nil
4444
def synopsis(doc) when is_binary(doc) do
4545
case :binary.split(doc, "\n\n") do
46-
[left, _] -> String.trim_trailing(left, ": ")
46+
[left, _] -> String.trim_trailing(left, ": ") <> "\n\n"
4747
[all] -> all
4848
end
4949
end
50-
def synopsis(_), do: nil
51-
52-
@doc """
53-
Add link headings for the given `content`.
5450

55-
IDs are prefixed with `prefix`.
56-
57-
We only link `h2` and `h3` headers. This is kept consistent in ExDoc.SearchData.
58-
"""
59-
@heading_regex ~r/<(h[23]).*?>(.*?)<\/\1>/m
60-
@spec link_headings(String.t() | nil, String.t()) :: String.t() | nil
61-
def link_headings(content, prefix \\ "")
62-
def link_headings(nil, _), do: nil
51+
def synopsis(_), do: nil
6352

64-
def link_headings(content, prefix) do
53+
@heading_regex ~r/^(\#{1,6})\s+(.*)/m
54+
defp rewrite_headings(content) when is_binary(content) do
6555
@heading_regex
6656
|> Regex.scan(content)
67-
|> Enum.reduce({content, %{}}, fn [match, tag, title], {content, occurrences} ->
68-
possible_id = text_to_id(title)
69-
id_occurred = Map.get(occurrences, possible_id, 0)
70-
71-
anchor_id = if id_occurred >= 1, do: "#{possible_id}-#{id_occurred}", else: possible_id
72-
replacement = link_heading(match, tag, title, anchor_id, prefix)
73-
linked_content = String.replace(content, match, replacement, global: false)
74-
incremented_occs = Map.put(occurrences, possible_id, id_occurred + 1)
75-
{linked_content, incremented_occs}
57+
|> Enum.reduce(content, fn [match, level, title], content ->
58+
replacement = rewrite_heading(level, title)
59+
String.replace(content, match, replacement, global: false)
7660
end)
77-
|> elem(0)
7861
end
7962

80-
defp link_heading(match, _tag, _title, "", _prefix), do: match
63+
defp rewrite_headings(_), do: nil
8164

82-
defp link_heading(_match, _tag, title, id, prefix) do
83-
# The Markdown syntax that we support for the admonition text
84-
# blocks is something like this:
85-
#
86-
# > ### Never open this door! {: .warning}
87-
# >
88-
# > ...
89-
#
65+
defp rewrite_heading("#", title), do: do_rewrite_heading("#####", title)
66+
defp rewrite_heading(_, title), do: do_rewrite_heading("######", title)
9067

68+
defp do_rewrite_heading(level, title) do
9169
"""
92-
## [#{title}](##{prefix}#{id})
70+
#{level} #{title}
9371
"""
9472
end
9573

96-
def link_moduledoc_headings(content) do
97-
link_headings(content, "module-")
98-
end
99-
100-
def link_detail_headings(content, prefix) do
101-
link_headings(content, prefix <> "-")
102-
end
74+
defp enc(binary), do: URI.encode(binary) |> String.replace("/", "-")
10375

10476
@doc """
10577
Creates a chapter which contains all the details about an individual module.
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
1-
# <%=h node.signature %>
2-
3-
<%= if node.source_url do %>
4-
[View Source](<%= node.source_url %>)
5-
<% end %>
6-
7-
<%= for annotation <- node.annotations do %>
8-
> (<%= annotation %>)
9-
<% end %>
1+
<a id="<%= enc node.id %>"></a>
2+
#### `<%=h node.signature %>` <%= if node.source_url do %>[🔗](<%= node.source_url %>)<% end %> <%= for annotation <- node.annotations do %>(<%= annotation %>) <% end %>
103

114
<%= if deprecated = node.deprecated do %>
125
> This <%= node.type %> is deprecated. <%= h(deprecated) %>.
136
<% end %>
147

158
<%= if node.specs != [] do %>
16-
<%= for spec <- node.specs do %>
17-
> <%= H.format_spec_attribute(module, node) %>: <%= spec %>
9+
<%= for spec <- node.specs do %>
10+
> <%= H.format_spec_attribute(module, node) %> <%= spec %>
1811
<% end %>
1912
<% end %>
2013

21-
<%= link_detail_headings(node_doc(node), H.enc(node.id)) %>
14+
<%= rewrite_headings(node_doc(node)) %>
15+
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
1-
# <%= module.title %> <%= module_type(module) %>
1+
# <%= module.title %> <%= module_type(module) %> (<%= config.project %> v<%= config.version %>)
2+
3+
<%= for annotation <- module.annotations do %>*(<%= annotation %>)* <% end %>
24

35
<%= if deprecated = module.deprecated do %>
46
> This <%= module.type %> is deprecated. <%=h deprecated %>.
57
<% end %>
68

79
<%= if doc = node_doc(module) do %>
8-
<%= H.link_moduledoc_headings(doc) %>
10+
<%= doc %>
911
<% end %>
1012

1113
<%= if summary != [] do %>
12-
## Summary
14+
## Table of Contents
1315
<%= for {name, nodes} <- summary, do: summary_template(name, nodes) %>
1416
<% end %>
1517

18+
## Contents
19+
1620
<%= for {name, nodes} <- summary, _key = text_to_id(name) do %>
17-
## <%=h to_string(name) %>
18-
<%= for node <- nodes, do: detail_template(node, module) %>
21+
22+
### <%=h to_string(name) %>
23+
24+
<%= for node <- nodes do %>
25+
<%= detail_template(node, module) %>
26+
<% end %>
27+
1928
<% end %>
29+
30+
---
31+
32+
<%= if module.source_url do %>
33+
[<%= String.capitalize(to_string(module.type)) %> Source Code](<%= module.source_url %>)
34+
<% end %>
35+
2036
<%= before_closing_body_tag(config, :markdown) %>
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<%= unless Enum.empty?(nodes) do %>
22
- <%= name %>
33
<%= for node <- nodes do %>
4-
1. [<%=h node.title %>](<%= URI.encode node.id %>.md)
4+
- [<%=h node.title %>](<%= URI.encode node.id %>.md)
55
<% end %>
66
<% end %>

lib/ex_doc/formatter/markdown/templates/nav_template.eex

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Table of contents
1+
# <%= config.project %> v<%= config.version %> - Documentation - Table of contents
22

33
<%= nav_grouped_item_template config.extras %>
44
<%= unless Enum.empty?(nodes.modules) do %>
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
## <%= name %>
1+
### <%= name %>
2+
23
<%= for node <- nodes do %>
34

4-
### <%=h node.signature %>
5+
#### [`<%=h node.signature %>`](#<%= enc node.id %>)
56

67
<%= if deprecated = node.deprecated do %>
78
> <%= h(deprecated) %>
@@ -10,4 +11,5 @@
1011
<%= if doc = node_doc(node) do %>
1112
<%= synopsis(doc) %>
1213
<% end %>
14+
1315
<% end %>

test/ex_doc/formatter/markdown/templates_test.exs

+4-4
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,20 @@ defmodule ExDoc.Formatter.MARKDOWN.TemplatesTest do
5656

5757
assert content =~ ~r{#\s*CompiledWithDocs\s*}
5858

59-
assert content =~ ~s{# Summary</h1>}
59+
assert content =~ ~s{## Table of Contents}
6060

6161
assert content =~
62-
~r{## .*Example.*}ms
62+
~r{\n## .*Example.*}ms
6363

6464
assert content =~
65-
~r{### .*Example H3 heading.*}ms
65+
~r{\n### .*Example H3 heading.*}ms
6666

6767
assert content =~
6868
~r{moduledoc.*Example.*CompiledWithDocs\.example.*}ms
6969

7070
assert content =~ ~r{Some example}ms
7171
assert content =~ ~r{example_without_docs().*}ms
72-
assert content =~ ~r{example_1().*> \(macro\)}ms
72+
assert content =~ ~r{example_1().* \(macro\)}ms
7373

7474
assert content =~ ~s{example(foo, bar \\\\ Baz)}
7575
end

test/ex_doc/formatter/markdown_test.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ defmodule ExDoc.Formatter.MARKDOWNTest do
7272
~r{\n`TypesAndSpecs.Sub`\n}
7373

7474
content = File.read!(tmp_dir <> "/markdown/index.md")
75-
assert content =~ "# Table of contents\n\n - [README](readme.md)"
75+
assert content =~ "Table of contents\n\n - [README](readme.md)"
7676
end
7777
end

0 commit comments

Comments
 (0)